Both shipped in #538 with no interface at all: the bridge could only be
configured by editing integrations/mqtt_bridge/bridge_config.json over SSH, and
the Pixlet editor was a script you had to know existed. Neither appeared
anywhere in the web UI. They are now two sections in the Tools tab.
**MQTT bridge.** Service state (installed / running / stopped), install, start,
stop and restart, and a form for every setting: broker host and port, username,
TLS, command topic, client id, API base, request timeout, on-demand duration
and log level.
The password is write-only. GET returns every other field plus a password_set
flag, never the value -- this interface has no authentication, so anything it
hands back is readable by anyone who can reach the port. Submitting a blank
password keeps whatever is stored; there is an explicit Clear for removing one.
The file is written through a temp file in the same directory and chmod 0600, so
a crash mid-write cannot leave a config the bridge would refuse to load. Values
are range-checked server-side (port, timeouts, log level, http(s) API base).
**Pixlet editor.** Lists the apps on disk and starts a session per app, with a
banner showing which app is open, a link to the editor, a countdown, and Stop.
The banner survives a page reload because status is polled while a session runs,
and Edit is disabled while one is open.
Two changes to the script make that safe to drive from a browser:
- It binds 0.0.0.0 by default (PIXLET_EDITOR_HOST overrides). Loopback-only
meant the URL shown in a browser was unreachable and needed an SSH tunnel,
which is the confusing path. The no-auth argument for loopback does not hold
when web_interface already serves 0.0.0.0:5000 unauthenticated and can
reconfigure everything.
- The session ends by itself after PIXLET_EDITOR_TIMEOUT (default 30 min),
enforced by `timeout` inside the script rather than by the caller. The display
is stopped while editing, so a forgotten session would otherwise leave the
panel dark and read as broken hardware -- the timeout is the whole reason a
Start button is defensible.
Two bugs found while testing that lifecycle, both of which would have bitten the
Stop button:
- GNU timeout runs its child in a NEW process group, so signalling the script's
group killed only bash and orphaned pixlet with the port still bound. Now
--foreground keeps one group, and the EXIT trap kills the recorded child too.
- The liveness check treated a zombie as running: the script is a child of the
web process and stays unreaped after exiting, and signal 0 succeeds against a
zombie, so a finished session would have read as running forever. It now reaps
non-blockingly and falls back to /proc state for a process that is not ours.
Covered by test/js/dom/test_tools_sections.js (26 assertions, real DOM against
the server-rendered partial): form prefill, the blank-means-unchanged password
contract, the running-session banner and countdown, and that the editor link
uses the host the page was loaded from. Also chmod +x on both scripts, which the
docs tell you to run directly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9