<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Dashboards on F451 Labs</title><link>https://f451labs.com/dashboards/</link><description>Recent content in Dashboards on F451 Labs</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 31 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://f451labs.com/dashboards/index.xml" rel="self" type="application/rss+xml"/><item><title>Preservation of Order — Alarm Dashboard</title><link>https://f451labs.com/dashboards/alerts/</link><pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate><guid>https://f451labs.com/dashboards/alerts/</guid><description>&lt;div class="alarm-display"
 role="status"
 aria-live="polite"
 data-signals='{"ambient_temperature_f":"--","whisper_alert":"--","seashell_interference_pct":"--","updated":"--"}'
 data-init="@get('/api/sensors/stream?device=iot-hound-01')"
 data-class='{"alarm": $ambient_temperature_f &gt;= 451 || $whisper_alert &gt;= 1 || ($seashell_interference_pct !== "--" &amp;&amp; $seashell_interference_pct &lt;= 0)}'&gt;
 &lt;div class="alarm-display-head"&gt;
 &lt;span class="alarm-display-title"&gt;PRESERVATION OF ORDER&lt;/span&gt;
 &lt;span class="alarm-display-device"&gt;iot-hound-01&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alarm-display-sensors"&gt;
 &lt;div&gt;
 &lt;span class="alarm-display-sensor-label"&gt;TEMP °F&lt;/span&gt;
 &lt;span class="alarm-display-sensor-value" data-text="$ambient_temperature_f"&gt;--&lt;/span&gt;
 &lt;/div&gt;
 &lt;div&gt;
 &lt;span class="alarm-display-sensor-label"&gt;WHISPER&lt;/span&gt;
 &lt;span class="alarm-display-sensor-value" data-text="$whisper_alert"&gt;--&lt;/span&gt;
 &lt;/div&gt;
 &lt;div&gt;
 &lt;span class="alarm-display-sensor-label"&gt;SEASHELL %&lt;/span&gt;
 &lt;span class="alarm-display-sensor-value" data-text="$seashell_interference_pct"&gt;--&lt;/span&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="alarm-display-level" id="alarm-level-iot-hound-01"&gt;—&lt;/div&gt;
 &lt;div class="alarm-display-message" id="alarm-message-iot-hound-01"&gt;no alerts on record&lt;/div&gt;
 &lt;div class="alarm-display-meta"&gt;LAST ALERT &lt;span id="alarm-ts-iot-hound-01"&gt;—&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
(() =&gt; {
 const lvl = document.getElementById("alarm-level-iot-hound-01");
 const msg = document.getElementById("alarm-message-iot-hound-01");
 const ts = document.getElementById("alarm-ts-iot-hound-01");
 const es = new EventSource("/api/alerts/stream?backlog=5");
 es.addEventListener("alert", (e) =&gt; {
 const a = JSON.parse(e.data);
 lvl.textContent = a.level.toUpperCase();
 msg.textContent = a.message;
 ts.textContent = String(a.ts).replace("T", " ").slice(0, 19);
 });
 window.addEventListener("beforeunload", () =&gt; es.close(), { once: true });
})();
&lt;/script&gt;</description></item><item><title>Sector Field Map</title><link>https://f451labs.com/dashboards/street-map/</link><pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate><guid>https://f451labs.com/dashboards/street-map/</guid><description>&lt;div class="street-map"&gt;
 &lt;svg class="street-map-svg" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg"
 aria-hidden="true"&gt;
 &lt;rect width="600" height="400" fill="#EFE7D5"/&gt;
 &lt;line x1="0" y1="130" x2="600" y2="130" stroke="#1A1715" stroke-width="6"/&gt;
 &lt;line x1="0" y1="270" x2="600" y2="270" stroke="#1A1715" stroke-width="6"/&gt;
 &lt;line x1="150" y1="0" x2="150" y2="400" stroke="#1A1715" stroke-width="6"/&gt;
 &lt;line x1="420" y1="0" x2="420" y2="400" stroke="#1A1715" stroke-width="6"/&gt;
 &lt;text x="20" y="120" font-family="monospace" font-size="9" fill="#1A1715"
 letter-spacing="2"&gt;FIREMEN'S WAY&lt;/text&gt;
 &lt;text x="20" y="260" font-family="monospace" font-size="9" fill="#1A1715"
 letter-spacing="2"&gt;MONTAG TERRACE&lt;/text&gt;
 &lt;text x="155" y="20" font-family="monospace" font-size="9" fill="#1A1715"
 letter-spacing="2"&gt;SECTOR 4&lt;/text&gt;
 &lt;text x="425" y="20" font-family="monospace" font-size="9" fill="#1A1715"
 letter-spacing="2"&gt;SECTOR 9&lt;/text&gt;
 &lt;circle cx="240" cy="195" r="6" fill="#D43A2E"/&gt;
 &lt;circle cx="495" cy="300" r="6" fill="#D43A2E"/&gt;
 &lt;/svg&gt;
 &lt;div class="street-map-tiles"&gt;
 &lt;div class="map-tile" id="tile-iot-hound-01"
 style="left:33%;top:42%;transform:translate(-50%,-50%)"&gt;
 &lt;span class="map-tile-label"&gt;IOT-HOUND-01 / MONTAG&lt;/span&gt;
 &lt;div class="map-tile-temp" id="t01-temp"&gt;--°F&lt;/div&gt;
 &lt;div class="map-tile-meta" id="t01-meta"&gt;no signal&lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="map-tile" id="tile-iot-hound-02"
 style="left:78%;top:69%;transform:translate(-50%,-50%)"&gt;
 &lt;span class="map-tile-label"&gt;IOT-HOUND-02 / MILDRED&lt;/span&gt;
 &lt;div class="map-tile-temp" id="t02-temp"&gt;--°F&lt;/div&gt;
 &lt;div class="map-tile-meta" id="t02-meta"&gt;no signal&lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
