alfred-battery icon indicating copy to clipboard operation
alfred-battery copied to clipboard

Couldn't working on Apple M1 chips.

Open syhily opened this issue 3 years ago • 6 comments

This scripts cause error. echo "$INFO" | grep MaxCapacity | awk '{printf $3; exit}'

image

Here is a sample battery info from Apple M1

→ ioreg -l -n AppleSmartBattery -r
+-o AppleSmartBattery  <class AppleSmartBattery, id 0x100000710, registered, matched, active, busy 0 (1 ms), retain 8>
    {
      "PostChargeWaitSeconds" = 120
      "built-in" = Yes
      "AppleRawAdapterDetails" = ({"IsWireless"=No,"AdapterID"=0,"FamilyCode"=18446744073172697098,"UsbHvcHvcIndex"=0,"Watts"=15,"UsbHvcMenu"=({"Index"=0,"MaxC$
      "CurrentCapacity" = 100
      "PackReserve" = 133
      "DeviceName" = "bq20z451"
      "PostDischargeWaitSeconds" = 120
      "OCVData" = {}
      "LPEMData" = {}
      "CarrierMode" = {"CarrierModeLowVoltage"=3600,"CarrierModeHighVoltage"=4100,"CarrierModeStatus"=0}
      "TimeRemaining" = 0
      "ChargerConfiguration" = 2904
      "IOGeneralInterest" = "IOCommand is not serializable"
      "IOReportLegend" = ({"IOReportChannels"=((7167869599145487988,6460407809,"BatteryCycleCount")),"IOReportGroupName"="Battery","IOReportChannelInfo"={"IORe$
      "AtCriticalLevel" = No
      "BatteryCellDisconnectCount" = 0
      "UpdateTime" = 1613812945
      "Amperage" = 0
      "AppleRawCurrentCapacity" = 5103
      "AbsoluteCapacity" = 0
      "AvgTimeToFull" = 65535
      "ExternalConnected" = Yes
      "ExternalChargeCapable" = Yes
      "AppleRawBatteryVoltage" = 12874
      "BootVoltage" = 0
      "BatteryData" = {"Ra03"=0,"Ra10"=0,"CellWom"=(0,0),"RaTableRaw"=(<0000006e005f0073007d008e006b006e00730079007b0070008500c9015e0224>,<000000600051005d0066$
      "BatteryInstalled" = Yes
      "IOReportLegendPublic" = Yes
      "Serial" = "F5D05015H8RKGGJB4"
      "AppleRawExternalConnected" = Yes
      "KioskMode" = {"KioskModeLastHighSocHours"=0,"KioskModeFullChargeVoltage"=0,"KioskModeMode"=0,"KioskModeHighSocSeconds"=0,"KioskModeHighSocDays"=0}
      "NominalChargeCapacity" = 5103
      "FullyCharged" = Yes
      "FullPathUpdated" = 1613812645
      "ManufacturerData" = <00000000100200012400000003353339033031300341544c024d000000000000>
      "ChargingOverride" = 0
      "BatteryInvalidWakeSeconds" = 30
      "ChargerData" = {"ChargingCurrent"=0,"NotChargingReason"=4194305,"ChargerStatus"=45194,"ChargingVoltage"=4292,"VacVoltageLimit"=4350,"ChargerID"=18446744$
      "BootPathUpdated" = 1613301880
      "DesignCycleCount9C" = 1000
      "AdapterDetails" = {"IsWireless"=No,"AdapterID"=0,"FamilyCode"=18446744073172697098,"UsbHvcHvcIndex"=0,"Watts"=15,"UsbHvcMenu"=({"Index"=0,"MaxCurrent"=7$
      "MaxCapacity" = 100
      "InstantAmperage" = 0
      "GasGaugeFirmwareVersion" = 1
      "AdapterInfo" = 0
      "Location" = 0
      "Temperature" = 3052
      "AvgTimeToEmpty" = 65535
      "BestAdapterIndex" = 0
      "DesignCapacity" = 5103
      "IsCharging" = No
      "PermanentFailureStatus" = 0
      "Voltage" = 12874
      "UserVisiblePathUpdated" = 1613812945
      "CycleCount" = 16
      "AppleRawMaxCapacity" = 5158
      "VirtualTemperature" = 3200
    }

Change this line 8 to MAX_CAPACITY=$(echo "$INFO" | grep '"MaxCapacity" = ' | awk '{printf $3; exit}') fixed the issue.

syhily avatar Feb 20 '21 09:02 syhily

Thank you for reporting, and sharing a fix.

It is getting to a point where subtle changes in ioreg's output across OS versions (and now, chip versions?) is making it hard to maintain a fully compatible version of this workflow. Scraping off of ioreg's output was not really a robust solution to start with IMO.

I will keep this issue open for (1) visibility and (2) to see I can come up with a better approach.

BenziAhamed avatar Mar 19 '21 08:03 BenziAhamed

Thanks sharing @syhily Since line 58 also occurs errors on M1. Also with the temperature: image

h-jia avatar Sep 15 '21 16:09 h-jia

Here's the fix for x86 Big sur

#!/usr/bin/env bash

INFO=$(ioreg -l -n AppleSmartBattery -r)

# Charge and time remaining
CURRENT_CAPACITY=$(echo "$INFO" | grep CurrentCapacity | awk '{printf $3; exit}')
MAX_CAPACITY=$(echo "$INFO" | grep MaxCapacity | awk '{printf $3; exit}')
CHARGE=$((CURRENT_CAPACITY * 100 / MAX_CAPACITY))
CELLS=$(python -c "f='●'*($CHARGE/10) + '○'*(10-$CHARGE/10); print f")
STATUS_INFO=Draining...

CHARGING=$(echo "$INFO" | grep -i ischarging | awk '{printf("%s", $3)}')
TIME_TO_EMPTY=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%s", $3)}')
TIME_LEFT=Calculating…

if [ "$TIME_TO_EMPTY" -lt 15000 ]; then
    TIME_LEFT=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%i:%.2i", $3/60, $3%60)}')
fi

if [ "$CHARGING" == Yes ]; then
    TIME_FULL=$(echo "$INFO" | grep -i AvgTimeToFull | tr '\n' ' | ' | awk '{printf("%i:%.2i", $3/60, $3%60)}')
    TIME_INFO=$(echo "$TIME_FULL" until full)
    STATUS_INFO=Charging...
    BATT_ICON=charging.png
else
    FULLY_CHARGED=$(echo "$INFO" | grep -i FullyCharged | awk '{printf("%s", $3)}')
    EXTERNAL=$(echo "$INFO" | grep -i ExternalConnected | awk '{printf("%s", $3)}')
    if [ "$FULLY_CHARGED" == Yes ]; then
        if [ "$EXTERNAL" == Yes ]; then
            TIME_INFO="On AC power"
            STATUS_INFO="Fully Charged"
            BATT_ICON=power.png
        else
            TIME_INFO=$TIME_LEFT
            BATT_ICON=full.png
        fi
    else
        TIME_INFO=$TIME_LEFT
        BATT_ICON=critical.png
        if [ "$CHARGE" -gt 80 ]; then
            BATT_ICON=full.png
        elif [ "$CHARGE" -gt 50 ]; then
            BATT_ICON=medium.png
        elif [ "$CHARGE" -gt 10 ]; then
            BATT_ICON=low.png
        fi
    fi
fi

TRACKPAD_ICON=trackpad.png
# trackpad
TrackpadPercent=`ioreg -c AppleDeviceManagementHIDEventService | grep 'Magic Trackpad' -A8 | grep BatteryPercent | sed 's/[a-z,A-Z, ,|,\",=]//g' | tail -1 | awk '{print $1}'`
if [ ${#TrackpadPercent} = 0 ]
then
	TrackpadTitle="Not connected"
else
	TrackpadSlug=$(python -c "f='●'*($TrackpadPercent/10) + '○'*(10-$TrackpadPercent/10);print f")
	TrackpadTitle="$TrackpadPercent% $TrackpadSlug"
fi

MOUSE_ICON=mouse.png
# mouse
MousePercent=`ioreg -c AppleDeviceManagementHIDEventService | grep 'Magic Mouse' -A8 | grep BatteryPercent | sed 's/[a-z,A-Z, ,|,\",=]//g' | tail -1 | awk '{print $1}'`
if [ ${#MousePercent} = 0 ]
then
	MouseTitle="Not connected"
else
	MouseSlug=$(python -c "f='●'*($MousePercent/10) + '○'*(10-$MousePercent/10);print f")
	MouseTitle="$MousePercent% $MouseSlug"
fi

KEYBOARD_ICON=keyboard.png
# keyboard
KeyboardPercent=`ioreg -c AppleDeviceManagementHIDEventService | grep 'Magic Keyboard' -A8 | grep BatteryPercent | sed 's/[a-z,A-Z, ,|,\",=]//g' | tail -1 | awk '{print $1}'`
if [ ${#KeyboardPercent} = 0 ]
then
	KeyboardTitle="Not connected"
else
	KeyboardSlug=$(python -c "f='●'*($KeyboardPercent/10) + '○'*(10-$KeyboardPercent/10);print f")
	KeyboardTitle="$KeyboardPercent% $KeyboardSlug"
fi


# Temperature
TEMPERATURE=$(echo "$INFO" | grep Temperature | tail -1 | awk '{printf ("%.1f", $3/10-273)}')

# Cycle count
CYCLE_COUNT=$(echo "$INFO" | grep -e '"CycleCount" =' | awk '{printf ("%i", $3)}')

# Battery health
DESIGN_CAPACITY=$(echo "$INFO" | grep DesignCapacity | tail -1 | awk '{printf $3; exit}')
HEALTH=$((MAX_CAPACITY * 100 / DESIGN_CAPACITY))

if [ "$HEALTH" -gt 100 ]; then
    HEALTH=100
fi

# Serial
SERIAL=$(echo "$INFO" | grep -o 'SerialString.*$' | tail -1 | awk '{printf $1}' | grep SerialString |  awk -F '\\"Watts' '{print $1""}' | tr -d "SerialString" | tr -d '"' | tr -d '=' | tr -d ',')

# Battery age
MANUFACTURE_DATE=$(echo "$INFO" | grep ManufactureDate | awk '{printf ("%i", $3)}')
day=$((MANUFACTURE_DATE&31))
month=$(((MANUFACTURE_DATE>>5)&15))
year=$((1980+(MANUFACTURE_DATE>>9)))
AGE=$(python -c "from datetime import date as D; d1=D.today(); d2=D($year, $month, $day); print ( (d1.year - d2.year)*12 + d1.month - d2.month )")

# Alfred feedback
cat << EOB
<?xml version="1.0"?>
<items>
  <item>
    <title>$MouseTitle</title>
    <subtitle>Magic Mouse 2</subtitle>
    <icon>icons/$MOUSE_ICON</icon>
  </item>
  <item>
    <title>$KeyboardTitle</title>
    <subtitle>Magic Keyboard 2</subtitle>
    <icon>icons/$KEYBOARD_ICON</icon>
  </item>
  <item>
    <title>$TrackpadTitle</title>
    <subtitle>Magic TrackPad 2</subtitle>
    <icon>icons/$TRACKPAD_ICON</icon>
  </item>
  <item>
    <title>$CHARGE% $CELLS</title>
	<subtitle>$STATUS_INFO</subtitle>
	<icon>icons/$BATT_ICON</icon>
  </item>
  <item>
    <title>$TIME_INFO</title>
	<subtitle>Time Left</subtitle>
	<icon>icons/clock.png</icon>
  </item>
  <item>
    <title>$TEMPERATURE °C</title>
	<subtitle>Temperature</subtitle>
	<icon>icons/temp.png</icon>
  </item>
  <item>
    <title>$CYCLE_COUNT</title>
	<subtitle>Charge Cycles Completed</subtitle>
	<icon>icons/cycles.png</icon>
  </item>
  <item>
    <title>$HEALTH%</title>
	<subtitle>Health</subtitle>
	<icon>icons/health.png</icon>
  </item>
  <item>
    <title>$SERIAL</title>
	<subtitle>Serial</subtitle>
	<icon>icons/serial.png</icon>
  </item>
  <item>
    <title>$AGE months</title>
	<subtitle>Age</subtitle>
	<icon>icons/age.png</icon>
  </item>
</items>
EOB

zenopopovici avatar Sep 24 '21 18:09 zenopopovici

Here is the configuration for M1. Battery age is impossible to calculate, it seems they don't follow the standard anymore.

#!/usr/bin/env bash

INFO=$(ioreg -l -n AppleSmartBattery -r)

# Charge and time remaining
CURRENT_CAPACITY=$(echo "$INFO" | grep AppleRawCurrentCapacity | awk '{printf $3; exit}')
MAX_CAPACITY=$(echo "$INFO" | grep \"AppleRawMaxCapacity\" | tail -1 | awk '{printf $3; exit}')
CHARGE=$((CURRENT_CAPACITY * 100 / MAX_CAPACITY))
CELLS=$(python -c "f='●'*($CHARGE/10) + '○'*(10-$CHARGE/10); print f")
STATUS_INFO=Draining...

CHARGING=$(echo "$INFO" | grep -i ischarging | awk '{printf("%s", $3)}')
TIME_TO_EMPTY=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%s", $3)}')
TIME_LEFT=Calculating…

if [ "$TIME_TO_EMPTY" -lt 65536 ]; then
    TIME_LEFT=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%i:%.2i", $3/60/60, $3%60)}')
fi

if [ "$CHARGING" == Yes ]; then
    TIME_FULL=$(echo "$INFO" | grep -i AvgTimeToFull | tr '\n' ' | ' | awk '{printf("%i:%.2i", $3/60, $3%60)}')
    TIME_INFO=$(echo "$TIME_FULL" until full)
    STATUS_INFO=Charging...
    BATT_ICON=charging.png
else
    FULLY_CHARGED=$(echo "$INFO" | grep -i FullyCharged | awk '{printf("%s", $3)}')
    EXTERNAL=$(echo "$INFO" | grep -i ExternalConnected | awk '{printf("%s", $3)}')
    if [ "$FULLY_CHARGED" == Yes ]; then
        if [ "$EXTERNAL" == Yes ]; then
            TIME_INFO="On AC power"
            STATUS_INFO="Fully Charged"
            BATT_ICON=power.png
        else
            TIME_INFO=$TIME_LEFT
            BATT_ICON=full.png
        fi
    else
        TIME_INFO=$TIME_LEFT
        BATT_ICON=critical.png
        if [ "$CHARGE" -gt 80 ]; then
            BATT_ICON=full.png
        elif [ "$CHARGE" -gt 50 ]; then
            BATT_ICON=medium.png
        elif [ "$CHARGE" -gt 10 ]; then
            BATT_ICON=low.png
        fi
    fi
fi

TRACKPAD_ICON=trackpad.png
# trackpad
TrackpadPercent=`ioreg -c AppleDeviceManagementHIDEventService | grep 'Magic Trackpad' -A8 | grep BatteryPercent | sed 's/[a-z,A-Z, ,|,\",=]//g' | tail -1 | awk '{print $1}'`
if [ ${#TrackpadPercent} = 0 ]
then
	TrackpadTitle="Not connected"
else
	TrackpadSlug=$(python -c "f='●'*($TrackpadPercent/10) + '○'*(10-$TrackpadPercent/10);print f")
	TrackpadTitle="$TrackpadPercent% $TrackpadSlug"
fi

MOUSE_ICON=mouse.png
# mouse
MousePercent=`ioreg -c AppleDeviceManagementHIDEventService | grep 'Magic Mouse' -A8 | grep BatteryPercent | sed 's/[a-z,A-Z, ,|,\",=]//g' | tail -1 | awk '{print $1}'`
if [ ${#MousePercent} = 0 ]
then
	MouseTitle="Not connected"
else
	MouseSlug=$(python -c "f='●'*($MousePercent/10) + '○'*(10-$MousePercent/10);print f")
	MouseTitle="$MousePercent% $MouseSlug"
fi

KEYBOARD_ICON=keyboard.png
# keyboard
KeyboardPercent=`ioreg -c AppleDeviceManagementHIDEventService | grep 'Magic Keyboard' -A8 | grep BatteryPercent | sed 's/[a-z,A-Z, ,|,\",=]//g' | tail -1 | awk '{print $1}'`
if [ ${#KeyboardPercent} = 0 ]
then
	KeyboardTitle="Not connected"
else
	KeyboardSlug=$(python -c "f='●'*($KeyboardPercent/10) + '○'*(10-$KeyboardPercent/10);print f")
	KeyboardTitle="$KeyboardPercent% $KeyboardSlug"
fi


# Temperature
TEMPERATURE=$(echo "$INFO" | grep Temperature | tail -1 | awk '{printf ("%.1f", $3/10-273)}')

# Cycle count
CYCLE_COUNT=$(echo "$INFO" | grep -e '"CycleCount" =' | awk '{printf ("%i", $3)}')

# Battery health
HEALTH=$((CURRENT_CAPACITY * 100 / MAX_CAPACITY))

if [ "$HEALTH" -gt 100 ]; then
    HEALTH=100
fi

# Serial
SERIAL=$(echo "$INFO" | grep -o 'SerialString.*$' | tail -1 | awk '{printf $1}' | grep SerialString |  awk -F '\\"Watts' '{print $1""}' | tr -d "SerialString" | tr -d '"' | tr -d '=' | tr -d ',')

# Battery age
# MANUFACTURE_DATE=$(echo "$INFO" | grep -o 'ManufactureDate.*$' | awk -F '\\"ISS' '{print $1""}' | tr -d "ManufactureDate" | tr -d '"' | tr -d '=' | tr -d ',')
# day=$((MANUFACTURE_DATE&31))
# month=$(((MANUFACTURE_DATE>>5)&15))
# year=$((1980+(MANUFACTURE_DATE>>9)))
# AGE=$(python -c "from datetime import date as D; d1=D.today(); d2=D($year, $month, $day); print ( (d1.year - d2.year)*12 + d1.month - d2.month )")

# Alfred feedback
cat << EOB
<?xml version="1.0"?>
<items>
  <item>
    <title>$MouseTitle</title>
    <subtitle>Magic Mouse 3</subtitle>
    <icon>icons/$MOUSE_ICON</icon>
  </item>
  <item>
    <title>$KeyboardTitle</title>
    <subtitle>Magic Keyboard 3</subtitle>
    <icon>icons/$KEYBOARD_ICON</icon>
  </item>$
  <item>
    <title>$TrackpadTitle</title>
    <subtitle>Magic TrackPad 3</subtitle>
    <icon>icons/$TRACKPAD_ICON</icon>
  </item>
  <item>
    <title>$CHARGE% $CELLS</title>
	<subtitle>$STATUS_INFO</subtitle>
	<icon>icons/$BATT_ICON</icon>
  </item>
  <item>
    <title>$TIME_INFO</title>
	<subtitle>Time Left</subtitle>
	<icon>icons/clock.png</icon>
  </item>
  <item>
    <title>$TEMPERATURE °C</title>
	<subtitle>Temperature</subtitle>
	<icon>icons/temp.png</icon>
  </item>
  <item>
    <title>$CYCLE_COUNT</title>
	<subtitle>Charge Cycles Completed</subtitle>
	<icon>icons/cycles.png</icon>
  </item>
  <item>
    <title>$HEALTH%</title>
	<subtitle>Health</subtitle>
	<icon>icons/health.png</icon>
  </item>
  <item>
    <title>$SERIAL</title>
	<subtitle>Serial</subtitle>
	<icon>icons/serial.png</icon>
  </item>
</items>
EOB

# <item>
#     <title>$AGE months</title>
# 	<subtitle>Age</subtitle>
# 	<icon>icons/age.png</icon>
#   </item>

zenopopovici avatar Oct 05 '21 20:10 zenopopovici

I have fixed the issues for Apple Silicon and x86. Hopefully this fixes it for some time in the future. I don't have an x86 MBP any more to test this. There is a pull request pending and I don't know when the author will look into it, but if you are interested, you can look at the PR repo and copy the shell script to get it working again.

Screenshot

adwaraki avatar May 06 '22 04:05 adwaraki

A version on BigSur with fixes for DesignCapacity and Serial format changes:

#!/usr/bin/env bash

INFO=$(ioreg -l -n AppleSmartBattery -r)

# Charge and time remaining
CURRENT_CAPACITY=$(echo "$INFO" | grep CurrentCapacity | awk '{printf $3; exit}')
MAX_CAPACITY=$(echo "$INFO" | grep MaxCapacity | awk '{printf $3; exit}')
CHARGE=$((CURRENT_CAPACITY * 100 / MAX_CAPACITY))
CELLS=$(python -c "f='●'*($CHARGE/10) + '○'*(10-$CHARGE/10); print f")
STATUS_INFO=Draining...

CHARGING=$(echo "$INFO" | grep -i ischarging | awk '{printf("%s", $3)}')
TIME_TO_EMPTY=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%s", $3)}')
TIME_LEFT=Calculating…

if [ "$TIME_TO_EMPTY" -lt 15000 ]; then
    TIME_LEFT=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%i:%.2i", $3/60, $3%60)}')
fi

if [ "$CHARGING" == Yes ]; then
    TIME_FULL=$(echo "$INFO" | grep -i AvgTimeToFull | tr '\n' ' | ' | awk '{printf("%i:%.2i", $3/60, $3%60)}')
    TIME_INFO="$TIME_FULL until full"
    STATUS_INFO=Charging...
    BATT_ICON=charging.png
else
    FULLY_CHARGED=$(echo "$INFO" | grep -i FullyCharged | awk '{printf("%s", $3)}')
    EXTERNAL=$(echo "$INFO" | grep -i ExternalConnected | awk '{printf("%s", $3)}')
    if [ "$FULLY_CHARGED" == Yes ]; then
        if [ "$EXTERNAL" == Yes ]; then
            TIME_INFO="On AC power"
            STATUS_INFO="Fully Charged"
            BATT_ICON=power.png
        else
            TIME_INFO=$TIME_LEFT
            BATT_ICON=full.png
        fi
    else
        TIME_INFO=$TIME_LEFT
        BATT_ICON=critical.png
        if [ "$CHARGE" -gt 80 ]; then
            BATT_ICON=full.png
        elif [ "$CHARGE" -gt 50 ]; then
            BATT_ICON=medium.png
        elif [ "$CHARGE" -gt 10 ]; then
            BATT_ICON=low.png
        fi
    fi
fi

# Temperature
TEMPERATURE=$(echo "$INFO" | grep Temperature | awk '{printf ("%.1f", $3/10-273)}')

# Cycle count
CYCLE_COUNT=$(echo "$INFO" | grep -e '"CycleCount" =' | awk '{printf ("%i", $3)}')

# Battery health
DESIGN_CAPACITY=$(echo "$INFO" | grep '"DesignCapacity" =' | awk '{printf $3; exit}')
HEALTH=$((MAX_CAPACITY * 100 / DESIGN_CAPACITY))

if [ "$HEALTH" -gt 100 ]; then
    HEALTH=100
fi

# Serial
SERIAL=$(echo "$INFO" | grep '"Serial" = ' | awk '{printf ("%s", $3)}' | tr -d '"')

# Battery age
MANUFACTURE_DATE=$(echo "$INFO" | grep ManufactureDate | awk '{printf ("%i", $3)}')
day=$((MANUFACTURE_DATE&31))
month=$(((MANUFACTURE_DATE>>5)&15))
year=$((1980+(MANUFACTURE_DATE>>9)))
AGE=$(python -c "from datetime import date as D; d1=D.today(); d2=D($year, $month, $day); print ( (d1.year - d2.year)*12 + d1.month - d2.month )")

# Alfred feedback
cat << EOB
<?xml version="1.0"?>
<items>
  <item>
    <title>$CHARGE% $CELLS</title>
	<subtitle>$STATUS_INFO</subtitle>
	<icon>icons/$BATT_ICON</icon>
  </item>
  <item>
    <title>$TIME_INFO</title>
	<subtitle>Time Left</subtitle>
	<icon>icons/clock.png</icon>
  </item>
  <item>
    <title>$TEMPERATURE °C</title>
	<subtitle>Temperature</subtitle>
	<icon>icons/temp.png</icon>
  </item>
  <item>
    <title>$CYCLE_COUNT</title>
	<subtitle>Charge Cycles Completed</subtitle>
	<icon>icons/cycles.png</icon>
  </item>
  <item>
    <title>$HEALTH%</title>
	<subtitle>Health</subtitle>
	<icon>icons/health.png</icon>
  </item>
  <item>
    <title>$SERIAL</title>
	<subtitle>Serial</subtitle>
	<icon>icons/serial.png</icon>
  </item>
  <item>
    <title>$AGE months</title>
	<subtitle>Age</subtitle>
	<icon>icons/age.png</icon>
  </item>
</items>
EOB

benknoble avatar Nov 15 '22 18:11 benknoble