From d60a0f122b6e5501dc58390111887afd5045c8bc Mon Sep 17 00:00:00 2001 From: Max Gramser Date: Thu, 17 Sep 2026 15:31:11 +0200 Subject: [PATCH] Show who is at the door: camera images on the Guition (0.2.66) An alert from esp_screens_show_alert takes a `camera` (a camera.* or image.* entity): a Guition with firmware 0.2.57 shows that moment's picture across the top of the card, and a tap opens the camera full screen. A camera or image tile opens the same full-screen view, refreshed every four seconds at a steady pace. ESP Screen Manager fetches the snapshot with its own access, sizes it for the screen and serves a 24-bit BMP under a random, short-lived link on port 8098; the screen loads it with ESPHome's online_image and holds no Home Assistant token. BMP because ESPHome decodes it per chunk, where a full-screen JPEG held the loop 0.6 s. The CYD keeps its alerts without the picture and gets no camera tiles. The Guition also builds with ESPHome 2026.8+ again: backlight_fade.h derived from ESPHome's LEDC output, which 2026.8 made final, so the backlight now dims through ESPHome's own light transition. Tested on the bench boards and a local add-on on the Home Assistant Yellow; docs/TEST_RESULTS_0266.md. Co-Authored-By: Claude Opus 5 --- README.md | 9 +- README_EXTENDED.md | 29 ++ components/smart_display/backlight_fade.h | 60 --- components/smart_display/camera_view.h | 50 +++ .../smart_display/guition_diagnostics.h | 27 +- components/smart_display/runtime_model.h | 2 +- components/smart_display/runtime_tiles.h | 278 ++++++++++++ components/smart_display/theme.h | 10 +- docs/CAMERA.md | 84 ++++ docs/DOCKER.md | 8 +- docs/GUITION.md | 8 +- docs/RELEASING.md | 45 ++ docs/TEST_RESULTS_0266.md | 95 +++++ docs/images/guition-alert-camera.png | Bin 0 -> 127080 bytes docs/images/guition-camera.png | Bin 0 -> 156346 bytes guition-4848s040.yaml | 153 ++++++- home-like-2432s028.yaml | 2 +- packages/cyd.yaml | 2 +- packages/guition.yaml | 153 ++++++- screen_manager/CHANGELOG.md | 13 + screen_manager/app/camera_feed.py | 283 +++++++++++++ screen_manager/app/claude_skill.py | 4 +- screen_manager/app/core.py | 28 +- screen_manager/app/server.py | 123 +++++- screen_manager/app/static/app.js | 17 + screen_manager/app/tile_icons.py | 2 +- screen_manager/config.yaml | 7 +- tests/test_camera.py | 399 ++++++++++++++++++ tests/test_camera_view.cpp | 65 +++ tests/test_wake_sleep.py | 6 +- tools/render_topbar.py | 2 +- 31 files changed, 1847 insertions(+), 117 deletions(-) delete mode 100644 components/smart_display/backlight_fade.h create mode 100644 components/smart_display/camera_view.h create mode 100644 docs/CAMERA.md create mode 100644 docs/TEST_RESULTS_0266.md create mode 100644 docs/images/guition-alert-camera.png create mode 100644 docs/images/guition-camera.png create mode 100644 screen_manager/app/camera_feed.py create mode 100644 tests/test_camera.py create mode 100644 tests/test_camera_view.cpp diff --git a/README.md b/README.md index f6a28ce..9855d12 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ lights, the heating or the vacuum. **What.** Firmware for two affordable panels, the 2.8-inch CYD and the 4-inch Guition, with up to twenty tiles over four pages: lights, climate, blinds and curtains, the vacuum, media, the weather, history graphs, clocks and timers. An automation can put an alert on every screen when someone rings -the bell. +the bell, and a Guition shows who is there with the doorbell camera's picture. **How.** ESP Screen Manager is an app inside Home Assistant. It flashes a new screen over USB, updates it over Wi-Fi and sends it your tiles. Changing a screen is pick, drag and **Save & send to screen**: @@ -77,11 +77,16 @@ no reflash, no YAML to write, no blueprint, MQTT or token. ## Alerts +

+ An alert on the Guition with the front door camera's picture across the top: someone is at the door, with a Coming button + The front door camera full screen on the Guition, with the round back key and the camera's name at the top +

+

Someone at the door? One event in an automation wakes every screen and shows it. Add the doorbell camera and a Guition shows who is there; tap the picture, or a camera tile, for the camera full screen, refreshed every few seconds. Camera images.

An alert on the Guition: someone is at the door, with a Coming button The Alerts cheatsheet in ESP Screens: the action name of every screen, ready to copy

-

Someone at the door? One action in an automation wakes the screen and shows it, on one screen or all of them. How alerts work.

+

Any alert, on one screen or all of them, in a pastel color of your choice. How alerts work.

## Installing from Home Assistant diff --git a/README_EXTENDED.md b/README_EXTENDED.md index 8c42d82..445253c 100644 --- a/README_EXTENDED.md +++ b/README_EXTENDED.md @@ -209,6 +209,35 @@ actions: **`esp_screens_dismiss_alert`** clears the alert on every screen. The app has to be running for these two events; the per-screen actions work without it. +### With a camera picture + +

+ An alert on the Guition with the front door camera's picture across the top: someone is at the door, with a Coming button + The front door camera full screen on the Guition, with the round back key and the camera's name at the top +