(() =&gt; {
 const SIG_PREFIX = "signals ";
 const parseSig = (data) =&gt;
 JSON.parse(data.startsWith(SIG_PREFIX) ? data.slice(SIG_PREFIX.length) : data);

 const tiles = [
 { device: "iot-hound-01",
 tempEl: document.getElementById("t01-temp"),
 metaEl: document.getElementById("t01-meta"),
 tileEl: document.getElementById("tile-iot-hound-01") },
 { device: "iot-hound-02",
 tempEl: document.getElementById("t02-temp"),
 metaEl: document.getElementById("t02-meta"),
 tileEl: document.getElementById("tile-iot-hound-02") },
 ];
 const connections = [];
 for (const { device, tempEl, metaEl, tileEl } of tiles) {
 const es = new EventSource(
 `/api/sensors/stream?device=${encodeURIComponent(device)}`
 );
 connections.push(es);
 es.addEventListener("datastar-patch-signals", (e) =&gt; {
 const sig = parseSig(e.data);
 const temp = sig.ambient_temperature_f;
 const whisper = sig.whisper_alert;
 const seashell = sig.seashell_interference_pct;
 tileEl.classList.remove("disconnected");
 if (temp != null) tempEl.textContent = `${temp}°F`;
 if (sig.updated != null) metaEl.textContent = String(sig.updated).slice(0, 8);
 const isAlarm =
 (temp != null &amp;&amp; temp &gt;= 451) ||
 (whisper != null &amp;&amp; whisper &gt;= 1) ||
 (seashell != null &amp;&amp; seashell &lt;= 0);
 tileEl.classList.toggle("alarm", isAlarm);
 });
 es.onerror = () =&gt; {
 metaEl.textContent = "disconnected";
 tileEl.classList.add("disconnected");
 };
 }
 window.addEventListener("beforeunload", () =&gt; connections.forEach((c) =&gt; c.close()), { once: true });
})();
&lt;/script&gt;</description></item><item><title>sim-01</title><link>https://f451labs.com/dashboards/sim-01/</link><pubDate>Mon, 25 May 2026 00:00:00 +0000</pubDate><guid>https://f451labs.com/dashboards/sim-01/</guid><description>&lt;p&gt;The synthetic first device — the simdev stand-in for hardware. Live values update over
SSE as readings arrive; the table below is the recent backlog from the logger.&lt;/p&gt;
&lt;div class="readout" role="status" aria-live="polite"
 data-signals="{temperature: '--', humidity: '--', updated: '--'}"
 data-init="@get('/api/sensors/stream?device=sim-01')"&gt;
 &lt;div class="readout-head"&gt;
 &lt;span class="readout-title"&gt;LIVE READOUT&lt;/span&gt;
 &lt;span class="readout-device"&gt;sim-01&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="readout-grid"&gt;
 &lt;div class="readout-cell"&gt;
 &lt;span class="readout-label"&gt;TEMP&lt;/span&gt;
 &lt;span class="readout-value" data-text="$temperature"&gt;--&lt;/span&gt;
 &lt;span class="readout-unit"&gt;°C&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="readout-cell"&gt;
 &lt;span class="readout-label"&gt;RH&lt;/span&gt;
 &lt;span class="readout-value" data-text="$humidity"&gt;--&lt;/span&gt;
 &lt;span class="readout-unit"&gt;%&lt;/span&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="readout-meta"&gt;LAST CONTACT &lt;span data-text="$updated"&gt;--&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="history" data-device="sim-01" data-limit="15"&gt;
 &lt;div class="history-head"&gt;
 &lt;span class="history-title"&gt;RECENT READINGS&lt;/span&gt;
 &lt;span class="history-device"&gt;sim-01&lt;/span&gt;
 &lt;/div&gt;
 &lt;table class="history-table"&gt;
 &lt;thead&gt;&lt;tr&gt;&lt;th&gt;TIME (UTC)&lt;/th&gt;&lt;th&gt;METRIC&lt;/th&gt;&lt;th&gt;VALUE&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
 &lt;tbody class="history-rows"&gt;&lt;tr&gt;&lt;td colspan="3"&gt;loading…&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;
 &lt;/table&gt;
&lt;/div&gt;
&lt;script&gt;
(() =&gt; {
 const el = document.currentScript.previousElementSibling;
 const tbody = el.querySelector(".history-rows");
 const note = (msg) =&gt; {
 tbody.replaceChildren();
 const tr = document.createElement("tr"), td = document.createElement("td");
 td.colSpan = 3; td.textContent = msg; tr.appendChild(td); tbody.appendChild(tr);
 };
 const url = `/api/sensors/${encodeURIComponent(el.dataset.device)}/history?limit=${encodeURIComponent(el.dataset.limit)}`;
 fetch(url, { headers: { Accept: "application/json" } })
 .then((r) =&gt; (r.ok ? r.json() : Promise.reject(r.status)))
 .then((rows) =&gt; {
 if (!rows.length) return note("no readings on record");
 tbody.replaceChildren();
 for (const x of rows) {
 const tr = document.createElement("tr");
 const cells = [
 String(x.recorded_at).replace("T", " ").slice(0, 19),
 x.metric,
 `${x.value}${x.unit || ""}`,
 ];
 for (const v of cells) {
 const td = document.createElement("td");
 td.textContent = v;
 tr.appendChild(td);
 }
 tbody.appendChild(tr);
 }
 })
 .catch(() =&gt; note("telemetry unavailable"));
})();
&lt;/script&gt;</description></item></channel></rss>