ReferenceAPI

System and power

Reference for dd.system status, vitals, volume, audio devices and Wi-Fi, and for dd.power capabilities and actions.

dd.system

Reads need the system permission; the write surface (setVolume, setMuted, the microphone verbs, setRadio, the audio device and app volume verbs, the Bluetooth verbs, the brightness verbs, the Wi-Fi verbs, openSettings) additionally needs systemControls.

dd.system.status()

dd.system.status(): Promise<SystemVitals | null>

The latest vitals snapshot, a cheap cache read (null until the sampler's first pass). Seed your UI with this, then follow onVitals.

dd.system.onVitals()

dd.system.onVitals(cb: (vitals: SystemVitals) => void): () => void

interface SystemVitals {
  /** CPU busy fraction 0..1 (null on the very first sample). */
  cpu: number | null;
  ram: { usedMb: number; totalMb: number; percent: number } | null;
  /** GPU busy fraction 0..1: the busiest engine (3D, copy, video, compute)
   *  of ONE adapter, the figure Task Manager shows. The host measures the
   *  hardware adapter with the most dedicated video memory unless the user
   *  picked another in Settings > General. App 0.3.8+; earlier apps summed
   *  the 3D engines of every adapter. */
  gpu: number | null;
  /** Disk busy fraction 0..1 (physical disks total). */
  disk: number | null;
  /** Fixed drives (letters), resampled about every 30s inside the 1Hz
   *  stream. `percent` is used/total 0..1; `label` is the volume name or
   *  null; null when enumeration fails, empty when no fixed drives exist. */
  drives:
    | { mount: string; label: string | null; usedMb: number; totalMb: number; percent: number }[]
    | null;
  net: { rxBps: number; txBps: number } | null;
  battery: { percent: number | null; charging: boolean } | null;
  wifi: { ssid: string; signal: number } | null;
  volume: { level: number; muted: boolean } | null;
  /** The default microphone; null with no microphone. App 0.4.2+. */
  mic: { level: number; muted: boolean } | null;
  /** Radio state as Windows Quick Settings shows it; null while Windows
   *  cannot list the radios. App 0.4.2+. */
  radios: { wifi: RadioState; bluetooth: RadioState; cellular: RadioState } | null;
}

/** "disabled": off by hardware switch or airplane mode. null: no such radio. */
type RadioState = "on" | "off" | "disabled" | null;

A 1 Hz stream. Every field fails independently: a machine with no GPU counters, no Wi-Fi adapter, no battery, or no audio device reports null for that field while the rest keep flowing. Render nulls as absent, not as zero. cpu, gpu, disk, volume.level, mic.level and ram.percent are 0..1 fractions; wifi.signal is 0..100. drives lists fixed volumes only and refreshes about every 30 seconds inside the stream (app 0.2.5+); sizes are MiB, like ram. net sums the up hardware interfaces only, so a VPN tunnel or a virtual switch port never counts the same bytes again; a machine with no hardware interface up (a VM guest) sums every up interface, and the first tick after that rule flips is null (app 0.3.7 or newer; earlier apps summed every up interface). gpu is the busiest engine of one graphics adapter, the figure Task Manager shows for that card: the hardware adapter with the most dedicated video memory, or the one the user picked in Settings > General (app 0.3.8 or newer; earlier apps summed the 3D engines of every adapter, integrated graphics included).

dd.system.setVolume()

dd.system.setVolume(level: number): Promise<void>  // 0..1

Master volume. 120 calls per rolling 10 seconds; throttle slider drags client-side to roughly one call per 100 ms.

dd.system.setMuted()

dd.system.setMuted(muted: boolean): Promise<void>

20 calls per rolling 10 seconds.

dd.system.setMicVolume()

dd.system.setMicVolume(level: number): Promise<void>  // 0..1

The default microphone's level, the one the mic vitals field reads. 120 calls per rolling 10 seconds; throttle slider drags like setVolume. A machine with no microphone rejects with INTERNAL. App 0.4.2 or newer.

dd.system.setMicMuted()

dd.system.setMicMuted(muted: boolean): Promise<void>

Mutes or unmutes the default microphone. 20 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.setRadio()

dd.system.setRadio(
  kind: "wifi" | "bluetooth" | "cellular",
  on: boolean,
): Promise<RadioSetResult>

interface RadioSetResult {
  access: "allowed" | "deniedByUser" | "deniedBySystem" | "unspecified";
  state: RadioState;
}

Turns every radio of a kind on or off, like the tiles in Windows Quick Settings. Call it from a click: the host refuses it unless the cursor is inside your widget, its pane, or your bar, and to a desktop widget in edit mode, because Wi-Fi off cuts the network.

Windows has its own privacy switch, "Let apps control device radios". When it is off, the call resolves with access: "deniedByUser" instead of rejecting; show that and offer openSettings("privacy-radios"). state is the radio's state right after the switch, and the radios vitals field confirms it within a second. A machine with no radio of that kind rejects with NOT_FOUND. 5 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.audioDevices()

dd.system.audioDevices(): Promise<AudioDevices>

interface AudioDevices {
  outputs: AudioDevice[];
  inputs: AudioDevice[];
}

interface AudioDevice {
  /** Opaque token for setAudioDevice, valid for this app run only. */
  id: string;
  /** The name Windows shows, e.g. "Speakers (Realtek Audio)". */
  name: string;
  /** The Windows default for its direction. */
  isDefault: boolean;
}

The active audio outputs and inputs, each list with the default first, then by name. The hardware id never reaches your widget: id is a token the host issues per app run, so list again after a restart. 20 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.setAudioDevice()

dd.system.setAudioDevice(id: string): Promise<AudioDevices>

Makes a listed device the Windows default for its direction, in every role (console, multimedia, communications), as the Windows sound menu does. It resolves with the fresh list as Windows now reports it: render that, not a guess. A stale id rejects NOT_FOUND (list again). The volume calls and the audio spectrum follow the new default by themselves. 5 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.onAudioDevicesChanged()

dd.system.onAudioDevicesChanged(cb: () => void): () => void

A data-free ping when a device comes, goes, is enabled or disabled, or becomes the default (your own setAudioDevice included), at most once a second: call audioDevices() again. Needs system and systemControls. App 0.4.2 or newer. For a ready-made list, use <dd-audio-devices>.

dd.system.audioApps()

dd.system.audioApps(): Promise<{ apps: AudioApp[] }>

interface AudioApp {
  /** Opaque token, valid for this app run. */
  id: string;
  /** "Spotify"; "System sounds" for the system session. */
  name: string;
  /** The app's icon as a data: URI, or null. */
  icon: string | null;
  /** The app's own level 0..1, a fraction of the master volume. */
  level: number;
  muted: boolean;
  /** Playing sound right now. */
  active: boolean;
  /** The Windows system sounds session. */
  system: boolean;
}

The apps with sound on the default output device, as the Windows volume mixer shows them: one row per app, playing apps first, then by name, and the system sounds row last. Running app names and icons say more than the vitals do, so this read needs systemControls too. There is no change event: poll while your mixer is visible, or use <dd-audio-mixer>, which does. 20 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.setAppVolume()

dd.system.setAppVolume(id: string, level: number): Promise<void>  // 0..1

Sets one app's level, every stream it has. 120 calls per rolling 10 seconds; throttle slider drags like setVolume. A stale id rejects with NOT_FOUND (list again). App 0.4.2 or newer.

dd.system.setAppMuted()

dd.system.setAppMuted(id: string, muted: boolean): Promise<void>

Mutes or unmutes one app. 20 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.bluetoothDevices()

dd.system.bluetoothDevices(): Promise<{ devices: BluetoothDevice[] }>

interface BluetoothDevice {
  /** Opaque token, valid for this app run. */
  id: string;
  /** The name Windows shows. */
  name: string;
  connected: boolean;
  /** "audio": headsets and speakers; the rest from the device class. */
  kind: "audio" | "input" | "phone" | "computer" | "other";
  /** The finer type, or null. App 0.4.5+. */
  type:
    | "headphones" | "headset" | "earbuds" | "speaker" | "gamepad" | "keyboard"
    | "mouse" | "pen" | "watch" | "phone" | "tablet" | "computer" | null;
  /** bluetoothConnect / bluetoothDisconnect work on this device. */
  canConnect: boolean;
  /** 0..100, or null. Always null while disconnected. App 0.4.5+. */
  battery: number | null;
  /** null when the source does not say. App 0.4.5+. */
  charging: boolean | null;
  /** Earbuds that report each part (AirPods, Beats), else null. App 0.4.5+. */
  parts: {
    left: BatteryPart | null;
    right: BatteryPart | null;
    case: BatteryPart | null;
  } | null;
}

interface BatteryPart {
  /** 0..100. */
  level: number;
  charging: boolean;
}

The paired Bluetooth devices, classic and Low Energy (a dual-mode device is one row), connected first. It reads what Windows already knows: no scan, and no pairing. Send users to openSettings("bluetooth") to add a device. The list stays readable while the radio is off. Paired device names say more than the vitals do, so this read needs systemControls too. List again on onBluetoothDevicesChanged (app 0.4.5 or newer; on older apps, poll while your list is visible), or use <dd-bluetooth-devices>, which does both. 20 calls per rolling 10 seconds. App 0.4.2 or newer.

Type. type is the finer device type when the device class names one, else null. It comes from the classic minor device class or the LE appearance, so an Xbox controller is kind: "input" and type: "gamepad". Earbuds that report parts are "earbuds", whatever their class says. Pick an icon from type first and fall back to kind. App 0.4.5 or newer.

Battery. battery is the level Windows Settings shows for the device. When Windows has none, the host reads the device's Bluetooth LE Battery Service directly. A disconnected device always reads null, because Windows keeps the last level after the link drops. charging is null when the source does not say, and neither Windows nor the Battery Service does. AirPods and Beats also report each earbud and the case in parts, where a part they do not report is null. A device with no level anywhere reads null: some headsets send their level only to their maker's app. Once a minute is often enough for a battery display. The three battery fields need app 0.4.5 or newer; older apps leave them out.

dd.system.onBluetoothDevicesChanged()

dd.system.onBluetoothDevicesChanged(cb: () => void): () => void

A data-free ping when a paired device connects, disconnects, or is paired or removed, at most once a second: call bluetoothDevices() again. Battery levels change without a ping, and Windows sets a level a few seconds after a device connects, so keep a slow poll (once a minute is plenty) for them. Needs system and systemControls. App 0.4.5 or newer.

dd.system.bluetoothConnect() and bluetoothDisconnect()

dd.system.bluetoothConnect(id: string): Promise<void>
dd.system.bluetoothDisconnect(id: string): Promise<void>

Connect or disconnect a paired audio device (canConnect: true), like the Connect button in Windows Quick Settings; disconnecting does not unpair. Call them from a click: the host refuses them unless the cursor is inside your widget, its pane, or your bar, and to a desktop widget in edit mode. They resolve once Windows has the request, and the link follows within a few seconds, so list again. A device with no audio connection rejects with INVALID_PARAMS, a stale id with NOT_FOUND. 5 calls per rolling 10 seconds each. App 0.4.2 or newer.

dd.system.brightness()

dd.system.brightness(): Promise<{ displays: DisplayBrightness[] }>

interface DisplayBrightness {
  /** Opaque token, valid for this app run. */
  id: string;
  /** "LG ULTRAGEAR"; "Built-in display" for a nameless laptop panel. */
  name: string;
  /** 0..1 */
  level: number;
  primary: boolean;
  /** The display showing your widget, bar or pane. */
  here: boolean;
}

The displays whose brightness can be set: a laptop's built-in panel, and external monitors that answer DDC/CI over the cable. A monitor without DDC/CI, or with it turned off in its own menu, is left out, so a desktop often gets an empty list; render nothing then. There is no change event: poll while visible, or use <dd-brightness>, which does. Monitor reads are cached for 15 seconds, so polling faster shows nothing new. 20 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.setBrightness()

dd.system.setBrightness(id: string, level: number): Promise<void>  // 0..1

Sets one display's brightness. The host serves every display from one queue: sets for the same display collapse to the newest, and writes to an external monitor stay 200 ms apart, because many monitors store each write. Throttle slider drags to roughly one call per 150 ms. A stale id rejects with NOT_FOUND (list again). 120 calls per rolling 10 seconds. App 0.4.2 or newer.

dd.system.wifiNetworks()

dd.system.wifiNetworks(): Promise<{ networks: WifiNetwork[] }>

interface WifiNetwork {
  ssid: string;
  /** Signal quality 0..100. */
  signal: number;
  secured: boolean;
  connected: boolean;
  /** Windows has a saved profile: wifiConnect only works for these. */
  known: boolean;
}

Available networks, deduped by SSID (strongest kept), connected first. The host triggers a background scan at most every 30 seconds. 6 calls per rolling 10 seconds.

dd.system.wifiConnect()

dd.system.wifiConnect(ssid: string): Promise<void>

Connects only to networks with a saved Windows profile (known: true); passwords never cross the bridge. No profile rejects NOT_FOUND; send users to openSettings("wifi") for new networks. 3 calls per rolling 10 seconds.

dd.system.wifiDisconnect()

dd.system.wifiDisconnect(): Promise<void>

3 calls per rolling 10 seconds.

dd.system.openSettings()

dd.system.openSettings(panel: SettingsPanel): Promise<void>

type SettingsPanel =
  | "sound"
  | "power"
  | "wifi"
  | "battery"
  | "bluetooth"      // app 0.4.2+
  | "display"        // app 0.4.2+
  | "apps-volume"    // app 0.4.2+: the per-app volume mixer page
  | "privacy-radios" // app 0.4.2+: where Windows lets apps control the radios

Opens a Windows settings page. panel is a whitelist key mapped host-side; widgets can never launch arbitrary settings targets. An app older than 0.4.2 rejects the newer keys with INVALID_PARAMS. 3 calls per rolling 10 seconds.

dd.power

Needs the power permission, which is deliberately separate from systemControls: granting a volume slider is not granting the power to turn the machine off.

dd.power.capabilities()

dd.power.capabilities(): Promise<{ sleep: boolean; hibernate: boolean }>

What this machine can actually do, read from its firmware. Check it before drawing a Sleep button: many desktops have no sleep state at all, and a button that fails every press reads as a broken widget. An unreadable answer reports true for both, so a machine that would have worked never loses its button. No gesture gate (a widget needs this before any interaction). 30 calls per rolling 10 seconds.

dd.power.run()

dd.power.run(action: "shutdown" | "restart" | "restartAdvanced" | "sleep" | "lock" | "signOut"): Promise<{ ran: boolean }>

Ends or suspends the Windows session. Only these six actions exist; nothing else (no flags, no timeouts, no targets) reaches the OS. Refused unless the real cursor is inside the widget, and refused to a desktop widget in edit mode (to a bar too before app 0.5.1), so a background timer can never trigger it. From a bar, the test is the bar window or its pane (app 0.3.7 or newer; older apps refuse bars outright).

restartAdvanced restarts into the advanced startup menu (recovery, firmware settings, safe mode), what shutdown /r /o does. App 0.3.7 or newer; an older app rejects it INVALID_PARAMS with "unknown power action", so catch that to feature-detect.

shutdown, restart, restartAdvanced and signOut first raise a host-drawn confirmation the widget cannot draw, style, or auto-answer; Cancel holds the initial focus, and Escape, closing the window, or a timeout all answer no. ran: false means the user declined, which is the moment to re-enable your button:

const { ran } = await dd.power.run("shutdown");
if (!ran) button.disabled = false;

sleep and lock skip the confirmation, being instantly reversible. Nothing here forces applications to close: an app with unsaved work still gets Windows' own "this app is preventing shutdown" screen. On actions that proceed, the session usually ends before the promise settles. 6 calls per rolling 10 seconds.