+ +From app 0.2.66, the event takes one more field: **`camera`**, a `camera.*` or `image.*` entity. +A Guition with firmware 0.2.57+ shows that camera's picture of the moment across the top of the +card; a tap on it opens the camera full screen over the alert, and Back returns to the alert. +Other screens show the same alert without the picture. The per-screen actions have no `camera` +field. + +```yaml +actions: + - event: esp_screens_show_alert + event_data: + title: "Someone is at the door" + subtitle: "Front door" + icon: doorbell + color: orange + button_text: "Coming" + camera: camera.front_door +``` + +A camera or image entity also works as a **tile** on a Guition: a tap opens it full screen, refreshed +every four seconds. How the image travels (port 8098 of the app, no token on the screen) is in +[docs/CAMERA.md](docs/CAMERA.md). + ### Ask Claude Use Claude Code in Home Assistant? **Settings → Claude → Install for Claude Code** writes an diff --git a/components/smart_display/backlight_fade.h b/components/smart_display/backlight_fade.h deleted file mode 100644 index a5e404f..0000000 --- a/components/smart_display/backlight_fade.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include -#include -#include -#include "esphome/components/ledc/ledc_output.h" -#include "esphome/components/light/light_state.h" - -// Backlight fades through the LEDC hardware fader. ESPHome's software -// transition steps the duty from the main loop, and the full LVGL redraws that -// standby triggers on the Guition's RGB panel stall that loop long enough to -// make dimming visibly jerky. The peripheral steps on its own clock instead. -namespace backlight_fade { -template struct Peek : T { - static uint8_t channel(T &o) { return o.*(&Peek::channel_); } - static uint8_t bits(T &o) { return o.*(&Peek::bit_depth_); } -}; -inline bool installed = false, hardware_owns = false; -inline ledc_mode_t mode(uint8_t channel) { -#ifdef SOC_LEDC_SUPPORT_HS_MODE - return channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE; -#else - return LEDC_LOW_SPEED_MODE; -#endif -} -// Returns false when the fader is unavailable; the caller keeps ESPHome's transition. -inline bool start(esphome::ledc::LEDCOutput &output, esphome::light::LightState &light, float level, uint32_t ms) { -#ifndef SOC_LEDC_SUPPORT_FADE_STOP - return false; // Classic ESP32 cannot interrupt a running fade for a touch wake. -#else - using P = Peek; - const auto channel = static_cast(P::channel(output)); - const uint8_t bits = P::bits(output); - if (!bits) return false; - if (!installed) installed = ledc_fade_func_install(0) == ESP_OK; - if (!installed) return false; - const auto speed = mode(channel); - const uint32_t max_duty = (1u << bits) - 1; - ledc_fade_stop(speed, channel); - // ESPHome parks 0 % and 100 % with ledc_stop and leaves a stale duty register. - // Restart the channel at the level it believes, unless a fade already owns it. - float current = 0; - light.current_values_as_brightness(¤t); - const uint32_t from = hardware_owns ? ledc_get_duty(speed, channel) : static_cast(std::lround(current * max_duty)); - ledc_set_duty(speed, channel, from); - ledc_update_duty(speed, channel); - hardware_owns = true; - const auto target = static_cast(std::lround(light.gamma_correct_lut(std::clamp(level, 0.0f, 1.0f)) * max_duty)); - return ledc_set_fade_with_time(speed, channel, target, ms) == ESP_OK && - ledc_fade_start(speed, channel, LEDC_FADE_NO_WAIT) == ESP_OK; -#endif -} -// Hand the finished level back to ESPHome so HA and later transitions start from the truth. -inline void sync(esphome::ledc::LEDCOutput &output, esphome::light::LightState &light, float level) { -#ifdef SOC_LEDC_SUPPORT_FADE_STOP - if (hardware_owns) ledc_fade_stop(mode(Peek::channel(output)), static_cast(Peek::channel(output))); -#endif - light.turn_on().set_transition_length(0).set_brightness(std::clamp(level, 0.0f, 1.0f)).perform(); - hardware_owns = false; -} -} // namespace backlight_fade diff --git a/components/smart_display/camera_view.h b/components/smart_display/camera_view.h new file mode 100644 index 0000000..0f76390 --- /dev/null +++ b/components/smart_display/camera_view.h @@ -0,0 +1,50 @@ +#pragma once +// A camera image full screen (firmware 0.2.57+, Guition): when to ask ESP Screen Manager for a link and when to load it +// again. Pure bookkeeping, free of LVGL and ESPHome, so tests/test_camera_view.cpp can check it on a PC; runtime_tiles.h +// draws the view and the board's online_image loads the link. +// +// The app answers `esphome.screen_camera` with a link to a BMP it keeps fresh (screen_manager/app/camera_feed.py). +// Loading shares the main loop with touch and drawing, so the view loads one image at a time and leaves time free after +// each. The rhythm is fixed rather than as fast as the Wi-Fi allows: a picture every four seconds, every time, reads as +// smoother than one after three seconds and the next after five. Never a queue: a slow load makes the next one later. +#include +#include + +namespace camera_view { +constexpr uint32_t REFRESH_MS = 4000; // from the start of one load to the start of the next: a steady rhythm +constexpr uint32_t GAP_MS = 800; // at least this long between the end of one load and the next +constexpr uint32_t ASK_AGAIN_MS = 10000; // a link that does not come (or an app without an image) is asked for again +constexpr uint8_t MAX_FAILURES = 3; // a link that fails this often in a row is old: ask for a new one +constexpr uint32_t PENDING_MS = 20000; // an alert's camera announced this long before the alert still belongs to it + +struct Feed { + std::string entity, url; + uint32_t asked_at = 0, started_at = 0, finished_at = 0; + bool asked = false, loading = false, shown = false, empty = false; // empty: the app said it has no image + uint8_t failures = 0; + + void open(const std::string &camera) { *this = Feed{}; entity = camera; } + bool open() const { return !entity.empty(); } + bool should_ask(uint32_t now) const { return open() && !loading && url.empty() && (!asked || now - asked_at >= ASK_AGAIN_MS); } + void ask(uint32_t now) { asked = true; asked_at = now; } + // The app's answer: a link, or none (no image from Home Assistant, or a camera this screen may not show). + void link(const std::string &address) { + url = address; + empty = address.empty(); + failures = 0; + started_at = finished_at = 0; + } + bool should_load(uint32_t now) const { + if (!open() || loading || url.empty()) return false; + if (!started_at) return true; + return now - started_at >= REFRESH_MS && now - finished_at >= GAP_MS; + } + void start(uint32_t now) { loading = true; started_at = now ? now : 1; } + void finish(uint32_t now, bool ok) { + loading = false; + finished_at = now; + if (ok) { shown = true; failures = 0; return; } + if (++failures >= MAX_FAILURES) { url.clear(); asked = false; failures = 0; } + } +}; +} // namespace camera_view diff --git a/components/smart_display/guition_diagnostics.h b/components/smart_display/guition_diagnostics.h index 13b94f1..9d4b273 100644 --- a/components/smart_display/guition_diagnostics.h +++ b/components/smart_display/guition_diagnostics.h @@ -23,9 +23,13 @@ inline bool check_geometry(lv_obj_t *obj) { } #if LV_USE_SNAPSHOT inline lv_draw_buf_t *snapshot = nullptr; +// LVGL's top layer (an alert, a camera full screen) when something is shown on it, with its transparency. +inline lv_draw_buf_t *overlay = nullptr; inline int snapshot_row = 0; inline void snapshot_begin() { if (snapshot) lv_draw_buf_destroy(snapshot); + if (overlay) lv_draw_buf_destroy(overlay); + overlay = nullptr; snapshot = lv_snapshot_take(lv_screen_active(), LV_COLOR_FORMAT_RGB565); snapshot_row = 0; if (!snapshot || snapshot->header.w != 480 || snapshot->header.h != 480) { @@ -34,7 +38,24 @@ inline void snapshot_begin() { ESP_LOGE("ui_image", "IMAGE FAIL allocation/dimensions"); return; } - ESP_LOGI("ui_image", "IMAGE BEGIN 240 240"); + for (uint32_t i = 0; i < lv_obj_get_child_count(lv_layer_top()); ++i) + if (!lv_obj_has_flag(lv_obj_get_child(lv_layer_top(), i), LV_OBJ_FLAG_HIDDEN)) { + overlay = lv_snapshot_take(lv_layer_top(), LV_COLOR_FORMAT_ARGB8888); + if (overlay && (overlay->header.w != 480 || overlay->header.h != 480)) { lv_draw_buf_destroy(overlay); overlay = nullptr; } + break; + } + ESP_LOGI("ui_image", "IMAGE BEGIN 240 240%s", overlay ? " with top layer" : ""); +} +// The top layer's pixel over the page's, as the panel shows them. +inline uint16_t layered(uint16_t pixel, int x, int y) { + if (!overlay) return pixel; + const uint8_t *p = overlay->data + y * overlay->header.stride + x * 4; // B, G, R, A + const unsigned alpha = p[3]; + if (!alpha) return pixel; + const unsigned r = ((pixel >> 11) & 31) * 255 / 31, g = ((pixel >> 5) & 63) * 255 / 63, b = (pixel & 31) * 255 / 31; + const unsigned mr = (p[2] * alpha + r * (255 - alpha)) / 255, mg = (p[1] * alpha + g * (255 - alpha)) / 255, + mb = (p[0] * alpha + b * (255 - alpha)) / 255; + return static_cast((mr * 31 / 255) << 11 | (mg * 63 / 255) << 5 | (mb * 31 / 255)); } inline void snapshot_next_row() { if (!snapshot) return; @@ -43,7 +64,7 @@ inline void snapshot_next_row() { static constexpr char hex[] = "0123456789abcdef"; char line[961]; for (int x = 0; x < 240; ++x) { - uint16_t pixel = row[x * 2]; + uint16_t pixel = layered(row[x * 2], x * 2, snapshot_row * 2); for (int digit = 0; digit < 4; ++digit) line[x * 4 + digit] = hex[(pixel >> (12 - digit * 4)) & 15]; } @@ -52,6 +73,8 @@ inline void snapshot_next_row() { if (++snapshot_row == 240) { lv_draw_buf_destroy(snapshot); snapshot = nullptr; + if (overlay) lv_draw_buf_destroy(overlay); + overlay = nullptr; ESP_LOGI("ui_image", "IMAGE COMPLETE"); } } diff --git a/components/smart_display/runtime_model.h b/components/smart_display/runtime_model.h index c51da7d..1e37a0c 100644 --- a/components/smart_display/runtime_model.h +++ b/components/smart_display/runtime_model.h @@ -23,7 +23,7 @@ inline bool valid_entity(const std::string &entity) { std::string domain = entity.substr(0, dot); // screen.* are built-in cards without a Home Assistant entity behind them. if (domain == "screen") return entity == "screen.clock" || entity == "screen.settings"; - for (const auto *allowed : {"light", "switch", "input_boolean", "scene", "script", "climate", "vacuum", "fan", "cover", "sensor", "binary_sensor", "input_select", "select", "number", "input_number", "weather", "media_player", "button", "input_button", "sun", "timer", "person"}) + for (const auto *allowed : {"light", "switch", "input_boolean", "scene", "script", "climate", "vacuum", "fan", "cover", "sensor", "binary_sensor", "input_select", "select", "number", "input_number", "weather", "media_player", "button", "input_button", "sun", "timer", "person", "camera", "image"}) if (domain == allowed) return true; return false; } diff --git a/components/smart_display/runtime_tiles.h b/components/smart_display/runtime_tiles.h index c14658f..22b7a30 100644 --- a/components/smart_display/runtime_tiles.h +++ b/components/smart_display/runtime_tiles.h @@ -11,6 +11,7 @@ #include "light_controls.h" #include "tile_controls.h" #include "history_view.h" +#include "camera_view.h" #include "swipe_profile.h" #include "esphome/components/json/json_util.h" #include "esphome/components/api/api_server.h" @@ -71,6 +72,10 @@ inline const char *weather_text(const std::string &condition); inline std::string timer_text(const Tile &t); inline std::string last_run_text(uint32_t epoch); inline void history_received(); +// Camera images full screen and on an alert (firmware 0.2.57+, the Guition binds them; see the end of this file). +inline void camera_open(const std::string &entity, const std::string &name); +inline void camera_answer(const std::string &view, const std::string &entity, const std::string &url); +inline bool camera_supported(); inline uint32_t domain_accent(const Tile &t); inline const char *icon_for(const Tile &tile); inline void label(lv_obj_t *obj, const std::string &text); @@ -340,6 +345,16 @@ inline std::string receive(const std::string &payload) { result = model.ready() ? "Synced" : "Loading tiles"; return true; } + if (op == "camera") { + // A link to a camera's image (app 0.2.66+): the answer to camera_request ("full"), or an alert's image ("alert", + // announced with an empty link before show_alert and sent again with the link). Only ESP Screens' own port. + const std::string view = string(root["t"], 8), entity = string(root["e"], 120), url = string(root["u"], 240); + if (!valid_entity(entity) || (view != "full" && view != "alert")) return false; + if (!url.empty() && url.rfind("http://", 0) != 0) return false; + camera_answer(view, entity, url); + result = model.ready() ? "Synced" : "Loading tiles"; + return true; + } if (op == "history") { // A detail card's history (app 0.2.59+), the answer to history_request. Checked whole before it replaces // the one the screen holds. @@ -1684,6 +1699,7 @@ inline const char *icon_for(const Tile &tile) { if (d == "timer") return "\U000F051B"; if (d == "person") return "\U000F0004"; if (d == "screen") return tile.is_settings() ? "\U000F0493" : "\U000F0150"; + if (d == "camera" || d == "image") return "\U000F07AE"; return "\U000F0425"; } // HA duration strings ("0:05:00") to seconds; 0 when unusable. @@ -1749,6 +1765,8 @@ inline void event(lv_event_t *event) { auto d = tile.domain(); // Scenes/scripts often have timestamps or 'off'; unavailable devices never act. if (!tile.available() || tile.loading(esphome::millis()) || tile.tap=="none") return; + // A camera or an image entity opens full screen on a board that draws images (firmware 0.2.57+). + if(d=="camera" || d=="image"){if(camera_supported())camera_open(tile.entity,tile.name);return;} bool open = code == LV_EVENT_LONG_PRESSED || d == "climate" || d == "vacuum" || d == "cover"; if(code==LV_EVENT_SHORT_CLICKED && tile.tap=="detail")open=true; if(code==LV_EVENT_SHORT_CLICKED && tile.tap=="toggle")open=false; @@ -2395,6 +2413,8 @@ inline void render_slot(size_t slot) { else if (d == "sun") value = !t.extra().sunrise.empty() && !t.extra().sunset.empty() ? t.extra().sunrise+" - "+t.extra().sunset : t.state=="above_horizon"?"Above the horizon":"Below the horizon"; else if (d == "timer") value = timer_text(t); else if (d == "script" || d == "scene" || d == "button" || d == "input_button") value = t.state == "on" ? "Running..." : last_run_text(t.last_run); + else if (d == "camera") value = t.state == "streaming" ? "Live" : t.state == "recording" ? "Recording" : "Tap to view"; + else if (d == "image") value = t.last_run ? "Tap to view" : "No image yet"; else if (d == "binary_sensor" && (value == "on" || value == "off")) value = tile_controls::binary_state_text(t.device_class, value == "on"); else if (value == "on") value = "On"; else if (value == "off") value = "Off"; @@ -3084,3 +3104,261 @@ inline std::string vacuum_option(unsigned index) { return index < speeds.size() ? speeds[index] : ""; } } + +// ---- Camera images (firmware 0.2.57+) ---- +// A camera or image tile, and an alert's image, open the camera full screen: the image as large as fits, the round back +// key at the top left like on every card, the name beside it. ESP Screen Manager fetches the snapshot, sizes it for this +// screen and serves it on its own port; camera_view::Feed decides when to ask for a link and when to load it again. The +// board binds the two online_images (the full view and the alert's frame) through ImageHooks; a board without them (the +// CYD) never opens the view. Nothing here exists while no camera is open, apart from the alert's small frame. +namespace runtime_tiles { +struct ImageHooks { + std::function load; // set the online_image's URL and download it + std::function release; // free the decoded image + std::function source; // the decoded image for LVGL +}; +inline ImageHooks camera_full, camera_thumb; +inline camera_view::Feed camera; +// Freeing the image waits for the next tick: ending a download under way can take a few hundred ms, and Back should +// show the page below at once. +inline bool camera_release_due = false; +inline lv_obj_t *camera_root = nullptr, *camera_picture = nullptr, *camera_note = nullptr, *camera_back = nullptr, *camera_title = nullptr; +// The alert's image: the board's frame at the bottom left of the card, the camera the app announced for the next alert +// and the one the card on screen shows. +inline lv_obj_t *alert_frame = nullptr, *alert_picture = nullptr, *alert_frame_icon = nullptr; +inline std::function alert_room; // the board makes the card taller for the frame, or back +inline std::string alert_announced, alert_camera, alert_url; +inline uint32_t alert_announced_at = 0, alert_retry_at = 0; +inline uint8_t alert_retries = 0; +inline bool alert_thumb_loading = false; +constexpr uint8_t ALERT_IMAGE_RETRIES = 3; // an alert's picture is worth another try after a failed connection + +inline bool camera_supported() { return static_cast(camera_full.load); } +inline bool camera_visible() { return camera_root != nullptr; } + +// Asks ESP Screen Manager for a link (app 0.2.66+ answers with op "camera"). An event, like history_request. +inline void camera_request(const std::string &entity) { + if (inbox.empty()) return; + esphome::api::HomeassistantActionRequest request; + request.service = esphome::StringRef("esphome.screen_camera"); + request.is_event = true; + const std::string keys[] = {"inbox", "entity"}, values[] = {inbox, entity}; + request.data.init(2); + for (int i = 0; i < 2; ++i) { + esphome::api::HomeassistantServiceMap entry; + entry.key = esphome::StringRef(keys[i]); + entry.value = esphome::StringRef(values[i]); + request.data.push_back(entry); + } + esphome::api::global_api_server->send_homeassistant_action(request); + ESP_LOGI("camera", "asked for %s", entity.c_str()); +} + +inline void camera_note_text(const char *text) { + if (!camera_note) return; + lv_label_set_text(camera_note, text); + if (text[0]) lv_obj_remove_flag(camera_note, LV_OBJ_FLAG_HIDDEN); + else lv_obj_add_flag(camera_note, LV_OBJ_FLAG_HIDDEN); +} + +inline void camera_release() { + camera_release_due = false; + if (camera_full.release) camera_full.release(); +} + +inline void camera_close() { + if (!camera_root) return; + lv_obj_delete(camera_root); + camera_root = camera_picture = camera_note = camera_back = camera_title = nullptr; + camera_release_due = true; + ESP_LOGI("camera", "closed %s", camera.entity.c_str()); + camera = camera_view::Feed{}; +} + +inline void camera_open(const std::string &entity, const std::string &name) { + if (!camera_supported() || !valid_entity(entity)) return; + camera_close(); + // The last camera's image goes before this one loads into the same online_image. + if (camera_release_due) camera_release(); + camera.open(entity); + const int width = lv_display_get_horizontal_resolution(lv_display_get_default()); + const bool large = width >= 480; + // On the top layer: above the tiles, every card and an alert, which is there again after Back. + camera_root = lv_obj_create(lv_layer_top()); + lv_obj_remove_style_all(camera_root); + lv_obj_set_size(camera_root, lv_pct(100), lv_pct(100)); + lv_obj_remove_flag(camera_root, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_add_flag(camera_root, LV_OBJ_FLAG_CLICKABLE); // nothing reaches the tiles below + lv_obj_set_style_bg_color(camera_root, theme::color(theme::CAMERA_PAGE), 0); + lv_obj_set_style_bg_opa(camera_root, LV_OPA_COVER, 0); + camera_note = lv_label_create(camera_root); + if (detail_font) lv_obj_set_style_text_font(camera_note, detail_font, 0); + lv_obj_set_style_text_color(camera_note, theme::color(theme::CAMERA_NOTE), 0); + lv_obj_center(camera_note); + camera_note_text("Loading image"); + // The same top bar as a tile's card: a round back arrow at the left, the name centred. + const int bar = large ? 60 : 40, bar_x = large ? 16 : 10, bar_y = large ? 16 : 8; + camera_back = lv_obj_create(camera_root); + lv_obj_remove_style_all(camera_back); + lv_obj_set_pos(camera_back, bar_x, bar_y); + lv_obj_set_size(camera_back, bar, bar); + lv_obj_add_flag(camera_back, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_style_radius(camera_back, LV_RADIUS_CIRCLE, 0); + lv_obj_set_style_bg_opa(camera_back, LV_OPA_COVER, 0); + lv_obj_set_style_bg_color(camera_back, theme::color(theme::KEY), 0); + lv_obj_set_style_bg_color(camera_back, theme::color(theme::KEY_PRESSED), LV_STATE_PRESSED); + auto *arrow = lv_label_create(camera_back); + if (mini_icon_font) lv_obj_set_style_text_font(arrow, mini_icon_font, 0); + lv_obj_set_style_text_color(arrow, theme::color(theme::INK), 0); + lv_label_set_text(arrow, "\U000F004D"); + lv_obj_center(arrow); + lv_obj_add_event_cb(camera_back, [](lv_event_t *) { + // Closed after this event: the key that sends it goes with the view. + lv_async_call([](void *) { camera_close(); }, nullptr); + }, LV_EVENT_SHORT_CLICKED, nullptr); + const lv_font_t *title_font = watch_font ? watch_font : detail_font; + camera_title = lv_label_create(camera_root); + if (title_font) lv_obj_set_style_text_font(camera_title, title_font, 0); + lv_obj_set_style_text_color(camera_title, theme::color(theme::CAMERA_INK), 0); + lv_obj_set_style_text_align(camera_title, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_long_mode(camera_title, LV_LABEL_LONG_DOT); + lv_obj_set_pos(camera_title, bar_x + bar + 8, bar_y + (bar - (title_font ? lv_font_get_line_height(title_font) : 20)) / 2); + lv_obj_set_size(camera_title, width - 2 * (bar_x + bar + 8), title_font ? lv_font_get_line_height(title_font) : 20); + lv_label_set_text(camera_title, name.c_str()); + ESP_LOGI("camera", "open %s", entity.c_str()); +} + +// The board's interval (250 ms): ask for a link, or load the image again when it is time. Loading happens here, in +// ESPHome's loop, and never while the screen is in standby. +inline void camera_tick() { + const uint32_t now = esphome::millis(); + if (camera_release_due && !camera_root) camera_release(); + if (alert_retry_at && now >= alert_retry_at) { + alert_retry_at = 0; + if (!alert_camera.empty() && !alert_url.empty() && camera_thumb.load) { + alert_thumb_loading = true; + camera_thumb.load(alert_url); + } + } + if (!camera_root || !awake()) return; + if (camera.should_ask(now)) { + if (!fresh()) return; + camera.ask(now); + camera_request(camera.entity); + } else if (camera.should_load(now)) { + // Not under a finger: a load that starts now would hold up the tap that is on its way. + auto *input = lv_indev_get_next(nullptr); + if (input && lv_indev_get_state(input) == LV_INDEV_STATE_PRESSED) return; + camera.start(now); + camera_full.load(camera.url); + } +} + +inline void alert_picture_clear() { + alert_retry_at = 0; + if (alert_picture) { lv_obj_delete(alert_picture); alert_picture = nullptr; } + if (alert_frame_icon) lv_obj_remove_flag(alert_frame_icon, LV_OBJ_FLAG_HIDDEN); + if (alert_thumb_loading || alert_camera.size()) { if (camera_thumb.release) camera_thumb.release(); } + alert_thumb_loading = false; +} + +// alert_show: the card gets its frame when the app announced a camera for it just before. A new alert closes the camera. +inline void alert_prepare() { + camera_close(); + alert_picture_clear(); + const bool with_image = camera_supported() && alert_frame && !alert_announced.empty() && + esphome::millis() - alert_announced_at < camera_view::PENDING_MS; + alert_camera = with_image ? alert_announced : std::string(); + alert_url.clear(); + alert_announced.clear(); + if (alert_frame) { + if (with_image) lv_obj_remove_flag(alert_frame, LV_OBJ_FLAG_HIDDEN); + else lv_obj_add_flag(alert_frame, LV_OBJ_FLAG_HIDDEN); + } + if (alert_room) alert_room(with_image); +} + +// alert_dismiss: the frame goes, and so does its image. +inline void alert_clear() { + alert_picture_clear(); + alert_camera.clear(); + alert_url.clear(); + if (alert_frame) lv_obj_add_flag(alert_frame, LV_OBJ_FLAG_HIDDEN); +} + +inline void camera_answer(const std::string &view, const std::string &entity, const std::string &url) { + if (!camera_supported()) return; + if (view == "full") { + if (!camera_root || camera.entity != entity) return; + camera.link(url); + if (url.empty() && !camera.shown) camera_note_text("No image from this camera"); + return; + } + if (url.empty()) { // announced before its alert + alert_announced = entity; + alert_announced_at = esphome::millis(); + return; + } + if (entity != alert_camera || !alert_frame || lv_obj_has_flag(alert_frame, LV_OBJ_FLAG_HIDDEN)) return; + alert_picture_clear(); + alert_url = url; + alert_retries = 0; + alert_thumb_loading = true; + camera_thumb.load(url); +} + +// LVGL's image widget is only built for a board whose profile draws images (the Guition's hidden seed); the CYD's has none. +inline void camera_show(lv_obj_t *parent, lv_obj_t *&picture, lv_image_dsc_t *source, bool fresh_pixels) { +#if LV_USE_IMAGE + if (!source || !source->data) return; + if (!picture) { + picture = lv_image_create(parent); + lv_obj_remove_flag(picture, LV_OBJ_FLAG_CLICKABLE); + lv_image_set_src(picture, source); + lv_obj_center(picture); + return; + } + if (!fresh_pixels) return; + // The same buffer with new pixels. LVGL keeps no decoded copy of an RGB565 image (its image cache is off in + // ESPHome's build), so drawing the area again shows them. + lv_image_set_src(picture, source); + lv_obj_invalidate(picture); +#else + (void) parent; (void) picture; (void) source; (void) fresh_pixels; +#endif +} + +// The board's online_image triggers. `thumb`: the alert's frame; `cached`: the app answered 304, the image is unchanged. +inline void camera_loaded(bool thumb, bool cached) { + if (thumb) { + alert_thumb_loading = false; + if (alert_camera.empty() || !alert_frame) return; + camera_show(alert_frame, alert_picture, camera_thumb.source(), !cached); + if (alert_picture && alert_frame_icon) lv_obj_add_flag(alert_frame_icon, LV_OBJ_FLAG_HIDDEN); + return; + } + if (!camera_root) return; + camera.finish(esphome::millis(), true); + const bool first = camera_picture == nullptr; + camera_show(camera_root, camera_picture, camera_full.source(), !cached); + if (first && camera_picture) { + camera_note_text(""); + lv_obj_move_foreground(camera_back); + lv_obj_move_foreground(camera_title); + } +} + +inline void camera_failed(bool thumb) { + if (thumb) { + alert_thumb_loading = false; + if (!alert_camera.empty() && !alert_picture && alert_retries < ALERT_IMAGE_RETRIES) { + ++alert_retries; + alert_retry_at = esphome::millis() + 1500; + } + return; + } + if (!camera_root) return; + camera.finish(esphome::millis(), false); + if (!camera.shown) camera_note_text("No image from this camera"); +} +} // namespace runtime_tiles diff --git a/components/smart_display/theme.h b/components/smart_display/theme.h index ff49afe..35b7639 100644 --- a/components/smart_display/theme.h +++ b/components/smart_display/theme.h @@ -73,6 +73,10 @@ enum Role : uint8_t { AMBER_TRACK, // the track of a light's brightness slider HISTORY_OFF, // an off or away stretch on a timeline (the add-on's CFCFCF) HISTORY_EMPTY, // a stretch without data on a timeline (the add-on's E6E6E6) + // ---- a camera image: dark in both looks, like a photo viewer (firmware 0.2.57+) + CAMERA_PAGE, // behind the image full screen and in the alert's image frame + CAMERA_INK, // the camera's name over the image + CAMERA_NOTE, // "Loading image", "No image from this camera" // ---- the CYD's touch calibration: dark in both looks, a yellow crosshair CALIBRATION_PAGE, CALIBRATION_INK, @@ -137,6 +141,9 @@ inline constexpr Pair ROLES[ROLE_COUNT] = { /* AMBER_TRACK */ {0xFDEFC3, 0x483B16}, /* HISTORY_OFF */ {0xCFCFCF, 0x4A4A4A}, /* HISTORY_EMPTY */ {0xE6E6E6, 0x2A2A2A}, + /* CAMERA_PAGE */ {0x000000, 0x000000}, + /* CAMERA_INK */ {0xF2F2F2, 0xDADADA}, + /* CAMERA_NOTE */ {0x9E9E9E, 0x8A8A8A}, /* CALIBRATION_PAGE */ {0x101820, 0x101820}, /* CALIBRATION_INK */ {0xFFFFFF, 0xFFFFFF}, /* CALIBRATION_MARK */ {0xFFD34D, 0xFFD34D}, @@ -281,7 +288,7 @@ inline lv_color_t rgb(uint32_t value) { return lv_color_hex(value); } constexpr uint8_t NONE = 0xFF; enum class Paint : uint8_t { page, page_soft, page_pressed, card, raised, key, key_pressed, track, ink, ink_soft, muted, subtle, slate, - scrim, veil, accent_tint, accent_bright, button_dark, button_dark_pressed, knob, spinner, calibration, COUNT + scrim, veil, accent_tint, accent_bright, button_dark, button_dark_pressed, knob, spinner, calibration, camera, COUNT }; struct PaintRoles { uint8_t bg, border, text, line, arc; }; inline constexpr PaintRoles PAINTS[static_cast(Paint::COUNT)] = { @@ -307,6 +314,7 @@ inline constexpr PaintRoles PAINTS[static_cast(Paint::COUNT)] = { /* knob */ {KNOB, NONE, NONE, NONE, NONE}, /* spinner */ {NONE, NONE, NONE, NONE, SPINNER_TRACK}, /* calibration */ {CALIBRATION_PAGE, NONE, CALIBRATION_INK, NONE, NONE}, + /* camera */ {CAMERA_PAGE, NONE, CAMERA_NOTE, NONE, NONE}, }; // Fill a style with a paint in the current look. Setting a property the style already has allocates nothing. inline void fill(lv_style_t *style, Paint paint) { diff --git a/docs/CAMERA.md b/docs/CAMERA.md new file mode 100644 index 0000000..0131dba --- /dev/null +++ b/docs/CAMERA.md @@ -0,0 +1,84 @@ +# Camera images on a Guition + +App 0.2.66 with firmware 0.2.57 shows camera images on a Guition 4848S040: + +- **A camera tile.** Add a `camera.*` or `image.*` entity as a tile. A tap opens the image full + screen, with the round back key at the top left like every card. The image is refreshed every + four seconds while it is open. It is not video: ESPHome has no video decoder. +- **An alert with a picture.** Add `camera: camera.front_door` to the `esp_screens_show_alert` + event. The card shows the picture of that moment across its top (it stays that picture); a tap + on it opens the camera full screen over the alert, and Back returns to the alert. + +The CYD has no memory for images (a 320×180 image needs 115 KB in one piece, the CYD's largest +free block is about 45 KB). It shows the alert without the picture, and the editor doesn't offer +camera tiles for it. + +## A doorbell + +```yaml +triggers: + - trigger: state + entity_id: event.front_door_ding +actions: + - event: esp_screens_show_alert + event_data: + title: Someone is at the door + icon: doorbell + camera: camera.front_door + timeout: 60 +``` + +Any `camera.*` entity works, and so does an `image.*` entity, such as the snapshot a doorbell or +motion integration keeps of its last event. + +## How the image gets to the screen + +The screen never talks to Home Assistant about images, and it never holds a Home Assistant token. + +1. The screen asks ESP Screen Manager for a camera (the event `esphome.screen_camera`), or the app + sends the picture of an alert by itself. +2. The app fetches the snapshot from Home Assistant with its own access (the same pictures the + Home Assistant frontend shows), and makes it exactly as large as the screen draws it: at most + 480×480 full screen, 392×220 on an alert card, proportions kept. +3. It serves the result as an uncompressed 24-bit BMP on **port 8098** under a random link, and + sends the link to the screen. ESPHome's `online_image` loads it. + +While a camera is open, the screen loads its link every four seconds, one image at a time. The app +serves the last snapshot at once and starts fetching the next one, so each load gets a picture one +load younger: the picture changes at the screen's steady pace. (A fetch on its own clock next to the +screen's made the picture change after 1.5 s one time and 6 s the next.) A slow camera makes the +images older, never the screen slower, and nothing queues up. Nobody loading means nothing fetched. +A link that nobody loads for two minutes stops working; an alert's picture stays for half an hour. + +**Why BMP.** ESPHome decodes a BMP piece by piece while it downloads (4 KB per round of its main +loop). A JPEG of the full screen took 0.6 s in one piece on the Guition, during which the screen +missed taps. A full-screen BMP is about 390 KB; on the LAN that takes one to three seconds. + +## Network + +- **Home Assistant OS:** the app publishes port 8098 on the Home Assistant host. Keep it at 8098 in + the app's network settings; the screens need to reach Home Assistant's address on that port. +- **Docker** (docs/DOCKER.md): the container uses the host network, so 8098 is open as is. When + the screens reach the host under another address, set `SCREEN_CAMERA_URL`, for example + `http://192.168.1.20:8098`. +- The images travel unencrypted over the LAN, like the screens' other HTTP traffic. Links are + random, short-lived, and only issued for a camera on that screen's tiles or in a recent alert. + +## Memory and speed (Guition, measured 2026-09-17) + +- Full screen: 480×270 RGB565 is 259 KB of PSRAM; the alert picture 172 KB. Both are freed when + the camera or the alert closes. A new alert closes an open camera first. +- The internal heap stays level while a camera refreshes: 77.2 KB free after 91 images in six minutes, + and PSRAM unchanged. +- Standby, **Back to page 1** and a new layout close the camera; nothing loads in standby. + +## For developers + +- `screen_manager/app/camera_feed.py`: fetching, sizing, links and the port. +- `components/smart_display/camera_view.h`: when to ask for a link and when to load again + (`tests/test_camera_view.cpp`). +- `components/smart_display/runtime_tiles.h`: the full-screen view, the alert picture and the + `camera` message. +- `guition-4848s040.yaml`: the two `online_image` components, the alert frame, and the diagnostic + action `preview_camera` (an entity opens it, an empty entity closes it). +- `tests/test_camera.py`: the app side and the words both sides share. diff --git a/docs/DOCKER.md b/docs/DOCKER.md index c9772da..3b1becf 100644 --- a/docs/DOCKER.md +++ b/docs/DOCKER.md @@ -80,6 +80,10 @@ under **Settings → Devices & services** in Home Assistant, and then choose the ESPHome folder. `data/build` and `data/platformio` are caches. - **Claude:** **Install for Claude Code** is meant for the Claude Code app on Home Assistant OS. Use **Download for claude.ai** instead. +- **Camera images (Guition, app 0.2.66+):** the screens load camera pictures from port **8098** + of this host, on all its addresses, so keep that port open to the screens. The app uses Home + Assistant's own LAN address; when the screens reach this host under another one, set + `SCREEN_CAMERA_URL` (see below). The links are random and short-lived. [docs/CAMERA.md](CAMERA.md) ## Updating @@ -96,8 +100,10 @@ After an update, ESP Screens shows per screen whether newer firmware is availabl | Setting | What it does | | --- | --- | -| `SCREEN_DEV: "1"` | Runs the app outside the Supervisor: it reads the token from `HA_TOKEN_FILE` and only listens on 127.0.0.1 | +| `SCREEN_DEV: "1"` | Runs the app outside the Supervisor: it reads the token from `HA_TOKEN_FILE` and serves its page on 127.0.0.1 only (camera images still on port 8098 for the screens) | | `HA_API` | Home Assistant's address, ending in `/api` | | `HA_TOKEN_FILE` | The token file inside the container (the `ha_token` secret) | | `ESPHOME_CONFIG` | The ESPHome folder inside the container | | `SCREEN_DATA` | Layouts, update settings, and build caches | +| `SCREEN_CAMERA_URL` | Optional: where screens load camera images, such as `http://192.168.1.20:8098`; by default Home Assistant's own LAN address | +| `SCREEN_CAMERA_PORT` | Optional: the camera image port instead of 8098 | diff --git a/docs/GUITION.md b/docs/GUITION.md index 4165b9f..70cee11 100644 --- a/docs/GUITION.md +++ b/docs/GUITION.md @@ -44,10 +44,10 @@ four pages; navigation disappears at six or fewer. The current interface has a light gray background, white cards, and colored domain icons. From 0.2.10, you can choose a pastel background with dark text per tile. Standby starts after ten minutes without touch by default and is adjustable in the management page. -From 0.2.13, the backlight dims via the LEDC hardware fader (`backlight_fade.h`, -1.5 s to standby, 80 ms to wake): the full LVGL redraw on standby no longer -interrupts the transition. ESPHome's light state is synced after the fade, -so the entity in HA and later transitions stay correct. +The backlight dims through ESPHome's own light transition (1.5 s to standby, 80 ms to +wake). Firmware 0.2.13-0.2.56 used the LEDC hardware fader (`backlight_fade.h`) instead; +0.2.57 went back to ESPHome's transition, because that fader reached into ESPHome's LEDC +output, which ESPHome 2026.8 no longer allows. The existing tile actions, climate control, and vacuum card are preserved. Every card type works in all twenty positions. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 1a1a636..af0d348 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -176,6 +176,51 @@ icons sit off-center in the browser); run `generate_packages.py` afterward. The `MDI_GLYPH_*` substitutions are retired: `TILEn_ICON` in manual profiles must come from the set. No changed preferences or keys. +### Compatibility 0.2.66 / firmware 0.2.57 + +Camera images on the Guition (docs/CAMERA.md). Storage, keys, preferences and the settings block are unchanged; the +layout message is unchanged apart from two tile domains, and the `show_alert` action keeps its seven fields. + +- New tile domains `camera` and `image` in `core.DOMAINS` and the firmware's `valid_entity()`. `min_firmware()` asks + 0.2.57 for them, and `Manager.save` refuses them for a screen whose board is not in `camera_feed.BOXES` (the CYD) + before it asks for firmware, so a CYD never hears "update first". The editor hides them for other boards; the top + bar refuses them (`header_entity`). An `image` tile carries `x.last` like a scene. Older firmware never gets these + tiles because of `min_firmware`. +- New protocol, all optional: the screen fires `esphome.screen_camera` {inbox, entity} when a camera opens; the app + answers through `screen_message` with op `camera` {t: `full`|`alert`, e, u}. An empty `u` means no image. For an + alert the app sends op `camera` with `t: alert` and an empty `u` to screens that can show it (`camera_feed.can_show`: + a Guition on 0.2.57+) BEFORE `show_alert`, so the card opens with room, and the link after it. `show_alert` has no + camera field on purpose: Home Assistant requires every field of an ESPHome action, so a new field would break every + automation calling `esphome._show_alert` directly. The camera is only a field of the + `esp_screens_show_alert` event (`core.alert_camera`, `ALERT_CAMERA_FIELD`). +- The app publishes port 8098 (`config.yaml` `ports`) and serves `GET /camera/.bmp` without the ingress guard. + Tokens are 24 random URL-safe characters, per camera and size; live links expire 120 s after their last use, an + alert's still after 30 min; at most 64 links. Only a camera on the screen's layout or in an alert of the last + 30 min gets one. The address is Home Assistant's default adapter from the `network` websocket command, else the + host of `network/url`; `SCREEN_CAMERA_URL` / `SCREEN_CAMERA_PORT` override it (Docker). A port that cannot be + bound logs an error and leaves the rest of the app running. +- Images are 24-bit BMP, not JPEG: ESPHome 2026.6.2 decodes a JPEG in one loop call (623 ms for 480x270 on the + Guition) and a BMP per downloaded chunk (`buffer_size: 4096`). Boxes: full 480x480, alert 392x220, proportions kept. +- Fetching follows the screen: serving a live link starts the next snapshot fetch (`CameraFeed.frame(fresh=True)`), + one at a time per camera, so the picture changes at the screen's pace. The screen loads every 4 s start to start with + at least 800 ms free after a load (`camera_view.h`), never under a finger and never in standby. An alert fetches its + own snapshot (`now=True`), never one kept from an earlier view. A failing camera is asked again after 5-30 s. +- Firmware (Guition profile only): `http_request` (4 s timeout, no TLS), two top-level `online_image`s + (`camera_image`, `alert_image`, the form 2026.6.2 knows; 2026.7+ reads it with a deprecation note), a hidden LVGL + `image` seed so `LV_USE_IMAGE` is compiled, the `alert_image_frame` in the alert card, `preview_camera` for + diagnostics and renders, theme roles `CAMERA_PAGE/INK/NOTE` and paint `camera`. The load hooks only call `set_url()` + for a new link, since it forgets the ETag. `runtime_tiles.h` builds the full view on `lv_layer_top()`; closing + frees the image on the next tick. `LV_USE_IMAGE` guards the drawing, so the CYD (no image widget) still compiles; + the CYD profile binds no hooks and never opens a camera. +- Swipes, the settings hold and Back to page 1 treat an open camera like an open card; `close_cards` (standby, + Back to page 1, a new layout) closes it, and a new alert closes it first. +- `guition_diagnostics.h` snapshots composite the top layer, so `capture_ui.py` shows alerts and the camera. +- `backlight_fade.h` is gone. It derived from `esphome::ledc::LEDCOutput` to read its channel and bit depth, and + ESPHome 2026.8 declared that class `final`, so the Guition package no longer compiled in ESPHome Device Builder + 2026.8+ (the app's own ESPHome 2026.6.2 still built it). `set_backlight` now only calls ESPHome's light transition + (1.5 s to standby, 80 ms to wake); a new call interrupts a running transition as ESPHome does. Both profiles and the + camera code were compiled with ESPHome 2026.6.2 and 2026.8.1 for this release. + ### Compatibility 0.2.65 / firmware 0.2.56 Both board profiles and the editor page; the app raises `FIRMWARE_VERSION`. Storage, tile protocol, preferences, keys diff --git a/docs/TEST_RESULTS_0266.md b/docs/TEST_RESULTS_0266.md new file mode 100644 index 0000000..c2b721a --- /dev/null +++ b/docs/TEST_RESULTS_0266.md @@ -0,0 +1,95 @@ +# Test results app 0.2.66 / firmware 0.2.57 (2026-09-17) + +Camera images on the Guition, asked for by Max: an alert that shows who is at the door, and a camera tile that opens a +refreshed image full screen. Plus the Guition building again with ESPHome 2026.8+. See CHANGELOG 0.2.66, docs/CAMERA.md +and the compatibility note in docs/RELEASING.md. Built on 0.2.65 (`9567ab5`). + +## Design decisions, with the measurement behind each + +- **The add-on serves the image, the screen holds no token.** Home Assistant's camera access token changes every five + minutes and a long-lived token on every screen opens all of Home Assistant. The app fetches with its own access and + serves a random, short-lived link on port 8098 (Max chose a LAN port over a file in `/config/www`). +- **BMP, not JPEG.** On the bench Guition (Wi-Fi -70 dBm) ESPHome 2026.6.2 decoded a 480x270 JPEG in one loop call: + `online_image took a long time for an operation (623 ms)`, long enough to lose a tap. A 24-bit BMP is decoded per + 4 KB as it downloads; the longest single loop operation over a six-minute soak was 353 ms, typically under 170 ms. + The full-screen BMP is 388,854 bytes and downloads in 2.7-3.3 s over that Wi-Fi (the same from the Mac and from the + Home Assistant Yellow, so the screen's Wi-Fi is the limit). +- **A steady rhythm.** Max saw the picture change after 3, 5, 7 s. The EZVIZ camera answered every snapshot in a + steady 2.4 s (10 fetches: 2.36-2.56 s), so the cause was the app fetching on its own 2.6 s clock next to the screen's + 3.75 s. Now each load starts the next fetch and the screen loads every 4 s start to start: pulling every 4 s against + the real camera gave camera timestamps 5, 4, 4, 4, 4, 3, 4, 5, 3, 5 s apart (the camera stamps whole seconds). +- **The alert keeps the picture of its moment** (Max's choice); a tap opens the camera now. An alert fetches its own + snapshot, never one kept from a view in the last 30 s (found in review). +- **Alert design** (Max): the picture across the top of the card, 392x220, title and subtitle under it. +- **CYD: no images.** 320x180 RGB565 needs 115 KB in one piece; the CYD's largest free block is 41-53 KB. + +## Automated + +- Python (`.venv-portal`, with Pillow 12.2.0 as in the ESPHome image): 337 tests OK (334 before the review fixes). + New `tests/test_camera.py` (23): the rules (domains, firmware, board, header, alert field), BMP encoding of JPEG, PNG + with alpha, GIF and portrait snapshots (24 bits, no compression, exact size), links (304, expiry, bounds, stills), + fetching per load, a failing camera's pause, an alert's own snapshot, the HTTP port, the broadcast order (announce, + alert, link) with and without an image, requests a screen may and may not make, camera tiles only on a Guition, the + words firmware and app share, and the profile's `set_url` guard. `test_wake_sleep.py` counts `preview_camera` among + the writers of `last_use_ms`; `tile_icons` knows the cctv default. +- C++ (`clang++ -std=c++17 -Wall -Wextra -Werror -I.`): 17/17 PASS, new `tests/test_camera_view.cpp` (asking, loading + rhythm, the gap after a slow load, failures, an empty link). +- `generate_packages.py --check` green. No token or Home Assistant URL in tracked files. +- Code review (high) found three issues, all fixed with tests: the alert picture could be a snapshot kept from a view + up to 30 s earlier; a busy camera port stopped the whole app; `set_url()` on every load threw away the ETag, so an + unchanged picture was downloaded again instead of answering 304. + +## Builds + +Easy profiles with the generated packages and local components (ESPHome 2026.6.2, the app's own): + +| Profile | RAM | Flash | vs 0.2.65 | +|---|---|---|---| +| CYD | 23.8% (77,940 B) | 77.6% (1,423,815 B) | +368 B RAM, +2.6 KB flash | +| Guition | 25.5% (83,516 B) | 20.5% (1,664,915 B) | +2.6 KB RAM, +140 KB flash (http_request, online_image, BMP decoder) | + +(0.2.65's numbers came from check profiles with other device names, a few bytes apart.) + +ESPHome 2026.8.1 (ESPHome Device Builder on Max's Home Assistant), separate build folders: both packages compile. +Before this release the Guition package failed there: `backlight_fade.h` derived from `esphome::ledc::LEDCOutput`, +which ESPHome 2026.8 made `final`. With Max's agreement the hardware fader is gone and the backlight uses ESPHome's own +transition. Warnings left for later: top-level `online_image:` is removed in ESPHome 2027.1.0 (use +`image: - platform: online_image` once min_version is 2026.7+), and `platformio_options: build_flags` in 2026.12.0. + +## Hardware (bench, Max's home Home Assistant, HA 2026.9.2 on a Home Assistant Yellow) + +The app ran as a local add-on built from this tree on the Yellow (store add-on stopped meanwhile); both screens OTA. + +| Check | Result | +|---|---| +| Guition boots 0.2.57 (compiled 15:22:34), inbox Synced, `sensor.guition_wallbox_screen_firmware` 0.2.57 | yes | +| `diagnostics/run_ui_test.py` on the Guition | PASS: 10 page checks and 50 overlay render cycles | +| Sleep and Wake from Home Assistant twice, ESPHome transition | no long operations logged; Max watched: "dimmen gaat mooi" | +| Alert with `camera: camera.max` through the real event | picture after 1.8-1.9 s (258,774 B, 391x220) | +| An `image.*` entity as the alert camera | loads (392x98: that entity's own 400x100 picture) | +| Alert without camera, Guition and CYD | the old card, unchanged | +| Tap on the alert picture (Max) | camera full screen; Back returns to the alert | +| Camera tile tapped (Max), refresh | seven images, 2.73-2.79 s downloads each, Back closes it | +| Camera open, then an alert with a camera | camera closes (PSRAM back to 6.09 MB), alert picture loads | +| Camera opened over an alert | both images held: PSRAM 5.66 MB free; close keeps the alert | +| Six-minute soak, 91 images | internal heap level at 77.2 KB free, PSRAM unchanged, no errors | +| Five real alerts in a row (Max testing) | all shown, pictures 0.9-1.9 s, no failed download | +| First image after the add-on started | one `ESP_ERR_HTTP_CONNECT`; the alert picture now retries three times | +| Home Assistant Yellow while a camera refreshes | add-on CPU 0-1.5 %, 51 MB | +| CYD boots 0.2.57 (compiled 15:23:49), inbox Synced | yes | +| Alert with a camera on the CYD | shown without the picture, OK closes it | +| Camera tile saved for the CYD | refused: "Camera images need a Guition screen." | + +Internal heap from the screens' own sensors, five minutes after the release build booted (the Guition's window held the +UI self test, Sleep/Wake twice, a camera view and an alert with a picture; the CYD's a sync and an alert): + +| Screen | Free | Largest block | Lowest since boot | Before (earlier today) | +|---|---|---|---|---| +| Guition 0.2.57 | 80,108 B | 34,816 B | 56,548 B | 0.2.55 after hours of use: 83,172 / 40,960 / 72,472 B | +| CYD 0.2.57 | 114,024 B | 57,344 B | 104,884 B | 0.2.54 after hours of use: 104,424 / 49,152 / 85,600 B | + +PSRAM on the Guition stays near 6.1 MB free with nothing open, 5.9 MB with a camera and 5.7 MB with a camera over an +alert. The Guition's lowest point is lower than this morning's after a UI self test plus camera and alert in the same +five minutes; the soak kept the heap level, so it is headroom used at once, not a leak. + +Not tested: the Docker route (no Linux Docker host here); a doorbell integration (Max has none, `camera.max` stood in). diff --git a/docs/images/guition-alert-camera.png b/docs/images/guition-alert-camera.png new file mode 100644 index 0000000000000000000000000000000000000000..0bc75ba6c97a60167e7d9c70eba80626d000273e GIT binary patch literal 127080 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 z zL%!1R$JdM{b{(TtJe(8hqw$ek&-gfg%kthajqc7;rzd?H8xPvDtFAE3HbBsAfe`La zJ|Fa4xCZ6b-`qpi6OY0D;DiVM3gGQPp3ypIx;*+$^({$FhPQ7_KXpNX#JTtwn09@m9oaYcWEe2DS# z1(cdTqCfBDe{tsejp6N1l05JiaRHG`4o6l2Scq8^1|k(@`zHpOuxe%~n+HN~j_o)R z>{XaNINCGEP#aWshR%(%*y**cqz02(y+4UYr&$s_N6RmP!jlE_%krM7X@JdXgVYRa zJc@G}IrBxiOdi;yN2Q&)Ic5(etJTeP6_V_fdCR)Es*D>_$9M#24@&FJ34yc7+;C*3 zVq-!?D z*l`{M`n$pwcDPICTRD#-{Uzv48kSD}a|P|Hi@&Y%UuuZ)PW?XyevQ%i@4__px!phN z{#GCO{-H_y$7OWLLkElDU-JJiBAwgf6+Vdb#Mm$Ql{F>+=mTLuNtS$K+Cihy4xktI?Cypc0Yl_r0U zcn{xg;aJLOJYaLclY0udt{4=HfU=zS2-puuix^chSufDE59?I8GVn^j7aO6bmm8Qml?sFYib+ZYTp-L}?N zw2vhBD9LT6gvq!J-->J@g>juxBZI+UFvghiJu|Ytuh;MQ{r>kD=Q*FxIiJrt=ly=4 z^SqANqbg_~grk14Jo8D?Xd$yjdd}0OTdyrL$Qyn-Rh9B1v)l|GGuS#?10%Ow0$f(2 zU(JVdG3vKrHjTUq9;5nLBts>_cOtD-YgQ1xJ7ShPF~b9sN5vO3jGRc5s$Dyz7)tUt zSKv}OgrS?r)6w709w&O14WjXO+g&$BO#Dd0Wcch*gia1&_f_YW3i-tqCUAjIgUhu= zT6fldwu_v+1tS)%lObIhQQsszCDf5t!Hf(D$%4|)7q2O8${Fr^*=NZ73lcZmY_&zo zh9)$%lE0xoH`L|6F*P+BgUglO)W&4k1S|Yf*t@YqTs~4j)P;v7N%*y^{@Bt82Xa`l zop7L#;GqAPvO-Q!Ex&J?Q_MP%7=io?_Yt`Hwo5S8rS1!D1 zz?X+AYJz+vuYI}_KNU~2LXxKkJ=WY?=$hX=h6Fd4EqbQMONsGiw!6(cxAok)0^{#2 zLPy*XcW>{%U6fF(3xzf!J$QI#EE2e4Phe*YKeTxydmo)XDlAJB9aao>t!v7m!=rK# z4;Zr@&j5v0`ET0RiYYz2?8Te`(^6G5F+;if$xS>3tbYLO+2;H=?@|tQgZ1{GlIF58q{( zOEguksM(B_2Jz~t0*lGk^Dv?bZkvapsz)I%fb#ORZXf=idn+gu$TBTC;Cy4Vr38Wl ztCna&aJ1QED^wd$vmqW5_nI&hpb}mx34u&Q2Ca}z@bmHv`%XJd5oLf^L|Jo3h$x4i zMbmP_*gfNgip6ldpXx|cu!od0r~b5LFHu45k&RE5R*yw8xf=vlh;vBWg-EIFQ<`j? zT4ViZ?$XgD_V^RX`>2Dp?hu*{%=v+hB_}`lXEDKL?N)j1E_rk4n5i6kj;b^M{x&ex z*DB5=)qqNQW&#+w#4Zb~N^@}dY`w~$(QK&j6Y^faG81|0gfB}&wonYxF2o5;c`Zuo@g=;^Y72Z?cg%iF^WG!2(s1T5;H@71SjP*Gt zFSg1@aCMth-7GO+aJus(?z#kXDR*6fR95WU!63WfGUF3bK$(-yS|=Ku^=r{%g>XW- zcO0!3xzrMbQU^`Gp;IxG;Hp{TD0Id>FxZBtUUTli2_CT>g3P{VMw9Y|@(fr)A%BGR z4X32xI(5>M{9UeLU*m90hnTE1ayUx>zN+a0WSUyi`$r4KZyl#smOpB!BYtbSx(i=_ zf}7qOaP5@DU=C_^D;aIu7OyPeJMTZubaC)RtuayGJD&19G|jgw$woKa#=h3a*wJ>A z>QLOO$x`hA-KWh2hPDBmH~iKHY?UC*4Uxk^x1vw1#nJeq%``HB#VTi8no*=KQl_xM zf?^+Yt37&v-DMk*G{B2{4Nxb1Dd~KS8A$n07!$+kJ-!k;;=#)vJtZtotXa1CTaS7e zYIN6g-*+o%*@0DG!5rbOddNOodCsUCUQCfBhI?A&n-k<-?+O zHsj#Kp8_%Nbu^9NQ{?y0O7$6hC5N$6q5!OH)pyqQG7j5ZRdQ=G zn;PLGZ|D zEgvx+X^|nwqtA>Q9U$Y+-<41|PU;dcHbeKzoHwUqYz#eVJ;f#1OU5vj za1o>$UH31qrtwol!9n0QrGr<4KFAcL@y~OT9ErF~J2#<>%CHdwc952ourt>uKm}5A8KyS*;u0j06mFu? zq|=M!3)ssY(Uz+%?CvB+N+xyTi@n-6&BS-+E43qRH1+S^2SgTG0+@aYDbUnY0)NmK zwPw4%#l#f!C=Eq#b}nxIvZXnn&Q9#HWEGY7Ci);Vec?3A#MX1>me(|KZ%{f+S)EB(0Ph=3GCNS*%SMsqNb1Vtl!vjtyNG)d$D^y>zmF_jd?N~ zI`B-hTe?|s%3F&}@m_k&{$uCQ&_3BN@{zJlhhJ{8{D_(MFI^UE?`RU5P1J4**fz<_ z-dIEuQK{mlrXEjP&ippUu?L^+61j^jpY0J}=hl3QY?&@>9(tMZ6h~;bhY^$VevC~x z8!QIyjcIhhy51UHguzDO%1T>>oPOp#7F{&JR7W6ExvAoM!l4QOTCYa{9|HJ>{*)?wSZIV!ikdxL2RJ?n`Q|GzFD=czf<)YaCnPt^^0~R*ualS#10qXl*&GBl@|}MLGcQPh~{$= z>!D>vsLGt2>t7vQWHGUjPU#RuYt?DJBJw!Kr0br0g%h!Px;VR?Q#|~^-q_rGVDFB+ zTD*b`DTw8@FBuNW@c?7J>!0S+z*&kqNpXjt&2}a^IG>wb&8YO{A9WCo4yc&t@HWnK zEhSX+djPZ&q1}9O0|x07f0d|xzdrp8uLS8nu8Md1m~=mpbA}n-)D)Ige{dea0i+(2 zOAEyyJr`(UrB#?h;>Jx&;8iz`uWmdws4m#dYBHgkU8O%_IUub2^#$ zA4%l`fRz@Uw-oq0TBBo!T;f!e^8-4Y!=BWeE*NtE-FwU>Nlr(Y51_Up588gE`){7y zS;we1UMQ58r#R^{Q&o&L>AS@qTc@(*^lE}jwoq*Wu;y|HjrZ{5WdoU-dN7;#s!nCe zuHOjS*~0G^%J^^ri2el*oIMz$_uSm*t}fWB<^8bGSKE*B7jr~K%%Q!qI+JDJKYPfN zjep7)%}v#EckWiX>P+?WsbD0Awv{4QSFg-ijXCjD`O+f_2rD<`{uJpZ;w0%1O%^p&@5_8;|g4=g6t>=_ghaw6!{f1 z;xN*KW07~kfxLKuv6a!o`fyoLEac!inh4cqH;`}apWDWe_eJ-2oA*z*PJ-+7Oqs!W zq~{T3MhpF~yH!s|%K;YFZR|=|FuVQ~y)Qg(xFBtM&=rDZ?!%*Yc;-8|s_o)8L9Tb9 zx$#;1u2-8t&|Bb+1|QH2?-l&#C+kN33!&BfZ-f>-TnH8@Igkg{T~>3eGn%9N|3Cfy zAAJ4)aPAMj;hpS}^vKd!h?BNwGaNYnnrsOS8Lh6cAf05D{W7m-w3hJG9RfMixsZ_23Xp2xC7!@#IpuxhJ@rsZD70 zoUmixnB2&-4uFs0F|jH0E)>>pvD+ld4=5LveeGycFw(>1jByZ1eQ&Gd2Hs;0J2~W+ zt1;S}NurS901nuVM|!%ez-~zrUMz%aZ`JQHh70(fMSySZJ5n%76lfR&%*!T5vKnSZ z$1HW>RB)M{KAdVSTJz1u}OFq_eI)7 z9@Raxi$Rzl$GI8aB;rte(TEzQAm}T%?~w@**)H|%#oA$XVe{Ec3DDui{T>k9k`fq* z^mv_^ZBQ7@yr~YTSXiG7A6!SOpDDqrKTb%%Vn$44lX%k@&eRbH^-LOh$Oji=F>%5o z4%*H2pzKrxeT}~czB5pKR1@4^G4cu=kb~_8f=$6^FdOKPc@jFlWCuLfqfc1*g_~8u z`vo-a#=jnYmzE5P*%~R$c-bof``P2!S(dBR8xf!BenOEo$QJs`NufTl+jM8cDF}b9Mm@Pm>CbX?HG-WlD9L?DuP(2o#I~6B8pA{ zNf9Bl5gGQ2qX9Uhz7~PxU7tI8Pu_qPxQG4yX{o{(1hSCKP#!=DE*9~-?1GWrNBVml zJfG+g0c7;57it`*+aa8pPYhcrF!=TSerJU-_(aLFxSuX62K@L-gq zr^tiXhH|0NC_}@Iz8{pjd#p_AsOZ4ziPfIJf{sCH6^+jwva2ppy}wEh({CT2o&$^A z3N>Wz7whQ`1ErmSL!jIsJ*KpCk?%?ng~|_hkc@#@l&r)fHP0G?jrwq`zHGf740_`qiuFId_MhUDj^UvEm`t3XYW6y$`Tk_~l l<7=54W6yy}nmTAOZ> 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%0DGK8fvu` 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

