Add Pi throttling / undervoltage state (vcgencmd get_throttled)#53
Merged
Conversation
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
commented
Jul 15, 2026
Owner
Author
There was a problem hiding this comment.
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()andparseThrottlederrors are checked and wrapped; missingvcgencmdreturns(nil, nil)and degrades gracefully off-Pi. - Resource leaks ✅ —
context.WithTimeoutpaired withdefer cancel(); no open files/readers. /proc//sys(bitmask) parsing robustness ✅ — malformed / empty / missing-prefix / non-hex inputs are rejected and covered byTestParseThrottled_Malformed.ParseUint(raw, 0, 64)correctly infers the0xbase.- Command execution safety ✅ — fixed argument list (
c.vcgencmdPath, "get_throttled"), no shell string-concatenation. - REST API stability ✅ — additive
*Throttledfield withomitempty; existingv1shapes unchanged,docs/API.mdupdated with example + note. - Test coverage ✅ — table test over five real bitmasks, malformed cases, and the no-
vcgencmdpath. (The liveCollect→vcgencmdinvocation 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
detectRetryIntervaland mirrorsTemperatureCollector.
One nit (non-blocking)
internal/collector/collector.goisn'tgofmt-clean — adding the longerthrottledfield widened the alignment column but the surrounding fields (and theNew(...)literal) weren't re-aligned. CI won't flag it (nogofmtlinter configured), so it would merge as-is.gofmt -w internal/collector/collector.goresolves it. See inline comment.
Everything else looks good to merge once that's tidied up.
Adding the throttled field widened the alignment column; re-run gofmt over the whole struct and composite literal so the untouched lines match.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
throttledobject to the metrics snapshot that decodes theRaspberry Pi
vcgencmd get_throttledbitmask 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 alatched-since-boot flag (
*_since_boot):under_voltage_now/under_voltage_since_bootfrequency_capped_now/frequency_capped_since_bootthrottled_now/throttled_since_bootsoft_temp_limit_now/soft_temp_limit_since_bootraw— the original hex bitmask string (e.g."0x50005")Implementation notes:
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.
vcgencmdis discovered lazily using the same throttled re-detectionpattern (and shared
detectRetryInterval) as the temperature collector,so a firmware tool appearing after startup is picked up without a restart.
throttledis taggedomitemptyand thewhole object is omitted when
vcgencmdis unavailable (e.g. off-Pi),so it degrades gracefully and does not alter existing
v1field shapes.Related Issue
Closes #13
Checklist
go test ./...passes locally) —table test decodes fixture bitmasks (
0x0,0x50005,0x50000,0xf000f,0x80002) to the correct flag set, plus malformed-inputand no-
vcgencmdcasesgo vet ./...andgolangci-lint runare clean (0 issues)docs/API.md: addedthrottledto the/api/v1/metricsexample and a note explaining the flags)/api/v1/...response shapes — the field ispurely additive (
omitempty)Verification note
Verified via unit tests and off-Pi build/vet/lint. The live
vcgencmd get_throttledinvocation path could not be exercised herebecause this environment has no Raspberry Pi firmware tooling; on-hardware
confirmation that the collector reads and decodes a real bitmask is still
recommended.