diff --git a/modules/home/programs/opencode/default.nix b/modules/home/programs/opencode/default.nix index f3389f1..5ce41c2 100755 --- a/modules/home/programs/opencode/default.nix +++ b/modules/home/programs/opencode/default.nix @@ -37,8 +37,8 @@ in baseURL = "http://${net.hosts.nas.lan}:${toString net.ports.nas.llamaCpp}/v1"; }; models = { - Qwen3-Coder-Next-Q4_0 = { - name = "Qwen3 Coder (local)"; + "gemma-4-26B-A4B-it-UD-Q8_K_XL" = { + name = "Gemma 4 26B-A4B (local)"; modalities = { input = [ "image" @@ -47,8 +47,8 @@ in output = [ "text" ]; }; limit = { - context = 131072; - output = 32768; + context = 32768; + output = 8192; }; }; }; diff --git a/modules/nixos/homeassistant/services/esphome/bedroom.yaml b/modules/nixos/homeassistant/services/esphome/bedroom.yaml new file mode 100644 index 0000000..c75536b --- /dev/null +++ b/modules/nixos/homeassistant/services/esphome/bedroom.yaml @@ -0,0 +1,202 @@ +############################################################ +# SmartDisplay – Bedroom +# Tiles: Lights | Lamp | Fan | Air Purifier | Closet | BedJet +############################################################ + +substitutions: + + DIRECT_ACTIONS: "true" + ROOM_NAME: "Bedroom" + TIME_24H: "false" + + # ── TILE 1 – Bedroom Lights (group) ───────────────────── + TILE1_ENTITY: "light.bedroom_lights" + TILE1_STATE_ENTITY: "light.bedroom_light_1" + TILE1_TITLE: "Lights" + TILE1_ICON: "\U000F0769" + TILE1_TYPE: "light" + TILE1_TAP_ACTION: "toggle" + TILE1_LONGPRESS: "auto" + TILE1_VALUE_MODE: "auto" + TILE1_LABEL_OFF: "Off" + TILE1_LABEL_ON: "On" + TILE1_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE1_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE1_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE1_ICON_DISABLED_COLOR: "0xFEC600" + TILE1_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE1_BG_DISABLED_COLOR: "0x939391" + TILE1_TITLE_ACTIVE_COLOR: "0x000000" + TILE1_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE1_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE1_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE1_TAP_SERVICE: "" + TILE1_TAP_PARAM_KEY: "" + TILE1_TAP_PARAM_VAL: "" + TILE1_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 2 – Bedroom Lamp ──────────────────────────────── + TILE2_ENTITY: "light.bedroom_lamp" + TILE2_STATE_ENTITY: "light.bedroom_lamp" + TILE2_TITLE: "Lamp" + TILE2_ICON: "\U000F06B5" + TILE2_TYPE: "light" + TILE2_TAP_ACTION: "auto" + TILE2_LONGPRESS: "auto" + TILE2_VALUE_MODE: "auto" + TILE2_LABEL_OFF: "Off" + TILE2_LABEL_ON: "On" + TILE2_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE2_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE2_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE2_ICON_DISABLED_COLOR: "0xFEC600" + TILE2_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE2_BG_DISABLED_COLOR: "0x939391" + TILE2_TITLE_ACTIVE_COLOR: "0x000000" + TILE2_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE2_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE2_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE2_TAP_SERVICE: "" + TILE2_TAP_PARAM_KEY: "" + TILE2_TAP_PARAM_VAL: "" + TILE2_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 3 – Bedroom Fan ───────────────────────────────── + TILE3_ENTITY: "fan.bedroom_fan" + TILE3_STATE_ENTITY: "fan.bedroom_fan" + TILE3_TITLE: "Bedroom Fan" + TILE3_ICON: "\U000F0210" + TILE3_TYPE: "fan" + TILE3_TAP_ACTION: "fan_toggle_preset" + TILE3_LONGPRESS: "auto" + TILE3_VALUE_MODE: "auto" + TILE3_LABEL_OFF: "Off" + TILE3_LABEL_ON: "On" + TILE3_CIRCLE_ACTIVE_COLOR: "0x00C5EC" + TILE3_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE3_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE3_ICON_DISABLED_COLOR: "0x00C5EC" + TILE3_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE3_BG_DISABLED_COLOR: "0x939391" + TILE3_TITLE_ACTIVE_COLOR: "0x000000" + TILE3_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE3_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE3_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE3_TAP_SERVICE: "fan.toggle" + TILE3_TAP_PARAM_KEY: "" + TILE3_TAP_PARAM_VAL: "" + TILE3_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 4 – Air Purifier ──────────────────────────────── + TILE4_ENTITY: "fan.bedroom_air_purifier" + TILE4_STATE_ENTITY: "fan.bedroom_air_purifier" + TILE4_TITLE: "Air Purifier" + TILE4_ICON: "\U000F0D43" + TILE4_TYPE: "fan" + TILE4_TAP_ACTION: "fan_toggle_preset" + TILE4_LONGPRESS: "auto" + TILE4_VALUE_MODE: "auto" + TILE4_LABEL_OFF: "Off" + TILE4_LABEL_ON: "On" + TILE4_CIRCLE_ACTIVE_COLOR: "0x00C5EC" + TILE4_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE4_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE4_ICON_DISABLED_COLOR: "0x00C5EC" + TILE4_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE4_BG_DISABLED_COLOR: "0x939391" + TILE4_TITLE_ACTIVE_COLOR: "0x000000" + TILE4_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE4_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE4_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE4_TAP_SERVICE: "fan.toggle" + TILE4_TAP_PARAM_KEY: "preset_mode" + TILE4_TAP_PARAM_VAL: "auto" + TILE4_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 5 – Front Closet Lights ──────────────────────── + TILE5_ENTITY: "light.front_closet_lights" + TILE5_STATE_ENTITY: "light.front_closet_light_1" + TILE5_TITLE: "Closet" + TILE5_ICON: "\U000F1051" + TILE5_TYPE: "light" + TILE5_TAP_ACTION: "toggle" + TILE5_LONGPRESS: "none" + TILE5_VALUE_MODE: "auto" + TILE5_LABEL_OFF: "Off" + TILE5_LABEL_ON: "On" + TILE5_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE5_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE5_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE5_ICON_DISABLED_COLOR: "0xFEC600" + TILE5_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE5_BG_DISABLED_COLOR: "0x939391" + TILE5_TITLE_ACTIVE_COLOR: "0x000000" + TILE5_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE5_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE5_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE5_TAP_SERVICE: "" + TILE5_TAP_PARAM_KEY: "" + TILE5_TAP_PARAM_VAL: "" + TILE5_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 6 – BedJet ───────────────────────────────────── + TILE6_ENTITY: "fan.bedjet_dbbf_c222" + TILE6_STATE_ENTITY: "fan.bedjet_dbbf_c222" + TILE6_TITLE: "BedJet" + TILE6_ICON: "\U000F07E4" + TILE6_TYPE: "fan" + TILE6_TAP_ACTION: "toggle" + TILE6_LONGPRESS: "auto" + TILE6_VALUE_MODE: "percentage" + TILE6_LABEL_OFF: "Off" + TILE6_LABEL_ON: "On" + TILE6_CIRCLE_ACTIVE_COLOR: "0xFF6B35" + TILE6_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE6_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE6_ICON_DISABLED_COLOR: "0xFF6B35" + TILE6_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE6_BG_DISABLED_COLOR: "0x939391" + TILE6_TITLE_ACTIVE_COLOR: "0x000000" + TILE6_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE6_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE6_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE6_TAP_SERVICE: "fan.toggle" + TILE6_TAP_PARAM_KEY: "" + TILE6_TAP_PARAM_VAL: "" + TILE6_LONGPRESS_OFF_VALUE: "0" + +packages: + hw: !include cyd-base-hw.yaml + ui: !include cyd-base-ui.yaml + +esphome: + name: bedroom-display + friendly_name: BedroomDisplay + on_boot: + priority: 600 + then: + - script.execute: ui_refresh + +esp32: + board: esp32dev + framework: + type: arduino + +logger: + +api: + encryption: + key: !secret api_encryption_key + +ota: + - platform: esphome + password: !secret ota_password + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + ap: + ssid: "BedroomDisplay Fallback" + password: !secret ota_password + +captive_portal: diff --git a/modules/nixos/homeassistant/services/esphome/cyd-base-hw.yaml b/modules/nixos/homeassistant/services/esphome/cyd-base-hw.yaml new file mode 100644 index 0000000..7faeb82 --- /dev/null +++ b/modules/nixos/homeassistant/services/esphome/cyd-base-hw.yaml @@ -0,0 +1,312 @@ +############################################################ +# CYD Base – Hardware layer +# ESP32-2432S028 (Cheap Yellow Display) +# Include via: packages: !include cyd-base-hw.yaml +############################################################ + +time: + - platform: homeassistant + id: homeassistant_time + on_time: + - seconds: 0 + minutes: /1 + then: + - script.execute: ui_refresh + +globals: + - id: active_entity + type: std::string + restore_value: no + - id: active_control_kind + type: std::string + restore_value: no + - id: active_value_suffix + type: std::string + restore_value: no + - id: overlay_slider_bg_color + type: uint32_t + restore_value: no + initial_value: '0x939391' + - id: overlay_slider_fill_color + type: uint32_t + restore_value: no + initial_value: '0xFEC600' + +font: + - file: "gfonts://Roboto@500" + id: time_label + size: 18 + bpp: 4 + glyphs: ['0','1','2','3','4','5','6','7','8','9',':',' ','A','M','P'] + + - file: "gfonts://Roboto@500" + id: headline + size: 18 + bpp: 4 + glyphs: ['&','@','!',',','.','?','"','%','(',')','+','-','_',':','°', + '0','1','2','3','4','5','6','7','8','9', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + ' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + 'ä','ö','ü','Ä','Ö','Ü','ß','/'] + + - file: "gfonts://Roboto@700" + id: label + size: 11 + bpp: 4 + glyphs: ['&','@','!',',','.','?','"','%','(',')','+','-','_',':','°', + '0','1','2','3','4','5','6','7','8','9', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + ' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + 'ä','ö','ü','Ä','Ö','Ü','ß','/'] + + - file: "gfonts://Roboto@400" + id: sublabel + size: 11 + bpp: 4 + glyphs: ['&','@','!',',','.','?','"','%','(',')','+','-','_',':','°', + '0','1','2','3','4','5','6','7','8','9', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + ' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + 'ä','ö','ü','Ä','Ö','Ü','ß','/','…'] + + - file: "gfonts://Roboto@400" + id: sublabel_big + size: 14 + bpp: 4 + glyphs: ['&','@','!',',','.','?','"','%','(',')','+','-','_',':','°', + '0','1','2','3','4','5','6','7','8','9', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + ' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + 'ä','ö','ü','Ä','Ö','Ü','ß','/','…'] + + - file: 'fonts/materialdesignicons-webfont.ttf' + id: materialdesign_icons + size: 28 + glyphs: + - "${TILE1_ICON}" + - "${TILE2_ICON}" + - "${TILE3_ICON}" + - "${TILE4_ICON}" + - "${TILE5_ICON}" + - "${TILE6_ICON}" + +image: + - file: "images/home-background.png" + id: bg_home + type: RGB565 + +sensor: + - platform: wifi_signal + name: "Wifi Signal" + update_interval: 600s + - platform: uptime + name: "Uptime" + id: uptime_s + update_interval: 15s + - platform: homeassistant + id: tile1_brightness + entity_id: ${TILE1_ENTITY} + attribute: brightness + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile1_percentage + entity_id: ${TILE1_ENTITY} + attribute: percentage + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile2_brightness + entity_id: ${TILE2_ENTITY} + attribute: brightness + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile2_percentage + entity_id: ${TILE2_ENTITY} + attribute: percentage + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile3_brightness + entity_id: ${TILE3_ENTITY} + attribute: brightness + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile3_percentage + entity_id: ${TILE3_ENTITY} + attribute: percentage + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile4_brightness + entity_id: ${TILE4_ENTITY} + attribute: brightness + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile4_percentage + entity_id: ${TILE4_ENTITY} + attribute: percentage + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile5_brightness + entity_id: ${TILE5_ENTITY} + attribute: brightness + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile5_percentage + entity_id: ${TILE5_ENTITY} + attribute: percentage + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile6_brightness + entity_id: ${TILE6_ENTITY} + attribute: brightness + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile6_percentage + entity_id: ${TILE6_ENTITY} + attribute: percentage + on_value: { then: [ script.execute: ui_refresh ] } + +binary_sensor: + - platform: status + name: "Node Status" + id: system_status + - platform: homeassistant + id: ha_state_tile1 + entity_id: ${TILE1_STATE_ENTITY} + on_state: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: ha_state_tile2 + entity_id: ${TILE2_STATE_ENTITY} + on_state: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: ha_state_tile3 + entity_id: ${TILE3_STATE_ENTITY} + on_state: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: ha_state_tile4 + entity_id: ${TILE4_STATE_ENTITY} + on_state: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: ha_state_tile5 + entity_id: ${TILE5_STATE_ENTITY} + on_state: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: ha_state_tile6 + entity_id: ${TILE6_STATE_ENTITY} + on_state: { then: [ script.execute: ui_refresh ] } + +text_sensor: + - platform: template + id: smartdisplay_action + name: "${ROOM_NAME} Action" + icon: mdi:gesture-tap-button + - platform: homeassistant + id: tile1_preset + entity_id: ${TILE1_ENTITY} + attribute: preset_mode + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile2_preset + entity_id: ${TILE2_ENTITY} + attribute: preset_mode + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile3_preset + entity_id: ${TILE3_ENTITY} + attribute: preset_mode + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile4_preset + entity_id: ${TILE4_ENTITY} + attribute: preset_mode + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile5_preset + entity_id: ${TILE5_ENTITY} + attribute: preset_mode + on_value: { then: [ script.execute: ui_refresh ] } + - platform: homeassistant + id: tile6_preset + entity_id: ${TILE6_ENTITY} + attribute: preset_mode + on_value: { then: [ script.execute: ui_refresh ] } + +switch: + - platform: restart + name: "Restart" + +spi: + - id: lcd + clk_pin: GPIO14 + mosi_pin: GPIO13 + miso_pin: GPIO12 + - id: my_touchscreen + clk_pin: GPIO25 + mosi_pin: GPIO32 + miso_pin: GPIO39 + +output: + - platform: ledc + pin: GPIO21 + id: gpio_backlight_pwm + - platform: ledc + id: output_red + pin: GPIO4 + inverted: true + - platform: ledc + id: output_green + pin: GPIO16 + inverted: true + - platform: ledc + id: output_blue + pin: GPIO17 + inverted: true + +light: + - platform: monochromatic + output: gpio_backlight_pwm + name: "Power Display Backlight" + id: back_light + restore_mode: ALWAYS_ON + - platform: rgb + name: LED + red: output_red + id: led + green: output_green + blue: output_blue + restore_mode: ALWAYS_OFF + +touchscreen: + platform: xpt2046 + id: ts_touch + spi_id: my_touchscreen + cs_pin: 33 + interrupt_pin: 36 + update_interval: 20ms + threshold: 300 + calibration: + x_min: 280 + x_max: 3860 + y_min: 340 + y_max: 3860 + transform: + swap_xy: true + mirror_x: false + mirror_y: false + +display: + - platform: ili9xxx + id: my_display + spi_id: lcd + model: ILI9341 + color_palette: 8BIT + cs_pin: 15 + dc_pin: 2 + invert_colors: false + update_interval: never + auto_clear_enabled: false + transform: + swap_xy: true + mirror_x: false + mirror_y: false + dimensions: + width: 320 + height: 240 diff --git a/modules/nixos/homeassistant/services/esphome/cyd-base-ui.yaml b/modules/nixos/homeassistant/services/esphome/cyd-base-ui.yaml new file mode 100644 index 0000000..04f7ed0 --- /dev/null +++ b/modules/nixos/homeassistant/services/esphome/cyd-base-ui.yaml @@ -0,0 +1,1074 @@ +############################################################ +# CYD Base – LVGL UI + scripts layer +# Include via: packages: !include cyd-base-ui.yaml +############################################################ + +lvgl: + displays: + - my_display + touchscreens: + - touchscreen_id: ts_touch + + 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: 0x939391 + 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 diff --git a/modules/nixos/homeassistant/services/esphome/home-like.yaml b/modules/nixos/homeassistant/services/esphome/home-like.yaml new file mode 100644 index 0000000..bfc1bf7 --- /dev/null +++ b/modules/nixos/homeassistant/services/esphome/home-like.yaml @@ -0,0 +1,207 @@ +############################################################ +# SmartDisplay – iOS Home app–inspired Tiles UI +# Target device: ESP32-2432S028 / Cheap Yellow Display (CYD) +# +# Edit the substitutions below, then flash. +# All shared hardware/UI logic lives in: +# cyd-base-hw.yaml – sensors, fonts, SPI, display, touch +# cyd-base-ui.yaml – LVGL layout, scripts +############################################################ + +substitutions: + + DIRECT_ACTIONS: "true" + ROOM_NAME: "Bedroom" + TIME_24H: "false" + + # ── TILE 1 ────────────────────────────────────────────── + TILE1_ENTITY: "light.bedroom_lights" + TILE1_STATE_ENTITY: "light.bedroom_light_1" + TILE1_TITLE: "Lights" + TILE1_ICON: "\U000F0769" + TILE1_TYPE: "light" + TILE1_TAP_ACTION: "toggle" + TILE1_LONGPRESS: "auto" + TILE1_VALUE_MODE: "auto" + TILE1_LABEL_OFF: "Off" + TILE1_LABEL_ON: "On" + TILE1_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE1_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE1_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE1_ICON_DISABLED_COLOR: "0xFEC600" + TILE1_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE1_BG_DISABLED_COLOR: "0x939391" + TILE1_TITLE_ACTIVE_COLOR: "0x000000" + TILE1_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE1_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE1_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE1_TAP_SERVICE: "" + TILE1_TAP_PARAM_KEY: "" + TILE1_TAP_PARAM_VAL: "" + TILE1_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 2 ────────────────────────────────────────────── + TILE2_ENTITY: "light.bedroom_lamp" + TILE2_STATE_ENTITY: "light.bedroom_lamp" + TILE2_TITLE: "Lamp" + TILE2_ICON: "\U000F06B5" + TILE2_TYPE: "light" + TILE2_TAP_ACTION: "auto" + TILE2_LONGPRESS: "auto" + TILE2_VALUE_MODE: "auto" + TILE2_LABEL_OFF: "Off" + TILE2_LABEL_ON: "On" + TILE2_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE2_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE2_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE2_ICON_DISABLED_COLOR: "0xFEC600" + TILE2_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE2_BG_DISABLED_COLOR: "0x939391" + TILE2_TITLE_ACTIVE_COLOR: "0x000000" + TILE2_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE2_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE2_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE2_TAP_SERVICE: "" + TILE2_TAP_PARAM_KEY: "" + TILE2_TAP_PARAM_VAL: "" + TILE2_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 3 ────────────────────────────────────────────── + TILE3_ENTITY: "light.living_room_lights" + TILE3_STATE_ENTITY: "light.living_room_lights" + TILE3_TITLE: "Living Room" + TILE3_ICON: "\U000F08DD" + TILE3_TYPE: "light" + TILE3_TAP_ACTION: "auto" + TILE3_LONGPRESS: "auto" + TILE3_VALUE_MODE: "auto" + TILE3_LABEL_OFF: "Off" + TILE3_LABEL_ON: "On" + TILE3_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE3_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE3_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE3_ICON_DISABLED_COLOR: "0xFEC600" + TILE3_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE3_BG_DISABLED_COLOR: "0x939391" + TILE3_TITLE_ACTIVE_COLOR: "0x000000" + TILE3_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE3_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE3_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE3_TAP_SERVICE: "" + TILE3_TAP_PARAM_KEY: "" + TILE3_TAP_PARAM_VAL: "" + TILE3_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 4 ────────────────────────────────────────────── + TILE4_ENTITY: "switch.closet_lights" + TILE4_STATE_ENTITY: "switch.closet_lights" + TILE4_TITLE: "Closet Lights" + TILE4_ICON: "\U000F1051" + TILE4_TYPE: "light" + TILE4_TAP_ACTION: "auto" + TILE4_LONGPRESS: "auto" + TILE4_VALUE_MODE: "auto" + TILE4_LABEL_OFF: "Off" + TILE4_LABEL_ON: "On" + TILE4_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE4_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE4_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE4_ICON_DISABLED_COLOR: "0xFEC600" + TILE4_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE4_BG_DISABLED_COLOR: "0x939391" + TILE4_TITLE_ACTIVE_COLOR: "0x000000" + TILE4_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE4_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE4_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE4_TAP_SERVICE: "" + TILE4_TAP_PARAM_KEY: "" + TILE4_TAP_PARAM_VAL: "" + TILE4_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 5 ────────────────────────────────────────────── + TILE5_ENTITY: "fan.bedroom_fan" + TILE5_STATE_ENTITY: "fan.bedroom_fan" + TILE5_TITLE: "Bedroom Fan" + TILE5_ICON: "\U000F0210" + TILE5_TYPE: "fan" + TILE5_TAP_ACTION: "auto" + TILE5_LONGPRESS: "auto" + TILE5_VALUE_MODE: "auto" + TILE5_LABEL_OFF: "Off" + TILE5_LABEL_ON: "On" + TILE5_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE5_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE5_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE5_ICON_DISABLED_COLOR: "0xFEC600" + TILE5_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE5_BG_DISABLED_COLOR: "0x939391" + TILE5_TITLE_ACTIVE_COLOR: "0x000000" + TILE5_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE5_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE5_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE5_TAP_SERVICE: "" + TILE5_TAP_PARAM_KEY: "" + TILE5_TAP_PARAM_VAL: "" + TILE5_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 6 ────────────────────────────────────────────── + TILE6_ENTITY: "fan.bedroom_air_purifier" + TILE6_STATE_ENTITY: "fan.bedroom_air_purifier" + TILE6_TITLE: "Air Purifier" + TILE6_ICON: "\U000F0D43" + TILE6_TYPE: "fan" + TILE6_TAP_ACTION: "fan_toggle_preset" + TILE6_LONGPRESS: "auto" + TILE6_VALUE_MODE: "auto" + TILE6_LABEL_OFF: "Off" + TILE6_LABEL_ON: "On" + TILE6_CIRCLE_ACTIVE_COLOR: "0x00C5EC" + TILE6_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE6_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE6_ICON_DISABLED_COLOR: "0x00C5EC" + TILE6_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE6_BG_DISABLED_COLOR: "0x939391" + TILE6_TITLE_ACTIVE_COLOR: "0x000000" + TILE6_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE6_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE6_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE6_TAP_SERVICE: "fan.toggle" + TILE6_TAP_PARAM_KEY: "preset_mode" + TILE6_TAP_PARAM_VAL: "Auto" + TILE6_LONGPRESS_OFF_VALUE: "0" + +packages: + hw: !include cyd-base-hw.yaml + ui: !include cyd-base-ui.yaml + +esphome: + name: smartdisplay + friendly_name: SmartDisplay + on_boot: + priority: 600 + then: + - script.execute: ui_refresh + +esp32: + board: esp32dev + framework: + type: arduino + +logger: + +api: + encryption: + key: !secret api_encryption_key + +ota: + - platform: esphome + password: !secret ota_password + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + ap: + ssid: "Smartdisplay Fallback" + password: !secret ota_password + +captive_portal: diff --git a/modules/nixos/homeassistant/services/esphome/living-room.yaml b/modules/nixos/homeassistant/services/esphome/living-room.yaml new file mode 100644 index 0000000..67b1ac1 --- /dev/null +++ b/modules/nixos/homeassistant/services/esphome/living-room.yaml @@ -0,0 +1,202 @@ +############################################################ +# SmartDisplay – Living Room +# Tiles: Lights | Air Purifier | Vacuum | TV | Speaker | Closet +############################################################ + +substitutions: + + DIRECT_ACTIONS: "true" + ROOM_NAME: "Living Room" + TIME_24H: "false" + + # ── TILE 1 – Living Room Lights ────────────────────────── + TILE1_ENTITY: "light.living_room_lights" + TILE1_STATE_ENTITY: "light.living_room_light_1" + TILE1_TITLE: "Lights" + TILE1_ICON: "\U000F08DD" + TILE1_TYPE: "light" + TILE1_TAP_ACTION: "toggle" + TILE1_LONGPRESS: "auto" + TILE1_VALUE_MODE: "auto" + TILE1_LABEL_OFF: "Off" + TILE1_LABEL_ON: "On" + TILE1_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE1_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE1_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE1_ICON_DISABLED_COLOR: "0xFEC600" + TILE1_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE1_BG_DISABLED_COLOR: "0x939391" + TILE1_TITLE_ACTIVE_COLOR: "0x000000" + TILE1_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE1_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE1_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE1_TAP_SERVICE: "" + TILE1_TAP_PARAM_KEY: "" + TILE1_TAP_PARAM_VAL: "" + TILE1_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 2 – Living Room Air Purifier ─────────────────── + TILE2_ENTITY: "fan.living_room_air_purifier" + TILE2_STATE_ENTITY: "fan.living_room_air_purifier" + TILE2_TITLE: "Air Purifier" + TILE2_ICON: "\U000F0D43" + TILE2_TYPE: "fan" + TILE2_TAP_ACTION: "fan_toggle_preset" + TILE2_LONGPRESS: "auto" + TILE2_VALUE_MODE: "auto" + TILE2_LABEL_OFF: "Off" + TILE2_LABEL_ON: "On" + TILE2_CIRCLE_ACTIVE_COLOR: "0x00C5EC" + TILE2_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE2_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE2_ICON_DISABLED_COLOR: "0x00C5EC" + TILE2_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE2_BG_DISABLED_COLOR: "0x939391" + TILE2_TITLE_ACTIVE_COLOR: "0x000000" + TILE2_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE2_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE2_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE2_TAP_SERVICE: "fan.toggle" + TILE2_TAP_PARAM_KEY: "preset_mode" + TILE2_TAP_PARAM_VAL: "auto" + TILE2_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 3 – Garbage Goober (vacuum) ──────────────────── + TILE3_ENTITY: "vacuum.garbage_goober" + TILE3_STATE_ENTITY: "binary_sensor.garbage_goober_cleaning" + TILE3_TITLE: "Vacuum" + TILE3_ICON: "\U000F09A8" + TILE3_TYPE: "switch" + TILE3_TAP_ACTION: "custom" + TILE3_LONGPRESS: "none" + TILE3_VALUE_MODE: "text" + TILE3_LABEL_OFF: "Docked" + TILE3_LABEL_ON: "Cleaning" + TILE3_CIRCLE_ACTIVE_COLOR: "0x43A047" + TILE3_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE3_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE3_ICON_DISABLED_COLOR: "0x43A047" + TILE3_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE3_BG_DISABLED_COLOR: "0x939391" + TILE3_TITLE_ACTIVE_COLOR: "0x000000" + TILE3_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE3_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE3_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE3_TAP_SERVICE: "vacuum.start_pause" + TILE3_TAP_PARAM_KEY: "" + TILE3_TAP_PARAM_VAL: "" + TILE3_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 4 – TV (remote) ──────────────────────────────── + TILE4_ENTITY: "remote.living_room" + TILE4_STATE_ENTITY: "remote.living_room" + TILE4_TITLE: "TV" + TILE4_ICON: "\U000F0502" + TILE4_TYPE: "switch" + TILE4_TAP_ACTION: "custom" + TILE4_LONGPRESS: "none" + TILE4_VALUE_MODE: "text" + TILE4_LABEL_OFF: "Off" + TILE4_LABEL_ON: "On" + TILE4_CIRCLE_ACTIVE_COLOR: "0x1565C0" + TILE4_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE4_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE4_ICON_DISABLED_COLOR: "0x1565C0" + TILE4_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE4_BG_DISABLED_COLOR: "0x939391" + TILE4_TITLE_ACTIVE_COLOR: "0x000000" + TILE4_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE4_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE4_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE4_TAP_SERVICE: "remote.toggle" + TILE4_TAP_PARAM_KEY: "" + TILE4_TAP_PARAM_VAL: "" + TILE4_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 5 – Living Room Speaker ──────────────────────── + TILE5_ENTITY: "media_player.living_room_speaker" + TILE5_STATE_ENTITY: "media_player.living_room_speaker" + TILE5_TITLE: "Speaker" + TILE5_ICON: "\U000F04C3" + TILE5_TYPE: "switch" + TILE5_TAP_ACTION: "custom" + TILE5_LONGPRESS: "none" + TILE5_VALUE_MODE: "text" + TILE5_LABEL_OFF: "Off" + TILE5_LABEL_ON: "Playing" + TILE5_CIRCLE_ACTIVE_COLOR: "0x8E24AA" + TILE5_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE5_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE5_ICON_DISABLED_COLOR: "0x8E24AA" + TILE5_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE5_BG_DISABLED_COLOR: "0x939391" + TILE5_TITLE_ACTIVE_COLOR: "0x000000" + TILE5_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE5_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE5_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE5_TAP_SERVICE: "media_player.toggle" + TILE5_TAP_PARAM_KEY: "" + TILE5_TAP_PARAM_VAL: "" + TILE5_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 6 – Front Closet Lights ──────────────────────── + TILE6_ENTITY: "light.front_closet_lights" + TILE6_STATE_ENTITY: "light.front_closet_light_1" + TILE6_TITLE: "Closet" + TILE6_ICON: "\U000F1051" + TILE6_TYPE: "light" + TILE6_TAP_ACTION: "toggle" + TILE6_LONGPRESS: "none" + TILE6_VALUE_MODE: "auto" + TILE6_LABEL_OFF: "Off" + TILE6_LABEL_ON: "On" + TILE6_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE6_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE6_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE6_ICON_DISABLED_COLOR: "0xFEC600" + TILE6_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE6_BG_DISABLED_COLOR: "0x939391" + TILE6_TITLE_ACTIVE_COLOR: "0x000000" + TILE6_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE6_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE6_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE6_TAP_SERVICE: "" + TILE6_TAP_PARAM_KEY: "" + TILE6_TAP_PARAM_VAL: "" + TILE6_LONGPRESS_OFF_VALUE: "0" + +packages: + hw: !include cyd-base-hw.yaml + ui: !include cyd-base-ui.yaml + +esphome: + name: livingroom-display + friendly_name: LivingroomDisplay + on_boot: + priority: 600 + then: + - script.execute: ui_refresh + +esp32: + board: esp32dev + framework: + type: arduino + +logger: + +api: + encryption: + key: !secret api_encryption_key + +ota: + - platform: esphome + password: !secret ota_password + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + ap: + ssid: "LivingroomDisplay Fallback" + password: !secret ota_password + +captive_portal: diff --git a/modules/nixos/homeassistant/services/esphome/pets.yaml b/modules/nixos/homeassistant/services/esphome/pets.yaml new file mode 100644 index 0000000..585bcc0 --- /dev/null +++ b/modules/nixos/homeassistant/services/esphome/pets.yaml @@ -0,0 +1,202 @@ +############################################################ +# SmartDisplay – Pets +# Tiles: Joey Feed | Luci Feed | Litter Box | Fountain | Vacuum | Ftn Reset +############################################################ + +substitutions: + + DIRECT_ACTIONS: "true" + ROOM_NAME: "Pets" + TIME_24H: "false" + + # ── TILE 1 – Joey Smart Feeder (manual feed) ───────────── + TILE1_ENTITY: "button.joey_smart_feeder_manual_feed" + TILE1_STATE_ENTITY: "binary_sensor.joey_smart_feeder_low_food" + TILE1_TITLE: "Joey Feed" + TILE1_ICON: "\U000F009A" + TILE1_TYPE: "script" + TILE1_TAP_ACTION: "custom" + TILE1_LONGPRESS: "none" + TILE1_VALUE_MODE: "text" + TILE1_LABEL_OFF: "Ready" + TILE1_LABEL_ON: "Fed" + TILE1_CIRCLE_ACTIVE_COLOR: "0xF4A820" + TILE1_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE1_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE1_ICON_DISABLED_COLOR: "0xF4A820" + TILE1_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE1_BG_DISABLED_COLOR: "0x939391" + TILE1_TITLE_ACTIVE_COLOR: "0x000000" + TILE1_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE1_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE1_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE1_TAP_SERVICE: "button.press" + TILE1_TAP_PARAM_KEY: "" + TILE1_TAP_PARAM_VAL: "" + TILE1_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 2 – Luci Smart Feeder (manual feed) ───────────── + TILE2_ENTITY: "button.luci_smart_feeder_manual_feed" + TILE2_STATE_ENTITY: "binary_sensor.luci_smart_feeder_low_food" + TILE2_TITLE: "Luci Feed" + TILE2_ICON: "\U000F009A" + TILE2_TYPE: "script" + TILE2_TAP_ACTION: "custom" + TILE2_LONGPRESS: "none" + TILE2_VALUE_MODE: "text" + TILE2_LABEL_OFF: "Ready" + TILE2_LABEL_ON: "Fed" + TILE2_CIRCLE_ACTIVE_COLOR: "0xEC407A" + TILE2_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE2_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE2_ICON_DISABLED_COLOR: "0xEC407A" + TILE2_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE2_BG_DISABLED_COLOR: "0x939391" + TILE2_TITLE_ACTIVE_COLOR: "0x000000" + TILE2_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE2_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE2_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE2_TAP_SERVICE: "button.press" + TILE2_TAP_PARAM_KEY: "" + TILE2_TAP_PARAM_VAL: "" + TILE2_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 3 – Litter-Robot 4 ────────────────────────────── + TILE3_ENTITY: "vacuum.litter_robot_4_litter_box" + TILE3_STATE_ENTITY: "binary_sensor.litter_robot_4_is_cleaning" + TILE3_TITLE: "Litter Box" + TILE3_ICON: "\U000F054D" + TILE3_TYPE: "switch" + TILE3_TAP_ACTION: "custom" + TILE3_LONGPRESS: "none" + TILE3_VALUE_MODE: "text" + TILE3_LABEL_OFF: "Docked" + TILE3_LABEL_ON: "Cycling" + TILE3_CIRCLE_ACTIVE_COLOR: "0x43A047" + TILE3_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE3_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE3_ICON_DISABLED_COLOR: "0x43A047" + TILE3_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE3_BG_DISABLED_COLOR: "0x939391" + TILE3_TITLE_ACTIVE_COLOR: "0x000000" + TILE3_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE3_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE3_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE3_TAP_SERVICE: "vacuum.start" + TILE3_TAP_PARAM_KEY: "" + TILE3_TAP_PARAM_VAL: "" + TILE3_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 4 – Pet Fountain ──────────────────────────────── + TILE4_ENTITY: "switch.dockstream_smart_rfid_fountain_wi_fi" + TILE4_STATE_ENTITY: "binary_sensor.dockstream_smart_rfid_fountain_indicator" + TILE4_TITLE: "Fountain" + TILE4_ICON: "\U000F0765" + TILE4_TYPE: "switch" + TILE4_TAP_ACTION: "toggle" + TILE4_LONGPRESS: "none" + TILE4_VALUE_MODE: "text" + TILE4_LABEL_OFF: "Off" + TILE4_LABEL_ON: "On" + TILE4_CIRCLE_ACTIVE_COLOR: "0x039BE5" + TILE4_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE4_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE4_ICON_DISABLED_COLOR: "0x039BE5" + TILE4_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE4_BG_DISABLED_COLOR: "0x939391" + TILE4_TITLE_ACTIVE_COLOR: "0x000000" + TILE4_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE4_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE4_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE4_TAP_SERVICE: "" + TILE4_TAP_PARAM_KEY: "" + TILE4_TAP_PARAM_VAL: "" + TILE4_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 5 – Garbage Goober (vacuum) ──────────────────── + TILE5_ENTITY: "vacuum.garbage_goober" + TILE5_STATE_ENTITY: "binary_sensor.garbage_goober_cleaning" + TILE5_TITLE: "Vacuum" + TILE5_ICON: "\U000F09A8" + TILE5_TYPE: "switch" + TILE5_TAP_ACTION: "custom" + TILE5_LONGPRESS: "none" + TILE5_VALUE_MODE: "text" + TILE5_LABEL_OFF: "Docked" + TILE5_LABEL_ON: "Cleaning" + TILE5_CIRCLE_ACTIVE_COLOR: "0x6D4C41" + TILE5_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE5_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE5_ICON_DISABLED_COLOR: "0x6D4C41" + TILE5_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE5_BG_DISABLED_COLOR: "0x939391" + TILE5_TITLE_ACTIVE_COLOR: "0x000000" + TILE5_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE5_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE5_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE5_TAP_SERVICE: "vacuum.start_pause" + TILE5_TAP_PARAM_KEY: "" + TILE5_TAP_PARAM_VAL: "" + TILE5_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 6 – Fountain Cleaning Reset ──────────────────── + TILE6_ENTITY: "button.dockstream_smart_rfid_fountain_cleaning_reset" + TILE6_STATE_ENTITY: "binary_sensor.dockstream_smart_rfid_fountain_wi_fi" + TILE6_TITLE: "Ftn. Reset" + TILE6_ICON: "\U000F0ECC" + TILE6_TYPE: "script" + TILE6_TAP_ACTION: "custom" + TILE6_LONGPRESS: "none" + TILE6_VALUE_MODE: "text" + TILE6_LABEL_OFF: "Offline" + TILE6_LABEL_ON: "Online" + TILE6_CIRCLE_ACTIVE_COLOR: "0x039BE5" + TILE6_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE6_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE6_ICON_DISABLED_COLOR: "0x039BE5" + TILE6_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE6_BG_DISABLED_COLOR: "0x939391" + TILE6_TITLE_ACTIVE_COLOR: "0x000000" + TILE6_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE6_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE6_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE6_TAP_SERVICE: "button.press" + TILE6_TAP_PARAM_KEY: "" + TILE6_TAP_PARAM_VAL: "" + TILE6_LONGPRESS_OFF_VALUE: "0" + +packages: + hw: !include cyd-base-hw.yaml + ui: !include cyd-base-ui.yaml + +esphome: + name: pets-display + friendly_name: PetsDisplay + on_boot: + priority: 600 + then: + - script.execute: ui_refresh + +esp32: + board: esp32dev + framework: + type: arduino + +logger: + +api: + encryption: + key: !secret api_encryption_key + +ota: + - platform: esphome + password: !secret ota_password + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + ap: + ssid: "PetsDisplay Fallback" + password: !secret ota_password + +captive_portal: diff --git a/modules/nixos/homeassistant/services/esphome/printer.yaml b/modules/nixos/homeassistant/services/esphome/printer.yaml new file mode 100644 index 0000000..6691a49 --- /dev/null +++ b/modules/nixos/homeassistant/services/esphome/printer.yaml @@ -0,0 +1,202 @@ +############################################################ +# SmartDisplay – 3D Printer (Bambu P1P) +# Tiles: Status | Chamber Light | Pause | Cooling Fan | AMS | Stop +############################################################ + +substitutions: + + DIRECT_ACTIONS: "true" + ROOM_NAME: "Printer" + TIME_24H: "false" + + # ── TILE 1 – P1P Online / Force Refresh ───────────────── + TILE1_ENTITY: "button.p1p_01s00c371400147_force_refresh_data" + TILE1_STATE_ENTITY: "binary_sensor.p1p_01s00c371400147_online" + TILE1_TITLE: "P1P Status" + TILE1_ICON: "\U000F08F5" + TILE1_TYPE: "script" + TILE1_TAP_ACTION: "custom" + TILE1_LONGPRESS: "none" + TILE1_VALUE_MODE: "text" + TILE1_LABEL_OFF: "Offline" + TILE1_LABEL_ON: "Online" + TILE1_CIRCLE_ACTIVE_COLOR: "0x43A047" + TILE1_CIRCLE_DISABLED_COLOR: "0xE53935" + TILE1_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE1_ICON_DISABLED_COLOR: "0xFFFFFF" + TILE1_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE1_BG_DISABLED_COLOR: "0x939391" + TILE1_TITLE_ACTIVE_COLOR: "0x000000" + TILE1_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE1_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE1_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE1_TAP_SERVICE: "button.press" + TILE1_TAP_PARAM_KEY: "" + TILE1_TAP_PARAM_VAL: "" + TILE1_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 2 – Chamber Light ─────────────────────────────── + TILE2_ENTITY: "light.p1p_01s00c371400147_chamber_light" + TILE2_STATE_ENTITY: "light.p1p_01s00c371400147_chamber_light" + TILE2_TITLE: "Chamber" + TILE2_ICON: "\U000F0A02" + TILE2_TYPE: "light" + TILE2_TAP_ACTION: "toggle" + TILE2_LONGPRESS: "none" + TILE2_VALUE_MODE: "text" + TILE2_LABEL_OFF: "Off" + TILE2_LABEL_ON: "On" + TILE2_CIRCLE_ACTIVE_COLOR: "0xFEC600" + TILE2_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE2_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE2_ICON_DISABLED_COLOR: "0xFEC600" + TILE2_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE2_BG_DISABLED_COLOR: "0x939391" + TILE2_TITLE_ACTIVE_COLOR: "0x000000" + TILE2_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE2_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE2_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE2_TAP_SERVICE: "" + TILE2_TAP_PARAM_KEY: "" + TILE2_TAP_PARAM_VAL: "" + TILE2_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 3 – Pause Printing ────────────────────────────── + TILE3_ENTITY: "button.p1p_01s00c371400147_pause_printing" + TILE3_STATE_ENTITY: "binary_sensor.p1p_01s00c371400147_print_error" + TILE3_TITLE: "Pause" + TILE3_ICON: "\U000F03E4" + TILE3_TYPE: "script" + TILE3_TAP_ACTION: "custom" + TILE3_LONGPRESS: "none" + TILE3_VALUE_MODE: "text" + TILE3_LABEL_OFF: "Idle" + TILE3_LABEL_ON: "Error" + TILE3_CIRCLE_ACTIVE_COLOR: "0xE53935" + TILE3_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE3_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE3_ICON_DISABLED_COLOR: "0x7B7B6F" + TILE3_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE3_BG_DISABLED_COLOR: "0x939391" + TILE3_TITLE_ACTIVE_COLOR: "0x000000" + TILE3_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE3_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE3_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE3_TAP_SERVICE: "button.press" + TILE3_TAP_PARAM_KEY: "" + TILE3_TAP_PARAM_VAL: "" + TILE3_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 4 – Cooling Fan ──────────────────────────────── + TILE4_ENTITY: "fan.p1p_01s00c371400147_cooling_fan" + TILE4_STATE_ENTITY: "fan.p1p_01s00c371400147_cooling_fan" + TILE4_TITLE: "Cooling" + TILE4_ICON: "\U000F0210" + TILE4_TYPE: "fan" + TILE4_TAP_ACTION: "toggle" + TILE4_LONGPRESS: "auto" + TILE4_VALUE_MODE: "percentage" + TILE4_LABEL_OFF: "Off" + TILE4_LABEL_ON: "On" + TILE4_CIRCLE_ACTIVE_COLOR: "0x00C5EC" + TILE4_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE4_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE4_ICON_DISABLED_COLOR: "0x00C5EC" + TILE4_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE4_BG_DISABLED_COLOR: "0x939391" + TILE4_TITLE_ACTIVE_COLOR: "0x000000" + TILE4_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE4_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE4_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE4_TAP_SERVICE: "fan.toggle" + TILE4_TAP_PARAM_KEY: "" + TILE4_TAP_PARAM_VAL: "" + TILE4_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 5 – AMS 1 Active ─────────────────────────────── + TILE5_ENTITY: "button.p1p_01s00c371400147_force_refresh_data" + TILE5_STATE_ENTITY: "binary_sensor.p1p_01s00c371400147_ams_1_active" + TILE5_TITLE: "AMS" + TILE5_ICON: "\U000F01AE" + TILE5_TYPE: "script" + TILE5_TAP_ACTION: "custom" + TILE5_LONGPRESS: "none" + TILE5_VALUE_MODE: "text" + TILE5_LABEL_OFF: "Idle" + TILE5_LABEL_ON: "Active" + TILE5_CIRCLE_ACTIVE_COLOR: "0x8E24AA" + TILE5_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE5_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE5_ICON_DISABLED_COLOR: "0x8E24AA" + TILE5_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE5_BG_DISABLED_COLOR: "0x939391" + TILE5_TITLE_ACTIVE_COLOR: "0x000000" + TILE5_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE5_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE5_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE5_TAP_SERVICE: "button.press" + TILE5_TAP_PARAM_KEY: "" + TILE5_TAP_PARAM_VAL: "" + TILE5_LONGPRESS_OFF_VALUE: "0" + + # ── TILE 6 – Stop Printing (red accent) ───────────────── + TILE6_ENTITY: "button.p1p_01s00c371400147_stop_printing" + TILE6_STATE_ENTITY: "binary_sensor.p1p_01s00c371400147_online" + TILE6_TITLE: "Stop" + TILE6_ICON: "\U000F04DB" + TILE6_TYPE: "script" + TILE6_TAP_ACTION: "custom" + TILE6_LONGPRESS: "none" + TILE6_VALUE_MODE: "text" + TILE6_LABEL_OFF: "Offline" + TILE6_LABEL_ON: "Ready" + TILE6_CIRCLE_ACTIVE_COLOR: "0xE53935" + TILE6_CIRCLE_DISABLED_COLOR: "0x7B7B6F" + TILE6_ICON_ACTIVE_COLOR: "0xFFFFFF" + TILE6_ICON_DISABLED_COLOR: "0xE53935" + TILE6_BG_ACTIVE_COLOR: "0xFFFFFF" + TILE6_BG_DISABLED_COLOR: "0x939391" + TILE6_TITLE_ACTIVE_COLOR: "0x000000" + TILE6_TITLE_DISABLED_COLOR: "0xFFFFFF" + TILE6_VALUE_ACTIVE_COLOR: "0x7A7A7C" + TILE6_VALUE_DISABLED_COLOR: "0xD9D9D9" + TILE6_TAP_SERVICE: "button.press" + TILE6_TAP_PARAM_KEY: "" + TILE6_TAP_PARAM_VAL: "" + TILE6_LONGPRESS_OFF_VALUE: "0" + +packages: + hw: !include cyd-base-hw.yaml + ui: !include cyd-base-ui.yaml + +esphome: + name: printer-display + friendly_name: PrinterDisplay + on_boot: + priority: 600 + then: + - script.execute: ui_refresh + +esp32: + board: esp32dev + framework: + type: arduino + +logger: + +api: + encryption: + key: !secret api_encryption_key + +ota: + - platform: esphome + password: !secret ota_password + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + ap: + ssid: "PrinterDisplay Fallback" + password: !secret ota_password + +captive_portal: diff --git a/modules/nixos/services/actual/default.nix b/modules/nixos/services/actual/default.nix index 9e8a264..8c66e2d 100755 --- a/modules/nixos/services/actual/default.nix +++ b/modules/nixos/services/actual/default.nix @@ -45,7 +45,7 @@ let discoveryURL = "https://authentik.mjallen.dev/application/o/actual/.well-known/openid-configuration"; client_id._secret = config.sops.secrets."jallen-nas/actual/client-id".path; client_secret._secret = config.sops.secrets."jallen-nas/actual/client-secret".path; - server_hostname = "https://authentik.mjallen.dev"; + server_hostname = "https://actual.mjallen.dev"; authMethod = "openid"; }; }; diff --git a/modules/nixos/services/ai/default.nix b/modules/nixos/services/ai/default.nix index d143690..ec71e2c 100755 --- a/modules/nixos/services/ai/default.nix +++ b/modules/nixos/services/ai/default.nix @@ -13,14 +13,14 @@ let cfg = config.${namespace}.services.ai; - ntfyModelFailScript = pkgs.writeShellScript "update-qwen-model-notify-failure" '' + ntfyModelFailScript = pkgs.writeShellScript "update-gemma-model-notify-failure" '' HOST="$(${pkgs.hostname}/bin/hostname)" ${pkgs.curl}/bin/curl -sf \ --user "$NTFY_USER:$NTFY_PASSWORD" \ - -H "Title: Qwen model update FAILED on $HOST" \ + -H "Title: Gemma model update FAILED on $HOST" \ -H "Priority: high" \ -H "Tags: rotating_light,robot_face" \ - -d "The daily update-qwen-model job failed. Check: journalctl -u update-qwen-model.service" \ + -d "The daily update-gemma-model job failed. Check: journalctl -u update-gemma-model.service" \ "https://ntfy.mjallen.dev/builds" || true ''; @@ -30,10 +30,7 @@ let description = "AI Services"; options = { llama-cpp = { - model = - mkOpt types.str - "models--unsloth--gemma-4-26B-A4B-it-GGUF/snapshots/b8654b48d979f2853b7a81d6541ca64eea7dc3c5/gemma-4-26B-A4B-it-UD-Q8_K_XL" - ""; + model = mkOpt types.str "gemma-4-26B-A4B-it-UD-Q8_K_XL" ""; }; }; moduleConfig = { @@ -59,21 +56,17 @@ let model = "${cfg.configDir}/llama-cpp/models/${cfg.llama-cpp.model}.gguf"; package = inputs.llama-cpp.packages.${system}.rocm; extraFlags = [ - "--fit" - "on" - "--seed" - "3407" - "--temp" - "0.7" - "--top-p" - "0.9" - "--min-p" - "0.05" - "--top-k" - "30" "--jinja" + "--chat-template-kwargs" + "{\"enable_thinking\":true}" + "--temp" + "1.0" + "--top-p" + "0.95" + "--top-k" + "64" "--ctx-size" - "131072" + "32768" "--threads" "8" "--batch-size" @@ -81,7 +74,7 @@ let "--gpu-layers" "999" "--flash-attn" - "auto" + "on" "--mlock" ]; }; @@ -120,16 +113,16 @@ let # Systemd service for automatic model updates systemd = { services = { - update-qwen-model = { - description = "Update Qwen3-Coder-Next model from HuggingFace"; + update-gemma-model = { + description = "Update Gemma 4 model from HuggingFace"; serviceConfig = { Type = "oneshot"; - ExecStart = "${pkgs.writeShellScript "update-qwen-model" '' + ExecStart = "${pkgs.writeShellScript "update-gemma-model" '' set -euo pipefail MODEL_DIR="${cfg.configDir}/llama-cpp/models" MODEL_NAME="${cfg.llama-cpp.model}.gguf" - REPO_ID="unsloth/Qwen3-Coder-Next-GGUF" + REPO_ID="unsloth/gemma-4-26B-A4B-it-GGUF" # Create model directory if it doesn't exist mkdir -p "$MODEL_DIR" @@ -147,13 +140,13 @@ let Group = "jallen-nas"; EnvironmentFile = [ config.sops.templates."ntfy.env".path ]; }; - unitConfig.OnFailure = "update-qwen-model-notify-failure.service"; + unitConfig.OnFailure = "update-gemma-model-notify-failure.service"; # Run daily at 3 AM startAt = "*-*-* 03:00:00"; }; - update-qwen-model-notify-failure = { - description = "Notify ntfy on update-qwen-model failure"; + update-gemma-model-notify-failure = { + description = "Notify ntfy on update-gemma-model failure"; serviceConfig = { Type = "oneshot"; ExecStart = "${ntfyModelFailScript}"; @@ -163,8 +156,8 @@ let # Ensure model is available before llama-cpp starts llama-cpp = { - after = [ "update-qwen-model.service" ]; - wants = [ "update-qwen-model.service" ]; + after = [ "update-gemma-model.service" ]; + wants = [ "update-gemma-model.service" ]; }; }; };