Session Handover — 2026-09-05
For the next agent
Long multi-day homelab session (2026-09-02 → 2026-09-05) spanning TV network control, a presence daemon, a bambuddy preheat bug + clog RCA, the Starlink WAN migration, and a 2.4 GHz interference hunt. Most work is done and verified. The headline open items are: (1) the TV is physically powered off and unreachable (and
Auto Power Offhas still never been disabled), (2) the Starlink dish mount is printed but not installed while obstruction climbed to 3.3%, and (3) the north camera is marginal due to multipath, which channel tuning cannot fix. Pull deeper context via thehistorian; the per-topic vault notes are linked below.
Status: Between tasks, 2026-09-05. Predecessor: 2026-09-02-session-handover.
What we accomplished
1. LG TV network control — built, working, currently OFF
See 2026-09-02-lg-tv-network-control-presence for the full write-up.
- Device: LG 43UP75003LF,
192.168.1.171, MACac:5a:f0:8b:48:da, webOS fwp20.03.53.45. Paired 2026-09-02 16:13; client key at/opt/tv-control/client-key.json(0600). - CLI:
/opt/tv-control/tv—pair | status | on | off | camwall | input <id>. venv at/opt/tv-control/venv,aiowebostv 0.10.0. - HTTP service:
/opt/tv-control/tv-http, stdlib-only, binds127.0.0.2:8102, published tailnet-only athttps://telep-mainframe.taild4189d.ts.net:8451. RoutesPOST /api/{on,off,camwall,pair}. Embedded in Homepage via a gethomepageiframeservice widget (classes: h-56 ...). - Four bugs found and fixed (all detailed in the linked note):
err or type(err).__name__truthiness bug printing empty error strings.aiowebostv’s hardcoded 10-second pairing window — monkeypatched to 180 s insidecmd_paironly.- Active Standby leaves port 3000 open, so the reachability probe succeeded and WoL was skipped entirely.
- webOS accepts TCP before SSAP is ready — fixed with a 6 × 3 s retry loop and
connect_timeout=10.
- Power-state debounce (added later): decides on a live
get_power_state()rather than the cached value; only short-circuits on a settled reading (two consecutive agreeing reads); verifies the TV actually reached the target and exits1naming the real state if not; serialiseson/offwithfcntl.flockon/run/tv-control.lock.aiowebostv.power_off()has the same stale-cache bugif not self.tv_state.is_on: return— so the library's ownpower_off()silently no-ops. It is bypassed withclient.command("request", ep.POWER_OFF).
THE HEADLINE GOTCHA — HDMI numbering is a lie
The GPU’s xrandr output is
HDMI-1, but the mainframe is physically plugged into the TV’s HDMI 2. Those numbers are unrelated. Switching the TV toHDMI_1blanks it to “no signal” while xrandr, the framebuffer and camwall all look perfectly healthy — there is no local symptom at all. The TV reports the truth viaWebOsTvState.inputs(connected: True/Falseper input). The subcommand was renamedhdmi1→camwalland the old name was REMOVED (exits2) rather than repointed, so no stale caller silently blanks the wall.
2. TV presence daemon
See 2026-09-02-tv-presence-wifi-union-daemon.
/opt/tv-control/presence+tv-presence.service. Polls every 60 s, presence window 900 s.- Presence = union of the router’s
iwinfo assoclist(phy0-ap0/phy1-ap0, over SSH key/home/levander/.ssh/router_alarm) andarp-scanonenp5s0. - Tracked MACs:
38:7f:8b:df:2a:79(spider-web iPhone),a4:40:e1:02:01:e9(F_M). - The union is load-bearing and was proven live: a sleeping iPhone is ABSENT from arp-scan while PRESENT in the assoclist. arp-scan alone would switch the TV off with someone standing in front of it.
- Acts on transitions only, never re-asserts, and does not actuate on startup. A failed poll is discarded, not aged out.
- The camera VLAN AP
phy1-ap1is deliberately NOT queried — it would leak camera devices into presence. - ⚠️ The arrival path has still never fired for real — both tracked devices have been home throughout.
3. bambuddy — chamber-target bug, clog RCA, and hardening
Full detail in 2026-09-03-bambuddy-preheat-chamber-target-bug-and-clog-rca. Summary:
- The bug:
_derive_chamber_targettakes the MAX chamber target over all loaded AMS trays, ignoring the print’s ownams_mapping. A PC spool parked in slot 1 forced chamber 50 °C + bed 90 °C onto every PLA print — ~6 minutes of preheat/soak on a 3-gram keychain, and PLA printing on a 90 °C bed. - Root cause of the 2026-09-01 nozzle replacement (half of it): cold-end heat creep from that soak. The other half is PC residue carbonising at PLA temps on frequent PC→PLA transitions.
- Fix (counter-intuitive):
PCandPC-FRset to0inpreheat_filament_targets, because a per-itempreheat_chamber_target_overridebeats the map.PC-FR jobs must now carry an override PC-FR jobs MUST pass
preheat_chamber_target_override: 60when queued or they get no chamber preheat at all. ABS and ASA are still 45 — the same trap returns the moment either is loaded alongside PLA.PLA is correct with zero action, but
- Rejected option, recorded so it is not retried: pulling the PC spool out of the AMS. The AMS is the driest storage available (~40% RH with desiccant); removing PC worsens the moisture half of the clog.
print-guarddaemon —/opt/print-guard/print-guard+print-guard.service. Polls the queue every 30 s and setsmanual_start: trueon any pending job whose material is LOW-temp when its predecessor is HIGH-temp, halting the queue for a human — the purge window. bambuddy honours the flag; verified live (Queue skip summary: {'manual_start': 1}). One-way only — it never clears the flag. ⚠️ Has never fired on real data.- Maintenance:
Clean Nozzle/Hotendcounter reset twice with notes (nozzle replacement, then the 2026-09-04 cold pull). Two new types created and assigned: Cold End / Extruder Inspection (100 h) and PC / PC-FR Dryness Check (14 days). - Local backups enabled and VERIFIED — daily 03:00, 7-day retention.
bambuddy-backup-20260903-030031.zip, 292 MB, actually written. - Per-filament humidity thresholds configured in
ams_humidity_thresholds: PLA 45 · PETG/ABS/ASA 40 · PETG-CF/TPU 35 · PC/PC-FR/PET-CF 30 · PA/PA-CF/PAHT-CF/PPS/PPA-CF/PVA 25 · default 40. Previously everything fell back toams_humidity_fair: 60.The PC humidity alert is correct behaviour, not a misconfiguration 37–42% RH, so PC will alert immediately. That is intended. The AMS physically cannot fix it — it tops out at 65 °C and PC needs 80 °C. The alert means "dry externally".
The AMS sits at
- Tapo P115 smart plug —
/opt/tapo-bridge/tapo-bridge(python-kasa 0.10.2 in a venv) adapts it to bambuddy’s genericrestbackend, binding127.0.0.2:8117. Plug at192.168.1.167, registered as plug id 1 linked to printer 1, monitoring-only (auto_on: false,auto_off: false) — bambuddy does not control printer power yet. Live readings confirmed (176 W, 0.408 kWh). Units are W and kWh, all multipliers1.0;rest_methodmust beGET.P115 exposes no lifetime energy counter locally
consumption_totalreturnsNonefor all Tapo devices in python-kasa, so the bridge synthesizes a lifetime total from daily values persisted to/opt/tapo-bridge/state.json. It is monotonic and restart-safe, but it starts at zero and under-counts if the bridge is down across midnight.
SECURITY: bambuddy's API is completely unauthenticated
The users table is EMPTY.
GETandPATCHagainst127.0.0.2:8000succeed with no credentials. Anyone who reachesbambuddy.taild4189d.ts.nethas full control of a machine that heats to 280 °C. The tailnet ACL is the only gate. Separately: the bambuddy API key was leaked into a chat transcript and must be rotated. It is the credentialbambuddy-mcp-bridgeuses — regenerate in bambuddy and update that container’s env.
4. Starlink WAN migration
Full detail in 2026-09-04-starlink-wan-migration-dish-telemetry. Summary:
- NE200 5G CPE → Starlink Bypass. 235–279 Mbps, 18–35 ms, 0% loss, versus the NE200’s final logged
RSRP −103 / SINR 9 / QPSK. This closes out the chronic episodic WAN degradation investigation. - Still CGNAT (
100.64.0.0/10) → no inbound ports. - Dish reachable at
192.168.100.1via a route on telep-router, persisted two ways: a uciconfig routestanza (unverified — the network was deliberately never reloaded) and/etc/hotplug.d/iface/99-starlink-dish(verified for real: route deleted → script run → route restored).NEVER run
/etc/init.d/network reload|restarton telep-router It would drop the site's connectivity and the tailnet SSH used to manage it. Use the live-then-persist pattern: apply withip route add, then write uci without reloading. - Telemetry:
/home/levander/net-monitor/starlink_status.py→starlink.csv, cron*/5, using grpcurl v1.9.4.-emit-defaultsis mandatory Without it, proto3 omits zero-values and silently dropspopPingDropRate/fractionObstructedexactly when everything is healthy. A logger without the flag looks fine and records nothing useful. - NE200 logger retired — its
*/15cron line was removed, but the script and 342 rows ofrflog.csvwere deliberately preserved as the evidence base that justified the switch. - ⚠️ Obstruction climbed 0.12% → 3.3% over the first hours, with the prolonged-outage estimate falling from 6 h to 45 min. A raised mount was printed in PC-FR (2026-09-03, “Starlink Gen3 mounting bracket”) but is not yet installed. The CSV holds the before-baseline.
5. WiFi / camera diagnosis — 2026-09-04/05
Camwall was flashing; root cause was a watchdog re-roll loop driven by stalled camera streams.
- The channel survey was decisive: 2.4 GHz ch11 was 93% busy while our own traffic was only ~20%, and the noise floor across ch8–13 sat at −60…−76 dBm versus −93…−98 dBm on ch1–7, with only 1–3 APs found in the entire scan.
That is a non-WiFi emitter the user owns
Not neighbours. Few APs + a raised noise floor confined to the upper band = a local device radiating on 2.4 GHz upper channels.
- Moved
radio1ch11 → ch1 (non-overlapping with the HP printer’s WiFi-Direct on ch6 at −20 dBm). Channel busy fell 92.9% → 25.8%. Backup at/etc/config/wireless.bak-1788552343. - South camera recovered immediately. North (
192.168.30.139) did not — it needed a reboot via the user’s own/home/levander/tapo-ctl/reboot-cams-onvif.py 192.168.30.139, after which all four cameras returned to ~5 fps and recording resumed.The north camera's real problem is multipath, not congestion −63 dBm / SNR 40 yet negotiates only 8.6–11 Mbit/s, where the south unit gets 114.7 Mbit/s at −47 dBm / SNR 57. Good RSSI with a collapsed rate is the signature of reflections in a metal-and-dense-concrete building. Channel tuning cannot fix this. It needs an AP closer with wired backhaul, a directional antenna to reject off-axis reflections, or moving either endpoint a metre or two to change the reflection geometry. More TX power and wider channels both make multipath worse.
It sits at
- New logger:
/home/levander/net-monitor/wifi_survey.py→wifi_survey.csv, cron daily 04:00 (a scan briefly interrupts clients, hence once a day, at night). It only measures — it never changes a wireless setting. Runs from the mainframe over SSH to the router at192.168.1.1(the LAN address — the tailnet ACL blocks port 22 from mainframe → router).Two caveats for anyone reading wifi_survey.csv
- The in-use row’s
busy_pctis a lifetime average over monotonic counters, so day-to-day it barely moves. Real daily congestion needs deltas between consecutive rows, handlingactive_time_msdecreasing on interface restart. - Scanned (non-in-use) rows are a single ~150 ms sample and very noisy — ch2 read 98.67% then 78.0% nineteen seconds apart.
active_time_msis in the CSV precisely so high- and low-confidence rows can be told apart.
- The in-use row’s
- Parser trap worth recording: a naive
Channel:\s+(\d+)regex oniwinfo scanalso matchesPrimary Channel:inside HT/VHT blocks and double-counts every AP. Anchor on^Mode:and key by frequency.
6. Starlink routers cannot be access points — verified
- Two states only: Bypass (WiFi off, pure L2 bridge) or not bypass (it is the main router). There is no AP/bridge mode that joins a third-party network. Starlink mesh nodes have no Ethernet backhaul and pair only to a Starlink router as main router. Reversing bypass requires a factory reset. One spare unit reports “Not on account” and is unmanageable.
Going non-bypass would be actively harmful telep-router and takes out
br-cams(the192.168.30.0/24camera VLAN + thetelep-ccSSID), dnsmasq leases, and theiwinfo assoclistthat BOTH the intruder alarm and tv-presence depend on.It displaces
- The wanted “one big seamless WiFi” is NOT mesh — it is same SSID + wired APs on different channels + 802.11r/k/v fast roaming. That recommendation stands on its own and is unaffected by the extender question below.
TL-WA850RE — RESOLVED 2026-09-05: it is already a WIRED AP, not a repeater
The “it is a repeater” claim in this session was wrong. It was inferred from the model name, never measured, and it propagated into 2026-09-04-starlink-wan-migration-dish-telemetry,
LOG.mdandTOPICS.mdbefore being corrected in all four places. [[telep-router#tp-link-tl-wa850re-added-as-a-wired-ap-ssid-bandi|TP-Link TL-WA850RE added as a wired AP (SSIDbandi)]] is authoritative: the unit was reconfigured repeater → Access Point and wired intobr-lan, broadcasting SSIDbandi. eth/mgmt MACac:84:c6:1b:04:30, WiFi BSSIDac:84:c6:1b:04:31, static reservation.101. That note already characterises it as a “coverage AP, not a fast-lane AP”.bandi-vipis NOT this device. That AP’s BSSID is5E:6D:F7:27:10:E3— locally-administered, nothing likeac:84:c6:1b:04:31. So the “extender may still be stuck on ch11” theory is also void;bandi-vipis an unidentified third-party AP. The real ~50 Mbps ceiling is structural: a 100 Mb Fast-Ethernet uplink port + a single-band 2.4 GHz N300 radio, on a channel that was 93% busy. Nothing to do with repeating. “Replace the repeater with a wired AP” is a no-op — that conversion already happened; the actual upgrade is a dual-band AP on a gigabit port. ⚠️ Live re-verification was not possible:192.168.1.101ARP FAILED after 6 probes (device offline), absent frombridge fdb show br br-lan, and not associated on any of the three APs. The conclusion above rests on thetelep-routerrecord plus the BSSID mismatch, not on a live probe.
7. Smaller items
- Frigate config tuned 2026-09-02 (2026-09-02-frigate-resource-tuning): birdseye
mode: continuous→objects, and 3840×1080 → 1920×1080;face_recognitiondisabled (library was empty,/api/facesreturned{}, 0 of 500 events had asub_label). VRAM 2148 → 1804 MiB, RAM 3.887 → 3.164 GiB. ⚠️ CPU improvement was NOT proven — samples were bursty and the “before” was measured during post-boot startup. - ⚠️
ps -eo pcpureports a lifetime average, not instantaneous CPU — worthless on a freshly booted box. Use repeateddocker stats --no-streamortop -bn2. - Camera recordings exported for 2026-09-04 07:23–07:25 local →
/home/levander/freecad/exports/cam-2026-09-04_0723/(4 files, ~19 MB each), browsable athttps://cad.taild4189d.ts.net:8080/cam-2026-09-04_0723/.Frigate stores recordings in UTC 07:23 lives in the
05/hour directory. Frigate's own export API was abandoned — three of four exports stuck as orphanedin_progressrows with no worker process (plus an olderlastnight_telep_cam3stuck from a previous session). The files were built directly withffmpeg -f concat -c copyinstead.Local
- reMarkable Paper Pure evaluation written — device not purchased. See 2026-09-03-remarkable-paper-pure-claude-integration.
- tailcat client half installed on the mainframe (v0.4.0, client nodekey generated).
/home/levander/tailcat-mac-setup.shis staged for the offline company Macceges-mac(100.69.95.112) but has never been run. - Incidental:
/home/levander/tapo-ctl/already contains a venv with python-kasa 0.10.2 — the same version/opt/tapo-bridge/venvinstalled separately. Duplicate venvs, and TP-Link credentials likely already on the box.
Where we paused / open items
Not done yet
- 🔴 The TV is physically powered off and unreachable — WiFi radio off, no ARP, no association,
tv ontimes out on WoL. It needs a physical power button press. AndAuto Power Offhas STILL never been disabled (All Settings → General → Timers → Auto Power Off → Off) — this is the third time the TV has gone dark. It cannot be set over the network: the settings surface 404s withaiowebostv’s permission manifest, and obtaining a wider manifest means re-pairing, which means a trip to the TV anyway. So: press the button, then change the setting while you’re standing there.- 🔴 Install the printed Starlink mount. Obstruction was 3.3% and rising, prolonged-outage estimate down to 45 min. The bracket is printed (PC-FR). The CSV has the before-baseline — re-check
fraction_obstructedafter install.- 🔴 North camera (
192.168.30.139) is marginal — multipath, 8.6–11 Mbit/s at good RSSI. Needs a closer wired AP, a directional antenna, or repositioning. Do not attempt to fix it with channel/TX-power tuning.- Rotate the bambuddy API key (leaked in a transcript) and decide what to do about bambuddy’s unauthenticated API / empty users table.
- Identify the 2.4 GHz upper-band interferer — the daily wifi survey will fingerprint it by time-of-day pattern.
- Frigate: unexplained external
docker restarttwice on 2026-09-04 (RestartCount=0, healthy,StartedAtmoved) — source unknown. Also clear the orphanedin_progressexport rows.- bambuddy:
allow_skip_partsstillfalse; plate detection uncalibrated (require_plate_clear: false, no reference images). Calibration is a REMOTE call once the bed is empty with the chamber light on; brim needs a per-material process preset built in Bambu Studio.print-guard’s guard path andtv-presence’s arrival path have never fired on real data. Both are unproven in production. ⚠️ Clarified 2026-09-07 — do not read this as broken alerting. It refers to their action paths only. Neither is an alert producer:print-guardtalks only to the bambuddy API onhttp://127.0.0.2:8000, andtv-presencehas no HTTP client at all — its “arrival path” powers the TV on and messages nobody. So neither is a Telegram → Matrix migration target. Source-verified in 2026-09-07-alert-source-inventory.- Route persistence on the router is unverified until the next reboot — the uci stanza was committed but never applied by netifd; the hotplug script IS verified.
- VERIFY (not do) the TL-WA850RE when it is back online — it was unreachable this session (ARP failed, absent from the
br-lanfdb, not associated on any AP), so its mode was never confirmed. Check its actual mode and channel —[[telep-router]]records it as an already-converted wired AP onbr-lan(SSIDbandi), which is better sourced than this session’s model-name assumption. If it is still on ch11, move it off — that is where the 93%-busy interference is, and the router has already escaped to ch1. Do not action a repeater→AP conversion until the mode is actually established.- Tapo plug is monitoring-only — temperature-gated
auto_off(70 °C) andpower_alert_highare configured but not enabled.ceges-mactailcat setup script never run.
Key endpoints, paths & gotchas
Endpoints (tailnet-only):
| Service | URL |
|---|---|
| Frigate | https://telep-mainframe.taild4189d.ts.net |
| Homepage dashboard | https://telep-mainframe.taild4189d.ts.net:8450 |
tv-http (TV control) | https://telep-mainframe.taild4189d.ts.net:8451 |
bambuddy (UI + /mcp) | https://bambuddy.taild4189d.ts.net |
| CAD / camera exports | https://cad.taild4189d.ts.net:8080 |
Local bind convention: services bind 127.0.0.2:<port> and are published only via tailscale serve. See tailnet-service-exposure-convention. Verified 127.0.0.2 port map (ss -ltnp, 2026-09-05):
8000 bambuddy (uvicorn, UNAUTHENTICATED)
8091 bambuddy-mcp-bridge (mcp-proxy)
8102 tv-http -> tailnet :8451
8117 tapo-bridge (Tapo P115 -> bambuddy rest plug)
3001 bambu-studio-api (slicer sidecar)
3010 homepage -> tailnet :8450
11000 nextcloud 11001 tsauth-proxy 11002 onlyoffice
All four custom services confirmed active on 2026-09-05: tv-http, tapo-bridge, print-guard, tv-presence.
Paths:
/opt/tv-control/{tv,tv-http,presence,client-key.json,venv}·/run/tv-control.lock/opt/print-guard/print-guard·/opt/tapo-bridge/{tapo-bridge,state.json,venv}·/etc/tapo-bridge.env/home/levander/net-monitor/{starlink_status.py,starlink.csv,wifi_survey.py,wifi_survey.csv,ne200_signal.py,rflog.csv}/home/levander/tapo-ctl/{reboot-cams-onvif.py,set-cam-time.py}·/home/levander/tailcat-mac-setup.sh- Router:
/etc/hotplug.d/iface/99-starlink-dish·/etc/config/wireless.bak-1788552343
Reusable gotchas:
- 🔴 NEVER run
/etc/init.d/network reload|restarton telep-router — it drops the site and the tailnet SSH used to manage it. Live-then-persist instead:ip route add, then write uci without reloading. - 🔴 busybox lacks
timeout,nc -zandping -Mlie. This produced FOUR false diagnoses in one session on the router. Test from the mainframe, not from busybox. - 🔴 Frigate stores recordings in UTC — local 07:23 is in the
05/hour directory. - HDMI numbers are unrelated: xrandr
HDMI-1≠ the TV’s HDMI 1. TrustWebOsTvState.inputs.connected. - grpcurl needs
-emit-defaultsor proto3 drops zero-values exactly when healthy. aiowebostvcaches power state — bothpower_off()and anyis_onshort-circuit are unreliable; read live and verify the result.ps -eo pcpuis a lifetime average, not instantaneous CPU.iwinfo scanparsing: anchor on^Mode:, notChannel:(which also matchesPrimary Channel:in HT/VHT blocks and double-counts APs).- Good RSSI + collapsed PHY rate = multipath, not congestion. More power and wider channels make it worse.
Related notes: 2026-09-02-session-handover (predecessor) · 2026-09-02-lg-tv-network-control-presence · 2026-09-02-tv-presence-wifi-union-daemon · 2026-09-02-frigate-resource-tuning · 2026-09-03-bambuddy-preheat-chamber-target-bug-and-clog-rca · 2026-09-03-remarkable-paper-pure-claude-integration · 2026-09-04-starlink-wan-migration-dish-telemetry · telep-mainframe · telep-router · 2026-08-31-episodic-wan-degradation · tailnet-service-exposure-convention
Not yet in its own note
Section 5 (the WiFi channel move, the ch11→ch1 change,
wifi_survey.py, and the north-camera multipath finding) has no dedicated vault note yet — this handover is currently the only record. Worth promoting to a standalone note.
Continuation prompt (copy-paste to resume)
Pick up the 2026-09-05 homelab session (read
projects/homelab/2026-09-05-session-handover.md, and use thehistorianfor deeper context). Priorities: (1) the TV is physically powered off and unreachable — press the physical power button, then disableAuto Power Offwhile standing at it (All Settings → General → Timers → Auto Power Off → Off; it cannot be done over the network, the settings surface 404s with the current permission manifest); (2) install the printed PC-FR Starlink mount and check whetherfraction_obstructeddrops from 3.3% in~/net-monitor/starlink.csv(the CSV has the before-baseline); (3) address the north camera’s multipath (192.168.30.139, 8.6–11 Mbit/s at −63 dBm / SNR 40) — it needs a closer wired AP, a directional antenna, or repositioning; channel/TX-power tuning will NOT fix it. Also queued: rotate the leaked bambuddy API key and decide on its unauthenticated API. Everything else — TV control CLI/HTTP + presence daemon, the bambuddy chamber-target fix, print-guard, backups, humidity thresholds, the Tapo bridge, the Starlink WAN migration and telemetry logger, the 2.4 GHz ch11→ch1 move and the daily wifi survey — is done and verified. Never run/etc/init.d/network reload|restarton telep-router.