api
Package api provides the public client interface for the z13ctl daemon. It contains the shared protocol types and socket client functions used by CLI commands, GUI frontends, and any other tool that communicates with the z13ctl daemon over its Unix socket.
Index
- Constants
- Variables
- func IsStockProfileName(name string) bool
- func SendApply(device, color, color2, mode, speed string, brightness int) (bool, error)
- func SendAutoswitchGet() (handled bool, value string, err error)
- func SendAutoswitchSet(enabled bool, ac, battery string) (bool, error)
- func SendBatteryLimitGet() (handled bool, limit int, err error)
- func SendBatteryLimitSet(limit int) (bool, error)
- func SendBootSoundGet() (handled bool, value int, err error)
- func SendBootSoundSet(value int) (bool, error)
- func SendBrightness(device string, level int) (bool, error)
- func SendFanCurveGet() (handled bool, value string, err error)
- func SendFanCurveReset() (bool, error)
- func SendFanCurveResetFor(profile string) (bool, error)
- func SendFanCurveSet(curve string) (bool, error)
- func SendFanCurveSetFor(profile, curve string) (bool, error)
- func SendOff(device string) (bool, error)
- func SendPanelOverdriveGet() (handled bool, value int, err error)
- func SendPanelOverdriveSet(value int) (bool, error)
- func SendProfileCreate(name string) (bool, error)
- func SendProfileDelete(name string) (bool, error)
- func SendProfileGet() (handled bool, profile string, err error)
- func SendProfileList() (handled bool, value string, err error)
- func SendProfileSave(name string) (bool, error)
- func SendProfileSet(profile string) (bool, error)
- func SendTdpGet() (handled bool, value string, err error)
- func SendTdpReset() (bool, error)
- func SendTdpResetFor(profile string) (bool, error)
- func SendTdpSet(watts, pl1, pl2, pl3 string, force bool) (bool, error)
- func SendTdpSetFor(profile, watts, pl1, pl2, pl3 string, force bool) (bool, error)
- func SendUndervoltGet() (handled bool, value string, err error)
- func SendUndervoltReset() (bool, error)
- func SendUndervoltResetFor(profile string) (bool, error)
- func SendUndervoltSet(cpu string) (bool, error)
- func SendUndervoltSetFor(profile, cpu string) (bool, error)
- func SocketPath() string
- func Subscribe(events []string) (eventCh \<-chan string, cancel func(), err error)
- type AutoswitchState
- func (a *AutoswitchState) Target(onAC bool) string
- type CustomProfile
- func (p CustomProfile) Empty() bool
- type FanCurvePoint
- type FanCurveState
- type LightingState
- type State
- func SendGetState() (bool, *State, error)
- func (s State) ActiveCustomProfile() (CustomProfile, bool)
- func (s State) InCustomProfile() bool
- func (s State) IsCustomProfile(name string) bool
- type TDPState
- type UndervoltState
Constants
const (
// EventGUIToggle is emitted when the Armoury Crate button is pressed.
EventGUIToggle = "gui-toggle"
// EventPowerSource is emitted when the machine moves between mains and
// battery power. It fires on the transition itself, so it is useful whether
// or not autoswitch is configured — a client can drive a plug/battery
// indicator from it alone.
EventPowerSource = "power-source"
// EventStateChanged is emitted when the active profile, its settings, the
// saved profiles, or the autoswitch configuration change — whatever the
// cause: this client, another client, the CLI, autoswitch, or a resume.
// A client displaying profile, TDP, fan curve, or undervolt values should
// re-read them with SendGetState when it arrives.
//
// Lighting is deliberately excluded. A brightness slider drag would emit a
// burst of events describing values the client just set itself.
EventStateChanged = "state-changed"
)
DefaultCustomProfile is the name of the custom profile created implicitly by the first fan curve, TDP, or undervolt setting made while a stock profile is active. It is reserved and cannot be chosen as a user-supplied name.
Variables
AllEvents lists every event name the daemon can emit. Subscribing with an empty event list is equivalent to subscribing to all of them.
StockProfiles are the firmware performance profiles that can be written to platform_profile. They are reserved: a custom profile can never take one of these names, so selecting one always reaches the firmware profile.
func IsStockProfileName
IsStockProfileName reports whether name is one of the reserved firmware profile names.
func SendApply
SendApply sends an apply command to the daemon. color and color2 must be "RRGGBB" hex strings. device may be "keyboard", "lightbar", a /dev/hidrawN path, or "" to target all devices. Returns (true, nil) on success, (false, nil) if the daemon is not running (caller should fall back to direct HID access).
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Apply a static red color at full brightness to all devices.
handled, err := api.SendApply("", "FF0000", "000000", "static", "normal", 3)
if !handled {
fmt.Println("daemon not running, falling back to direct HID access")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("applied")
}
func SendAutoswitchGet
SendAutoswitchGet queries the daemon for the autoswitch configuration. Returns a JSON AutoswitchState. Returns (false, "", nil) if the daemon is not running.
Example
package main
import (
"encoding/json"
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
handled, value, err := api.SendAutoswitchGet()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
var st struct {
api.AutoswitchState
OnAC bool `json:"on_ac"`
}
if err := json.Unmarshal([]byte(value), &st); err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(st.Enabled, st.AC, st.Battery, st.OnAC)
}
func SendAutoswitchSet
SendAutoswitchSet configures automatic profile selection by power source. An empty ac or battery target leaves the profile alone on that source.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Balanced on AC, a custom profile on battery. An empty target leaves that
// side to the desktop's own power management.
handled, err := api.SendAutoswitchSet(true, "balanced", "battery-uv")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("autoswitch configured")
}
func SendBatteryLimitGet
SendBatteryLimitGet queries the daemon for the current battery charge limit by reading sysfs (not cached daemon state). Intended for GUI/plugin callers. Returns (false, 0, nil) if the daemon is not running.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Read the current battery charge limit.
handled, limit, err := api.SendBatteryLimitGet()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("battery limit:", limit)
}
func SendBatteryLimitSet
SendBatteryLimitSet sends a battery limit set command to the daemon.
Example
func SendBootSoundGet
SendBootSoundGet queries the daemon for the current boot sound setting by reading sysfs. Returns (false, 0, nil) if the daemon is not running.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Read the current boot sound setting.
handled, value, err := api.SendBootSoundGet()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("boot sound:", value)
}
func SendBootSoundSet
SendBootSoundSet sends a boot sound set command to the daemon.
Example
func SendBrightness
SendBrightness sends a brightness-only command to the daemon. device may be "keyboard", "lightbar", a /dev/hidrawN path, or "" to target all devices.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Set brightness to medium on the keyboard only.
handled, err := api.SendBrightness("keyboard", 2)
if !handled {
fmt.Println("daemon not running, falling back to direct HID access")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("brightness set")
}
func SendFanCurveGet
SendFanCurveGet queries the daemon for the current fan curve data. Returns JSON value string with both fans' curve and mode.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Read the current fan curve for both fans via the daemon.
handled, value, err := api.SendFanCurveGet()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("fan curve:", value)
}
func SendFanCurveReset
SendFanCurveReset resets both fans to firmware auto mode.
Example
func SendFanCurveResetFor
SendFanCurveResetFor clears the fan curve from the named custom profile. An empty profile means the active one, which also releases both fans to firmware auto mode.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Clear the fan curve from a stored profile, so it no longer controls fans.
handled, err := api.SendFanCurveResetFor("battery-uv")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("fan curve cleared")
}
func SendFanCurveSet
SendFanCurveSet sends a fan curve set command to the daemon, editing the active custom profile. The curve is applied to both fans simultaneously.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Set a custom 8-point fan curve (applied to both fans).
handled, err := api.SendFanCurveSet("48:2,53:22,57:30,60:43,63:56,65:68,70:89,76:102")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("fan curve set")
}
func SendFanCurveSetFor
SendFanCurveSetFor stores a fan curve in the named custom profile. An empty profile means the active one, in which case the curve is also written to hardware; naming a profile that is not active only records it.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// An empty profile name edits the active profile and writes hardware, which
// is exactly what SendFanCurveSet does.
handled, err := api.SendFanCurveSetFor("battery-uv", "30:40%,40:45%,50:50%,60:60%,70:70%,80:85%,90:100%,100:100%")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("stored in battery-uv")
}
func SendOff
SendOff sends an off command to the daemon. device may be "keyboard", "lightbar", a /dev/hidrawN path, or "" to target all devices.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Turn off lighting on all devices.
handled, err := api.SendOff("")
if !handled {
fmt.Println("daemon not running, falling back to direct HID access")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("lights off")
}
func SendPanelOverdriveGet
SendPanelOverdriveGet queries the daemon for the current panel overdrive setting by reading sysfs. Returns (false, 0, nil) if the daemon is not running.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Read the current panel overdrive setting.
handled, value, err := api.SendPanelOverdriveGet()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("panel overdrive:", value)
}
func SendPanelOverdriveSet
SendPanelOverdriveSet sends a panel overdrive set command to the daemon.
Example
func SendProfileCreate
SendProfileCreate creates an empty custom profile. It does not activate it.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Create an empty custom profile. It is not activated; add settings with
// the *For variants, then select it with SendProfileSet.
handled, err := api.SendProfileCreate("battery-uv")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("profile created")
}
func SendProfileDelete
SendProfileDelete removes a saved custom profile. The daemon refuses to delete the active profile or one referenced by autoswitch.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// The daemon refuses to delete the active profile or one referenced by
// autoswitch.
handled, err := api.SendProfileDelete("gaming")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("profile deleted")
}
func SendProfileGet
SendProfileGet queries the daemon for the current performance profile by reading sysfs (not cached daemon state). Intended for GUI/plugin callers. Returns (false, "", nil) if the daemon is not running.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Read the current performance profile from sysfs via the daemon.
handled, profile, err := api.SendProfileGet()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("profile:", profile)
}
func SendProfileList
SendProfileList queries the daemon for the saved custom profiles. Returns a JSON array of CustomProfile. Returns (false, "", nil) if the daemon is not running.
Example
package main
import (
"encoding/json"
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
handled, value, err := api.SendProfileList()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
var profiles []struct {
api.CustomProfile
Active bool `json:"active"`
}
if err := json.Unmarshal([]byte(value), &profiles); err != nil {
fmt.Println("error:", err)
return
}
for _, p := range profiles {
fmt.Println(p.Name, p.Active)
}
}
func SendProfileSave
SendProfileSave copies the active custom profile under a new name. It does not activate the copy.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Copy the profile currently in force under a new name, leaving the
// original active.
handled, err := api.SendProfileSave("gaming")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("profile copied")
}
func SendProfileSet
SendProfileSet sends a profile set command to the daemon.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Switch to the performance power profile.
handled, err := api.SendProfileSet("performance")
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("profile set")
}
func SendTdpGet
SendTdpGet queries the daemon for current TDP/PPT values. Returns JSON value string.
Example
func SendTdpReset
SendTdpReset sends a TDP reset command to the daemon.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Reset to balanced profile, restoring its stock PPT and auto fan curves.
handled, err := api.SendTdpReset()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("tdp reset")
}
func SendTdpResetFor
SendTdpResetFor clears the TDP limits from the named custom profile. An empty profile means the active one, which also restores stock power limits.
Example
func SendTdpSet
SendTdpSet sends a TDP set command to the daemon, editing the active custom profile.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Set TDP to 50W (all PPT values equal).
handled, err := api.SendTdpSet("50", "", "", "", false)
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("tdp set")
}
func SendTdpSetFor
SendTdpSetFor stores TDP limits in the named custom profile. An empty profile means the active one, in which case the limits are also written to hardware; naming a profile that is not active only records them.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Store a 35W limit in a profile that is not running. Nothing is applied to
// hardware, which is what makes it possible to build the profile autoswitch
// selects on battery while still plugged in.
handled, err := api.SendTdpSetFor("battery-uv", "35", "", "", "", false)
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("stored in battery-uv")
}
func SendUndervoltGet
SendUndervoltGet queries the daemon for the current Curve Optimizer offsets. Returns JSON value string. Returns (false, "", nil) if the daemon is not running.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Read current Curve Optimizer offsets from daemon state.
handled, value, err := api.SendUndervoltGet()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("undervolt:", value)
}
func SendUndervoltReset
SendUndervoltReset resets Curve Optimizer to stock (0).
Example
func SendUndervoltResetFor
SendUndervoltResetFor clears the Curve Optimizer offset from the named custom profile. An empty profile means the active one, which also resets hardware.
Example
func SendUndervoltSet
SendUndervoltSet sends a Curve Optimizer set command to the daemon, editing the active custom profile. cpu is a string representation of the CO offset (e.g. "-20").
Example
func SendUndervoltSetFor
SendUndervoltSetFor stores a Curve Optimizer offset in the named custom profile. An empty profile means the active one, in which case the offset is also applied to hardware; naming a profile that is not active only records it.
Example
func SocketPath
SocketPath returns the runtime path for the daemon's Unix socket.
func Subscribe
Subscribe opens a long-lived subscription to the daemon and returns a channel that receives event name strings as they are streamed. Pass the events you want — EventGUIToggle, EventPowerSource, EventStateChanged — or nil for all of them. The daemon honours the list, so a client that asks only for EventGUIToggle will not be woken by anything else.
Events carry no payload by design: the name says what happened, and SendGetState answers with current truth. Switch on the name rather than treating every event alike —
for ev := range ch {
switch ev {
case api.EventGUIToggle:
toggleWindow()
case api.EventPowerSource, api.EventStateChanged:
refreshFromGetState()
}
}
The returned cancel func closes the underlying connection and stops the goroutine; the channel is closed when the connection drops or cancel is called. Returns (nil, nil, nil) if the daemon is not running.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Subscribe to Armoury Crate button press events.
ch, cancel, err := api.Subscribe([]string{"gui-toggle"})
if ch == nil {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
defer cancel()
for event := range ch {
fmt.Println("received event:", event)
}
}
type AutoswitchState
AutoswitchState configures automatic profile selection by power source. An empty AC or Battery target means "leave the profile alone on that source", which is how a caller hands one side back to power-profiles-daemon.
type AutoswitchState struct {
Enabled bool `json:"enabled"`
AC string `json:"ac,omitempty"`
Battery string `json:"battery,omitempty"`
}
func (*AutoswitchState) Target
Target returns the profile to apply for the given power source, or "" when autoswitch is disabled or that side is unconfigured.
type CustomProfile
CustomProfile is a named set of custom hardware settings. Each subsystem is a pointer so that nil means "this profile does not control that subsystem", which is what lets a profile stay loadable as new subsystems are added.
type CustomProfile struct {
Name string `json:"name"`
FanCurve *FanCurveState `json:"fan_curve,omitempty"`
TDP *TDPState `json:"tdp,omitempty"`
Undervolt *UndervoltState `json:"undervolt,omitempty"`
}
func (CustomProfile) Empty
Empty reports whether the profile controls no subsystem at all. An empty profile cannot be activated: there would be nothing to apply.
type FanCurvePoint
FanCurvePoint represents one point on an 8-point fan curve.
type FanCurvePoint struct {
Temp int `json:"temp"` // degrees Celsius
PWM int `json:"pwm"` // 0–255 duty cycle
}
type FanCurveState
FanCurveState captures the fan curve and mode applied to both fans.
type FanCurveState struct {
Mode int `json:"mode"` // pwm_enable: 0=full-speed, 1=custom, 2=auto
Points []FanCurvePoint `json:"points"` // 8 points
}
type LightingState
LightingState captures all parameters needed to reproduce one lighting zone.
type LightingState struct {
Enabled bool `json:"enabled"`
Mode string `json:"mode"`
Color string `json:"color"` // "RRGGBB" hex
Color2 string `json:"color2"` // "RRGGBB" hex
Speed string `json:"speed"`
Brightness int `json:"brightness"` // 0–3
}
type State
State holds the last-applied settings for all controllable subsystems. It is returned by SendGetState and broadcast as part of daemon responses.
CustomProfiles is the source of truth for custom settings. FanCurve, TDP and Undervolt are a projection, retained so clients written against earlier versions keep working: they carry the active custom profile's settings, or the default "custom" profile's when a firmware profile is active — the same values selecting "custom" would recall. Undervolt.Active is what says whether an offset is applied to hardware right now; the values themselves survive a switch to a firmware profile so they can be recalled.
type State struct {
Lighting LightingState `json:"lighting"`
Devices map[string]LightingState `json:"devices,omitempty"` // per-device overrides keyed by name
Profile string `json:"profile,omitempty"`
Battery int `json:"battery_limit,omitempty"`
BootSound int `json:"boot_sound,omitempty"`
PanelOverdrive int `json:"panel_overdrive,omitempty"`
CustomProfiles map[string]CustomProfile `json:"custom_profiles,omitempty"` // saved custom profiles keyed by name
Autoswitch *AutoswitchState `json:"autoswitch,omitempty"`
FanCurve *FanCurveState `json:"fan_curve,omitempty"` // projection; see the type doc
TDP *TDPState `json:"tdp,omitempty"` // projection; see the type doc
Undervolt *UndervoltState `json:"undervolt,omitempty"` // projection; see the type doc
UndervoltAvailable bool `json:"undervolt_available"` // true if ryzen_smu is loaded
OnAC bool `json:"on_ac"` // true when running on mains power
Temperature int `json:"temperature,omitempty"` // APU temp, degrees Celsius
FanRPM int `json:"fan_rpm,omitempty"` // fan1 speed in RPM
}
func SendGetState
SendGetState fetches the daemon's full cached state for GUI initialization. Returns (false, nil, nil) if the daemon is not running.
Example
package main
import (
"fmt"
"github.com/dahui/z13ctl/api"
)
func main() {
// Fetch the daemon's full cached state for GUI initialization.
handled, state, err := api.SendGetState()
if !handled {
fmt.Println("daemon not running")
return
}
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("mode:", state.Lighting.Mode)
}
func (State) ActiveCustomProfile
ActiveCustomProfile returns the active custom profile and true, or the zero value and false when a stock profile is active.
func (State) InCustomProfile
InCustomProfile reports whether the active profile is a custom one.
func (State) IsCustomProfile
IsCustomProfile reports whether name identifies a z13ctl-managed custom profile: the default "custom" profile, or a saved named one.
Clients that check Profile == "custom" to decide whether custom controls apply must move to this — a named profile would otherwise read as stock.
A reserved firmware profile name is never custom, whatever the map contains. The check is deliberately ahead of the lookup so that a hand-edited state file cannot make a stock profile look custom to the fan curve reconciler.
type TDPState
TDPState captures all PPT (Package Power Tracking) values in watts.
type TDPState struct {
PL1SPL int `json:"pl1_spl"` // Sustained Power Limit
PL2SPPT int `json:"pl2_sppt"` // Short Boost
FPPT int `json:"fppt"` // Fast Boost
APUSPPT int `json:"apu_sppt"` // APU Short PPT
PlatformSPPT int `json:"platform_sppt"` // Platform Short PPT
}
type UndervoltState
UndervoltState captures the AMD Curve Optimizer offset applied to the CPU. Values are non-positive integers (0 = stock, negative = undervolt). Active indicates whether the offset is currently applied to hardware.
type UndervoltState struct {
CPUCO int `json:"cpu_co"` // all-core CPU Curve Optimizer offset
Active bool `json:"active"` // true when CO is applied to hardware
}
Generated by gomarkdoc