mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 03:00:18 +02:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44dcdef8e3 |
No files matched your search
@@ -29,7 +29,6 @@ desktop or panels.
|
||||
| Mac GUI over all of this | `README.md` → Frame Control | `scripts/frame-ui.sh` |
|
||||
| iPhone/iPad app (server runs on the Frame, `FRAME_LOCAL=1`) | `docs/iphone.md` | `ios/`, `ui/local-bin/ssh` |
|
||||
| Frame unreachable, Wi-Fi dead, Steam won't start (doctor runbook) | `docs/frame-doctor.md` | — |
|
||||
| Power draw, heat, fan, battery wear, quiet-mode plan | `docs/power-and-heat.md` | — |
|
||||
| Recovery images, factory reset, boot loops | `docs/recovery-and-images.md`, `docs/how-the-frame-works.md` | `~/Downloads/steam-frame-recovery/` |
|
||||
| Test without the headset (the Frame OS image's own sshd) | `tests/frame-container/README.md` | `tests/frame-container/frame-image.sh` |
|
||||
| What's still unverified | `docs/open-questions.md` | — |
|
||||
|
||||
@@ -164,6 +164,4 @@ Astra (xhigh), 2026-09-28.
|
||||
- **Off the LAN:** a sleeping Frame's Tailscale can't receive anything, so
|
||||
something awake on the LAN has to send the packet (for example the
|
||||
EdgeRouter's `etherwake`, already used for lxso2, or the Mac).
|
||||
- **Staying on instead of sleeping:** what draws power and heat while idle, the
|
||||
controls, and the step-by-step plan are in
|
||||
[power-and-heat.md](power-and-heat.md).
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
# Power, heat and what you can control
|
||||
|
||||
What the Frame spends power on while it's on, where the heat comes from, and
|
||||
which controls exist. Everything here was **read** on the Frame on
|
||||
2026-09-29 (BUILD_ID 20260925.6191901). Nothing was changed. Numbers under
|
||||
load haven't been measured yet.
|
||||
|
||||
## Sensors you can read without sudo
|
||||
|
||||
| What | Where |
|
||||
|---|---|
|
||||
| Power per rail (W ×10⁶) | hwmon `max34417_10`: `vph` (whole system), `s1c`, `s3c`, `s6c`. `max34417_12`: `apc0`/`apc1`/`apc2` (CPU clusters), `nsp1`. `max34417_1a`: `gfx` (GPU), `nsp2`, `bob`. Each `powerN_input` has a `powerN_label` |
|
||||
| Board temperatures (m°C) | `/sys/bus/iio/devices/iio:device0/in_temp_*_input`: battery, left and right display, heatsink fins, fan exhaust, Wi-Fi, flash, 40-pin connector, nRF radio, PMIC and charger die |
|
||||
| CPU, GPU and modem zones | `/sys/class/thermal/thermal_zone*/{type,temp}` (per-core top and bottom, `gpuss-*`, `nsp*`, `video`) |
|
||||
| Charger input and charge current | `iio:device0/in_current_pm8550b_{iin,ichg}_fb_input` (µA) |
|
||||
| Battery | `/sys/class/power_supply/max1720x_bat_7-36/uevent` (cycle count, health, current) |
|
||||
| Fan | hwmon `slg4ax46073v`: `fan1_input` (RPM), `pwm1` (%) |
|
||||
| Proximity (worn or not) | `/sys/bus/iio/devices/iio:device2/in_proximity_raw` |
|
||||
| Why the fan ramped | `journalctl -u deckard-fan-control` (`C3 temperature of 95.36 greater than max 95! Setting fan to max speed.`) |
|
||||
|
||||
The right display thermistor reads −16 °C, so it's absent or broken. Ignore it.
|
||||
|
||||
## Idle baseline (2026-09-29 08:05)
|
||||
|
||||
Conditions:
|
||||
- On the 12 V USB-C charger, battery 100%, 5 cycles.
|
||||
- Headset off-head, SteamVR in standby, backlight 0.
|
||||
- Steam, SteamVR, the tracking service and one Chromium (Mac view) running.
|
||||
- `pauseCompositorOnStandby` = false, set by another session this morning for testing.
|
||||
|
||||
30 s average:
|
||||
|
||||
| Rail | W | Notes |
|
||||
|---|---|---|
|
||||
| `vph` (everything) | **4.71** | |
|
||||
| CPU `apc0+1+2` | 0.61 | 91% idle overall |
|
||||
| GPU `gfx` | 0.25 | GPU at 366 of 903 MHz |
|
||||
| NSP `nsp1+2` | 0.08 | Neural and DSP processors |
|
||||
| `s1c` + `s3c` + `s6c` + `bob` | 1.01 | SoC, memory and peripheral supplies (which rail is which isn't documented) |
|
||||
| Unmetered remainder | ~2.8 | Cameras, display link, Wi-Fi, fan, sensors, conversion losses (inferred) |
|
||||
|
||||
Temperatures:
|
||||
|
||||
| Sensor | °C |
|
||||
|---|---|
|
||||
| CPU cores | 40–45 |
|
||||
| Board (heatsink, Wi-Fi, flash) | 34–37 |
|
||||
| Left display thermistor | 46 (the warmest) |
|
||||
| Charger IC | 37 |
|
||||
| Battery | 23 |
|
||||
|
||||
The fan ran at about 8,350 RPM at `pwm1` 41.
|
||||
|
||||
What was running while idle (`top`):
|
||||
- The compositor was at about 14% of one core.
|
||||
- Steam was at about 7%.
|
||||
- The tracking service (XRService) was at about 4%, and still had 4 camera nodes open (`/dev/video0,3,9,13`).
|
||||
- vrserver and gamescope were at about 3% each.
|
||||
|
||||
## Why it's warm while "doing nothing"
|
||||
|
||||
- **The compositor keeps rendering in standby** when
|
||||
`power.pauseCompositorOnStandby` is false. The default is true. Check
|
||||
`~/.config/openvr/config/steamvr.vrsettings`.
|
||||
- **The tracking cameras stay open in standby.** XRService holds them so
|
||||
tracking resumes instantly.
|
||||
- **The fan never goes below 40% on the charger.** That's by design in
|
||||
`/usr/share/deckard-fan-control/deckard-config.yaml`:
|
||||
`fan_charging_min_speed: 40`, against `fan_min_speed: 30` on battery.
|
||||
Charging, including topping up at 100%, heats the charger IC and battery
|
||||
area.
|
||||
- **The display link stays up at backlight 0.** The DSI connector reports
|
||||
`dpms=On` while the backlight is 0, so the panels are dark but still driven.
|
||||
- **Heavy load reaches the throttle limit.** On 2026-09-28 at 22:09–22:12,
|
||||
cores C3, C5 and C7 hit 95 °C and the fan went to max. The cause wasn't
|
||||
investigated. It came around a Steam restart after the reboot.
|
||||
|
||||
## Controls
|
||||
|
||||
No sudo needed:
|
||||
|
||||
| Control | How | Effect | Caveat |
|
||||
|---|---|---|---|
|
||||
| Steam idle sleep | `scripts/keep-awake.sh`, `system_idle_suspend_{ac,battery}_sec` | When it sleeps | Sleep has no remote wake |
|
||||
| Compositor pause in standby | `vrcmd --set-settings-bool power.pauseCompositorOnStandby 1` | Stops rendering while off-head | Other sessions toggle it for testing, so coordinate |
|
||||
| Screens-off delay | `vrcmd --set-settings-float power.turnOffScreensTimeout <s>` | Backlight off sooner or later | Default 5 s |
|
||||
| Stop the whole VR stack | `systemctl --user stop steamvr.service` | Cameras, tracking and compositor off | Also stops the gamescope VR session and Steam (seen 2026-09-28), so panels and Mac view go too. The restart cost hasn't been measured |
|
||||
| Background apps | Close Mac-view Chromium, stop Lepton containers (`podman`) | Less CPU and memory | Mac view needs relaunching |
|
||||
| Brightness | Steam settings | Panel power while worn | — |
|
||||
|
||||
Needs root (reset at reboot unless made persistent):
|
||||
|
||||
| Control | Where | Effect |
|
||||
|---|---|---|
|
||||
| CPU governor and max frequency per cluster | `/sys/devices/system/cpu/cpufreq/policy{0,2,5,7}/scaling_{governor,max_freq}` (`powersave`, `conservative`, `schedutil`, …) | Caps CPU power and heat |
|
||||
| Take cores offline | `/sys/devices/system/cpu/cpuN/online` | Fewer active cores |
|
||||
| GPU max frequency | `/sys/class/devfreq/3d00000.gpu/max_freq` | Caps GPU power (it hurts VR smoothness when worn) |
|
||||
| Fan curve | The service reads `/usr/share/…/deckard-config.yaml`, which is on the read-only rootfs. It could be overridden with a systemd drop-in pointing at a copy in `/etc` | Quieter fan while charging, but hotter parts |
|
||||
| Charge current | `pm8550b-charger` `constant_charge_current` (1.0 A, max 1.2 A) | Writability unverified. There's **no** charge-limit or end-threshold file, so the battery sits at 100% on the charger |
|
||||
|
||||
None of these have been tried yet.
|
||||
|
||||
## Plan: leave it on, but cheaply
|
||||
|
||||
Goal: the Frame stays on the charger, reachable over SSH, drawing as little
|
||||
power and making as little heat, fan wear and battery wear as possible while
|
||||
nobody wears it. When someone puts it on, everything comes back quickly.
|
||||
Sleeping isn't an option until remote wake works (see
|
||||
[open-questions.md](open-questions.md#remote-wake-2026-09-28)).
|
||||
|
||||
Rules for every step:
|
||||
- Change one thing at a time. Snapshot the setting first, measure 5 minutes
|
||||
(`vph` plus temperatures and fan), then restore it unless it's being kept.
|
||||
- Freeze the Steam and SteamVR health-check trackers first
|
||||
([frame-doctor.md](frame-doctor.md) §4).
|
||||
- Anything that could leave the Frame unreachable, and every root change, waits
|
||||
until someone is home to recover it.
|
||||
- `power.pauseCompositorOnStandby` belongs to another session's testing. Ask
|
||||
before touching it.
|
||||
|
||||
### 1. Measure (read-only, safe remotely)
|
||||
|
||||
- [x] Idle baseline off-head on the charger (above).
|
||||
- [ ] A sampler script (`scripts/frame-power-sample.sh`) that logs `vph`, the
|
||||
CPU/GPU rails, key temperatures, fan RPM, the proximity sensor and the
|
||||
charger current every few seconds to a CSV. Every later step uses it.
|
||||
- [ ] The same baseline worn, idle in the home space.
|
||||
- [ ] Under load: Mac view streaming, and one VR game.
|
||||
- [ ] On battery (unplugged) to separate charging heat from everything else.
|
||||
- [ ] Find what caused the 95 °C spike on 2026-09-28 22:09–22:12 (journal and
|
||||
process history around the Steam restart).
|
||||
|
||||
### 2. Settings without sudo (one at a time, measured)
|
||||
|
||||
- [ ] Compositor pause in standby (after asking the owning session).
|
||||
- [ ] Shorter screens-off delay.
|
||||
- [ ] Stop `steamvr.service` while off-head. Measure the saving and how long it
|
||||
takes to come back, since it also stops the gamescope session and Steam.
|
||||
- [ ] Close Mac-view Chromium and stop idle Lepton containers.
|
||||
- [ ] Steam's "never sleep on AC" (`system_idle_suspend_ac_sec = 0`), keeping
|
||||
the battery timer. Confirm the displays go dark.
|
||||
|
||||
### 3. Root settings (at home, with approval)
|
||||
|
||||
- [ ] CPU: `powersave` or a lower max frequency while off-head.
|
||||
- [ ] Fan: a copy of the fan config with a lower charging minimum, through a
|
||||
systemd drop-in. Only if temperatures in steps 1–2 leave headroom.
|
||||
- [ ] Battery: check whether charge current is writable. There's no charge
|
||||
limit, so the fallback is a Home Assistant smart plug that lets the
|
||||
battery cycle between roughly 80% and 100%.
|
||||
- [ ] Decide which root changes to make persistent (drop-ins in `/etc`, which
|
||||
survive SteamOS updates, unlike `/usr`).
|
||||
|
||||
### 4. A quiet mode
|
||||
|
||||
- [ ] Put the kept settings behind one switch: off-head for N minutes → quiet
|
||||
mode; on-head (proximity sensor) or a Frame Control request → normal.
|
||||
- [ ] Run it from Frame Control / keep-awake, not a hand-edited setting, so it
|
||||
can always be undone.
|
||||
- [ ] Add a doctor check that reports whether quiet mode is on and that it
|
||||
restores cleanly.
|
||||
|
||||
### 5. Remote wake (at home)
|
||||
|
||||
- [ ] Charger wake: during confirmed sleep, plug in, unplug, and switch the
|
||||
charger's AC off and on, one at a time.
|
||||
- [ ] Controller-button wake.
|
||||
- [ ] RTC dark wake (root timer that wakes, checks for queued work, sleeps).
|
||||
- [ ] Re-test WoWLAN after each SteamOS or kernel update.
|
||||
|
||||
### 6. Doctor script
|
||||
|
||||
- [ ] Turn [frame-doctor.md](frame-doctor.md) into `scripts/frame-doctor.sh`:
|
||||
read-only checks by default, fixes only with a flag, and **ask** fixes
|
||||
never automatic. Add the sensor reads from this page.
|
||||
Reference in new issue
Block a user