├── .gitignore
├── Battery.alfredworkflow
├── README.md
├── info.png
└── src
├── battery.sh
├── icon.png
├── icons
├── age.png
├── charging.png
├── clock.png
├── critical.png
├── cycles.png
├── full.png
├── health.png
├── low.png
├── medium.png
├── power.png
├── serial.png
└── temp.png
└── info.plist
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/Battery.alfredworkflow:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/Battery.alfredworkflow
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Battery
2 |
3 | > For Apple M1 chip users: https://github.com/BenziAhamed/alfred-battery/issues/11#issue-812562822
4 |
5 | 
6 |
7 | An Alfred workflow to display battery information of your Apple laptop.
8 |
--------------------------------------------------------------------------------
/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/info.png
--------------------------------------------------------------------------------
/src/battery.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | INFO=$(ioreg -l -n AppleSmartBattery -r)
4 |
5 | # Charge and time remaining
6 | CURRENT_CAPACITY=$(echo "$INFO" | grep CurrentCapacity | awk '{printf $3; exit}')
7 | MAX_CAPACITY=$(echo "$INFO" | grep MaxCapacity | awk '{printf $3; exit}')
8 | CHARGE=$((CURRENT_CAPACITY * 100 / MAX_CAPACITY))
9 | CELLS=$(python -c "f='●'*($CHARGE/10) + '○'*(10-$CHARGE/10); print f")
10 | STATUS_INFO=Draining...
11 |
12 | CHARGING=$(echo "$INFO" | grep -i ischarging | awk '{printf("%s", $3)}')
13 | TIME_TO_EMPTY=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%s", $3)}')
14 | TIME_LEFT=Calculating…
15 |
16 | if [ "$TIME_TO_EMPTY" -lt 15000 ]; then
17 | TIME_LEFT=$(echo "$INFO" | grep -i AvgTimeToEmpty | awk '{printf("%i:%.2i", $3/60, $3%60)}')
18 | fi
19 |
20 | if [ "$CHARGING" == Yes ]; then
21 | TIME_FULL=$(echo "$INFO" | grep -i AvgTimeToFull | tr '\n' ' | ' | awk '{printf("%i:%.2i", $3/60, $3%60)}')
22 | TIME_INFO=$(echo "$TIME_FULL" until full)
23 | STATUS_INFO=Charging...
24 | BATT_ICON=charging.png
25 | else
26 | FULLY_CHARGED=$(echo "$INFO" | grep -i FullyCharged | awk '{printf("%s", $3)}')
27 | EXTERNAL=$(echo "$INFO" | grep -i ExternalConnected | awk '{printf("%s", $3)}')
28 | if [ "$FULLY_CHARGED" == Yes ]; then
29 | if [ "$EXTERNAL" == Yes ]; then
30 | TIME_INFO="On AC power"
31 | STATUS_INFO="Fully Charged"
32 | BATT_ICON=power.png
33 | CHARGE="100"
34 | CELLS="●●●●●●●●●●"
35 | else
36 | TIME_INFO=$TIME_LEFT
37 | BATT_ICON=full.png
38 | fi
39 | else
40 | TIME_INFO=$TIME_LEFT
41 | BATT_ICON=critical.png
42 | if [ "$CHARGE" -gt 80 ]; then
43 | BATT_ICON=full.png
44 | elif [ "$CHARGE" -gt 50 ]; then
45 | BATT_ICON=medium.png
46 | elif [ "$CHARGE" -gt 10 ]; then
47 | BATT_ICON=low.png
48 | fi
49 | fi
50 | fi
51 |
52 | # Temperature
53 | TEMPERATURE=$(echo "$INFO" | grep Temperature | awk '{printf ("%.1f", $3/10-273)}')
54 |
55 | # Cycle count
56 | CYCLE_COUNT=$(echo "$INFO" | grep -e '"CycleCount" =' | awk '{printf ("%i", $3)}')
57 |
58 | # Battery health
59 | # ref: https://github.com/BenziAhamed/alfred-battery/issues/10#issuecomment-745541202
60 | DESIGN_CAPACITY=$(echo "$INFO" | grep DesignCapacity | awk '{printf ("%.i", $3)}')
61 | HEALTH=$((MAX_CAPACITY * 100 / DESIGN_CAPACITY))
62 |
63 | if [ "$HEALTH" -gt 100 ]; then
64 | HEALTH=100
65 | fi
66 |
67 | # Serial
68 | SERIAL=$(echo "$INFO" | grep BatterySerialNumber | awk '{printf ("%s", $3)}' | tr -d '"')
69 |
70 | # Battery age
71 | MANUFACTURE_DATE=$(echo "$INFO" | grep ManufactureDate | awk '{printf ("%i", $3)}')
72 | day=$((MANUFACTURE_DATE&31))
73 | month=$(((MANUFACTURE_DATE>>5)&15))
74 | year=$((1980+(MANUFACTURE_DATE>>9)))
75 | 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 )")
76 |
77 | # Alfred feedback
78 | cat << EOB
79 |
80 |
81 | -
82 | $CHARGE% $CELLS
83 | $STATUS_INFO
84 | icons/$BATT_ICON
85 |
86 | -
87 | $TIME_INFO
88 | Time Left
89 | icons/clock.png
90 |
91 | -
92 | $TEMPERATURE °C
93 | Temperature
94 | icons/temp.png
95 |
96 | -
97 | $CYCLE_COUNT
98 | Charge Cycles Completed
99 | icons/cycles.png
100 |
101 | -
102 | $HEALTH%
103 | Health
104 | icons/health.png
105 |
106 | -
107 | $SERIAL
108 | Serial
109 | icons/serial.png
110 |
111 | -
112 | $AGE months
113 | Age
114 | icons/age.png
115 |
116 |
117 | EOB
118 |
--------------------------------------------------------------------------------
/src/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icon.png
--------------------------------------------------------------------------------
/src/icons/age.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/age.png
--------------------------------------------------------------------------------
/src/icons/charging.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/charging.png
--------------------------------------------------------------------------------
/src/icons/clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/clock.png
--------------------------------------------------------------------------------
/src/icons/critical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/critical.png
--------------------------------------------------------------------------------
/src/icons/cycles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/cycles.png
--------------------------------------------------------------------------------
/src/icons/full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/full.png
--------------------------------------------------------------------------------
/src/icons/health.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/health.png
--------------------------------------------------------------------------------
/src/icons/low.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/low.png
--------------------------------------------------------------------------------
/src/icons/medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/medium.png
--------------------------------------------------------------------------------
/src/icons/power.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/power.png
--------------------------------------------------------------------------------
/src/icons/serial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/serial.png
--------------------------------------------------------------------------------
/src/icons/temp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BenziAhamed/alfred-battery/78fa684b4b05a44b240e9e2b3eb9c8b2ffcf1734/src/icons/temp.png
--------------------------------------------------------------------------------
/src/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bundleid
6 | com.benzi.a2w.battery
7 | category
8 | Tools
9 | connections
10 |
11 | 3917FDAB-460E-4C28-A4A9-645B9773F34A
12 |
13 |
14 | destinationuid
15 | FC5EB146-FA11-4E33-8456-F60EA94E7EEE
16 | modifiers
17 | 0
18 | modifiersubtext
19 |
20 | vitoclose
21 |
22 |
23 |
24 | FC5EB146-FA11-4E33-8456-F60EA94E7EEE
25 |
26 |
27 | createdby
28 | Benzi Ahamed
29 | description
30 | Displays information about your laptop battery
31 | disabled
32 |
33 | name
34 | Battery
35 | objects
36 |
37 |
38 | config
39 |
40 | action
41 | 0
42 | argument
43 | 0
44 | focusedappvariable
45 |
46 | focusedappvariablename
47 |
48 | hotkey
49 | 0
50 | hotmod
51 | 0
52 | leftcursor
53 |
54 | modsmode
55 | 0
56 | relatedAppsMode
57 | 0
58 |
59 | type
60 | alfred.workflow.trigger.hotkey
61 | uid
62 | 3917FDAB-460E-4C28-A4A9-645B9773F34A
63 | version
64 | 2
65 |
66 |
67 | config
68 |
69 | alfredfiltersresults
70 |
71 | alfredfiltersresultsmatchmode
72 | 0
73 | argumenttrimmode
74 | 0
75 | argumenttype
76 | 1
77 | escaping
78 | 63
79 | keyword
80 | battery
81 | queuedelaycustom
82 | 3
83 | queuedelayimmediatelyinitially
84 |
85 | queuedelaymode
86 | 0
87 | queuemode
88 | 1
89 | runningsubtext
90 | Displays information about your battery, retrieving...
91 | script
92 | sh ./battery.sh
93 | scriptargtype
94 | 0
95 | scriptfile
96 |
97 | subtext
98 | Displays information about your battery
99 | title
100 | Battery
101 | type
102 | 0
103 | withspace
104 |
105 |
106 | type
107 | alfred.workflow.input.scriptfilter
108 | uid
109 | FC5EB146-FA11-4E33-8456-F60EA94E7EEE
110 | version
111 | 2
112 |
113 |
114 | config
115 |
116 | alfredfiltersresults
117 |
118 | alfredfiltersresultsmatchmode
119 | 0
120 | argumenttrimmode
121 | 0
122 | argumenttype
123 | 2
124 | escaping
125 | 102
126 | keyword
127 | battery
128 | queuedelaycustom
129 | 3
130 | queuedelayimmediatelyinitially
131 |
132 | queuedelaymode
133 | 0
134 | queuemode
135 | 1
136 | runningsubtext
137 |
138 | script
139 | # THESE VARIABLES MUST BE SET. SEE THE ONEUPDATER README FOR AN EXPLANATION OF EACH.
140 | readonly remote_info_plist='https://raw.githubusercontent.com/BenziAhamed/alfred-battery/master/src/info.plist'
141 | readonly workflow_url='BenziAhamed/alfred-battery'
142 | readonly download_type='github_release'
143 | readonly frequency_check='4'
144 |
145 | # FROM HERE ON, CODE SHOULD BE LEFT UNTOUCHED!
146 | function abort {
147 | echo "${1}" >&2
148 | exit 1
149 | }
150 |
151 | function url_exists {
152 | curl --silent --location --output /dev/null --fail --range 0-0 "${1}"
153 | }
154 |
155 | function notification {
156 | readonly local notificator="$(find . -type d -name 'Notificator.app')"
157 | if [[ -n "${notificator}" ]]; then
158 | "${notificator}/Contents/Resources/Scripts/notificator" --message "${1}" --title "${alfred_workflow_name}" --subtitle 'A new version is available'
159 | return
160 | fi
161 |
162 | readonly local terminal_notifier="$(find . -type f -name 'terminal-notifier')"
163 | if [[ -n "${terminal_notifier}" ]]; then
164 | "${terminal_notifier}" -title "${alfred_workflow_name}" -subtitle 'A new version is available' -message "${1}"
165 | return
166 | fi
167 |
168 | osascript -e "display notification \"${1}\" with title \"${alfred_workflow_name}\" subtitle \"A new version is available\""
169 | }
170 |
171 | # Local sanity checks
172 | readonly local_info_plist='info.plist'
173 | readonly local_version="$(/usr/libexec/PlistBuddy -c 'print version' "${local_info_plist}")"
174 |
175 | [[ -n "${local_version}" ]] || abort 'You need to set a workflow version in the configuration sheet.'
176 | [[ "${download_type}" =~ ^(direct|page|github_release)$ ]] || abort "'download_type' (${download_type}) needs to be one of 'direct', 'page', or 'github_release'."
177 | [[ "${frequency_check}" =~ ^[0-9]+$ ]] || abort "'frequency_check' (${frequency_check}) needs to be a number."
178 |
179 | # Check for updates
180 | if [[ $(find "${local_info_plist}" -mtime +"${frequency_check}"d) ]]; then
181 | if ! url_exists "${remote_info_plist}"; then abort "'remote_info_plist' (${remote_info_plist}) appears to not be reachable."; fi # Remote sanity check
182 |
183 | readonly tmp_file="$(mktemp)"
184 | curl --silent --location --output "${tmp_file}" "${remote_info_plist}"
185 | readonly remote_version="$(/usr/libexec/PlistBuddy -c 'print version' "${tmp_file}")"
186 |
187 | if [[ "${local_version}" == "${remote_version}" ]]; then
188 | touch "${local_info_plist}" # Reset timer by touching local file
189 | exit 0
190 | fi
191 |
192 | if [[ "${download_type}" == 'page' ]]; then
193 | notification 'Opening download page…'
194 | open "${workflow_url}"
195 | exit 0
196 | fi
197 |
198 | download_url="$([[ "${download_type}" == 'github_release' ]] && curl --silent "https://api.github.com/repos/${workflow_url}/releases/latest" | grep 'browser_download_url' | head -1 | sed -E 's/.*browser_download_url": "(.*)"/\1/' || echo "${workflow_url}")"
199 |
200 | if url_exists "${download_url}"; then
201 | notification 'Downloading and installing…'
202 | curl --silent --location --output "${HOME}/Downloads/${alfred_workflow_name}.alfredworkflow" "${download_url}"
203 | open "${HOME}/Downloads/${alfred_workflow_name}.alfredworkflow"
204 | else
205 | abort "'workflow_url' (${download_url}) appears to not be reachable."
206 | fi
207 | fi
208 | scriptargtype
209 | 1
210 | scriptfile
211 |
212 | subtext
213 |
214 | title
215 |
216 | type
217 | 0
218 | withspace
219 |
220 |
221 | type
222 | alfred.workflow.input.scriptfilter
223 | uid
224 | A35F4AB0-47ED-4FBB-8247-9EE1BCCAFFAD
225 | version
226 | 2
227 |
228 |
229 | readme
230 |
231 | uidata
232 |
233 | 3917FDAB-460E-4C28-A4A9-645B9773F34A
234 |
235 | xpos
236 | 30
237 | ypos
238 | 30
239 |
240 | A35F4AB0-47ED-4FBB-8247-9EE1BCCAFFAD
241 |
242 | colorindex
243 | 12
244 | note
245 | OneUpdater
246 | xpos
247 | 220
248 | ypos
249 | 170
250 |
251 | FC5EB146-FA11-4E33-8456-F60EA94E7EEE
252 |
253 | xpos
254 | 220
255 | ypos
256 | 30
257 |
258 |
259 | version
260 | 1.0
261 | webaddress
262 | benzi-ahamed.tumblr.com
263 |
264 |
265 |
--------------------------------------------------------------------------------