Skip to content

Add Pi throttling / undervoltage state (vcgencmd get_throttled)#53

Merged
LarsLaskowski merged 3 commits into
mainfrom
claude/issue-13-ru4rz5
Jul 16, 2026
Merged

Add Pi throttling / undervoltage state (vcgencmd get_throttled)#53
LarsLaskowski merged 3 commits into
mainfrom
claude/issue-13-ru4rz5

Conversation

@LarsLaskowski

@LarsLaskowski LarsLaskowski commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a new throttled object to the metrics snapshot that decodes the
Raspberry Pi vcgencmd get_throttled bitmask into individual booleans —
the single most-requested Pi health signal, since under-voltage and
thermal throttling silently degrade performance.

Each condition is exposed both as a current-state flag (*_now) and a
latched-since-boot flag (*_since_boot):

  • under_voltage_now / under_voltage_since_boot
  • frequency_capped_now / frequency_capped_since_boot
  • throttled_now / throttled_since_boot
  • soft_temp_limit_now / soft_temp_limit_since_boot
  • raw — the original hex bitmask string (e.g. "0x50005")

Implementation notes:

  • New internal/collector/throttled.go + throttled_test.go. The parser
    (parseThrottled) is unit-testable against fixture bitmask strings,
    independent of real hardware, per the acceptance criteria.
  • vcgencmd is discovered lazily using the same throttled re-detection
    pattern (and shared detectRetryInterval) as the temperature collector,
    so a firmware tool appearing after startup is picked up without a restart.
  • The change is additive: throttled is tagged omitempty and the
    whole object is omitted when vcgencmd is unavailable (e.g. off-Pi),
    so it degrades gracefully and does not alter existing v1 field shapes.

Related Issue

Closes #13

Checklist

  • Tests added/updated for the change (go test ./... passes locally) —
    table test decodes fixture bitmasks (0x0, 0x50005, 0x50000,
    0xf000f, 0x80002) to the correct flag set, plus malformed-input
    and no-vcgencmd cases
  • go vet ./... and golangci-lint run are clean (0 issues)
  • Documentation updated (docs/API.md: added throttled to the
    /api/v1/metrics example and a note explaining the flags)
  • No breaking change to /api/v1/... response shapes — the field is
    purely additive (omitempty)

Verification note

Verified via unit tests and off-Pi build/vet/lint. The live
vcgencmd get_throttled invocation path could not be exercised here
because this environment has no Raspberry Pi firmware tooling; on-hardware
confirmation that the collector reads and decodes a real bitmask is still
recommended.

Decode the vcgencmd get_throttled bitmask into individual flags for
under-voltage, ARM frequency capping, throttling, and soft temperature
limit — each as a current-state (*_now) and latched-since-boot
(*_since_boot) boolean. This surfaces the most-requested Pi health
signal, which silently degrades performance when a power supply is
inadequate or the SoC overheats.

The new throttled object is additive and omitted (omitempty) when
vcgencmd is unavailable, so it degrades gracefully off-Pi. vcgencmd is
discovered lazily with the same throttled re-detection pattern as the
temperature collector.

@LarsLaskowski LarsLaskowski left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Add Pi throttling / undervoltage state (vcgencmd get_throttled)

Reviewed against the PiMonitor Go/security/API conventions. This is a clean, well-scoped change — nice work. Approving in spirit; one non-blocking gofmt nit inline.

Verification (PR branch, off-Pi)

  • go build ./...
  • go vet ./...
  • go test ./... -race -cover ✅ (collector package 86.9%)

Checklist

  • Error handling ✅ — exec.CommandContext(...).Output() and parseThrottled errors are checked and wrapped; missing vcgencmd returns (nil, nil) and degrades gracefully off-Pi.
  • Resource leaks ✅ — context.WithTimeout paired with defer cancel(); no open files/readers.
  • /proc//sys (bitmask) parsing robustness ✅ — malformed / empty / missing-prefix / non-hex inputs are rejected and covered by TestParseThrottled_Malformed. ParseUint(raw, 0, 64) correctly infers the 0x base.
  • Command execution safety ✅ — fixed argument list (c.vcgencmdPath, "get_throttled"), no shell string-concatenation.
  • REST API stability ✅ — additive *Throttled field with omitempty; existing v1 shapes unchanged, docs/API.md updated with example + note.
  • Test coverage ✅ — table test over five real bitmasks, malformed cases, and the no-vcgencmd path. (The live Collectvcgencmd invocation can't be exercised off-Pi, as the PR notes; on-hardware confirmation still recommended.)
  • Language ✅ — all English.
  • Dependencies ✅ — none added; lazy detection reuses the shared detectRetryInterval and mirrors TemperatureCollector.

One nit (non-blocking)

  • internal/collector/collector.go isn't gofmt-clean — adding the longer throttled field widened the alignment column but the surrounding fields (and the New(...) literal) weren't re-aligned. CI won't flag it (no gofmt linter configured), so it would merge as-is. gofmt -w internal/collector/collector.go resolves it. See inline comment.

Everything else looks good to merge once that's tidied up.

Comment thread internal/collector/collector.go
claude and others added 2 commits July 15, 2026 19:27
Adding the throttled field widened the alignment column; re-run gofmt
over the whole struct and composite literal so the untouched lines match.
@LarsLaskowski
LarsLaskowski merged commit 18a2c42 into main Jul 16, 2026
3 checks passed
@LarsLaskowski
LarsLaskowski deleted the claude/issue-13-ru4rz5 branch July 16, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

D1: Throttling / undervoltage state (vcgencmd get_throttled)

2 participants