w^&#gk zw^Eu`>s%0X5x>Ko>eo6ExTE8AUCZP93Uxc6Pj;Q5QYEsw;gjHG=vVl{6#8h&ggT9(}6O+dxu;RYjr9gab(Ay=7k-JO}t z4gxX7m0bi+;Udj9)syi`%M-C0guJ1XGC?n!EL_pgsSCO)`=I{*NuxA=eN_k}ClxMz>Y*)sF+dv@P8)$VuI ze_eaGSzAy6r5d{^?g%tgUO!I_=$YX9Nm+ z)wxTL%`t0UyF1sZVs-jM$*nun%{BLRg>PK?W7Z;lo0_^E`l?I+AFJJGywPfXeNZytPcnv_EOWr$8rCE`zzsd5fI%O6Of175=%s@UA7CwMq7;#-4WHSR zItkNkOc8Ru3pa_hP=ag27v7^mIrvf~FydxIat}iV>|m}3u)?lEJOL^f2VICplp->< z;WL|3Ct)$0YTiYdO;RW!wBhmGXi!ouny43)6^v%j(r@rUvc`wtbLU~#7&atwnLslP zW*J|j7~jBohzTs;Fh8sg-bdvLUH~~2fT7MSzF{UCFT{vv%L{)Q!y4!_+O1fnM4`7O zpYfml3x3q?GsX6Vg-py4V}E7_)x#>s12$izR6-IUh8fuFzRLGze5MLDqE0KWu6min zXCbIB>_6)7uYfH!wJG5@(1O;VGvGJi4gTaoc6AdtNvxAe+Z_(!oPOzzu34osQTh+^S^tT*Hmai gT<{?E`_>QtnT2z9Px337+Xd3(>FVdQ&MBb@0E1 - - - - - - name: ${DEVICE_NAME} @@ -197,12 +206,14 @@ esphome: theme::fill(id(paint_accent_bright), Paint::accent_bright); theme::fill(id(paint_button_dark), Paint::button_dark); theme::fill(id(paint_button_dark_pressed), Paint::button_dark_pressed); + theme::fill(id(paint_camera), Paint::camera); }; theme::paints(); theme::set_dark(settings_screen::dark_mode != 0); runtime_tiles::settings_changed = []() { id(apply_screen_settings).execute(); }; runtime_tiles::dismiss = []() { runtime_tiles::hide_detail(); + runtime_tiles::camera_close(); id(active_entity).clear(); lv_obj_add_flag(id(brightness_overlay), LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(id(color_detail_overlay), LV_OBJ_FLAG_HIDDEN); @@ -210,6 +221,32 @@ esphome: lv_obj_add_flag(id(climate_mode_overlay), LV_OBJ_FLAG_HIDDEN); }; runtime_tiles::layout_changed = []() { id(show_tile_page).execute(); }; + // Camera images (firmware 0.2.57+): the two online_images and the alert's frame. + // set_url() forgets the ETag, so it is only called for a new link: an unchanged picture then answers 304. + runtime_tiles::camera_full.load = [](const std::string &url) { + static std::string current; + if (url != current) { id(camera_image).set_url(url); current = url; } + id(camera_image).update(); + }; + runtime_tiles::camera_full.release = []() { id(camera_image).release(); }; + runtime_tiles::camera_full.source = []() { return id(camera_image).get_lv_image_dsc(); }; + runtime_tiles::camera_thumb.load = [](const std::string &url) { + static std::string current; + if (url != current) { id(alert_image).set_url(url); current = url; } + id(alert_image).update(); + }; + runtime_tiles::camera_thumb.release = []() { id(alert_image).release(); }; + runtime_tiles::camera_thumb.source = []() { return id(alert_image).get_lv_image_dsc(); }; + runtime_tiles::alert_frame = id(alert_image_frame); + runtime_tiles::alert_frame_icon = id(alert_image_icon); + runtime_tiles::alert_room = [](bool image) { + const int shift = image ? ${ALERT_IMAGE_SHIFT} : 0; + lv_obj_set_height(id(alert_card), image ? ${ALERT_CARD_H_IMAGE} : ${ALERT_CARD_H}); + lv_obj_set_y(id(alert_icon), ${ALERT_ICON_Y} + shift); + lv_obj_set_y(id(alert_title), ${ALERT_TITLE_Y} + shift); + lv_obj_set_y(id(alert_subtitle), ${ALERT_SUBTITLE_Y} + shift); + lv_obj_set_height(id(alert_subtitle), image ? ${ALERT_SUBTITLE_H_IMAGE} : ${ALERT_SUBTITLE_H}); + }; runtime_tiles::refresh = []() { if (!id(ui_refresh).is_running()) id(ui_refresh).execute(); }; runtime_tiles::bind(0, id(tile1), id(t1_title), id(t1_value), id(tile1_icon_circle), id(tile1_icon_lbl)); runtime_tiles::bind(1, id(tile2), id(t2_title), id(t2_value), id(tile2_icon_circle), id(tile2_icon_lbl)); @@ -285,7 +322,7 @@ esphome: settings_screen::restart_device = []() { ESP_LOGI("settings", "restart from the screen"); App.safe_reboot(); }; // A dimmed screen, a calibration or an alert owns the glass; the page waits. settings_screen::may_open = []() { - return runtime_tiles::enabled && !id(display_dimmed) && !id(calibration_active) && !id(alert_active); + return runtime_tiles::enabled && !id(display_dimmed) && !id(calibration_active) && !id(alert_active) && !runtime_tiles::camera_visible(); }; settings_screen::drift = []() { return cyd::touch_guard.distance(); }; settings_screen::before_open = []() { id(close_cards).execute(); }; @@ -407,6 +444,20 @@ api: } runtime_tiles::show_detail(index); } + # A camera full screen from Home Assistant (firmware 0.2.57+), as a tap on its tile opens it; an empty entity closes + # it. Only a camera on the screen's tiles or in a recent alert gets an image from ESP Screens. + - action: preview_camera + variables: + entity: string + then: + - lambda: |- + if (entity.empty()) { runtime_tiles::camera_close(); return; } + id(last_use_ms) = millis(); + id(wake_display).execute(); + std::string name = entity; + for (size_t i = 0; i < runtime_tiles::model.count; ++i) + if (runtime_tiles::model.tiles[i].entity == entity) { name = runtime_tiles::model.tiles[i].name; break; } + runtime_tiles::camera_open(entity, name); # The settings page from Home Assistant: `page` 0 is its menu, 1-4 open a group straight away # (Brightness, Night, Screen, This screen) and a negative page closes it and goes back to page 1. # Handy for support ("look at Screen -> Rotation") and for the render tests. @@ -504,10 +555,43 @@ wifi: captive_portal: +# Camera images (firmware 0.2.57+): ESP Screen Manager serves each image already sized for this screen, as an uncompressed +# BMP on its own port on the LAN (screen_manager/app/camera_feed.py). ESPHome decodes a BMP piece by piece as it arrives, +# 4 KB per loop, where a JPEG of the full screen held the loop for 0.6 s; touch and drawing keep their turn. One image full +# screen and one in an alert's frame; runtime_tiles.h decides when they load and frees them when they close. Plain HTTP +# on the LAN, no certificates. +http_request: + timeout: 4s + verify_ssl: false + +# The top-level online_image form that ESPHome 2026.6.2 (min_version) knows; 2026.7+ still reads it and suggests +# `image: - platform: online_image`, which this profile can use once min_version reaches 2026.7. +online_image: + - id: camera_image + url: "http://127.0.0.1/camera.bmp" # set when a camera opens + format: BMP + type: RGB565 + buffer_size: 4096 + on_download_finished: + - lambda: 'runtime_tiles::camera_loaded(false, cached);' + on_error: + - lambda: 'runtime_tiles::camera_failed(false);' + - id: alert_image + url: "http://127.0.0.1/camera.bmp" # set when an alert brings an image + format: BMP + type: RGB565 + buffer_size: 4096 + on_download_finished: + - lambda: 'runtime_tiles::camera_loaded(true, cached);' + on_error: + - lambda: 'runtime_tiles::camera_failed(true);' + interval: - interval: 250ms then: - - lambda: runtime_tiles::tick(); + - lambda: |- + runtime_tiles::tick(); + runtime_tiles::camera_tick(); - interval: 1s then: - if: @@ -1306,7 +1390,8 @@ touchscreen: if (!step) continue; const char *blocked = !runtime_tiles::enabled ? "no runtime tiles" : !runtime_tiles::swipe_pages ? "setting off" : id(display_dimmed) ? "screen dimmed" : id(calibration_active) ? "calibration" : !id(active_entity).empty() ? "card open" - : (runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)) ? "detail card open" : nullptr; + : (runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)) ? "detail card open" + : runtime_tiles::camera_visible() ? "camera open" : nullptr; if (blocked) { ESP_LOGI("touch", "edge swipe ignored: %s", blocked); continue; } cyd::touch_guard.consume(); for (auto *indev = lv_indev_get_next(nullptr); indev; indev = lv_indev_get_next(indev)) lv_indev_wait_release(indev); @@ -1473,6 +1558,7 @@ lvgl: - id: paint_accent_bright - id: paint_button_dark - id: paint_button_dark_pressed + - id: paint_camera # ---------- ALERT OVERLAY (HA action show_alert) ---------- # LVGL's top layer sits above every page, card and the dim overlay; the card @@ -1542,6 +1628,39 @@ lvgl: text_font: sublabel_big styles: paint_ink_soft clickable: false + # The alert's camera image (firmware 0.2.57+) across the top of the card, shown when the app announced + # one; a tap opens the camera full screen over the alert. runtime_tiles.h puts the image in it. + - obj: + id: alert_image_frame + x: ${ALERT_IMAGE_INSET} + y: ${ALERT_IMAGE_INSET} + width: ${CAMERA_THUMB_W} + height: ${CAMERA_THUMB_H} + hidden: true + styles: paint_camera + bg_opa: COVER + radius: 0 + border_width: 0 + shadow_width: 0 + pad_all: 0 + clickable: true + scrollable: false + scrollbar_mode: 'OFF' + pressed: + bg_opa: COVER + on_click: + - if: + condition: + lambda: 'return cyd::touch_guard.accept(millis(), 14) && !runtime_tiles::alert_camera.empty();' + then: + - lambda: 'runtime_tiles::camera_open(runtime_tiles::alert_camera, id(alert_title_text));' + widgets: + - label: + id: alert_image_icon + align: CENTER + text: "\U000F07AE" + text_font: materialdesign_icons + clickable: false - obj: id: alert_ok align: BOTTOM_RIGHT @@ -1591,6 +1710,11 @@ lvgl: height: 2 spin_time: 1s arc_length: 60deg + # Never shown either: it makes ESPHome compile LVGL's image widget, which a camera image is drawn with. + - image: + id: camera_image_seed + hidden: true + src: alert_image - label: id: lbl_room x: 16 @@ -3619,7 +3743,7 @@ script: auto now = id(homeassistant_time).now(); const int minute = now.is_valid() ? now.hour * 60 + now.minute : -1; const int level = id(display_dimmed) ? settings.dim_level(minute) : settings.brightness; - // Standby dims slowly; the tile redraws below no longer interrupt the hardware fade. + // Standby dims slowly (ESPHome's transition); waking is quick. id(set_backlight).execute(level, id(display_dimmed) ? 1500 : 300); if (id(display_dimmed)) { lv_obj_clear_flag(id(dim_wake_overlay), LV_OBJ_FLAG_HIDDEN); lv_obj_move_foreground(id(dim_wake_overlay)); } else lv_obj_add_flag(id(dim_wake_overlay), LV_OBJ_FLAG_HIDDEN); @@ -3669,7 +3793,7 @@ script: lambda: |- if (!runtime_tiles::auto_home || id(touch_down) || id(calibration_active) || id(alert_active)) return false; if (id(display_dimmed)) return false; - bool away = settings_screen::visible() || !id(active_entity).empty() || id(tile_page) != 0 || + bool away = settings_screen::visible() || runtime_tiles::camera_visible() || !id(active_entity).empty() || id(tile_page) != 0 || (runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)); return away && (millis() - id(last_use_ms)) > (uint32_t) runtime_tiles::auto_home_seconds * 1000UL; then: @@ -3694,6 +3818,8 @@ script: if (id(alert_active)) id(alert_report).execute("replaced"); // An alert is the one thing that outranks the settings page, so that closes first. settings_screen::close(); + // An open camera closes; the card makes room for an image the app announced for this alert. + runtime_tiles::alert_prepare(); const auto alert = screen_alert::make(title, subtitle, icon, color, button_text, timeout, flash, ${ALERT_TITLE_MAX}, ${ALERT_SUBTITLE_MAX}, ${ALERT_BUTTON_MAX}); id(alert_active) = true; id(alert_title_text) = alert.title; @@ -3733,6 +3859,7 @@ script: - lambda: |- id(alert_active) = false; id(last_touch_ms) = millis(); + runtime_tiles::alert_clear(); ESP_LOGI("alert", "dismissed: %s", reason.c_str()); - lvgl.widget.hide: alert_overlay - script.stop: alert_timeout @@ -3789,20 +3916,16 @@ script: - lvgl.widget.hide: dim_wake_overlay - script.execute: close_cards - # One owner for the backlight level: the LEDC fader steps the duty itself, so - # LVGL redraws cannot make the transition stutter. A new call interrupts the - # running fade from its current duty; afterwards ESPHome's light state is synced. + # One owner for the backlight level, through ESPHome's own light transition (firmware 0.2.57+). Firmware 0.2.13-0.2.56 + # stepped the duty with the LEDC hardware fader by reaching into ESPHome's LEDC output, which ESPHome 2026.8 made final; + # a new call interrupts the running transition from where it is, as ESPHome does for any light. - id: set_backlight mode: restart parameters: level: int ms: int then: - - lambda: |- - if (!backlight_fade::start(*id(gpio_backlight_pwm), *id(back_light), level / 100.0f, ms)) - id(back_light).turn_on().set_transition_length(ms).set_brightness(level / 100.0f).perform(); - - delay: !lambda "return ms + 40;" - - lambda: backlight_fade::sync(*id(gpio_backlight_pwm), *id(back_light), level / 100.0f); + - lambda: id(back_light).turn_on().set_transition_length(ms).set_brightness(level / 100.0f).perform(); # Standby: the standby time ran out (the 1 s interval checks Auto standby) or Sleep was pressed. # The settings page and every card close; with "also on standby" the screen goes back to page 1 too. diff --git a/home-like-2432s028.yaml b/home-like-2432s028.yaml index 79d8c47..d205429 100644 --- a/home-like-2432s028.yaml +++ b/home-like-2432s028.yaml @@ -17,7 +17,7 @@ ############################################################ substitutions: - SCREEN_FIRMWARE_VERSION: "0.2.56" + SCREEN_FIRMWARE_VERSION: "0.2.57" # A tap survives a finger that drifts up to this far (320 px over 58 mm: 1 cm); further is a swipe. TOUCH_MOVE_LIMIT_PX: "56" # Shortest contact that counts as a tap; a resistive panel bounces, a capacitive one does not. diff --git a/packages/cyd.yaml b/packages/cyd.yaml index 6ec0a60..be9c458 100644 --- a/packages/cyd.yaml +++ b/packages/cyd.yaml @@ -18,7 +18,7 @@ ############################################################ substitutions: - SCREEN_FIRMWARE_VERSION: "0.2.56" + SCREEN_FIRMWARE_VERSION: "0.2.57" # A tap survives a finger that drifts up to this far (320 px over 58 mm: 1 cm); further is a swipe. TOUCH_MOVE_LIMIT_PX: "56" # Shortest contact that counts as a tap; a resistive panel bounces, a capacitive one does not. diff --git a/packages/guition.yaml b/packages/guition.yaml index b4ce68c..f1b8fe4 100644 --- a/packages/guition.yaml +++ b/packages/guition.yaml @@ -3,7 +3,7 @@ # Source profile for packages/guition.yaml (tools/generate_packages.py); see docs/GUITION.md. # A screen gets its tiles from the ESP Screen Manager add-on while it runs. The CYD is its own profile. substitutions: - SCREEN_FIRMWARE_VERSION: "0.2.56" + SCREEN_FIRMWARE_VERSION: "0.2.57" # 0: no drift limit; LVGL decides, releasing inside the tile is a tap, leaving it is not # (like iOS). The CYD keeps a limit because its resistive panel jumps. TOUCH_MOVE_LIMIT_PX: "0" @@ -70,6 +70,16 @@ substitutions: ALERT_TITLE_MAX: "64" # bytes; the label ends one line with an ellipsis ALERT_BUTTON_MAX: "16" # bytes on the OK button ALERT_SUBTITLE_MAX: "240" # bytes; wraps over the rows the card has + # An alert with a camera image (firmware 0.2.57+): the image across the top of a taller card, the words under it. + ALERT_CARD_H_IMAGE: "452" + ALERT_IMAGE_INSET: "14" + ALERT_IMAGE_SHIFT: "236" # the icon, title and subtitle move down by the image and a gap + ALERT_SUBTITLE_H_IMAGE: "62" # two lines between the title and the button + # Camera images (firmware 0.2.57+): the boxes ESP Screen Manager sizes a snapshot for (camera_feed.BOXES). + CAMERA_FULL_W: "480" + CAMERA_FULL_H: "480" + CAMERA_THUMB_W: "392" + CAMERA_THUMB_H: "220" OVERLAY_SLIDER_W: "144" OVERLAY_SLIDER_H: "300" OVERLAY_ICON_Y: "148" @@ -109,7 +119,6 @@ esphome: - - - - - - - name: ${DEVICE_NAME} @@ -201,12 +210,14 @@ esphome: theme::fill(id(paint_accent_bright), Paint::accent_bright); theme::fill(id(paint_button_dark), Paint::button_dark); theme::fill(id(paint_button_dark_pressed), Paint::button_dark_pressed); + theme::fill(id(paint_camera), Paint::camera); }; theme::paints(); theme::set_dark(settings_screen::dark_mode != 0); runtime_tiles::settings_changed = []() { id(apply_screen_settings).execute(); }; runtime_tiles::dismiss = []() { runtime_tiles::hide_detail(); + runtime_tiles::camera_close(); id(active_entity).clear(); lv_obj_add_flag(id(brightness_overlay), LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(id(color_detail_overlay), LV_OBJ_FLAG_HIDDEN); @@ -214,6 +225,32 @@ esphome: lv_obj_add_flag(id(climate_mode_overlay), LV_OBJ_FLAG_HIDDEN); }; runtime_tiles::layout_changed = []() { id(show_tile_page).execute(); }; + // Camera images (firmware 0.2.57+): the two online_images and the alert's frame. + // set_url() forgets the ETag, so it is only called for a new link: an unchanged picture then answers 304. + runtime_tiles::camera_full.load = [](const std::string &url) { + static std::string current; + if (url != current) { id(camera_image).set_url(url); current = url; } + id(camera_image).update(); + }; + runtime_tiles::camera_full.release = []() { id(camera_image).release(); }; + runtime_tiles::camera_full.source = []() { return id(camera_image).get_lv_image_dsc(); }; + runtime_tiles::camera_thumb.load = [](const std::string &url) { + static std::string current; + if (url != current) { id(alert_image).set_url(url); current = url; } + id(alert_image).update(); + }; + runtime_tiles::camera_thumb.release = []() { id(alert_image).release(); }; + runtime_tiles::camera_thumb.source = []() { return id(alert_image).get_lv_image_dsc(); }; + runtime_tiles::alert_frame = id(alert_image_frame); + runtime_tiles::alert_frame_icon = id(alert_image_icon); + runtime_tiles::alert_room = [](bool image) { + const int shift = image ? ${ALERT_IMAGE_SHIFT} : 0; + lv_obj_set_height(id(alert_card), image ? ${ALERT_CARD_H_IMAGE} : ${ALERT_CARD_H}); + lv_obj_set_y(id(alert_icon), ${ALERT_ICON_Y} + shift); + lv_obj_set_y(id(alert_title), ${ALERT_TITLE_Y} + shift); + lv_obj_set_y(id(alert_subtitle), ${ALERT_SUBTITLE_Y} + shift); + lv_obj_set_height(id(alert_subtitle), image ? ${ALERT_SUBTITLE_H_IMAGE} : ${ALERT_SUBTITLE_H}); + }; runtime_tiles::refresh = []() { if (!id(ui_refresh).is_running()) id(ui_refresh).execute(); }; runtime_tiles::bind(0, id(tile1), id(t1_title), id(t1_value), id(tile1_icon_circle), id(tile1_icon_lbl)); runtime_tiles::bind(1, id(tile2), id(t2_title), id(t2_value), id(tile2_icon_circle), id(tile2_icon_lbl)); @@ -289,7 +326,7 @@ esphome: settings_screen::restart_device = []() { ESP_LOGI("settings", "restart from the screen"); App.safe_reboot(); }; // A dimmed screen, a calibration or an alert owns the glass; the page waits. settings_screen::may_open = []() { - return runtime_tiles::enabled && !id(display_dimmed) && !id(calibration_active) && !id(alert_active); + return runtime_tiles::enabled && !id(display_dimmed) && !id(calibration_active) && !id(alert_active) && !runtime_tiles::camera_visible(); }; settings_screen::drift = []() { return cyd::touch_guard.distance(); }; settings_screen::before_open = []() { id(close_cards).execute(); }; @@ -411,6 +448,20 @@ api: } runtime_tiles::show_detail(index); } + # A camera full screen from Home Assistant (firmware 0.2.57+), as a tap on its tile opens it; an empty entity closes + # it. Only a camera on the screen's tiles or in a recent alert gets an image from ESP Screens. + - action: preview_camera + variables: + entity: string + then: + - lambda: |- + if (entity.empty()) { runtime_tiles::camera_close(); return; } + id(last_use_ms) = millis(); + id(wake_display).execute(); + std::string name = entity; + for (size_t i = 0; i < runtime_tiles::model.count; ++i) + if (runtime_tiles::model.tiles[i].entity == entity) { name = runtime_tiles::model.tiles[i].name; break; } + runtime_tiles::camera_open(entity, name); # The settings page from Home Assistant: `page` 0 is its menu, 1-4 open a group straight away # (Brightness, Night, Screen, This screen) and a negative page closes it and goes back to page 1. # Handy for support ("look at Screen -> Rotation") and for the render tests. @@ -493,10 +544,43 @@ api: captive_portal: +# Camera images (firmware 0.2.57+): ESP Screen Manager serves each image already sized for this screen, as an uncompressed +# BMP on its own port on the LAN (screen_manager/app/camera_feed.py). ESPHome decodes a BMP piece by piece as it arrives, +# 4 KB per loop, where a JPEG of the full screen held the loop for 0.6 s; touch and drawing keep their turn. One image full +# screen and one in an alert's frame; runtime_tiles.h decides when they load and frees them when they close. Plain HTTP +# on the LAN, no certificates. +http_request: + timeout: 4s + verify_ssl: false + +# The top-level online_image form that ESPHome 2026.6.2 (min_version) knows; 2026.7+ still reads it and suggests +# `image: - platform: online_image`, which this profile can use once min_version reaches 2026.7. +online_image: + - id: camera_image + url: "http://127.0.0.1/camera.bmp" # set when a camera opens + format: BMP + type: RGB565 + buffer_size: 4096 + on_download_finished: + - lambda: 'runtime_tiles::camera_loaded(false, cached);' + on_error: + - lambda: 'runtime_tiles::camera_failed(false);' + - id: alert_image + url: "http://127.0.0.1/camera.bmp" # set when an alert brings an image + format: BMP + type: RGB565 + buffer_size: 4096 + on_download_finished: + - lambda: 'runtime_tiles::camera_loaded(true, cached);' + on_error: + - lambda: 'runtime_tiles::camera_failed(true);' + interval: - interval: 250ms then: - - lambda: runtime_tiles::tick(); + - lambda: |- + runtime_tiles::tick(); + runtime_tiles::camera_tick(); - interval: 1s then: - if: @@ -1295,7 +1379,8 @@ touchscreen: if (!step) continue; const char *blocked = !runtime_tiles::enabled ? "no runtime tiles" : !runtime_tiles::swipe_pages ? "setting off" : id(display_dimmed) ? "screen dimmed" : id(calibration_active) ? "calibration" : !id(active_entity).empty() ? "card open" - : (runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)) ? "detail card open" : nullptr; + : (runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)) ? "detail card open" + : runtime_tiles::camera_visible() ? "camera open" : nullptr; if (blocked) { ESP_LOGI("touch", "edge swipe ignored: %s", blocked); continue; } cyd::touch_guard.consume(); for (auto *indev = lv_indev_get_next(nullptr); indev; indev = lv_indev_get_next(indev)) lv_indev_wait_release(indev); @@ -1462,6 +1547,7 @@ lvgl: - id: paint_accent_bright - id: paint_button_dark - id: paint_button_dark_pressed + - id: paint_camera # ---------- ALERT OVERLAY (HA action show_alert) ---------- # LVGL's top layer sits above every page, card and the dim overlay; the card @@ -1531,6 +1617,39 @@ lvgl: text_font: sublabel_big styles: paint_ink_soft clickable: false + # The alert's camera image (firmware 0.2.57+) across the top of the card, shown when the app announced + # one; a tap opens the camera full screen over the alert. runtime_tiles.h puts the image in it. + - obj: + id: alert_image_frame + x: ${ALERT_IMAGE_INSET} + y: ${ALERT_IMAGE_INSET} + width: ${CAMERA_THUMB_W} + height: ${CAMERA_THUMB_H} + hidden: true + styles: paint_camera + bg_opa: COVER + radius: 0 + border_width: 0 + shadow_width: 0 + pad_all: 0 + clickable: true + scrollable: false + scrollbar_mode: 'OFF' + pressed: + bg_opa: COVER + on_click: + - if: + condition: + lambda: 'return cyd::touch_guard.accept(millis(), 14) && !runtime_tiles::alert_camera.empty();' + then: + - lambda: 'runtime_tiles::camera_open(runtime_tiles::alert_camera, id(alert_title_text));' + widgets: + - label: + id: alert_image_icon + align: CENTER + text: "\U000F07AE" + text_font: materialdesign_icons + clickable: false - obj: id: alert_ok align: BOTTOM_RIGHT @@ -1580,6 +1699,11 @@ lvgl: height: 2 spin_time: 1s arc_length: 60deg + # Never shown either: it makes ESPHome compile LVGL's image widget, which a camera image is drawn with. + - image: + id: camera_image_seed + hidden: true + src: alert_image - label: id: lbl_room x: 16 @@ -3608,7 +3732,7 @@ script: auto now = id(homeassistant_time).now(); const int minute = now.is_valid() ? now.hour * 60 + now.minute : -1; const int level = id(display_dimmed) ? settings.dim_level(minute) : settings.brightness; - // Standby dims slowly; the tile redraws below no longer interrupt the hardware fade. + // Standby dims slowly (ESPHome's transition); waking is quick. id(set_backlight).execute(level, id(display_dimmed) ? 1500 : 300); if (id(display_dimmed)) { lv_obj_clear_flag(id(dim_wake_overlay), LV_OBJ_FLAG_HIDDEN); lv_obj_move_foreground(id(dim_wake_overlay)); } else lv_obj_add_flag(id(dim_wake_overlay), LV_OBJ_FLAG_HIDDEN); @@ -3658,7 +3782,7 @@ script: lambda: |- if (!runtime_tiles::auto_home || id(touch_down) || id(calibration_active) || id(alert_active)) return false; if (id(display_dimmed)) return false; - bool away = settings_screen::visible() || !id(active_entity).empty() || id(tile_page) != 0 || + bool away = settings_screen::visible() || runtime_tiles::camera_visible() || !id(active_entity).empty() || id(tile_page) != 0 || (runtime_tiles::detail_root && !lv_obj_has_flag(runtime_tiles::detail_root, LV_OBJ_FLAG_HIDDEN)); return away && (millis() - id(last_use_ms)) > (uint32_t) runtime_tiles::auto_home_seconds * 1000UL; then: @@ -3683,6 +3807,8 @@ script: if (id(alert_active)) id(alert_report).execute("replaced"); // An alert is the one thing that outranks the settings page, so that closes first. settings_screen::close(); + // An open camera closes; the card makes room for an image the app announced for this alert. + runtime_tiles::alert_prepare(); const auto alert = screen_alert::make(title, subtitle, icon, color, button_text, timeout, flash, ${ALERT_TITLE_MAX}, ${ALERT_SUBTITLE_MAX}, ${ALERT_BUTTON_MAX}); id(alert_active) = true; id(alert_title_text) = alert.title; @@ -3722,6 +3848,7 @@ script: - lambda: |- id(alert_active) = false; id(last_touch_ms) = millis(); + runtime_tiles::alert_clear(); ESP_LOGI("alert", "dismissed: %s", reason.c_str()); - lvgl.widget.hide: alert_overlay - script.stop: alert_timeout @@ -3778,20 +3905,16 @@ script: - lvgl.widget.hide: dim_wake_overlay - script.execute: close_cards - # One owner for the backlight level: the LEDC fader steps the duty itself, so - # LVGL redraws cannot make the transition stutter. A new call interrupts the - # running fade from its current duty; afterwards ESPHome's light state is synced. + # One owner for the backlight level, through ESPHome's own light transition (firmware 0.2.57+). Firmware 0.2.13-0.2.56 + # stepped the duty with the LEDC hardware fader by reaching into ESPHome's LEDC output, which ESPHome 2026.8 made final; + # a new call interrupts the running transition from where it is, as ESPHome does for any light. - id: set_backlight mode: restart parameters: level: int ms: int then: - - lambda: |- - if (!backlight_fade::start(*id(gpio_backlight_pwm), *id(back_light), level / 100.0f, ms)) - id(back_light).turn_on().set_transition_length(ms).set_brightness(level / 100.0f).perform(); - - delay: !lambda "return ms + 40;" - - lambda: backlight_fade::sync(*id(gpio_backlight_pwm), *id(back_light), level / 100.0f); + - lambda: id(back_light).turn_on().set_transition_length(ms).set_brightness(level / 100.0f).perform(); # Standby: the standby time ran out (the 1 s interval checks Auto standby) or Sleep was pressed. # The settings page and every card close; with "also on standby" the screen goes back to page 1 too. diff --git a/screen_manager/CHANGELOG.md b/screen_manager/CHANGELOG.md index 5cff1d1..9c8ee4a 100644 --- a/screen_manager/CHANGELOG.md +++ b/screen_manager/CHANGELOG.md @@ -1,3 +1,16 @@ +## 0.2.66 (firmware 0.2.57) + +Camera images on the Guition: see who is at the door. + +- **An alert with a picture.** Add `camera: camera.front_door` to the `esp_screens_show_alert` event and a Guition shows the camera's picture of that moment across the top of the alert card, with the title and subtitle under it. A tap on the picture opens the camera full screen over the alert; Back returns to the alert. Any `camera.*` or `image.*` entity works. Other screens show the same alert without the picture. +- **A camera tile.** Add a `camera.*` or `image.*` entity as a tile on a Guition. A tap opens the image full screen, with the round back key at the top left like on every card, and the image refreshes every four seconds, at a steady pace, while it is open. It is not video: ESPHome has no video decoder. Standby and **Back to page 1** close it, and a new alert closes it before it opens. +- **How it works.** The screen never gets a Home Assistant token. ESP Screen Manager fetches the snapshot, makes it exactly as large as the screen draws it and serves it on a new port, **8098**, under a random link that stops working when nobody uses it. On Home Assistant OS the app opens that port itself; keep it at 8098. docs/CAMERA.md has the details, Docker included. +- **Smooth while it loads.** The image arrives as an uncompressed BMP, which the Guition decodes piece by piece while it downloads; a JPEG held the screen for more than half a second per image, long enough to miss a tap. The app fetches the camera's next snapshot each time the screen loads one, so a new picture follows every four seconds instead of after one and a half seconds one time and six the next. A slow camera makes the picture older, never the screen slower. +- **The alert's picture is the moment it rang.** It stays as it was when the alert came in; tap it for the camera now. +- **The Guition builds with ESPHome 2026.8 and newer.** Its firmware no longer uses a backlight fader of its own, which reached into ESPHome's LEDC output; ESPHome 2026.8 closed that off, so **Install** in ESPHome Device Builder failed for a Guition. Standby now dims through ESPHome's own light transition, like any light. Updating from ESP Screens was not affected. +- **The Claude skill and the Alerts cheatsheet** describe the `camera` field. Install the skill again from Settings → Claude to get it. +- Needs firmware 0.2.57 on the Guition: press **Update** on the screen. The CYD gets 0.2.57 too, without camera images: it has no memory for them. + ## 0.2.65 (firmware 0.2.56) Wake lights the screen, and ESP Screens lets you pick the screen. diff --git a/screen_manager/app/camera_feed.py b/screen_manager/app/camera_feed.py new file mode 100644 index 0000000..93ec071 --- /dev/null +++ b/screen_manager/app/camera_feed.py @@ -0,0 +1,283 @@ +"""Camera images on a Guition screen (app 0.2.66, firmware 0.2.57). + +A screen never asks Home Assistant for a camera itself. This app fetches the snapshot with its own token (a +camera's access token changes every five minutes), makes it exactly as large as the screen shows it and serves +it as an uncompressed 24-bit BMP on its own port on the LAN, where the screen's ESPHome `online_image` loads it. +ESPHome decodes a BMP piece by piece while it downloads; a JPEG of the full screen held the Guition's main loop for +0.6 s (measured 2026-09-17), long enough to lose a tap. On the LAN the larger file costs nothing that matters. + +Links are random and short-lived, and only a camera on the screen's layout or in a recent alert gets one. A screen +that loads a link gets the last snapshot at once, however long the camera takes to answer (ESPHome's HTTP client waits +in the screen's main loop, where touch and drawing wait with it), and the load starts fetching the next snapshot. +""" +import asyncio +import hashlib +import io +import logging +import os +import re +import secrets +import time + +LOG = logging.getLogger(__name__) + +DOMAINS = ('camera', 'image') +MIN_FIRMWARE = (0, 2, 57) +PORT = 8098 +# A camera nobody loaded a picture of for this long is forgotten, its last snapshot with it. +WATCH_SECONDS = 30 +# A link to a live camera nobody used for this long is forgotten; the screen asks for a new one. +LINK_SECONDS = 120 +# An alert's still stays loadable this long, and its camera may be opened full screen that long. +STILL_SECONDS = 1800 +FIRST_FRAME_SECONDS = 8 +FETCH_SECONDS = 15 +MAX_SNAPSHOT_BYTES = 8 * 1024 * 1024 +MAX_LINKS = 64 +# What the screens load (online_image `format: BMP`). +CONTENT_TYPE = 'image/bmp' +# The pixel box per board and view; the image keeps its proportions inside it. Equal to the CAMERA_* +# substitutions of packages/guition.yaml (tests/test_camera.py). +BOXES = {'guition': {'full': (480, 480), 'thumb': (392, 220)}} + + +def supported(entity): + """True for a camera or image entity id.""" + return (isinstance(entity, str) and len(entity) <= 120 and re.fullmatch(r'[a-z0-9_]+\.[a-z0-9_]+', entity) is not None + and entity.split('.')[0] in DOMAINS) + + +def version(text): + try: + parts = tuple(int(part) for part in str(text or '').split('.')) + except ValueError: + return () + return parts if len(parts) == 3 else () + + +def can_show(screen): + """A paired Guition with firmware that draws camera images.""" + return bool(screen) and screen.get('board') in BOXES and version(screen.get('firmware')) >= MIN_FIRMWARE + + +def fit(size, box): + """The largest size with the proportions of `size` that fits `box`, at least one pixel each way.""" + width, height = size + scale = min(box[0] / width, box[1] / height) + return max(1, min(box[0], round(width * scale))), max(1, min(box[1], round(height * scale))) + + +def encode(raw, box): + """Any snapshot Home Assistant hands out (JPEG, PNG, GIF, WebP) as a 24-bit BMP that fits `box`, the size of the + screen's buffer.""" + from PIL import Image, ImageOps + with Image.open(io.BytesIO(raw)) as source: + # A JPEG decodes at a half, quarter or eighth of its size while that is still larger than the box. + source.draft('RGB', box) + image = ImageOps.exif_transpose(source) + if image.mode in ('RGBA', 'LA', 'P', 'PA'): + image = image.convert('RGBA') + ground = Image.new('RGB', image.size) + ground.paste(image, mask=image.getchannel('A')) + image = ground + elif image.mode != 'RGB': + image = image.convert('RGB') + size = fit(image.size, box) + if image.size != size: + image = image.resize(size, Image.Resampling.LANCZOS) + out = io.BytesIO() + image.save(out, 'BMP') + return out.getvalue() + + +class Watch: + """One camera: its last snapshot, the sizes made of it and the fetch on its way.""" + + def __init__(self, now): + self.used = now + self.raw, self.digest = None, '' + self.frames = {} + self.failures = 0 + self.retry_at = 0.0 + self.task = None + + +class Link: + __slots__ = ('entity', 'box', 'still', 'etag', 'used', 'lifetime') + + def __init__(self, entity, box, now, still=None): + self.entity, self.box, self.used = entity, box, now + self.still = still + self.etag = f'"{hashlib.sha1(still).hexdigest()[:16]}"' if still else '' + self.lifetime = STILL_SECONDS if still else LINK_SECONDS + + +class CameraFeed: + def __init__(self, fetch, clock=time.monotonic): + self.fetch, self.clock = fetch, clock + self.watches, self.links = {}, {} + + # ----- fetching ----- + # A camera is fetched when a screen loads its picture: serving one starts fetching the next, so each load gets a + # picture exactly one load younger and the picture changes in the screen's own steady rhythm. A fetch that ran on + # its own clock next to the screen's made the picture change after 1.5 s one time and after 6 s the next (measured + # 2026-09-17 with an EZVIZ camera that takes a steady 2.4 s per snapshot). Nobody loading means nothing fetched. + def watch(self, entity): + now = self.clock() + for old in [e for e, w in self.watches.items() if now - w.used > WATCH_SECONDS and (w.task is None or w.task.done())]: + del self.watches[old] + watch = self.watches.get(entity) + if watch is None: + watch = self.watches[entity] = Watch(now) + watch.used = now + return watch + + def refresh(self, entity, watch): + """Start fetching the next snapshot, unless one is on its way or the camera failed a moment ago.""" + if (watch.task is None or watch.task.done()) and self.clock() >= watch.retry_at: + watch.task = asyncio.ensure_future(self.fetch_one(entity, watch)) + + async def fetch_one(self, entity, watch): + try: + raw = await asyncio.wait_for(self.fetch(entity), FETCH_SECONDS) + if not raw: + raise ValueError('empty image') + digest = hashlib.sha1(raw).hexdigest() + if digest != watch.digest: + watch.raw, watch.digest, watch.frames = raw, digest, {} + if watch.failures: + LOG.info('Camera %s answers again', entity) + watch.failures = 0 + except asyncio.CancelledError: + raise + except Exception as error: + watch.failures += 1 + # A camera that fails is asked again after a pause, up to half a minute. + watch.retry_at = self.clock() + min(30, 5 * watch.failures) + if watch.failures in (1, 30): + LOG.info('No image from %s (%s)', entity, type(error).__name__) + + async def frame(self, entity, box, wait=FIRST_FRAME_SECONDS, fresh=True, now=False): + """(etag, BMP) of the camera's last snapshot at `box`, or None when it has none (yet). The first snapshot is + waited for; `fresh` starts fetching the next one for the next load. `now` (an alert) waits for a snapshot whose + fetch starts now or is already on its way, never one kept from an earlier load.""" + watch = self.watch(entity) + if now: + if watch.task is None or watch.task.done(): + watch.retry_at = 0.0 + self.refresh(entity, watch) + try: + await asyncio.wait_for(asyncio.shield(watch.task), wait) + except asyncio.TimeoutError: + return None + if watch.failures: + return None + elif watch.raw is None: + self.refresh(entity, watch) + if watch.task is not None and not watch.task.done(): + try: + await asyncio.wait_for(asyncio.shield(watch.task), wait) + except asyncio.TimeoutError: + return None + raw, digest = watch.raw, watch.digest + if raw is None: + return None + if fresh: + self.refresh(entity, watch) + cached = watch.frames.get(box) + if cached is None or cached[0] != digest: + try: + image = await asyncio.get_running_loop().run_in_executor(None, encode, raw, box) + except Exception as error: + LOG.info('The image of %s cannot be read (%s)', entity, type(error).__name__) + return None + cached = watch.frames[box] = (digest, image) + return f'"{digest[:16]}-{box[0]}x{box[1]}"', cached[1] + + # ----- links ----- + def prune(self): + now = self.clock() + for token in [token for token, link in self.links.items() if now - link.used > link.lifetime]: + del self.links[token] + while len(self.links) >= MAX_LINKS: + del self.links[min(self.links, key=lambda token: self.links[token].used)] + + def link(self, entity, box, still=None): + """A new random token for one camera at one size; `still` makes it one fixed image (an alert's).""" + self.prune() + token = secrets.token_urlsafe(18) + self.links[token] = Link(entity, box, self.clock(), still) + return token + + async def serve(self, token, etag=None): + """(HTTP status, BMP or None, etag) for one request of a screen.""" + link = self.links.get(token) + now = self.clock() + if link is None or now - link.used > link.lifetime: + self.links.pop(token, None) + return 404, None, '' + link.used = now + if link.still: + return (304, None, link.etag) if etag == link.etag else (200, link.still, link.etag) + found = await self.frame(link.entity, link.box) + if found is None: + return 503, None, '' + tag, image = found + return (304, None, tag) if etag == tag else (200, image, tag) + + +def web_app(feed): + """The camera port: GET /camera/.bmp and nothing else, open to the LAN like the screens are.""" + from aiohttp import web + + async def image(request): + status, body, etag = await feed.serve(request.match_info['token'], request.headers.get('If-None-Match')) + headers = {'Cache-Control': 'no-cache', **({'ETag': etag} if etag else {})} + if status == 200: + return web.Response(body=body, content_type=CONTENT_TYPE, headers=headers) + if status == 304: + return web.Response(status=304, headers=headers) + return web.Response(status=status, text='No image' if status == 503 else 'Unknown link', headers=headers) + + app = web.Application(client_max_size=1024) + app.router.add_get(r'/camera/{token:[A-Za-z0-9_-]{16,64}}.bmp', image) + return app + + +def port(): + try: + value = int(os.environ.get('SCREEN_CAMERA_PORT', PORT)) + except ValueError: + return PORT + return value if 0 < value < 65536 else PORT + + +async def base_url(request, cache={}): + """http://

