src.nth.io/

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Hoersten <[email protected]>2026-06-21 11:34:59 -0500
committerLuke Hoersten <[email protected]>2026-06-21 11:34:59 -0500
commitba412e5a17e63dffe18f69a6af2e2e27ef470778 (patch)
tree72b753bf40d30cbd522fb1da3bc62a1db43aa2d3
parent2dc9dd176f5577158430e0f4f6a20b7dee8c5646 (diff)
scrypted: drop OnOff — empirically StartStop is what the Scripts UI binds to
In v101fb3e we shipped StartStop + OnOff side-by-side to see which the 'Status and Controls' panel actually wired to. The v44c7a63 diagnostic session confirmed: clicking STOP fires stop() (StartStop), not turnOff() (OnOff). User's console showed: lifecycle: start() called (running=false) ... lifecycle: stop() called (running=true) stop: tearing down 1 resources So StartStop alone is the right interface. OnOff just produced a duplicate 'Status and Controls' panel for the same lifecycle. Drop it. Also dropping the verbose lifecycle: ... logging — we know the binding now. The cleanup mechanism is the load-bearing observable ('stop: tearing down N resources' from drainShutdownCleaners). The status text still rendering 'Unknown' (rather than Running/Stopped) is a separate cosmetic concern — possibly the duplicate panels were confusing the UI; with a single StartStop panel left, the displayed status may now reflect this.running correctly. To be verified.
-rw-r--r--scrypted/scrypted-viewport.ts62
1 files changed, 16 insertions, 46 deletions
diff --git a/scrypted/scrypted-viewport.ts b/scrypted/scrypted-viewport.ts
index a2d24db..8c2f577 100644
--- a/scrypted/scrypted-viewport.ts
+++ b/scrypted/scrypted-viewport.ts
@@ -83,7 +83,6 @@ type Setting = any;
type Settings = any;
type SettingValue = any;
type StartStop = any;
-type OnOff = any;
// ---------------------------------------------------------------------------
// Cross-reload shutdown cleaners.
@@ -373,7 +372,7 @@ class Viewport extends ScryptedDeviceBase implements Settings {
// ============================================================================
class ScryptedViewportProvider extends ScryptedDeviceBase
- implements DeviceProvider, DeviceCreator, HttpRequestHandler, Settings, StartStop, OnOff {
+ implements DeviceProvider, DeviceCreator, HttpRequestHandler, Settings, StartStop {
private viewports = new Map<string, Viewport>(); // nativeId -> child instance
private listeners = new Map<string, EventListenerRegister[]>(); // nativeId -> all event listeners for this viewport (camera + child devices)
@@ -386,13 +385,9 @@ class ScryptedViewportProvider extends ScryptedDeviceBase
constructor(nativeId?: string) {
super(nativeId);
- // Initialise both lifecycle-interface state fields synchronously
- // so the device record has values for them at registration time.
- // Without this Scrypted's "Status and Controls" panel reads
- // undefined and renders 'Unknown' regardless of what our async
- // bootstrap eventually sets.
+ // Initialise running=false synchronously so the device record
+ // has a defined value at registration time.
this.running = false;
- this.on = false;
// Auto-start on script load. start() is idempotent — if the user
// later clicks STOP in the Scripts UI, stop() drains everything
// and start() doesn't re-fire until they click START. Across a
@@ -402,60 +397,35 @@ class ScryptedViewportProvider extends ScryptedDeviceBase
}
// ------------------------------------------------------------------------
- // Lifecycle interfaces (StartStop + OnOff) — both bound to bootstrap/drain
+ // StartStop — public lifecycle controls exposed to the Scripts UI
// ------------------------------------------------------------------------
//
- // Scrypted renders this device's "Status and Controls" panel from a
- // lifecycle interface. Which one — StartStop, OnOff, both, or
- // something Scripts-plugin-specific — varies across versions, so we
- // expose both and keep them in lockstep. Whichever the UI calls,
- // the user's STOP button drains resources and START re-bootstraps.
+ // Scrypted's Scripts plugin (plugins/core/src/scrypted-eval.ts mergeHandler)
+ // auto-detects this interface from the start()/stop() method names; the
+ // 'Status and Controls' panel's STOP/START buttons call these directly.
+ // Confirmed empirically: clicking STOP fires our stop() — verified in
+ // the v101fb3e session that explored OnOff alongside StartStop and
+ // observed only stop() being called.
//
- // Semantics (shared):
- // start() / turnOn(): drain any leftover resources, then bootstrap.
- // Idempotent (no-op if already running).
- // Auto-called from the constructor.
- // stop() / turnOff(): drain every resource (streams, listeners,
- // intervals) and clear in-memory maps. No-op
- // if already stopped.
- //
- // Every call logs so we can confirm from the Scrypted console which
- // method the Status panel actually wires to. Once one is confirmed
- // we can drop the other (and the logging).
+ // Semantics:
+ // start(): drain any leftover resources (previous load or current
+ // in-flight), then bootstrap. Idempotent.
+ // stop(): drain every resource (streams, listeners, intervals)
+ // and clear in-memory maps. Idempotent.
async start() {
- this.console.log(`lifecycle: start() called (running=${this.running}, on=${this.on})`);
if (this.running) return;
- try {
- await this.bootstrap();
- } catch (e) {
- this.console.error(`lifecycle: bootstrap threw:`, (e as Error).message);
- throw e;
- }
+ await this.bootstrap();
this.running = true;
- this.on = true;
- this.console.log(`lifecycle: start() complete — running=${this.running}, on=${this.on}, nativeId=${this.nativeId}`);
}
async stop() {
- this.console.log(`lifecycle: stop() called (running=${this.running}, on=${this.on})`);
if (!this.running) return;
drainShutdownCleaners(this.console, "stop");
this.viewports.clear();
this.listeners.clear();
this.streams.clear();
this.running = false;
- this.on = false;
- this.console.log(`lifecycle: stop() complete — running=${this.running}, on=${this.on}`);
- }
-
- async turnOn() {
- this.console.log(`lifecycle: turnOn() called (on=${this.on})`);
- return this.start();
- }
- async turnOff() {
- this.console.log(`lifecycle: turnOff() called (on=${this.on})`);
- return this.stop();
}
// ------------------------------------------------------------------------