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 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-17 15:31:11 +02:00
parent 9567ab591a
commit d60a0f122b
31 changed files with 1847 additions and 117 deletions
+17
View File
@@ -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");