: where screens reach this app: SCREEN_CAMERA_URL when set, else Home Assistant's + own LAN address (the add-on's port is published on the host). `request` is HomeAssistant.request.""" + override = os.environ.get('SCREEN_CAMERA_URL', '').rstrip('/') + if override: + return override + now = time.monotonic() + if cache.get('url') and now - cache.get('at', 0) < 600: + return cache['url'] + host = None + try: + network = await request('network') + for adapter in (network or {}).get('adapters', []): + addresses = [item.get('address') for item in adapter.get('ipv4') or [] if item.get('address')] + if adapter.get('default') and addresses: + host = addresses[0] + break + except Exception as error: + LOG.info('Reading the network adapters failed (%s)', type(error).__name__) + if host is None: + try: + from urllib.parse import urlparse + host = urlparse((await request('network/url') or {}).get('internal') or '').hostname + except Exception as error: + LOG.info('Reading the internal URL failed (%s)', type(error).__name__) + if not host: + return None + cache.update(url=f'http://{host}:{port()}', at=now) + return cache['url'] diff --git a/screen_manager/app/claude_skill.py b/screen_manager/app/claude_skill.py index ef88c67..e675771 100644 --- a/screen_manager/app/claude_skill.py +++ b/screen_manager/app/claude_skill.py @@ -12,7 +12,7 @@ from pathlib import Path import zipfile import tile_icons -from core import (ALERT_ENDINGS, ALERT_EVENT, ALERT_FALLBACK_ICON, ALERT_FIELDS, ALERT_LIMITS, ALERT_MAX_TIMEOUT, +from core import (ALERT_CAMERA_FIELD, ALERT_ENDINGS, ALERT_EVENT, ALERT_FALLBACK_ICON, ALERT_FIELDS, ALERT_LIMITS, ALERT_MAX_TIMEOUT, ALERT_MIN_FIRMWARE, ALERT_SUGGESTED_ICONS, AUTO_STANDBY_MIN_FIRMWARE, BROADCAST_DISMISS, BROADCAST_SHOW, CONTROLS, DISPLAYS, MAX_PAGES, SETTINGS_PAGE_MIN_FIRMWARE, SLOTS_PER_PAGE, TILE_BACKGROUNDS, TILE_EVENTS, TILE_RESULT_EVENT, WAKE_SLEEP_MIN_FIRMWARE, SETTING_ENTITIES_MIN_FIRMWARE, @@ -181,6 +181,8 @@ actions: |---|---|---|---| {fields} +The event for every screen takes one more field, `{ALERT_CAMERA_FIELD[0]}`: {ALERT_CAMERA_FIELD[2]} Example: `{ALERT_CAMERA_FIELD[0]}: {ALERT_CAMERA_FIELD[3]}`. Use a real `camera.*` or `image.*` entity from this Home Assistant (a doorbell integration usually has one); the per-screen actions have no such field. + Text limits are in bytes; an accented letter takes two. Keep the title short: a screen shows about twenty characters of it on one line and ends a longer title with an ellipsis. Put details in the subtitle. ## Colors diff --git a/screen_manager/app/core.py b/screen_manager/app/core.py index edc633c..9ae1d72 100644 --- a/screen_manager/app/core.py +++ b/screen_manager/app/core.py @@ -9,15 +9,18 @@ import secrets import tile_icons -DOMAINS = frozenset('light switch input_boolean scene script climate vacuum fan cover sensor binary_sensor input_select select number input_number weather media_player button input_button sun timer person screen'.split()) +DOMAINS = frozenset('light switch input_boolean scene script climate vacuum fan cover sensor binary_sensor input_select select number input_number weather media_player button input_button sun timer person screen camera image'.split()) # Built-in cards without a Home Assistant entity; firmware 0.2.14+ renders them. BUILTIN = {'screen.clock': 'Clock', 'screen.settings': 'Settings'} NEW_DOMAINS = frozenset('sun timer person screen'.split()) +# A camera or an image entity opens full screen on a Guition with firmware 0.2.57+ (camera_feed.py). +CAMERA_DOMAINS = frozenset(('camera', 'image')) +CAMERA_MIN_FIRMWARE = (0, 2, 57) WEEKDAYS = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'] REPO = 'https://github.com/MaxGramser/homeassistant_espscreen' REFS = {'cyd': 'main', 'guition': 'main'} # Firmware shipped with this app release; screens below it get an update offer. -FIRMWARE_VERSION = '0.2.56' +FIRMWARE_VERSION = '0.2.57' # The Auto standby switch a screen offers Home Assistant automations. AUTO_STANDBY_MIN_FIRMWARE = '0.2.41' # The settings page the screen opens itself, and the screen.settings tile that opens it. @@ -308,7 +311,7 @@ HEADER_SHOWS = ('always', 'active') def header_entity(value): return (isinstance(value, str) and len(value) <= 120 and re.fullmatch(r'[a-z0-9_]+\.[a-z0-9_]+', value) is not None - and value.split('.')[0] in (DOMAINS - {'screen'}) | HEADER_ONLY_DOMAINS) + and value.split('.')[0] in (DOMAINS - {'screen'} - CAMERA_DOMAINS) | HEADER_ONLY_DOMAINS) def header_items(layout): """Items the top bar shows: the stored ones, else what firmware before the top bar drew (the clock).""" @@ -350,6 +353,8 @@ def validate_header(data): def min_firmware(layout): """Oldest firmware that still accepts this layout; None when any version works.""" + if any(t['entity'].split('.')[0] in CAMERA_DOMAINS for t in layout['tiles']): + return CAMERA_MIN_FIRMWARE if any(t['entity'] == 'screen.settings' for t in layout['tiles']): return (0, 2, 44) if any(t.get('options', {}).get('background') == 'none' for t in layout['tiles']): @@ -865,8 +870,9 @@ def extras(tile, states, forecast=None, tz=None, hourly=None, now=None, device=N if hours: result['hours'] = hours return result or None - if domain in ('scene', 'script', 'button', 'input_button'): - # When it last ran: scripts report last_triggered; scenes and buttons carry the time as their state. + if domain in ('scene', 'script', 'button', 'input_button', 'image'): + # When it last ran: scripts report last_triggered; scenes and buttons carry the time as their state, and so does + # an image entity (when its picture last changed). last = epoch(attrs.get('last_triggered') if domain == 'script' else states.get(tile['entity'], {}).get('state')) return {'last': last} if last else None if domain == 'sun': @@ -981,6 +987,9 @@ ALERT_LIMITS = {'cyd': {'title': 48, 'subtitle': 160, 'button_text': 12}, 'guiti ALERT_SUGGESTED_ICONS = ('doorbell', 'bell', 'bell-ring', 'alert-outline', 'alarm-light', 'lock', 'lock-open-variant', 'door-open', 'window-closed-variant', 'motion-sensor', 'cctv', 'smoke-detector', 'water-alert', 'fire', 'mailbox', 'car', 'account', 'account-group', 'washing-machine', 'robot-vacuum', 'timer-outline', 'check') +# Not an argument of show_alert: the app sends the image itself to screens that can draw it (app 0.2.66, a Guition with +# firmware 0.2.57+) and leaves it out for the others. (name, label, explanation, example) like ALERT_FIELDS. +ALERT_CAMERA_FIELD = ('camera', 'Camera', 'A camera or image entity. A Guition with firmware 0.2.57+ shows its picture of that moment across the top of the card; a tap on it opens the camera full screen. Other screens show the alert without it. Only through the esp_screens_show_alert event.', 'camera.front_door') # The firmware's MAX_TIMEOUT_SECONDS. ALERT_MAX_TIMEOUT = 86400 # One alert for every screen (app 0.2.45): an automation fires one of these Home Assistant events and the @@ -999,6 +1008,7 @@ def alert_reference(): 'endings': [{'action': action, 'label': label} for action, label in ALERT_ENDINGS], 'fallback_icon': ALERT_FALLBACK_ICON, 'fallback_cp': tile_icons.GLYPHS[ALERT_FALLBACK_ICON], 'fields': [{'name': name, 'type': kind, 'label': label, 'help': help_, 'example': example} for name, kind, label, help_, example in ALERT_FIELDS], + 'camera': dict(zip(('name', 'label', 'help', 'example'), ALERT_CAMERA_FIELD)), 'limits': ALERT_LIMITS, 'colors': [{'name': name, 'label': item['label'], 'color': item['color']} for name, item in TILE_BACKGROUNDS.items() if item['color']], 'suggested_icons': [{'name': name, 'cp': tile_icons.GLYPHS[name]} for name in ALERT_SUGGESTED_ICONS], @@ -1050,6 +1060,14 @@ def alert_data(data): unusable.append(name) return service, unusable +def alert_camera(data): + """(entity, usable): the alert's `camera` field when it names a camera or image entity; ('', True) without one.""" + value = data.get(ALERT_CAMERA_FIELD[0]) if isinstance(data, dict) else None + if value is None or value == '': + return '', True + usable = isinstance(value, str) and re.fullmatch(r'[a-z0-9_]+\.[a-z0-9_]+', value.strip()) is not None and value.strip().split('.')[0] in CAMERA_DOMAINS + return (value.strip(), True) if usable else ('', False) + def alert_targets(screens): """(ready, skipped): the paired screens that can show an alert now, and the others with the reason. diff --git a/screen_manager/app/server.py b/screen_manager/app/server.py index 509a567..5b4ee63 100644 --- a/screen_manager/app/server.py +++ b/screen_manager/app/server.py @@ -10,13 +10,14 @@ import secrets import time from datetime import datetime, timedelta, timezone import math +import camera_feed import claude_skill from firmware import Firmware import tile_icons from updates import Updater from aiohttp import ClientError, ClientSession, ClientTimeout, WSMsgType, web -from core import BROADCAST_EVENTS, BUILTIN, SETTINGS_BESIDE_BLOCK, TILE_EVENTS, TILE_RESULT_EVENT, apply_tile_event, layout_snapshot, match_screen, HEADER_MIN_FIRMWARE, NAME_TILE_SETTINGS, TILE_BACKGROUNDS, TRANSPORT_MIN_FIRMWARE, alert_data, alert_reference, alert_service, alert_targets, controls_catalogue, device_prefixes, discover, discover_screens, encode, extras, forecast_kinds, header_items, inbox_prefix, message_action, min_firmware, pack_slots, packets, revision, screen_items, state_message, validate_header, validate_layout, validate_settings +from core import BROADCAST_EVENTS, BROADCAST_SHOW, BUILTIN, CAMERA_DOMAINS, SETTINGS_BESIDE_BLOCK, TILE_EVENTS, TILE_RESULT_EVENT, apply_tile_event, layout_snapshot, match_screen, HEADER_MIN_FIRMWARE, NAME_TILE_SETTINGS, TILE_BACKGROUNDS, TRANSPORT_MIN_FIRMWARE, alert_camera, alert_data, alert_reference, alert_service, alert_targets, controls_catalogue, device_prefixes, discover, discover_screens, encode, extras, forecast_kinds, header_items, inbox_prefix, message_action, min_firmware, pack_slots, packets, revision, screen_items, state_message, validate_header, validate_layout, validate_settings from core import SETTING_ENTITIES, SETTING_RULES, setting_action, setting_entities, setting_from_state import header_bar import history_card @@ -107,6 +108,8 @@ class HomeAssistant: self.services_changed = asyncio.Event() # History a detail card asks for when it opens (firmware 0.2.51+): {inbox, entity, hours}, for Manager.card_history_loop. self.history_requests = asyncio.Queue() + # A camera a screen opens full screen (firmware 0.2.57+): {inbox, entity}, for Manager.camera_loop. + self.camera_requests = asyncio.Queue() async def request(self, kind, **data): if self.ws is None or self.ws.closed: @@ -142,6 +145,8 @@ class HomeAssistant: self.changed.set() elif event.get('event_type') == 'esphome.screen_history': self.history_requests.put_nowait(body) + elif event.get('event_type') == 'esphome.screen_camera': + self.camera_requests.put_nowait(body) elif event.get('event_type') == 'state_changed': eid = body.get('entity_id') if body.get('new_state'): @@ -205,6 +210,7 @@ class HomeAssistant: await self.request('subscribe_events', event_type='state_changed') await self.request('subscribe_events', event_type='esphome.screen_setting') await self.request('subscribe_events', event_type='esphome.screen_history') + await self.request('subscribe_events', event_type='esphome.screen_camera') for event_type in (*REGISTRY_EVENTS, *BROADCAST_EVENTS, *TILE_EVENTS, *SERVICE_EVENTS): await self.request('subscribe_events', event_type=event_type) self.states = {s['entity_id']: s for s in await self.request('get_states')} @@ -287,6 +293,21 @@ class HomeAssistant: domain, service = action.split('.', 1) await self.request('call_service', domain=domain, service=service, service_data=data) + async def camera_image(self, entity): + """The picture of a camera or image entity as Home Assistant hands it to its own frontend.""" + path = 'camera_proxy' if entity.startswith('camera.') else 'image_proxy' + async with self.session.get(f'{self.base}/{path}/{entity}', headers={'Authorization': 'Bearer ' + self.token}, + timeout=ClientTimeout(total=camera_feed.FETCH_SECONDS)) as response: + response.raise_for_status() + if (response.content_length or 0) > camera_feed.MAX_SNAPSHOT_BYTES: + raise ValueError('image too large') + raw = bytearray() + async for chunk in response.content.iter_chunked(65536): + raw += chunk + if len(raw) > camera_feed.MAX_SNAPSHOT_BYTES: + raise ValueError('image too large') + return bytes(raw) + async def fire(self, event_type, data): """One Home Assistant event of our own, such as the answer to a tile event.""" await self.request('fire_event', event_type=event_type, event_data=data) @@ -395,6 +416,10 @@ class Manager: self.retry_at, self.retries, self.no_answers = {}, {}, set() # History for detail cards (firmware 0.2.51+): (entity, hours) -> (monotonic, message), and the fetches under way. self.card_histories, self.card_history_fetches = {}, {} + # Camera images (firmware 0.2.57+): the feed behind the camera port, and the cameras of recent alerts + # (entity -> monotonic time) that a screen may open full screen without a tile. + self.camera = camera_feed.CameraFeed(lambda entity: self.ha.camera_image(entity)) + self.alert_cameras = {} if self.path.exists(): raw = json.loads(self.path.read_text()) # Versioned persistent data. Never silently overwrite an unknown schema. @@ -794,6 +819,9 @@ class Manager: if screen is None: raise ValueError("This isn't a paired ESP screen. Refresh the overview.") layout = validate_layout(data) + # A CYD has no memory for camera images, whatever its firmware; say so before asking for an update. + if any(t['entity'].split('.')[0] in CAMERA_DOMAINS for t in layout['tiles']) and screen.get('board') not in camera_feed.BOXES: + raise ValueError('Camera images need a Guition screen.') needed = self.needs_firmware(inbox, layout, screen) if needed: raise ValueError(f"Install screen firmware {needed} or newer first for these tiles.") @@ -1160,19 +1188,101 @@ class Manager: except Exception as error: LOG.warning('Refreshing history failed (%s)', type(error).__name__) + # ----- Camera images (firmware 0.2.57+) ----- + async def camera_loop(self): + """Answer the cameras screens open full screen, a few at a time.""" + limit = asyncio.Semaphore(4) + + async def answer(request): + async with limit: + try: + await self.answer_camera(request) + except Exception as error: + LOG.warning('Camera for %s was not sent (%s)', request.get('entity') if isinstance(request, dict) else '?', type(error).__name__) + queue = getattr(self.ha, 'camera_requests', None) + while queue is not None: + request = await queue.get() + asyncio.ensure_future(answer(request)) + + def camera_allowed(self, inbox, entity): + """A camera on the screen's own layout, or one a recent alert showed.""" + seen = self.alert_cameras.get(entity) + if seen is not None and time.monotonic() - seen < camera_feed.STILL_SECONDS: + return True + return entity in {tile['entity'] for tile in self.layouts.get(inbox, {}).get('tiles', [])} + + async def camera_message(self, entity, view, board, still=None): + """The screen message for one camera view: a link to its image, or an empty link when there is none.""" + url = '' + base = await camera_feed.base_url(self.ha.request) + if base: + box = camera_feed.BOXES[board][view] + if view == 'thumb': + token = self.camera.link(entity, box, still) if still else None + else: + token = self.camera.link(entity, box) if await self.camera.frame(entity, box) else None + url = f'{base}/camera/{token}.bmp' if token else '' + else: + LOG.warning('Camera images: no address for this app on the LAN; set SCREEN_CAMERA_URL') + return {'v': 1, 'op': 'camera', 't': 'alert' if view == 'thumb' else 'full', 'e': entity, 'u': url} + + async def answer_camera(self, request): + """One screen's request: a camera it may show, on a screen that draws camera images.""" + if not isinstance(request, dict): + return + inbox = self.aliases.get(request.get('inbox'), request.get('inbox')) + entity = request.get('entity') + screen = self.screen(inbox) if isinstance(inbox, str) else None + if not camera_feed.supported(entity) or not camera_feed.can_show(screen) or not screen.get('online'): + return + action = self.transport(inbox, screen) + if not action or not self.camera_allowed(inbox, entity): + return + message = await self.camera_message(entity, 'full', screen['board']) + await self.ha.send(inbox, message, action) + LOG.info('Camera %s on %s%s', entity, screen['name'], '' if message['u'] else ': no image') + + async def alert_images(self, camera, screens): + """The picture of an alert's camera at that moment, on every screen that draws it.""" + self.alert_cameras[camera] = time.monotonic() + for old in [entity for entity, moment in self.alert_cameras.items() if time.monotonic() - moment > camera_feed.STILL_SECONDS]: + del self.alert_cameras[old] + boards = {} + for screen in screens: + boards.setdefault(screen['board'], []).append(screen) + for board, group in boards.items(): + found = await self.camera.frame(camera, camera_feed.BOXES[board]['thumb'], fresh=False, now=True) + message = await self.camera_message(camera, 'thumb', board, found[1] if found else None) + results = await asyncio.gather(*(self.ha.send(screen['id'], message, self.transport(screen['id'], screen)) for screen in group), + return_exceptions=True) + failed = sum(isinstance(result, BaseException) for result in results) + LOG.info('Alert image of %s: %d of %d screens%s', camera, len(group) - failed, len(group), '' if message['u'] else ' (no image)') + async def broadcast(self, event_type, data): """An alert event for every screen: the matching action on each screen that can show it, all at once.""" action = BROADCAST_EVENTS[event_type] service_data, unusable = alert_data(data) if action == 'show_alert' else ({}, []) + camera, usable = alert_camera(data) if event_type == BROADCAST_SHOW else ('', True) + if not usable: + unusable.append('camera') if unusable: LOG.warning('%s: unusable %s left empty', event_type, ', '.join(unusable)) ready, skipped = alert_targets(self.screens()) + # A screen that draws the image hears about it before the alert, so the card opens with room for it. + viewers = [screen for screen in ready if camera and camera_feed.can_show(screen) and self.transport(screen['id'], screen)] + if viewers: + pending = {'v': 1, 'op': 'camera', 't': 'alert', 'e': camera, 'u': ''} + await asyncio.gather(*(self.ha.send(screen['id'], pending, self.transport(screen['id'], screen)) for screen in viewers), + return_exceptions=True) results = await asyncio.gather(*(self.ha.call(alert_service(screen['node'], action), service_data) for screen in ready), return_exceptions=True) failed = [(screen, type(result).__name__) for screen, result in zip(ready, results) if isinstance(result, BaseException)] notes = [f"{screen['name']} {reason}" for screen, reason in skipped + failed] LOG.info('%s: %d of %d screens%s', event_type, len(ready) - len(failed), len(ready) + len(skipped), f" (not: {'; '.join(notes)})" if notes else '') + shown = [screen for screen, result in zip(ready, results) if not isinstance(result, BaseException)] + if viewers and any(screen in shown for screen in viewers): + await self.alert_images(camera, [screen for screen in viewers if screen in shown]) return {'sent': len(ready) - len(failed), 'skipped': len(skipped), 'failed': len(failed)} async def tile_event(self, event_type, data): @@ -1416,10 +1526,19 @@ async def main(): runner = web.AppRunner(create_app(manager, development), access_log=None) await runner.setup() await web.TCPSite(runner, '127.0.0.1' if development else '0.0.0.0', 8099).start() + # Camera images for the screens: their own port on the LAN, not the ingress page (docs/CAMERA.md). + cameras = web.AppRunner(camera_feed.web_app(manager.camera), access_log=None) + await cameras.setup() + try: + await web.TCPSite(cameras, '0.0.0.0', camera_feed.port()).start() + except OSError as error: + # Everything else still works; only camera images stay away. + LOG.error('Camera images are off: port %d is not available (%s)', camera_feed.port(), error) try: await asyncio.gather(ha.run(), manager.run(), manager.history_loop(), manager.updates.run(), - manager.alert_loop(), manager.tile_loop(), manager.card_history_loop()) + manager.alert_loop(), manager.tile_loop(), manager.card_history_loop(), manager.camera_loop()) finally: + await cameras.cleanup() await runner.cleanup() if __name__ == '__main__': diff --git a/screen_manager/app/static/app.js b/screen_manager/app/static/app.js index 122ffa3..3873c11 100644 --- a/screen_manager/app/static/app.js +++ b/screen_manager/app/static/app.js @@ -806,6 +806,8 @@ const domains = { sun: ["Sun", "☼", "#c86620", "#ffebdc"], timer: ["Timer", "⏱", "#008577", "#def3ed"], person: ["Person", "☺", "#2f7d32", "#e1f2e2"], + camera: ["Camera", "◧", "#3d4a57", "#e6ebf0"], + image: ["Image", "◧", "#3d4a57", "#e6ebf0"], }; const displayNames = { standard: "standard", watch: "large value", forecast: "weather forecast", graph: "graph", digital: "digital clock", analog: "analog clock", sunpath: "sun path" }; // Same rule as the add-on: only a wide card in the standard layout shows direct controls; @@ -2009,8 +2011,11 @@ function renderResults() { if (!layout) return; const query = $("#search").value.toLocaleLowerCase(); const chosen = new Set(layout.tiles.map((t) => t.entity)); + // Camera images need a Guition (app 0.2.66); the add-on refuses them for other screens too. + const guition = inventory.screens.find((s) => s.id === selected)?.board === "guition"; const matches = [...(inventory.builtin || []), ...inventory.entities].filter( (e) => + (guition || !["camera", "image"].includes(e.id.split(".")[0])) && (!filter || e.id.startsWith(filter + ".") || ({switch:"input_boolean", number:"input_number", select:"input_select", weather:"sun"}[filter] === e.id.split(".")[0])) && `${e.name} ${e.id} ${e.device} ${e.area}` @@ -2612,6 +2617,8 @@ function alertWaitYaml(action) { function alertAllYaml() { const fields = inventory.alerts?.fields || []; const lines = fields.map((f) => ` ${f.name}: ${f.type === "string" ? (/^[a-z][a-z0-9-]*$/.test(f.example) ? f.example : yamlString(f.example)) : String(f.example)}`); + const camera = inventory.alerts?.camera; + if (camera) lines.push(` # ${camera.name}: ${camera.example} # a Guition shows its picture on the card`); return `event: ${inventory.alerts?.broadcast?.show || "esp_screens_show_alert"}\nevent_data:\n${lines.join("\n")}`; } function renderAlertBroadcast() { @@ -2751,6 +2758,16 @@ function renderAlertTables() { row.append(...cells); table.append(row); } + // The camera image (app 0.2.66): a field of the event for every screen, not of a screen's own action. + if (alerts.camera) { + const row = node("tr"), name = node("td"), example = node("td"); + name.append(node("code", alerts.camera.name), node("small", alerts.camera.label)); + example.append(node("code", alerts.camera.example)); + const cells = [name, node("td", "entity"), node("td", alerts.camera.help), example, node("td", "Guition, firmware 0.2.57+")]; + cells.forEach((cell, index) => cell.dataset.label = ["Field", "Type", "What it does", "Example", "Limit"][index]); + row.append(...cells); + table.append(row); + } const endings = $("#alerts-ending-table"); endings.replaceChildren(); const endHead = node("tr"); diff --git a/screen_manager/app/tile_icons.py b/screen_manager/app/tile_icons.py index f20f260..9298c48 100644 --- a/screen_manager/app/tile_icons.py +++ b/screen_manager/app/tile_icons.py @@ -235,7 +235,7 @@ GLYPHS = {**{name: codepoint for name, (codepoint, _) in ICONS.items()}, **dict( # Mirrors runtime_tiles::icon_for() so the editor mockup shows what the screen draws. DEFAULTS = {'light': 'lightbulb', 'climate': 'air-conditioner', 'vacuum': 'robot-vacuum', 'fan': 'fan', 'cover': 'window-shutter', 'scene': 'sofa', 'script': 'sofa', 'sensor': 'gauge', 'binary_sensor': 'gauge', - 'timer': 'timer-outline', 'person': 'account', 'screen': 'clock-outline'} + 'timer': 'timer-outline', 'person': 'account', 'camera': 'cctv', 'image': 'cctv', 'screen': 'clock-outline'} # The cards the screen brings itself: one icon per entity, not per domain. BUILTIN_TILES = {'screen.clock': 'clock-outline', 'screen.settings': 'cog'} FALLBACK = 'power' diff --git a/screen_manager/config.yaml b/screen_manager/config.yaml index 21be98b..d387a12 100644 --- a/screen_manager/config.yaml +++ b/screen_manager/config.yaml @@ -1,5 +1,5 @@ name: ESP Screen Manager -version: "0.2.65" +version: "0.2.66" slug: esp_screen_manager description: Choose tiles for your CYD and Guition touchscreen, without reflashing. url: https://github.com/MaxGramser/homeassistant_espscreen @@ -10,6 +10,11 @@ init: false homeassistant_api: true ingress: true ingress_port: 8099 +# Camera images for Guition screens (docs/CAMERA.md): the screens load them from this port on the LAN. +ports: + 8098/tcp: 8098 +ports_description: + 8098/tcp: Camera images for the screens (keep 8098) panel_icon: mdi:monitor-dashboard panel_title: ESP Screens panel_admin: true diff --git a/tests/test_camera.py b/tests/test_camera.py new file mode 100644 index 0000000..760ee1b --- /dev/null +++ b/tests/test_camera.py @@ -0,0 +1,399 @@ +"""Camera images on a Guition (app 0.2.66, firmware 0.2.57): the app fetches, sizes and serves the image on its own +port; the screen asks with esphome.screen_camera and loads the link with ESPHome's online_image.""" +import asyncio +import importlib.util +import io +from pathlib import Path +import re +import sys +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT / 'screen_manager/app')) +import camera_feed # noqa: E402 +from core import (ALERT_FIELDS, BROADCAST_SHOW, CAMERA_MIN_FIRMWARE, alert_camera, alert_reference, entity_id, # noqa: E402 + header_entity, min_firmware, validate_layout, extras) + +HAS_PIL = importlib.util.find_spec('PIL') is not None +HAS_AIOHTTP = importlib.util.find_spec('aiohttp') is not None +if HAS_AIOHTTP: + from server import HomeAssistant, Manager + +PROFILE = (ROOT / 'guition-4848s040.yaml').read_text() +TILES = (ROOT / 'components/smart_display/runtime_tiles.h').read_text() + + +def picture(fmt, size, mode='RGB'): + from PIL import Image + out = io.BytesIO() + Image.new(mode, size, (200, 30, 90) if mode == 'RGB' else None).save(out, fmt) + return out.getvalue() + + +class Rules(unittest.TestCase): + def test_camera_and_image_tiles_need_the_camera_firmware(self): + self.assertTrue(entity_id('camera.front_door') and entity_id('image.doorbell')) + self.assertEqual(camera_feed.MIN_FIRMWARE, CAMERA_MIN_FIRMWARE) + layout = validate_layout({'title': 'Hall', 'tiles': [{'entity': 'camera.front_door', 'name': ''}]}) + self.assertEqual(min_firmware(layout), (0, 2, 57)) + # Automatic and "open control" both open the image full screen; view only keeps the tile still. + validate_layout({'title': 'Hall', 'tiles': [{'entity': 'camera.front_door', 'name': '', 'options': {'tap': 'detail'}}]}) + validate_layout({'title': 'Hall', 'tiles': [{'entity': 'image.doorbell', 'name': '', 'options': {'tap': 'none'}}]}) + # A top bar item shows a state; a camera has nothing worth reading there. + self.assertFalse(header_entity('camera.front_door')) + + def test_an_image_tile_knows_when_its_picture_changed(self): + states = {'image.doorbell': {'state': '2026-09-17T12:00:00+00:00', 'attributes': {}}} + self.assertEqual(extras({'entity': 'image.doorbell'}, states), {'last': 1789646400}) + + def test_which_screens_draw_images(self): + self.assertTrue(camera_feed.can_show({'board': 'guition', 'firmware': '0.2.57'})) + self.assertTrue(camera_feed.can_show({'board': 'guition', 'firmware': '0.3.0'})) + for screen in ({'board': 'guition', 'firmware': '0.2.56'}, {'board': 'unknown', 'firmware': '0.2.57'}, + {'board': 'guition', 'firmware': 'unknown'}, None, {}): + self.assertFalse(camera_feed.can_show(screen), screen) + self.assertTrue(camera_feed.supported('camera.max') and camera_feed.supported('image.max_motion')) + for value in ('light.kitchen', 'camera', 'Camera.Max', None, 42, 'camera.' + 'x' * 120): + self.assertFalse(camera_feed.supported(value), value) + + def test_the_alert_camera_field(self): + self.assertEqual(alert_camera({'camera': 'camera.front_door'}), ('camera.front_door', True)) + self.assertEqual(alert_camera({'camera': ' image.doorbell '}), ('image.doorbell', True)) + self.assertEqual(alert_camera({}), ('', True)) + self.assertEqual(alert_camera({'camera': ''}), ('', True)) + for value in ('light.hall', True, ['camera.max'], 'camera'): + self.assertEqual(alert_camera({'camera': value}), ('', False), value) + # Not an argument of the show_alert action: older firmware would refuse the whole call. + self.assertNotIn('camera', [name for name, *_ in ALERT_FIELDS]) + self.assertEqual(alert_reference()['camera']['name'], 'camera') + + def test_the_boxes_are_the_profile_sizes(self): + subs = dict(re.findall(r'^ (CAMERA_\w+): "(\d+)"', PROFILE, re.M)) + self.assertEqual(camera_feed.BOXES['guition'], {'full': (int(subs['CAMERA_FULL_W']), int(subs['CAMERA_FULL_H'])), + 'thumb': (int(subs['CAMERA_THUMB_W']), int(subs['CAMERA_THUMB_H']))}) + + def test_the_firmware_and_the_app_speak_the_same_words(self): + self.assertIn('request.service = esphome::StringRef("esphome.screen_camera");', TILES) + self.assertIn("event_type='esphome.screen_camera'", (ROOT / 'screen_manager/app/server.py').read_text()) + self.assertIn('if (op == "camera") {', TILES) + self.assertIn('"camera", "image"})', (ROOT / 'components/smart_display/runtime_model.h').read_text()) + # The profile loads both images and binds them; the CYD has none, so it never opens a camera. + for needle in ('online_image:\n - id: camera_image', ' - id: alert_image', 'runtime_tiles::camera_loaded(false, cached);', + 'runtime_tiles::camera_loaded(true, cached);', 'runtime_tiles::camera_tick();', 'runtime_tiles::alert_prepare();', + 'runtime_tiles::alert_clear();', 'runtime_tiles::camera_close();', 'id: alert_image_frame'): + self.assertIn(needle, PROFILE, needle) + # A link only replaces the URL when it is new: set_url() forgets the ETag that makes an unchanged picture a 304. + self.assertEqual(PROFILE.count('if (url != current) {'), 2) + # A busy camera port leaves the rest of the app running. + self.assertIn("except OSError as error:\n # Everything else still works; only camera images stay away.", (ROOT / 'screen_manager/app/server.py').read_text()) + cyd = (ROOT / 'home-like-2432s028.yaml').read_text() + self.assertNotIn('online_image', cyd) + self.assertNotIn('camera_full.load', cyd) + # The add-on's port is published, and the Docker route passes it on with the host network. + config = (ROOT / 'screen_manager/config.yaml').read_text() + self.assertIn(f'{camera_feed.PORT}/tcp: {camera_feed.PORT}', config) + + +@unittest.skipUnless(HAS_PIL, 'Pillow comes with ESPHome in the add-on image') +class Encoding(unittest.TestCase): + def test_every_snapshot_becomes_a_bmp_that_fits(self): + from PIL import Image + cases = [(picture('JPEG', (1920, 1080)), (480, 480), (480, 270)), + (picture('JPEG', (1920, 1080)), (392, 220), (391, 220)), + (picture('PNG', (400, 100), 'RGBA'), (480, 480), (480, 120)), + (picture('GIF', (550, 512), 'P'), (392, 220), (236, 220)), + (picture('JPEG', (1080, 1440)), (480, 480), (360, 480)), + (picture('PNG', (100, 50)), (480, 480), (480, 240))] + for raw, box, size in cases: + bmp = camera_feed.encode(raw, box) + with Image.open(io.BytesIO(bmp)) as image: + self.assertEqual((image.format, image.size, image.mode), ('BMP', size, 'RGB')) + # What ESPHome's BMP decoder reads: 24 bits per pixel, no compression, rows padded to four bytes. + self.assertEqual((bmp[:2], int.from_bytes(bmp[28:30], 'little'), int.from_bytes(bmp[30:34], 'little')), (b'BM', 24, 0)) + self.assertEqual(len(bmp), int.from_bytes(bmp[10:14], 'little') + size[1] * ((size[0] * 3 + 3) // 4 * 4)) + with self.assertRaises(Exception): + camera_feed.encode(b'not an image', (480, 480)) + + def test_fit_keeps_proportions(self): + self.assertEqual(camera_feed.fit((1920, 1080), (480, 480)), (480, 270)) + self.assertEqual(camera_feed.fit((1, 5000), (224, 126)), (1, 126)) + self.assertEqual(camera_feed.fit((5000, 1), (224, 126)), (224, 1)) + + +class Clock: + def __init__(self): self.now = 1000.0 + def __call__(self): return self.now + + +@unittest.skipUnless(HAS_PIL, 'Pillow comes with ESPHome in the add-on image') +class Feed(unittest.IsolatedAsyncioTestCase): + def feed(self, answers): + self.fetched = [] + clock = Clock() + + async def fetch(entity): + self.fetched.append(entity) + answer = answers[min(len(self.fetched), len(answers)) - 1] + if isinstance(answer, Exception): + raise answer + return answer + return camera_feed.CameraFeed(fetch, clock=clock), clock + + async def settle(self): + for _ in range(5): + await asyncio.sleep(0) + + async def test_links_serve_the_last_frame_and_answer_unchanged_images_with_304(self): + feed, clock = self.feed([picture('JPEG', (1920, 1080))]) + token = feed.link('camera.max', (480, 480)) + status, bmp, etag = await feed.serve(token) + self.assertEqual((status, bmp[:2]), (200, b'BM')) + self.assertRegex(etag, r'^"[0-9a-f]{16}-480x480"$') + await self.settle() + # The camera answered the same picture again: the screen keeps what it has. + self.assertEqual(await feed.serve(token, etag), (304, None, etag)) + self.assertEqual((await feed.serve('unknown'))[0], 404) + # A link nobody used for LINK_SECONDS is gone; the screen asks for a new one. + clock.now += camera_feed.LINK_SECONDS + 1 + self.assertEqual((await feed.serve(token))[0], 404) + + async def test_each_load_fetches_the_next_picture_and_nothing_is_fetched_between_loads(self): + first, second, third = picture('JPEG', (640, 360)), picture('PNG', (640, 360)), picture('BMP', (640, 360)) + feed, clock = self.feed([first, second, third]) + token = feed.link('camera.max', (480, 480)) + _, one, tag_one = await feed.serve(token) + self.assertEqual(self.fetched, ['camera.max'] * 2, 'the first picture, and the next one started at once') + await self.settle() + await asyncio.sleep(0.05) + self.assertEqual(len(self.fetched), 2, 'nobody loads, nothing is fetched') + clock.now += 4 + _, two, tag_two = await feed.serve(token, tag_one) + self.assertNotEqual(tag_two, tag_one, 'the picture fetched after the last load') + self.assertEqual(len(self.fetched), 3) + # Two screens loading at once share one fetch. + await feed.serve(token, tag_two) + await feed.serve(token, tag_two) + self.assertLessEqual(len(self.fetched), 4) + + async def test_a_camera_that_fails_is_asked_again_after_a_pause(self): + feed, clock = self.feed([ConnectionError('500'), ConnectionError('500'), picture('JPEG', (640, 360))]) + token = feed.link('camera.woonkamer_live', (480, 480)) + with self.assertLogs(camera_feed.LOG, 'INFO'): + self.assertEqual((await feed.serve(token))[0], 503) + self.assertEqual((await feed.serve(token))[0], 503) + self.assertEqual(len(self.fetched), 1, 'no second try within the pause') + clock.now += 5 + self.assertEqual((await feed.serve(token))[0], 503) + self.assertEqual(len(self.fetched), 2) + clock.now += 10 + self.assertEqual((await feed.serve(token))[0], 200) + self.assertEqual(len(self.fetched), 4, 'the good picture, then the next one') + + async def test_an_alert_gets_a_snapshot_of_its_own_moment(self): + first, second = picture('JPEG', (640, 360)), picture('PNG', (640, 360)) + feed, clock = self.feed([first, second]) + tag_first, _ = await feed.frame('camera.front_door', (392, 220), fresh=False) + self.assertEqual(len(self.fetched), 1) + clock.now += 20 + # The bell rings 20 s later: the kept snapshot is not the moment, a new fetch is. + tag_alert, _ = await feed.frame('camera.front_door', (392, 220), fresh=False, now=True) + self.assertEqual(len(self.fetched), 2) + self.assertNotEqual(tag_alert, tag_first) + + async def test_an_alert_whose_camera_fails_gets_no_old_picture(self): + feed, clock = self.feed([picture('JPEG', (640, 360)), ConnectionError('offline')]) + await feed.frame('camera.front_door', (392, 220), fresh=False) + clock.now += 20 + with self.assertLogs(camera_feed.LOG, 'INFO'): + self.assertIsNone(await feed.frame('camera.front_door', (392, 220), fresh=False, now=True)) + + async def test_a_camera_nobody_loads_is_forgotten(self): + feed, clock = self.feed([picture('JPEG', (64, 36))]) + await feed.frame('camera.max', (480, 480), fresh=False) + self.assertIn('camera.max', feed.watches) + clock.now += camera_feed.WATCH_SECONDS + 1 + feed.watch('camera.garden') + self.assertNotIn('camera.max', feed.watches) + + async def test_a_still_is_one_fixed_image(self): + feed, _ = self.feed([RuntimeError('never asked')]) + bmp = camera_feed.encode(picture('JPEG', (640, 360)), (392, 220)) + token = feed.link('camera.max', (392, 220), bmp) + status, body, etag = await feed.serve(token) + self.assertEqual((status, body), (200, bmp)) + self.assertEqual((await feed.serve(token, etag))[0], 304) + self.assertEqual(self.fetched, []) + + async def test_the_number_of_links_is_bounded(self): + feed, clock = self.feed([picture('JPEG', (64, 36))]) + tokens = [] + for _ in range(camera_feed.MAX_LINKS + 10): + clock.now += 0.01 + tokens.append(feed.link('camera.max', (480, 480))) + self.assertLessEqual(len(feed.links), camera_feed.MAX_LINKS) + self.assertNotIn(tokens[0], feed.links) + self.assertIn(tokens[-1], feed.links) + self.assertTrue(all(re.fullmatch(r'[A-Za-z0-9_-]{24}', token) for token in tokens)) + + async def test_the_http_port(self): + from aiohttp.test_utils import TestClient, TestServer + feed, _ = self.feed([picture('JPEG', (1920, 1080))]) + token = feed.link('camera.max', (480, 480)) + async with TestClient(TestServer(camera_feed.web_app(feed))) as client: + response = await client.get(f'/camera/{token}.bmp') + body = await response.read() + self.assertEqual((response.status, response.content_type, int(response.headers['Content-Length'])), (200, 'image/bmp', len(body))) + etag = response.headers['ETag'] + self.assertEqual((await client.get(f'/camera/{token}.bmp', headers={'If-None-Match': etag})).status, 304) + self.assertEqual((await client.get('/camera/abcdefghijklmnopqrstuvwx.bmp')).status, 404) + self.assertEqual((await client.get('/api/inventory')).status, 404) + self.assertEqual((await client.post(f'/camera/{token}.bmp')).status, 405) + + +def fake_ha(image=None): + """Home Assistant with two current screens (a Guition and a CYD) and an old Guition.""" + class HA: + online = True + + def __init__(self): + self.registry, self.devices, self.states = [], [], {} + for device, node, firmware, guition in (('d1', 'hall', '0.2.57', True), ('d2', 'desk', '0.2.57', False), + ('d3', 'attic', '0.2.56', True)): + self.registry += [{'entity_id': f'text.{device}_tiles', 'platform': 'esphome', 'original_name': 'Tile settings', 'device_id': device}, + {'entity_id': f'sensor.{device}_node', 'platform': 'esphome', 'original_name': 'Device name', 'device_id': device}, + {'entity_id': f'sensor.{device}_fw', 'platform': 'esphome', 'original_name': 'Screen firmware', 'device_id': device}] + if guition: + self.registry.append({'entity_id': f'select.{device}_type', 'platform': 'esphome', 'original_name': 'Guition screen type', 'device_id': device}) + self.devices.append({'id': device, 'name': node.title()}) + self.states.update({f'text.{device}_tiles': {'state': 'Synced'}, f'sensor.{device}_node': {'state': node}, + f'sensor.{device}_fw': {'state': firmware}}) + self.areas = [] + self.changed = asyncio.Event() + self.log = [] + self.responses = set() + + async def call(self, action, data): + self.log.append(('call', action, data)) + + async def send(self, inbox, message, action=None, respond=False): + self.log.append(('send', inbox, dict(message))) + + async def request(self, kind, **data): + if kind == 'network': + return {'adapters': [{'name': 'end0', 'default': True, 'ipv4': [{'address': '192.168.1.57'}]}]} + raise ConnectionError(kind) + + async def camera_image(self, entity): + self.log.append(('fetch', entity)) + if image is None: + raise ConnectionError('500') + return image + return HA() + + +@unittest.skipUnless(HAS_AIOHTTP and HAS_PIL, 'Run using .venv-portal/bin/python for server tests') +class App(unittest.IsolatedAsyncioTestCase): + def setUp(self): + camera_feed.base_url.__defaults__[0].clear() + + async def test_an_alert_with_a_camera(self): + with tempfile.TemporaryDirectory() as tmp: + ha = fake_ha(picture('JPEG', (1920, 1080))) + m = Manager(ha, Path(tmp) / 'screens.json') + await m.broadcast(BROADCAST_SHOW, {'title': 'Someone is at the door', 'camera': 'camera.front_door'}) + sends = [entry for entry in ha.log if entry[0] == 'send'] + calls = [entry for entry in ha.log if entry[0] == 'call'] + # Only the current Guition hears of the image: first announced, then the alert, then the link. + self.assertEqual([target for _, target, _ in sends], ['text.d1_tiles', 'text.d1_tiles']) + self.assertEqual(sends[0][2], {'v': 1, 'op': 'camera', 't': 'alert', 'e': 'camera.front_door', 'u': ''}) + self.assertLess(ha.log.index(sends[0]), ha.log.index(calls[0])) + self.assertEqual(len(calls), 3, 'every current screen gets the alert itself') + self.assertNotIn('camera', calls[0][2]) + url = sends[1][2]['u'] + self.assertRegex(url, r'^http://192\.168\.1\.57:8098/camera/[A-Za-z0-9_-]{24}\.bmp$') + token = url.rsplit('/', 1)[1][:-4] + self.assertEqual(m.camera.links[token].box, (392, 220)) + self.assertEqual((await m.camera.serve(token))[0], 200) + # The alert's camera may be opened full screen without a tile. + self.assertTrue(m.camera_allowed('text.d1_tiles', 'camera.front_door')) + + async def test_an_alert_whose_camera_has_no_image_still_goes_out(self): + with tempfile.TemporaryDirectory() as tmp: + ha = fake_ha(None) + m = Manager(ha, Path(tmp) / 'screens.json') + with self.assertLogs('screen_manager', 'INFO') as logs: + await m.broadcast(BROADCAST_SHOW, {'title': 'Door', 'camera': 'camera.front_door'}) + sends = [entry for entry in ha.log if entry[0] == 'send'] + self.assertEqual([message['u'] for _, _, message in sends], ['', '']) + self.assertEqual(len([entry for entry in ha.log if entry[0] == 'call']), 3) + self.assertTrue(any('(no image)' in line for line in logs.output), logs.output) + + async def test_an_unusable_camera_is_named_and_left_out(self): + with tempfile.TemporaryDirectory() as tmp: + ha = fake_ha(picture('JPEG', (64, 36))) + m = Manager(ha, Path(tmp) / 'screens.json') + with self.assertLogs('screen_manager', 'INFO') as logs: + await m.broadcast(BROADCAST_SHOW, {'title': 'Door', 'camera': 'light.hall'}) + self.assertEqual([entry[0] for entry in ha.log], ['call'] * 3) + self.assertTrue(any('unusable camera left empty' in line for line in logs.output), logs.output) + + async def test_a_screen_asks_for_a_camera_it_may_show(self): + with tempfile.TemporaryDirectory() as tmp: + ha = fake_ha(picture('JPEG', (1920, 1080))) + m = Manager(ha, Path(tmp) / 'screens.json') + m.layouts['text.d1_tiles'] = validate_layout({'title': 'Hall', 'tiles': [{'entity': 'camera.max', 'name': ''}]}) + with self.assertLogs('screen_manager', 'INFO'): + await m.answer_camera({'inbox': 'text.d1_tiles', 'entity': 'camera.max'}) + (_, inbox, message), = [entry for entry in ha.log if entry[0] == 'send'] + self.assertEqual((inbox, message['op'], message['t'], message['e']), ('text.d1_tiles', 'camera', 'full', 'camera.max')) + token = message['u'].rsplit('/', 1)[1][:-4] + self.assertEqual(m.camera.links[token].box, (480, 480)) + ha.log.clear() + # Not on its layout, a CYD, an old Guition, a light: no link at all. + for request in ({'inbox': 'text.d1_tiles', 'entity': 'camera.garden'}, {'inbox': 'text.d2_tiles', 'entity': 'camera.max'}, + {'inbox': 'text.d3_tiles', 'entity': 'camera.max'}, {'inbox': 'text.d1_tiles', 'entity': 'light.hall'}, + {'inbox': 'text.unknown', 'entity': 'camera.max'}, 'nonsense'): + await m.answer_camera(request) + self.assertEqual([entry for entry in ha.log if entry[0] == 'send'], []) + + async def test_camera_tiles_only_on_a_guition(self): + with tempfile.TemporaryDirectory() as tmp: + ha = fake_ha() + m = Manager(ha, Path(tmp) / 'screens.json') + m.inventory = lambda: (m.screens(), [{'id': 'camera.max'}]) + m.write_layouts = lambda layouts: None + m.notify = lambda: None + with self.assertRaisesRegex(ValueError, 'Guition'): + m.save('text.d2_tiles', {'title': 'Desk', 'tiles': [{'entity': 'camera.max', 'name': ''}]}) + # A CYD on old firmware hears the same, not "update first": an update doesn't make room for images. + ha.states['sensor.d2_fw']['state'] = '0.2.54' + m._screens_key = None + with self.assertRaisesRegex(ValueError, 'Guition'): + m.save('text.d2_tiles', {'title': 'Desk', 'tiles': [{'entity': 'camera.max', 'name': ''}]}) + with self.assertRaisesRegex(ValueError, '0.2.57'): + m.save('text.d3_tiles', {'title': 'Attic', 'tiles': [{'entity': 'camera.max', 'name': ''}]}) + m.save('text.d1_tiles', {'title': 'Hall', 'tiles': [{'entity': 'camera.max', 'name': ''}]}) + self.assertEqual(m.layouts['text.d1_tiles']['tiles'][0]['entity'], 'camera.max') + + async def test_home_assistant_queues_camera_requests(self): + from aiohttp import WSMsgType + + class Message: + type = WSMsgType.TEXT + def __init__(self, data): self.data = data + def json(self): return self.data + + class Socket: + def __aiter__(self): return self._iterate() + async def _iterate(self): + yield Message({'type': 'event', 'event': {'event_type': 'esphome.screen_camera', 'data': {'inbox': 'text.d1_tiles', 'entity': 'camera.max'}}}) + ha = HomeAssistant(None, 'http://ha/api', 'token') + ha.ws = Socket() + with self.assertRaises(ConnectionError): + await ha.read() + self.assertEqual(ha.camera_requests.get_nowait(), {'inbox': 'text.d1_tiles', 'entity': 'camera.max'}) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_camera_view.cpp b/tests/test_camera_view.cpp new file mode 100644 index 0000000..2dbf12f --- /dev/null +++ b/tests/test_camera_view.cpp @@ -0,0 +1,65 @@ +// clang++ -std=c++17 -Wall -Wextra -Werror -I. tests/test_camera_view.cpp -o /tmp/test_camera_view && /tmp/test_camera_view +#include "../components/smart_display/camera_view.h" +#include + +using namespace camera_view; + +int main() { + Feed feed; + assert(!feed.open() && !feed.should_ask(0) && !feed.should_load(0)); + + // Opening asks at once; a link that does not come is asked for again after ASK_AGAIN_MS. + feed.open("camera.front_door"); + assert(feed.should_ask(1000)); + feed.ask(1000); + assert(!feed.should_ask(1000 + ASK_AGAIN_MS - 1)); + assert(feed.should_ask(1000 + ASK_AGAIN_MS)); + + // A link loads at once, then every REFRESH_MS from the start of the last load. + feed.link("http://192.168.1.2:8098/camera/abcdefghijklmnopqrstuvwx.jpg"); + assert(!feed.should_ask(2000) && feed.should_load(2000)); + feed.start(2000); + assert(!feed.should_load(2100) && !feed.should_ask(2100)); + feed.finish(2300, true); + assert(feed.shown && !feed.should_load(2000 + REFRESH_MS - 1) && feed.should_load(2000 + REFRESH_MS)); + + // A load that ends near the next start still leaves GAP_MS for touch and drawing before the next one. + const uint32_t slow_end = 5000 + REFRESH_MS - 100; + feed.start(5000); + feed.finish(slow_end, true); + assert(!feed.should_load(5000 + REFRESH_MS) && !feed.should_load(slow_end + GAP_MS - 1) && feed.should_load(slow_end + GAP_MS)); + // An ordinary load keeps the rhythm: the next start is REFRESH_MS after this one, however quickly it ended. + feed.start(20000); + feed.finish(20000 + REFRESH_MS / 2, true); + assert(!feed.should_load(20000 + REFRESH_MS - 1) && feed.should_load(20000 + REFRESH_MS)); + + // Failures keep the link until MAX_FAILURES in a row; then a new link is asked for, the image stays shown. + uint32_t now = 10000; + for (uint8_t i = 0; i < MAX_FAILURES; ++i) { + assert(!feed.url.empty()); + feed.start(now); + feed.finish(now + 100, false); + now += REFRESH_MS; + } + assert(feed.url.empty() && feed.shown && feed.should_ask(now)); + + // An app without an image answers an empty link: nothing loads, and the view asks again later. + feed.ask(now); + feed.link(""); + assert(feed.empty && !feed.should_load(now) && !feed.should_ask(now + 1) && feed.should_ask(now + ASK_AGAIN_MS)); + + // A success after a failure starts the count again. + feed.link("http://192.168.1.2:8098/camera/abcdefghijklmnopqrstuvwx.jpg"); + feed.start(now); feed.finish(now + 10, false); + feed.start(now + REFRESH_MS); feed.finish(now + REFRESH_MS + 10, true); + assert(feed.failures == 0 && !feed.url.empty()); + + // Opening another camera forgets everything of the last one; millis() 0 still counts as a start. + feed.open("image.doorbell_snapshot"); + assert(feed.url.empty() && !feed.shown && feed.should_ask(0)); + feed.link("http://h/camera/x.jpg"); + feed.start(0); + feed.finish(10, true); + assert(!feed.should_load(REFRESH_MS - 1) && feed.should_load(REFRESH_MS + 1)); + return 0; +} diff --git a/tests/test_wake_sleep.py b/tests/test_wake_sleep.py index d474a8f..b8ae188 100644 --- a/tests/test_wake_sleep.py +++ b/tests/test_wake_sleep.py @@ -84,9 +84,9 @@ class Profiles(unittest.TestCase): self.assertIn('- script.execute: back_to_page_1_when_due', interval, name) self.assertNotIn('auto_home', interval, f'{name}: one copy of the rule') self.assertEqual(len(re.findall(r'script\.execute: back_to_page_1_when_due', text)), 2, name) - # Written by the boot, the three touchscreen triggers, Home Assistant opening the settings page and the - # UI self test only; Wake, an alert ending and Auto standby restart the standby time alone. - self.assertEqual(len(re.findall(r'id\(last_use_ms\) = millis\(\);', text)), 6, name) + # Written by the boot, the three touchscreen triggers, Home Assistant opening the settings page (and, on the + # Guition, a camera) and the UI self test only; Wake, an alert ending and Auto standby restart the standby time alone. + self.assertEqual(len(re.findall(r'id\(last_use_ms\) = millis\(\);', text)), 7 if 'preview_camera' in text else 6, name) touch = section(text, 'touchscreen') for trigger in ('on_touch', 'on_update', 'on_release'): body = re.search(rf'^ {trigger}:\n(.*?)(?=^ [a-z_]+:|\Z)', touch, re.M | re.S)[1] diff --git a/tools/render_topbar.py b/tools/render_topbar.py index 3c0f1e3..fea0a52 100644 --- a/tools/render_topbar.py +++ b/tools/render_topbar.py @@ -23,7 +23,7 @@ WORK = ROOT / '.esphome' / 'render-topbar' PROFILES = {'guition': 'guition-4848s040.yaml', 'cyd': 'home-like-2432s028.yaml'} FONTS = ('headline', 'time_label', 'sublabel_big', 'label', 'materialdesign_icons', 'materialdesign_icons_mini') # Hardware headers the host cannot compile; the top bar needs none of them. -SKIP = {'backlight_fade.h', 'guition_diagnostics.h', '__pycache__'} +SKIP = {'guition_diagnostics.h', '__pycache__'} # Header band per board: page width and height above the tiles. BANDS = {'guition': (480, 72), 'cyd': (320, 40)}