macotron.system
Read the state of the Mac: CPU, GPU, memory, disk, network totals, processes, battery, and fans. Switch Dark Mode and Low Power Mode, and format the time in another zone.
// CPU and memory pressure in the menu bar, every two seconds.
function render() {
const cpu = Math.round(macotron.system.cpu().usage);
const { pressure } = macotron.system.memory();
macotron.menubar.status("load", {
title: cpu + "%",
color: pressure === "normal" ? undefined : "orange",
});
}
render();
macotron.every(2000, render);
CPU and GPU
cpu(): { usage, performance, efficiency, performanceCores, efficiencyCores }
usage is the busy percentage, 0…100, of all cores together since the previous call. The counters are shared by all plugins, so the window runs from whichever plugin called last. Call it on a steady timer for a steady reading.
performance and efficiency are the busy percentages of each core cluster on Apple silicon. performanceCores and efficiencyCores are the logical core counts. An Intel Mac reports every core as a performance core and efficiencyCores as 0.
gpu(): { name, usage } | null
The GPU's name and its utilization in percent. usage is 0 when macOS does not report it. Returns null when the Mac has no Metal GPU.
processes(limit?: number): Promise<Array<{ name, pid, cpu }>>
The processes using the most CPU, highest first. limit defaults to 10. cpu is the percentage that ps reports, where 100 is one full core, so a busy process can go above 100. name is the executable path or name.
Memory, disk, and network
memory(): { total, used, free, active, inactive, wired, compressed, pressure }
All sizes are bytes. used is active plus wired plus compressed memory, and free is total minus used, so free includes the file cache.
pressure is "normal", "warning", or "critical": the same signal as Activity Monitor's memory pressure graph. Read pressure to warn about memory. Do not compare used to total: macOS fills free memory with cache on purpose, so a Mac that looks nearly full with normal pressure is healthy.
disk(): { total, free, used }
Bytes on the startup volume. free is the space available for important use, which counts purgeable space that macOS can clear.
network(): { bytesIn, bytesOut }
Total bytes received and sent on every interface except loopback, since the interfaces came up. Take two readings and subtract to get a rate.
The counters come from 32-bit fields, so each interface wraps at 4 GiB. A rate that goes negative means a counter wrapped; skip that sample. For per-interface counters, see macotron.network.counters().
Battery and Low Power Mode
battery(): Battery
| Field | Meaning |
|---|---|
level | Charge in percent, 0…100. -1 on a Mac with no battery. |
charging | true while on AC power, even when the battery is full. Read charged to tell the two apart. |
charged | true when the battery is full. |
timeRemaining | Minutes until empty, or -1 when unknown. |
timeToFull | Minutes until full, or -1 when unknown. |
source | "ac" or "battery". |
health | Maximum capacity as a percent of the design capacity. Only when known. |
cycles | Charge cycle count. Only when known. |
watts | The power adapter's wattage. Only when known. |
lowPowerMode | Whether Low Power Mode is on. |
setLowPowerMode(enabled: boolean): Promise<{ ok, lowPowerMode, error? }>
Turns Low Power Mode on or off for both battery and power adapter, with pmset. macOS asks the user for an administrator password, and the promise resolves after the user answers. If the user cancels, ok is false, error says why, and lowPowerMode is the current setting.
Fans
Any plugin can read fan speeds. Setting a minimum speed, the fan floor, needs the Macotron background helper, because the fans are changed with root privileges. To offer the helper, put "helper" in the permissions of macotron.plugin(). The plugin's Settings page then shows an Install button.
fans(): FanState
| Field | Meaning |
|---|---|
available | true when this Mac has fans that can be read. |
controllable | true when a floor can be set now: the Mac has fans and the helper is installed. |
floor | The minimum in percent while Macotron holds one. Absent when the fans follow macOS. |
error | Why the fans could not be read, when they could not. |
fans | Array<{ index, rpm, min, max }>: the current, minimum, and maximum speed of each fan in RPM. |
setFanFloor(percent: number | null): Promise<FanState>
Holds the fans at or above percent of the range from each fan's minimum to its maximum speed. Values above 100 count as 100. null, or a value of 0 or less, gives control back to macOS. Resolves with the new fans() state. When the helper is not installed or cannot be reached, the state carries an error.
The floor never lowers a fan below the speed macOS wants. A floor below 100% is released when the Mac's thermal state reaches serious, so that macOS can run the fans faster.
A plugin reload keeps the floor only if a plugin sets it again while loading. If no plugin claims it, the fans go back to macOS. When Macotron quits, the helper gives the fans back too, so store the floor (for example in localStorage) and set it again at load.
const saved = Number(localStorage.getItem("fan.floor")) || null;
if (saved) macotron.system.setFanFloor(saved);
Appearance and Focus
darkMode(): boolean
Whether the system shows Dark Mode now. This is the macOS appearance, not Macotron's own Settings theme. To pick colors for the menu bar, read macotron.menubar.isDark() instead, because the menu bar follows the wallpaper.
setDarkMode(on: boolean): Promise<{ ok, darkMode, error? }>
Switches the system to Dark or Light Mode. If the direct switch is not available, Macotron asks System Events instead, and macOS can ask the user to allow that the first time.
appearance(): "light" | "dark" | "auto"
The appearance setting. "auto" means macOS switches with the time of day; it reads "auto" whichever theme shows now.
setAppearance(mode: "light" | "dark" | "auto"): Promise<{ ok, appearance, error? }>
Sets the appearance. "light" and "dark" turn off automatic switching first. Throws a TypeError for any other mode.
const next = { light: "dark", dark: "auto", auto: "light" }[macotron.system.appearance()];
macotron.system.setAppearance(next);
focus(): { focused: boolean }
Whether a Focus mode, such as Do Not Disturb, Sleep, or Work, is on. It reads false until macOS gives Macotron access to Focus status. You cannot change Focus from here.
home(): string
The path of the user's home folder, such as "/Users/alex". Every macotron.fs call already expands ~; use this when you build a path to compare against, or one for a tool that does not.
Locale and time zones
The JavaScript runtime has no Intl, so use these calls to format for the user's locale or for another zone.
locale(): { language, region, measurement, hour12 }
language is a code such as "en" and region a code such as "US"; either can be "". measurement is "metric" or "us". hour12 is true when the user's clock shows AM and PM.
timeIn(zone: string, format?: string): string
The time now in an IANA zone such as "Europe/London", or in a zone abbreviation such as "PST". format is a Unicode date pattern and defaults to "HH:mm". Returns "" for a zone macOS does not know.
macotron.system.timeIn("Asia/Tokyo"); // "02:42"
macotron.system.timeIn("Asia/Tokyo", "EEE h:mm a"); // "Fri 2:42 AM"
See also
- macotron.power to keep the Mac awake, and for sleep and lock events.
- macotron.network for Wi-Fi, Bluetooth, and per-interface counters.
- macotron.display for Night Shift, True Tone, and grayscale.
- The
system-metrics.js,battery.js,fan.js,appearance.js, andworld-clock.jsplugins.