From 0802e608765b6d1956851d215502319e1738d19f Mon Sep 17 00:00:00 2001 From: iosullivan Date: Sun, 18 Oct 2026 08:02:07 +1000 Subject: [PATCH] Updates for HA integration --- base/core.yaml | 71 ---- base/screens/thermostat.yaml | 3 +- base/screens/weather.ha-helper.yaml | 37 -- base/screens/weather.yaml | 541 ---------------------------- guition-va.yaml | 28 +- 5 files changed, 14 insertions(+), 666 deletions(-) delete mode 100644 base/screens/weather.ha-helper.yaml delete mode 100644 base/screens/weather.yaml diff --git a/base/core.yaml b/base/core.yaml index 0d09ba0..204d31a 100644 --- a/base/core.yaml +++ b/base/core.yaml @@ -1,77 +1,6 @@ -############################################################################### -# Guition JC3636K718C (1.8" 360x360 ROUND KNOB, ESP32-S3) - core config -# Pins and init_sequence from the OFFICIAL manufacturer demo (JC3636K718_knob_EN), -# files pincfg.h + scr_st77916.h. This is the correct pinout for THIS board -# (different from the JC3636W518!). -# -# Always-on core: display (ST77916/QSPI) + touch (CST816) + knob + audio + voice assistant + -# LED ring + the clock home screen, control tiles and settings. Optional carousel screens -# (player, timer, games, weather, demo) live as packages in base/screens/ - see base/screens/README.md. -############################################################################### - -substitutions: - name: voice-knob - friendly_name: "Voice Knob" - # Clock timezone. HA does not push its zone to the device, so set yours here. Use a friendly IANA - # name (e.g. Europe/Warsaw, America/New_York) - core maps the common ones to the POSIX form the - # device needs (it has no IANA database). For a zone not in that table, paste its POSIX string - # instead (see https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv). DST automatic. - timezone: "Australia/Brisbane" - # For album art: base URL of your HA + the media_player entity (change if different) - ha_base_url: "http://ha.iosull.com" - player_entity: media_player.voice_knob_player - # On-device wake word. Built-in models: alexa, okay_nabu, hey_jarvis, hey_mycroft. - wake_word: "hey_jarvis" - # Entities for the home screen (toggle each in Settings -> Home). Change if different. - weather_entity: weather.home - room_temp_entity: sensor.room_temperature - room_hum_entity: sensor.room_humidity - climate_entity: climate.home # thermostat screen target (a climate.* entity) - # Control tiles (swipe up): 4 toggleable HA entities, each with an icon + a name. Any domain. - # tileN_icon = a name from the built-in set: bulb lamp led power plug switch fan ac heater - # thermometer lock unlock door blinds tv speaker bell wifi home flash. The same icon may - # repeat across tiles. (For an icon outside the set, paste its glyph or a \U000Fxxxx code.) - tile1_entity: light.desk_lamp - tile1_icon: "bulb" - tile1_name: "Lamp" - tile2_entity: switch.neon - tile2_icon: "flash" - tile2_name: "Neon" - tile3_entity: light.desk_lamp - tile3_icon: "power" - tile3_name: "Tile " - # Sensors screen (knob cycles): up to 6 read-only HA entities, one shown big at a time. - # Set as many glanceN_entity as you want (+ a name, optional icon name); leave the rest at - # their default (a non-existent entity) and they're skipped. - glance1_entity: sensor.power - glance1_name: "Power" - glance1_icon: "flash" - glance2_entity: sensor.va_glance_unused2 - glance2_name: "" - glance2_icon: "" - glance3_entity: sensor.va_glance_unused3 - glance3_name: "" - glance3_icon: "" - glance4_entity: sensor.va_glance_unused4 - glance4_name: "" - glance4_icon: "" - glance5_entity: sensor.va_glance_unused5 - glance5_name: "" - glance5_icon: "" - glance6_entity: sensor.va_glance_unused6 - glance6_name: "" - glance6_icon: "" - forecast_entity: sensor.va_weekly_forecast # weather screen forecast (HA helper, see base/screens/weather.ha-helper.yaml) - # Carousel screen order (left-to-right). Screens not included in the build are skipped. - screen_order: "clock,player,timer,cars,space,snake,knobuss,weather,thermostat,sensors,demo" - esphome: name: ${name} friendly_name: ${friendly_name} - platformio_options: - board_build.flash_mode: dio - board_build.f_flash: 80000000L - board_build.f_cpu: 240000000L on_boot: - priority: 800 then: diff --git a/base/screens/thermostat.yaml b/base/screens/thermostat.yaml index c6e6c69..1291a74 100644 --- a/base/screens/thermostat.yaml +++ b/base/screens/thermostat.yaml @@ -149,8 +149,7 @@ script: sensor: - platform: homeassistant id: th_cur_s - entity_id: ${climate_entity} - attribute: current_temperature + entity_id: ${room_temp_entity} on_value: - lambda: 'id(g_th_cur) = x;' - script.execute: th_render diff --git a/base/screens/weather.ha-helper.yaml b/base/screens/weather.ha-helper.yaml deleted file mode 100644 index 7893c42..0000000 --- a/base/screens/weather.ha-helper.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# Home Assistant helper for the device's Weather screen (base/screens/weather.yaml). -# -# HA no longer exposes a weather entity's multi-day forecast as an attribute, so this -# template calls weather.get_forecasts and publishes a single compact sensor the device -# reads. State format: "condition,high,low,DayName|..." (one segment per day, up to 7). -# -# 1. Change weather.forecast_dom below to your weather entity (3 places). -# 2. Put this in HA configuration.yaml (or a packages/ file), then restart HA / reload -# template entities. It creates sensor.va_weekly_forecast. -# 3. On the device, ${forecast_entity} defaults to sensor.va_weekly_forecast - override -# the substitution if you name it differently. - -template: - - trigger: - - platform: homeassistant - event: start - - platform: time_pattern - minutes: "/30" - action: - - service: weather.get_forecasts - target: - entity_id: weather.forecast_dom - data: - type: daily - response_variable: fc - sensor: - - name: "VA weekly forecast" - unique_id: va_weekly_forecast - state: > - {% set ns = namespace(parts=[]) %} - {% for d in fc['weather.forecast_dom'].forecast[:7] %} - {% set hi = (d.temperature | round(0)) if d.temperature is not none else 0 %} - {% set lo = (d.templow | round(0)) if (d.templow is defined and d.templow is not none) else hi %} - {% set nm = as_timestamp(d.datetime) | timestamp_custom('%a', true) %} - {% set ns.parts = ns.parts + [d.condition ~ ',' ~ hi ~ ',' ~ lo ~ ',' ~ nm] %} - {% endfor %} - {{ ns.parts | join('|') }} diff --git a/base/screens/weather.yaml b/base/screens/weather.yaml deleted file mode 100644 index 4e0fff6..0000000 --- a/base/screens/weather.yaml +++ /dev/null @@ -1,541 +0,0 @@ -# Weather - carousel screen (base id 5). GENERATED by scripts/gen_weather.py. -# A dial of forecast days around the rim (knob scrolls), animated condition icon + colour-coded -# temperature in the centre, a glow that slides to the selected day. Forecast comes from a Home -# Assistant helper sensor (see base/screens/weather.ha-helper.yaml). Remove: drop from `files:`. - -esphome: - on_boot: - - priority: 655 - then: - - lambda: 'id(g_present)[5] = true;' - - priority: 650 - then: - - lambda: |- - int g = id(g_wgrp_n)++; - id(g_wgrp_labels) += (g ? "\n" : ""); id(g_wgrp_labels) += "Weather"; - int o = id(g_wopt_n)++; - id(g_wopt_group)[o] = g; id(g_wopt_label)[o] = "Fahrenheit"; id(g_wopt_kind)[o] = 0; id(g_wopt_ptr)[o] = &id(g_wx_fahrenheit); - -globals: - # --- forecast data --- - - id: g_wx_fahrenheit - type: bool - restore_value: yes - initial_value: 'false' - - id: g_wx_now - type: int - restore_value: no - initial_value: '-127' - - id: g_wx_state_cur - type: std::string - restore_value: no - - id: g_wx_cond - type: std::string[7] - restore_value: no - - id: g_wx_icon - type: std::string[7] - restore_value: no - - id: g_wx_name - type: std::string[7] - restore_value: no - - id: g_wx_hi - type: int[7] - restore_value: no - - id: g_wx_lo - type: int[7] - restore_value: no - - id: g_wx_n - type: int - restore_value: no - initial_value: '0' - - id: g_wx_day - type: int - restore_value: no - initial_value: '0' - # --- render cache --- - - id: g_wx_sel - type: std::string - restore_value: no - - id: g_wx_tc - type: int - restore_value: no - initial_value: '-127' - - id: g_wx_lastcond - type: std::string - restore_value: no - - id: g_wx_ikey - type: std::string - restore_value: no - - id: g_wx_gpos - type: float - restore_value: no - initial_value: '0.0' - -font: - - file: "https://github.com/Templarian/MaterialDesign-Webfont/raw/v7.4.47/fonts/materialdesignicons-webfont.ttf" - id: icons_wx - size: 30 - bpp: 4 - glyphs: ["󰖙", "󰖔", "󰖕", "󰖑", "󰖝", "󰖓", "󰖖", "󰖗", "󰖘", "󰖐"] - -image: - - id: img_wx_sun0 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun0.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_sun1 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun1.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_sun2 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun2.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_sun3 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun3.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_sun4 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun4.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_sun5 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun5.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_sun6 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun6.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_sun7 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/sun7.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly0 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly0.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly1 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly1.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly2 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly2.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly3 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly3.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly4 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly4.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly5 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly5.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly6 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly6.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_partly7 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/partly7.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon0 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon0.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon1 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon1.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon2 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon2.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon3 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon3.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon4 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon4.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon5 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon5.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon6 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon6.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_moon7 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/moon7.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud0 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud0.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud1 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud1.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud2 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud2.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud3 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud3.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud4 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud4.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud5 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud5.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud6 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud6.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_cloud7 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/cloud7.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain0 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain0.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain1 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain1.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain2 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain2.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain3 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain3.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain4 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain4.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain5 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain5.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain6 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain6.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_rain7 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/rain7.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm0 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm0.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm1 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm1.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm2 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm2.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm3 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm3.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm4 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm4.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm5 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm5.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm6 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm6.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_storm7 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/storm7.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow0 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow0.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow1 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow1.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow2 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow2.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow3 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow3.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow4 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow4.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow5 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow5.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow6 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow6.png" - type: RGB565 - transparency: alpha_channel - - id: img_wx_snow7 - file: "https://raw.githubusercontent.com/MichalZaniewicz/esphome-guition-jc3636k718c-va/main/assets/sprites/weather/snow7.png" - type: RGB565 - transparency: alpha_channel - -script: - - id: wx_render - then: - - lambda: |- - int d = id(g_wx_day); - bool has = (id(g_wx_n) > 0 && d < id(g_wx_n)); - id(g_wx_sel) = has ? id(g_wx_cond)[d] : id(g_wx_state_cur); - id(g_wx_tc) = has ? id(g_wx_hi)[d] : id(g_wx_now); - - lvgl.label.update: - id: wx_day - text: !lambda |- - int d = id(g_wx_day); - if (id(g_wx_n) <= 0 || d >= id(g_wx_n)) return std::string("TODAY"); - std::string s = id(g_wx_name)[d]; - if (s == "Mon") return std::string("MONDAY"); - if (s == "Tue") return std::string("TUESDAY"); - if (s == "Wed") return std::string("WEDNESDAY"); - if (s == "Thu") return std::string("THURSDAY"); - if (s == "Fri") return std::string("FRIDAY"); - if (s == "Sat") return std::string("SATURDAY"); - if (s == "Sun") return std::string("SUNDAY"); - return s; - - lvgl.label.update: - id: wx_htemp - text: !lambda |- - int d = id(g_wx_day); - bool f = id(g_wx_fahrenheit); - char u = f ? 'F' : 'C'; - if (id(g_wx_n) <= 0 || d >= id(g_wx_n)) { - if (id(g_wx_now) > -100) { int n = id(g_wx_now); if (f) n = n*9/5+32; char b[12]; snprintf(b,sizeof(b),"%d°%c",n,u); return std::string(b); } - return std::string("--"); - } - int hi = id(g_wx_hi)[d], lo = id(g_wx_lo)[d]; - if (f) { hi = hi*9/5+32; lo = lo*9/5+32; } - char b[24]; snprintf(b,sizeof(b),"%d° / %d°",hi,lo); return std::string(b); - - lvgl.label.update: - id: wx_cond - text: !lambda |- - if (id(g_wx_n) <= 0) return std::string("Add the HA forecast helper"); - std::string s = id(g_wx_sel); - if (s == "sunny") return std::string("Sunny"); - if (s == "clear-night") return std::string("Clear"); - if (s == "partlycloudy") return std::string("Partly Cloudy"); - if (s == "cloudy") return std::string("Cloudy"); - if (s == "fog") return std::string("Fog"); - if (s == "rainy") return std::string("Rainy"); - if (s == "pouring") return std::string("Heavy Rain"); - if (s == "lightning" || s == "lightning-rainy") return std::string("Storm"); - if (s == "snowy" || s == "snowy-rainy") return std::string("Snow"); - if (s == "hail") return std::string("Hail"); - if (s == "windy" || s == "windy-variant") return std::string("Windy"); - if (s == "exceptional") return std::string("Severe"); - return s; - - if: - condition: { lambda: 'return id(g_wx_sel) != id(g_wx_lastcond);' } - then: - - lambda: |- - id(g_wx_lastcond) = id(g_wx_sel); - std::string s = id(g_wx_sel), k; - if (s == "sunny") k = "sun"; - else if (s == "clear-night") k = "moon"; - else if (s == "partlycloudy") k = "partly"; - else if (s == "rainy" || s == "pouring") k = "rain"; - else if (s == "lightning" || s == "lightning-rainy") k = "storm"; - else if (s == "snowy" || s == "snowy-rainy" || s == "hail") k = "snow"; - else k = "cloud"; - id(g_wx_ikey) = k; - - lvgl.animimg.stop: wx_a_sun - - lvgl.animimg.stop: wx_a_partly - - lvgl.animimg.stop: wx_a_moon - - lvgl.animimg.stop: wx_a_cloud - - lvgl.animimg.stop: wx_a_rain - - lvgl.animimg.stop: wx_a_storm - - lvgl.animimg.stop: wx_a_snow - - lvgl.widget.hide: wx_a_sun - - lvgl.widget.hide: wx_a_partly - - lvgl.widget.hide: wx_a_moon - - lvgl.widget.hide: wx_a_cloud - - lvgl.widget.hide: wx_a_rain - - lvgl.widget.hide: wx_a_storm - - lvgl.widget.hide: wx_a_snow - - if: { condition: { lambda: 'return id(g_wx_ikey) == "sun";' }, then: [ lvgl.widget.show: wx_a_sun, lvgl.animimg.start: wx_a_sun ] } - - if: { condition: { lambda: 'return id(g_wx_ikey) == "partly";' }, then: [ lvgl.widget.show: wx_a_partly, lvgl.animimg.start: wx_a_partly ] } - - if: { condition: { lambda: 'return id(g_wx_ikey) == "moon";' }, then: [ lvgl.widget.show: wx_a_moon, lvgl.animimg.start: wx_a_moon ] } - - if: { condition: { lambda: 'return id(g_wx_ikey) == "cloud";' }, then: [ lvgl.widget.show: wx_a_cloud, lvgl.animimg.start: wx_a_cloud ] } - - if: { condition: { lambda: 'return id(g_wx_ikey) == "rain";' }, then: [ lvgl.widget.show: wx_a_rain, lvgl.animimg.start: wx_a_rain ] } - - if: { condition: { lambda: 'return id(g_wx_ikey) == "storm";' }, then: [ lvgl.widget.show: wx_a_storm, lvgl.animimg.start: wx_a_storm ] } - - if: { condition: { lambda: 'return id(g_wx_ikey) == "snow";' }, then: [ lvgl.widget.show: wx_a_snow, lvgl.animimg.start: wx_a_snow ] } - - lvgl.widget.update: { id: wx_glow, hidden: !lambda 'return id(g_wx_n) <= 0;' } - - lvgl.widget.update: { id: wx_d0, hidden: !lambda 'return 0 >= id(g_wx_n);', x: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(140.0f * sinf(0 * 6.2831853f / n));', y: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(-140.0f * cosf(0 * 6.2831853f / n));' } - - lvgl.label.update: { id: wx_d0, text: !lambda 'return id(g_wx_n) > 0 ? id(g_wx_icon)[0] : std::string("");' } - - lvgl.widget.update: { id: wx_d1, hidden: !lambda 'return 1 >= id(g_wx_n);', x: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(140.0f * sinf(1 * 6.2831853f / n));', y: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(-140.0f * cosf(1 * 6.2831853f / n));' } - - lvgl.label.update: { id: wx_d1, text: !lambda 'return id(g_wx_n) > 1 ? id(g_wx_icon)[1] : std::string("");' } - - lvgl.widget.update: { id: wx_d2, hidden: !lambda 'return 2 >= id(g_wx_n);', x: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(140.0f * sinf(2 * 6.2831853f / n));', y: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(-140.0f * cosf(2 * 6.2831853f / n));' } - - lvgl.label.update: { id: wx_d2, text: !lambda 'return id(g_wx_n) > 2 ? id(g_wx_icon)[2] : std::string("");' } - - lvgl.widget.update: { id: wx_d3, hidden: !lambda 'return 3 >= id(g_wx_n);', x: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(140.0f * sinf(3 * 6.2831853f / n));', y: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(-140.0f * cosf(3 * 6.2831853f / n));' } - - lvgl.label.update: { id: wx_d3, text: !lambda 'return id(g_wx_n) > 3 ? id(g_wx_icon)[3] : std::string("");' } - - lvgl.widget.update: { id: wx_d4, hidden: !lambda 'return 4 >= id(g_wx_n);', x: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(140.0f * sinf(4 * 6.2831853f / n));', y: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(-140.0f * cosf(4 * 6.2831853f / n));' } - - lvgl.label.update: { id: wx_d4, text: !lambda 'return id(g_wx_n) > 4 ? id(g_wx_icon)[4] : std::string("");' } - - lvgl.widget.update: { id: wx_d5, hidden: !lambda 'return 5 >= id(g_wx_n);', x: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(140.0f * sinf(5 * 6.2831853f / n));', y: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(-140.0f * cosf(5 * 6.2831853f / n));' } - - lvgl.label.update: { id: wx_d5, text: !lambda 'return id(g_wx_n) > 5 ? id(g_wx_icon)[5] : std::string("");' } - - lvgl.widget.update: { id: wx_d6, hidden: !lambda 'return 6 >= id(g_wx_n);', x: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(140.0f * sinf(6 * 6.2831853f / n));', y: !lambda 'int n=id(g_wx_n); if(n<1)n=1; return (int) lroundf(-140.0f * cosf(6 * 6.2831853f / n));' } - - lvgl.label.update: { id: wx_d6, text: !lambda 'return id(g_wx_n) > 6 ? id(g_wx_icon)[6] : std::string("");' } - - lvgl.label.update: { id: wx_htemp, text_color: 0xFFFFFF } - - if: { condition: { lambda: 'return id(g_wx_tc) > -100 && id(g_wx_tc) <= 0;' }, then: [ lvgl.label.update: { id: wx_htemp, text_color: 0x7FB2FF } ] } - - if: { condition: { lambda: 'return id(g_wx_tc) > 0 && id(g_wx_tc) < 10;' }, then: [ lvgl.label.update: { id: wx_htemp, text_color: 0x6FD0E8 } ] } - - if: { condition: { lambda: 'return id(g_wx_tc) >= 10 && id(g_wx_tc) < 18;' }, then: [ lvgl.label.update: { id: wx_htemp, text_color: 0x7FE6B0 } ] } - - if: { condition: { lambda: 'return id(g_wx_tc) >= 18 && id(g_wx_tc) < 25;' }, then: [ lvgl.label.update: { id: wx_htemp, text_color: 0xFFD061 } ] } - - if: { condition: { lambda: 'return id(g_wx_tc) >= 25;' }, then: [ lvgl.label.update: { id: wx_htemp, text_color: 0xFF7A4D } ] } - -sensor: - - platform: homeassistant - id: wx_now_temp - entity_id: ${weather_entity} - attribute: temperature - on_value: - - lambda: 'id(g_wx_now) = (int) roundf(x);' - - script.execute: wx_render - -text_sensor: - - platform: homeassistant - id: wx_now_state - entity_id: ${weather_entity} - on_value: - - lambda: 'id(g_wx_state_cur) = x;' - - script.execute: wx_render - - platform: homeassistant - id: wx_week - entity_id: ${forecast_entity} - on_value: - - lambda: |- - auto glyph = [](const std::string &s) -> std::string { - if (s == "sunny") return std::string("󰖙"); - if (s == "clear-night") return std::string("󰖔"); - if (s == "partlycloudy") return std::string("󰖕"); - if (s == "fog") return std::string("󰖑"); - if (s == "windy" || s == "windy-variant") return std::string("󰖝"); - if (s == "lightning" || s == "lightning-rainy") return std::string("󰖓"); - if (s == "pouring") return std::string("󰖖"); - if (s == "rainy") return std::string("󰖗"); - if (s == "snowy" || s == "snowy-rainy" || s == "hail") return std::string("󰖘"); - return std::string("󰖐"); - }; - std::string s = x; - for (int i = 0; i < 7; i++) { id(g_wx_icon)[i] = ""; id(g_wx_cond)[i] = ""; } - int n = 0; size_t pos = 0; - while (n < 7) { - size_t bar = s.find('|', pos); - std::string seg = (bar == std::string::npos) ? s.substr(pos) : s.substr(pos, bar - pos); - size_t c1 = seg.find(','); - if (c1 != std::string::npos) { - size_t c2 = seg.find(',', c1 + 1); - size_t c3 = (c2 != std::string::npos) ? seg.find(',', c2 + 1) : std::string::npos; - if (c2 != std::string::npos && c3 != std::string::npos) { - std::string cond = seg.substr(0, c1); - id(g_wx_cond)[n] = cond; - id(g_wx_icon)[n] = glyph(cond); - id(g_wx_hi)[n] = atoi(seg.substr(c1 + 1, c2 - c1 - 1).c_str()); - id(g_wx_lo)[n] = atoi(seg.substr(c2 + 1, c3 - c2 - 1).c_str()); - id(g_wx_name)[n] = seg.substr(c3 + 1); - n++; - } - } - if (bar == std::string::npos) break; - pos = bar + 1; - } - id(g_wx_n) = n; - if (id(g_wx_day) >= n) id(g_wx_day) = 0; - - script.execute: wx_render - -interval: - - interval: 50ms - then: - - if: - condition: { lambda: 'return id(g_nav_req) && id(g_base)==5;' } - then: - - lambda: 'id(g_nav_req) = false; id(g_knob_capture) = true; id(g_wx_day) = 0; id(g_wx_gpos) = 0.0f; id(g_wx_lastcond) = "";' - - if: { condition: { lambda: 'return id(g_nav_anim)==0;' }, then: [lvgl.page.show: { id: page_weather, animation: move_left, time: 250ms }] } - - if: { condition: { lambda: 'return id(g_nav_anim)==1;' }, then: [lvgl.page.show: { id: page_weather, animation: move_right, time: 250ms }] } - - if: { condition: { lambda: 'return id(g_nav_anim)==2;' }, then: [lvgl.page.show: { id: page_weather, animation: move_top, time: 250ms }] } - - if: { condition: { lambda: 'return id(g_nav_anim)==3;' }, then: [lvgl.page.show: { id: page_weather, animation: move_bottom, time: 250ms }] } - - script.execute: wx_render - - interval: 120ms - then: - - if: - condition: { lambda: 'return id(g_base)==5 && id(g_knob_delta) != 0;' } - then: - - lambda: |- - id(g_wx_day) += id(g_knob_delta); id(g_knob_delta) = 0; - int mx = (id(g_wx_n) > 0) ? id(g_wx_n) - 1 : 0; - if (id(g_wx_day) < 0) id(g_wx_day) = 0; - if (id(g_wx_day) > mx) id(g_wx_day) = mx; - - script.execute: wx_render - - interval: 30ms - then: - - if: - condition: { lambda: 'return id(g_base)==5;' } - then: - - lambda: |- - float p = id(g_wx_gpos), tgt = (float) id(g_wx_day); - if (fabsf(tgt - p) > 0.001f) { // only while actually sliding - int n = id(g_wx_n); if (n < 1) n = 1; - p += (tgt - p) * 0.35f; - if (fabsf(tgt - p) < 0.02f) p = tgt; - id(g_wx_gpos) = p; - float rx = 140.0f * sinf(p * 6.2831853f / n); - float ry = -140.0f * cosf(p * 6.2831853f / n); - lv_obj_set_pos(id(wx_glow), 180 + (int) lroundf(rx) - 28, 180 + (int) lroundf(ry) - 28); - } - -lvgl: - pages: - - id: page_weather - bg_color: 0x0B1020 - widgets: - - obj: { id: wx_bg, align: CENTER, x: 0, y: 0, width: 360, height: 360, radius: 0, bg_color: 0x1C2838, bg_opa: COVER, border_width: 0 } - - obj: { id: wx_ring_out, align: CENTER, width: 348, height: 348, radius: 174, bg_opa: TRANSP, border_width: 2, border_color: 0x33455C, border_opa: 55%, clickable: false, scrollable: false } - - obj: { id: wx_glow, x: 152, y: 12, width: 56, height: 56, radius: 28, bg_color: 0xCAD6E8, bg_opa: 30%, border_width: 0, hidden: true } - - label: { id: wx_d0, align: CENTER, x: 0, y: 0, text: "", text_font: icons_wx, text_color: 0xDCE6F2, hidden: true } - - label: { id: wx_d1, align: CENTER, x: 0, y: 0, text: "", text_font: icons_wx, text_color: 0xDCE6F2, hidden: true } - - label: { id: wx_d2, align: CENTER, x: 0, y: 0, text: "", text_font: icons_wx, text_color: 0xDCE6F2, hidden: true } - - label: { id: wx_d3, align: CENTER, x: 0, y: 0, text: "", text_font: icons_wx, text_color: 0xDCE6F2, hidden: true } - - label: { id: wx_d4, align: CENTER, x: 0, y: 0, text: "", text_font: icons_wx, text_color: 0xDCE6F2, hidden: true } - - label: { id: wx_d5, align: CENTER, x: 0, y: 0, text: "", text_font: icons_wx, text_color: 0xDCE6F2, hidden: true } - - label: { id: wx_d6, align: CENTER, x: 0, y: 0, text: "", text_font: icons_wx, text_color: 0xDCE6F2, hidden: true } - - animimg: { id: wx_a_sun, align: CENTER, x: 0, y: -52, duration: 1400ms, repeat_count: 65535, auto_start: false, hidden: true, src: [ img_wx_sun0, img_wx_sun1, img_wx_sun2, img_wx_sun3, img_wx_sun4, img_wx_sun5, img_wx_sun6, img_wx_sun7 ] } - - animimg: { id: wx_a_partly, align: CENTER, x: 0, y: -52, duration: 1400ms, repeat_count: 65535, auto_start: false, hidden: true, src: [ img_wx_partly0, img_wx_partly1, img_wx_partly2, img_wx_partly3, img_wx_partly4, img_wx_partly5, img_wx_partly6, img_wx_partly7 ] } - - animimg: { id: wx_a_moon, align: CENTER, x: 0, y: -52, duration: 1400ms, repeat_count: 65535, auto_start: false, hidden: true, src: [ img_wx_moon0, img_wx_moon1, img_wx_moon2, img_wx_moon3, img_wx_moon4, img_wx_moon5, img_wx_moon6, img_wx_moon7 ] } - - animimg: { id: wx_a_cloud, align: CENTER, x: 0, y: -52, duration: 1400ms, repeat_count: 65535, auto_start: false, hidden: true, src: [ img_wx_cloud0, img_wx_cloud1, img_wx_cloud2, img_wx_cloud3, img_wx_cloud4, img_wx_cloud5, img_wx_cloud6, img_wx_cloud7 ] } - - animimg: { id: wx_a_rain, align: CENTER, x: 0, y: -52, duration: 1400ms, repeat_count: 65535, auto_start: false, hidden: true, src: [ img_wx_rain0, img_wx_rain1, img_wx_rain2, img_wx_rain3, img_wx_rain4, img_wx_rain5, img_wx_rain6, img_wx_rain7 ] } - - animimg: { id: wx_a_storm, align: CENTER, x: 0, y: -52, duration: 1400ms, repeat_count: 65535, auto_start: false, hidden: true, src: [ img_wx_storm0, img_wx_storm1, img_wx_storm2, img_wx_storm3, img_wx_storm4, img_wx_storm5, img_wx_storm6, img_wx_storm7 ] } - - animimg: { id: wx_a_snow, align: CENTER, x: 0, y: -52, duration: 1400ms, repeat_count: 65535, auto_start: false, hidden: true, src: [ img_wx_snow0, img_wx_snow1, img_wx_snow2, img_wx_snow3, img_wx_snow4, img_wx_snow5, img_wx_snow6, img_wx_snow7 ] } - - label: { id: wx_day, align: CENTER, x: 0, y: -10, text: "", text_font: font_artist, text_color: 0x9AA6B2 } - - label: { id: wx_htemp, align: CENTER, x: 0, y: 24, text: "--", text_font: montserrat_34, text_color: 0xFFFFFF } - - label: { id: wx_cond, align: CENTER, x: 0, y: 62, text: "", text_font: font_med, text_color: 0xCFE0F2 } diff --git a/guition-va.yaml b/guition-va.yaml index 3a0dd32..6fc4de3 100644 --- a/guition-va.yaml +++ b/guition-va.yaml @@ -19,32 +19,32 @@ substitutions: friendly_name: "Voice Knob" timezone: "Australia/Brisbane" # IANA name; core maps common zones to POSIX. Zone not listed? paste a POSIX string (github.com/nayarsystems/posix_tz_db). DST automatic. # For album art: base URL of your HA + the media_player entity - ha_base_url: "http://ha.iosull.com" + ha_base_url: "https://ha.iosull.com" player_entity: media_player.voice_knob_player # On-device wake word. Built-in models: alexa, okay_nabu, hey_jarvis, hey_mycroft. - wake_word: "alexa" + wake_word: "hey_mycroft" # Home screen (weather + room climate). Change to your entities. weather_entity: weather.home - room_temp_entity: sensor.room_temperature - room_hum_entity: sensor.room_humidity + room_temp_entity: sensor.lounge_sensor_temperature + room_hum_entity: sensor.lounge_sensor_humidity # Weather screen forecast: an HA helper sensor (see base/screens/weather.ha-helper.yaml) forecast_entity: sensor.va_weekly_forecast # Thermostat screen: the climate.* entity it controls - climate_entity: climate.living_room + climate_entity: climate.livingroom_ac # Control tiles (swipe up): 4 toggles, each entity + icon + name. Works on any HA domain. # tileN_icon = a name from the built-in set: bulb lamp led power plug switch fan ac heater # thermometer lock unlock door blinds tv speaker bell wifi home flash. Same icon may repeat. # (For an icon outside the set: paste its glyph or a "\U000Fxxxx" code from pictogrammers.com.) - tile1_entity: light.living_room + tile1_entity: light.athom_rgbct_light_0e9e36_athom_rgbct_light tile1_icon: "bulb" - tile1_name: "Light" - tile2_entity: switch.desk_neon - tile2_icon: "flash" - tile2_name: "Neon" - tile3_entity: switch.power_socket + tile1_name: "Bed Light" + tile2_entity: light.athom_rgbct_light_0ec2ae_athom_rgbct_light + tile2_icon: "bulb" + tile2_name: "Lounge Light" + tile3_entity: switch.athom_smart_plug_v3_50bc98_switch tile3_icon: "power" - tile3_name: "Socket" + tile3_name: "Espresso" # Sensors screen (knob cycles): up to 6 read-only HA entities, shown one at a time, big. # Set as many glanceN as you want; leave the rest at their default (a non-existent entity) @@ -70,7 +70,7 @@ substitutions: # Carousel order, left to right. Reorder/remove names freely; screens you did not # include in "files:" below are skipped automatically. - screen_order: "clock,player,timer,cars,space,snake,knobuss,weather,thermostat,sensors,demo" + screen_order: "clock,thermostat,sensors,timer,player,space,snake,demo" packages: - !include base/core.yaml @@ -80,7 +80,6 @@ packages: - !include base/screens/space-wars.yaml # optional: Space Wars game - !include base/screens/snake.yaml # optional: Snake game (knob steers) - !include base/screens/knobuss.yaml # optional: Knobuss - a Gyruss-style tube shooter (knob aims, auto-fire) - - !include base/screens/weather.yaml # optional: weather (today + 7-day, knob scrolls days) - !include base/screens/thermostat.yaml # optional: thermostat (climate.* entity; knob sets target, tap on/off) - !include base/screens/sensors.yaml # optional: sensors glance (1-6 HA entities, knob cycles) #- !include base/screens/demo.yaml # optional: commented example screen (TAP ME!) + Widgets settings @@ -89,6 +88,5 @@ packages: - !include base/watchfaces/neon.yaml # optional: Neon - big two-tone digits + neon rings - !include base/watchfaces/minecraft.yaml # optional: Minecraft - blocky scene + pixel clock - !include base/watchfaces/demo.yaml # optional: Demo - minimal, heavily-commented template to copy - # Wi-Fi comes from your local secrets.yaml (the core uses !secret wifi_ssid / wifi_password). # Keep a secrets.yaml and partitions.csv next to this file (both must be local paths).