All widgets
Battery
Comes with Chopstick
Battery level, charging state and time left; pops up briefly when the battery drops to 20% on battery power and when you plug in the charger.
Already installed? It's in your widget library.





Type it in the notch's search
- Show battery
What it runs
A widget is a folder of plain files. Here is all of its code.
widget.json
{
"id": "battery",
"name": "Battery",
"icon": "icon.png",
"description": "Battery level, charging state and time left; pops up briefly when the battery drops to 20% on battery power and when you plug in the charger.",
"watch": [
{
"script": "battery.sh",
"every": 60,
"as": "batt"
}
],
"triggers": [
{
"when": {
"batt.low": true
},
"open": "low"
},
{
"when": {
"batt.pop": true
},
"open": "charging"
}
],
"initial": "glance",
"anytime": true,
"states": {
"glance": {
"on_enter": [
{
"run": "health.sh"
}
],
"compact": {
"leading": {
"symbol": "{{batt.symbol | battery.100percent}}",
"tint": "{{batt.tint | gray}}"
},
"trailing": {
"text": "{{batt.label}}"
}
},
"expanded": {
"size": "compact",
"header": {
"symbol": "{{batt.symbol | battery.100percent}}",
"tint": "{{batt.tint | gray}}",
"title": "Battery"
},
"blocks": [
{
"progress": {
"value": "{{batt.pct | 0}}",
"max": "100",
"label": "{{batt.status}}",
"tint": "{{batt.tint | gray}}"
}
},
{
"note": "{{batt.time}}"
},
{
"note": "{{result.health}}"
}
]
}
},
"low": {
"open": false,
"dismiss_after": 4,
"compact": {
"leading": {
"symbol": "{{batt.symbol | battery.25percent}}",
"tint": "{{batt.tint | orange}}"
},
"trailing": {
"text": "{{batt.label}}"
}
},
"expanded": {
"size": "compact",
"header": {
"symbol": "{{batt.symbol | battery.25percent}}",
"tint": "{{batt.tint | orange}}",
"title": "Battery Low"
},
"blocks": [
{
"progress": {
"value": "{{batt.pct | 0}}",
"max": "100",
"label": "{{batt.time | On battery}}",
"tint": "{{batt.tint | orange}}"
}
}
]
}
},
"charging": {
"open": false,
"dismiss_after": 4,
"compact": {
"leading": {
"symbol": "battery.100percent.bolt",
"tint": "green"
},
"trailing": {
"text": "{{batt.pct}}%"
}
},
"expanded": {
"size": "compact",
"header": {
"symbol": "battery.100percent.bolt",
"tint": "green",
"title": "{{batt.status | Charging}}"
},
"blocks": [
{
"progress": {
"value": "{{batt.pct | 0}}",
"max": "100",
"label": "{{batt.full_in | Plugged in}}",
"tint": "green"
}
}
]
}
}
},
"commands": {
"show": {
"description": "Show the battery level, charging state, time left and battery health.",
"phrase": "Show battery", "preview": { "state": "glance", "run": "health.sh" },
"do": [
{
"go": "glance"
}
]
}
},
"preview": {
"states": [
"glance",
"low",
"charging"
],
"data": {
"batt": {
"present": true,
"low": true,
"pop": false,
"ac": false,
"pct": 14,
"symbol": "battery.25percent",
"tint": "orange",
"status": "On battery",
"time": "38m left",
"full_in": "Full in 1h 50m",
"label": "14%"
},
"result": {
"cycles": "71",
"capacity": "98",
"health": "Maximum capacity 98% · 71 cycles"
}
}
}
}
battery.sh
#!/bin/sh
# Battery state from `pmset -g batt`, as one JSON object.
# `pop` is true for one run after the charger is plugged in; the last power
# source is kept in $CHOPSTICK_STORAGE so a restart doesn't announce it again.
OUT=$(pmset -g batt 2>/dev/null)
LINE=$(printf '%s\n' "$OUT" | grep InternalBattery | head -1)
if [ -z "$LINE" ]; then
echo '{"present":false,"low":false,"pop":false,"ac":true,"pct":0,"label":"No battery","symbol":"powerplug.fill","tint":"gray","status":"No battery","time":"","full_in":""}'
exit 0
fi
# " -InternalBattery-0 (id=…) 82%; charging; 1:05 remaining present: true"
PCT=$(printf '%s' "$LINE" | sed -n 's/.*[^0-9]\([0-9][0-9]*\)%;.*/\1/p')
STATE=$(printf '%s' "$LINE" | sed -n 's/.*%; *\([^;]*\);.*/\1/p')
HM=$(printf '%s' "$LINE" | sed -n 's/.*; *\([0-9][0-9]*:[0-9][0-9]\) remaining.*/\1/p')
[ -n "$PCT" ] || PCT=0
case "$OUT" in *"'AC Power'"*) AC=true ;; *) AC=false ;; esac
# "1:05" -> "1h 5m"; nothing for "0:00" or no estimate.
DUR=""
if [ -n "$HM" ] && [ "$HM" != "0:00" ]; then
H=${HM%%:*}; M=$(expr "${HM##*:}" + 0)
if [ "$H" -gt 0 ]; then DUR="${H}h ${M}m"; else DUR="${M}m"; fi
fi
TIME=""; FULL=""
case "$STATE" in
charging) STATUS="Charging"; [ -n "$DUR" ] && FULL="Full in $DUR" ;;
"finishing charge") STATUS="Finishing charge"; [ -n "$DUR" ] && FULL="Full in $DUR" ;;
charged) STATUS="Charged" ;;
"AC attached") STATUS="Plugged in, not charging" ;;
*) STATUS="On battery"; [ -n "$DUR" ] && TIME="$DUR left" ;;
esac
[ -n "$FULL" ] && TIME="$FULL"
if [ "$AC" = true ]; then
SYMBOL="battery.100percent.bolt"; TINT="green"; LOW=false
else
if [ "$PCT" -le 10 ]; then SYMBOL="battery.0percent"
elif [ "$PCT" -le 35 ]; then SYMBOL="battery.25percent"
elif [ "$PCT" -le 60 ]; then SYMBOL="battery.50percent"
elif [ "$PCT" -le 85 ]; then SYMBOL="battery.75percent"
else SYMBOL="battery.100percent"; fi
if [ "$PCT" -le 10 ]; then TINT="red"; LOW=true
elif [ "$PCT" -le 20 ]; then TINT="orange"; LOW=true
else TINT="#FFFFFF"; LOW=false; fi
fi
# Pop once per plug-in: only on a change from battery to AC we saw ourselves.
POP=false
F="$CHOPSTICK_STORAGE/power"
NOW=battery; [ "$AC" = true ] && NOW=ac
if [ -n "$CHOPSTICK_STORAGE" ]; then
PREV=$(cat "$F" 2>/dev/null)
[ "$NOW" = ac ] && [ "$PREV" = battery ] && POP=true
if [ "$NOW" != "$PREV" ]; then mkdir -p "$CHOPSTICK_STORAGE" && echo "$NOW" > "$F"; fi
fi
printf '{"present":true,"low":%s,"pop":%s,"ac":%s,"pct":%d,"label":"%d%%","symbol":"%s","tint":"%s","status":"%s","time":"%s","full_in":"%s"}\n' \
"$LOW" "$POP" "$AC" "$PCT" "$PCT" "$SYMBOL" "$TINT" "$STATUS" "$TIME" "$FULL"
health.sh
#!/bin/sh
# Cycle count and maximum capacity from ioreg (run when the card opens).
IO=$(ioreg -rc AppleSmartBattery 2>/dev/null)
val() { printf '%s\n' "$IO" | sed -n "s/^[ |]*\"$1\" = \([0-9][0-9]*\)\$/\1/p" | head -1; }
CYCLES=$(val CycleCount); MAX=$(val MaxCapacity); DESIGN=$(val DesignCapacity)
# Apple silicon reports MaxCapacity as a percent; Intel Macs in mAh.
CAP=""
if [ -n "$MAX" ]; then
if [ "$MAX" -le 100 ]; then CAP=$MAX
elif [ -n "$DESIGN" ] && [ "$DESIGN" -gt 0 ]; then CAP=$((MAX * 100 / DESIGN)); fi
fi
LINE=""
[ -n "$CAP" ] && LINE="Maximum capacity $CAP%"
[ -n "$CYCLES" ] && LINE="${LINE:+$LINE · }$CYCLES cycles"
printf '{"cycles":"%s","capacity":"%s","health":"%s"}\n' "$CYCLES" "$CAP" "$LINE"