aboutsummaryrefslogtreecommitdiffstats
path: root/deckit
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-10 10:46:04 +0100
committerDanilo M. <danix@danix.xyz>2026-11-10 10:46:04 +0100
commitb5b56e4c1854314fb519d13af9dda80a10ee0b8a (patch)
tree4ddbc4b348e4be4a5af99ea50566094a4bc5e2c6 /deckit
parent6ffa382c3f83e87da2e976868a9846f16ecc7321 (diff)
downloaddeck-it-master.tar.gz
deck-it-master.zip
feat(k1c): live camera stream instead of snapshotsHEADmaster
The camera was a snapshot reloaded on every poll. It is now the webcam's MJPEG stream_url, which an <img> plays by itself at the camera's own rate (15 fps on the K1C). The stream connects only while the K1C tab is on screen and the page visible, and disconnects otherwise, so a hidden tab does not keep the printer streaming. A dropped stream hides the image and reconnects on the next poll. The image is shown as soon as its source is set, since a never-ending stream may never fire load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'deckit')
-rw-r--r--deckit/modules/k1c.py18
1 files changed, 9 insertions, 9 deletions
diff --git a/deckit/modules/k1c.py b/deckit/modules/k1c.py
index 8481e91..1f89088 100644
--- a/deckit/modules/k1c.py
+++ b/deckit/modules/k1c.py
@@ -41,10 +41,10 @@ def _http(url, data=None, timeout=2):
return json.loads(r.read())
-def _snapshot(webcams) -> str | None:
- """The first enabled webcam's snapshot URL, if it is plain http(s)."""
+def _camera(webcams) -> str | None:
+ """The first enabled webcam's live MJPEG stream URL, if it is plain http(s)."""
for cam in webcams or []:
- url = cam.get("snapshot_url") or ""
+ url = cam.get("stream_url") or ""
if cam.get("enabled", True) and url.startswith(("http://", "https://")):
return url
return None
@@ -64,7 +64,7 @@ def _first(*values):
return next((v for v in values if v is not None), None)
-def summarize(status: dict, snapshot: str | None = None) -> dict:
+def summarize(status: dict, camera: str | None = None) -> dict:
"""The panel's state from Moonraker's object status."""
ps = status.get("print_stats") or {}
sd = status.get("virtual_sdcard") or {}
@@ -99,14 +99,14 @@ def summarize(status: dict, snapshot: str | None = None) -> dict:
(status.get("output_pin fan0") or {}).get("value")),
"position": ((status.get("toolhead") or {}).get("position") or [None] * 3)[:3],
"speed_factor": (status.get("gcode_move") or {}).get("speed_factor"),
- "snapshot": snapshot,
+ "camera": camera,
}
def make(cfg: dict) -> Module:
base = str(cfg.get("k1c", {}).get("url", "")).rstrip("/")
http = cfg.get("http", _http)
- down = {"until": 0.0, "snapshot": None}
+ down = {"until": 0.0, "camera": None}
# The current file's slicer metadata, fetched once per file.
meta = {"file": None, "thumbnail": None, "estimate": None}
@@ -130,12 +130,12 @@ def make(cfg: dict) -> Module:
return {"offline": True}
try:
status = http(base + QUERY)["result"]["status"]
- if down["snapshot"] is None:
- down["snapshot"] = _snapshot(http(base + "/server/webcams/list")["result"]["webcams"]) or ""
+ if down["camera"] is None:
+ down["camera"] = _camera(http(base + "/server/webcams/list")["result"]["webcams"]) or ""
except (OSError, ValueError, KeyError, TypeError):
down["until"] = time.monotonic() + BACKOFF
return {"offline": True}
- st = summarize(status, down["snapshot"] or None)
+ st = summarize(status, down["camera"] or None)
file_meta(st["file"])
st["thumbnail"] = meta["thumbnail"]
# Until the file-position estimate settles, the slicer's is better.