Devices may publish to their own out ports' messages (a level set on the device itself)
Docs / docs (push) Successful in 23s
Playwright Tests / test-playwright (1, 2) (push) Failing after 36s
Playwright Tests / test-playwright (2, 2) (push) Failing after 20s
pre-commit / pre-commit (push) Failing after 2m13s
Test Backend / test-backend (3.12) (push) Successful in 4m32s
Test Backend / test-backend (3.14) (push) Successful in 4m18s
Compose Smoke Test / test-compose (push) Failing after 26s
Playwright Tests / merge-reports (push) Failing after 2m16s

This commit is contained in:
Melvin Strobl
2026-10-29 21:58:38 +01:00
parent d2e8c01785
commit e0f5ddc3a4
3 changed files with 18 additions and 11 deletions
+9 -5
View File
@@ -139,15 +139,19 @@ def _device_writable(device: DeviceDef, request: Request) -> set[str]:
one is what entitles the screen to it. Reads are untouched — read-only is
not blind, and a locked dashboard has to keep drawing live data.
The device's own ``in`` ports, as flows wire them, are added outside the
lock: it covers the controls on a dashboard, not the sensors on the
device. Its ``out`` ports are read, not written, unless a widget targets
them too.
The device's own ports, as flows wire them, are added outside the lock:
it covers the controls on a dashboard, not the device itself. Its ``in``
ports are its sensors; its ``out`` ports it publishes when set on the
device (a panel's brightness on its config page), so what follows the
message hears of it.
"""
store: DashboardStore | None = getattr(request.app.state, "dashboard_store", None)
if store is None:
return set()
writable = _device_in(device, request)
owned: DeviceStore | None = getattr(request.app.state, "device_store", None)
writable = (
{b.message for b in owned.bound(device.id)} if owned is not None else set()
)
defns = devices.dashboards_for(device, store)
bound = sorted(
{s.message for d in defns if (s := d.settings.get("locked")) and s.message}
+6 -5
View File
@@ -639,10 +639,11 @@ def test_a_devices_own_ports_publish_through_a_lock(
) -> None:
"""An ``in`` port is the device's own sensor, which a dashboard lock is not about.
An ``out`` port is the device following a message, so it reads and does
not write, and only an ``in`` port's name opens the artifact upload. A
value published on a bound port is the device node's, whatever the device
says it is from.
An ``out`` port is the device following a message, which it publishes too
when set on the device itself (a panel's brightness on its config page).
Only an ``in`` port's name opens the artifact upload. A value published on
a bound ``in`` port is the device node's, whatever the device says it is
from.
"""
_dashboard_with(client, superuser_token_headers, "panel_io_locked", PANEL_WIDGETS)
_publish_settings(
@@ -690,7 +691,7 @@ def test_a_devices_own_ports_publish_through_a_lock(
client.post(
f"{messages}/porch.backlight", headers=panel_headers, json={"value": 50}
).status_code
== 403
== 200
)
assert (
client.get(
+3 -1
View File
@@ -550,7 +550,9 @@ The credential may publish to its `in` messages even when a dashboard is
locked, and may upload an artifact named after one
(`PUT /artifacts?name=<message>`), which is how a microphone sends a recording.
A value it publishes there is credited to its device node, so the node's edge
lights up on the canvas. `out` messages are read only. The node is shown
lights up on the canvas. It may publish to its `out` messages as well, for a
level set on the device itself (a panel's brightness on its config page), so
what follows the message hears of it; no upload there. The node is shown
degraded, *Offline*, in amber while the device is not connected: a warning on
Home, not a fault, since a panel switched off or asleep breaks nothing.