-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
167 lines (140 loc) · 4.76 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package main
import (
"flag"
"fmt"
"log"
"os/exec"
"regexp"
"strconv"
"time"
)
type batteryInfo struct {
Percentage int
State string
}
// getBattery retrieves the battery information for the first battery found on the system.
func getBattery() batteryInfo {
out, err := exec.Command("pmset", "-g", "batt").Output()
if err != nil {
log.Println("Failed to get battery information:", err)
}
re := regexp.MustCompile(`[0-9]+%`)
percentageStr := re.FindString(string(out))
percentage, err := strconv.Atoi(percentageStr[:len(percentageStr)-1])
if err != nil {
log.Println("Failed to get battery percantage:", err)
}
var state string
if regexp.MustCompile(`discharging`).MatchString(string(out)) {
state = "Discharging"
} else if regexp.MustCompile(`charging`).MatchString(string(out)) {
state = "Charging"
} else {
state = "Unknown"
}
return batteryInfo{
Percentage: percentage,
State: state,
}
}
// playWhenPercentageOutsideRange plays a sound repeatedly when the battery percentage is
// below or equal to the minimum threshold and discharging, or above or equal to the
// maximum threshold and charging. The sound to play is specified by the 'sound' parameter.
func playWhenPercentageOutsideRange(minPercentage, maxPercentage int, sound string) {
for {
batteryInfo := getBattery()
percentage := batteryInfo.Percentage
isDischarging := batteryInfo.State == "Discharging"
isCharging := batteryInfo.State == "Charging"
if (isDischarging && percentage <= minPercentage) || (isCharging && percentage >= maxPercentage) {
playSound(sound, percentage, isCharging)
// Wait 10 seconds, and play sound again
time.Sleep(10 * time.Second)
} else {
break
}
}
}
func main() {
// Define command-line flags for minimum and maximum battery percentage, and sound file path.
minPercentage := flag.Int("min", 20, "Minimum battery percentage")
maxPercentage := flag.Int("max", 80, "Maximum battery percentage")
sound := flag.String("sound", "", "Sound to play, for example: /System/Library/Sounds/Ping.aiff")
// Parse the command-line flags.
flag.Parse()
message := fmt.Sprintf("Battery Reminder Started. \nMinimum: %v \nMaximum: %v", *minPercentage, *maxPercentage)
log.Println(message)
notification(message)
for {
// Play sound when the battery percentage is outside the specified range.
playWhenPercentageOutsideRange(*minPercentage, *maxPercentage, *sound)
// Get current battery state
batteryInfo := getBattery()
// Calculate sleep time based on how close we are to the thresholds
var sleepTime time.Duration
if batteryInfo.State == "Charging" {
// if charging, and already at maxPercentage. don't wait.
if batteryInfo.Percentage >= *maxPercentage {
sleepTime = 0
}
// If charging, the closer we are to maxPercentage, the shorter the sleepTime
sleepTime = time.Duration(*maxPercentage-batteryInfo.Percentage) * time.Second
} else if batteryInfo.State == "Discharging" {
// If discharging, the closer we are to minPercentage, the shorter the sleepTime
sleepTime = time.Duration(batteryInfo.Percentage-*minPercentage) * time.Second
}
// Ensure that sleepTime is never less than 1 second
if sleepTime < 1*time.Second {
sleepTime = 1 * time.Second
}
// Wait for sleepTime seconds before checking the battery percentage again.
time.Sleep(sleepTime)
}
}
// unmute sets the system volume to maximum.
func unmute() {
cmd := exec.Command("osascript", "-e", "set volume output volume 100")
err := cmd.Run()
if err != nil {
log.Printf("Failed to unmute: %v", err)
}
}
// playSound plays the specified sound file.
func playSound(sound string, percentage int, isCharging bool) {
unmute()
if sound != "" {
// Play the sound using the afplay command
cmd := exec.Command("afplay", sound)
err := cmd.Run()
if err != nil {
log.Println("Failed to play sound:", err)
speak(percentage, isCharging)
}
} else {
speak(percentage, isCharging)
}
}
func speak(percentage int, isCharging bool) {
message := fmt.Sprintf("Battery is at %d%%. Please plugin your charger.", percentage)
if isCharging {
message = fmt.Sprintf("Battery is %d%% charged. Please unplug your charger.", percentage)
}
// First notify
notification(message)
time.Sleep(2 * time.Second)
cmd := exec.Command("say", message)
err := cmd.Run()
if err != nil {
log.Printf("Failed to speak: %v", err)
}
}
func notification(message string) {
// Define the AppleScript command for displaying a notification without an icon
script := fmt.Sprintf(`display notification "%v" with title "%v" sound name "default"`, message, "Battery Reminder")
// Execute the AppleScript command using the `osascript` utility
cmd := exec.Command("osascript", "-e", script)
err := cmd.Run()
if err != nil {
log.Printf("Failed to send notification: %v", err)
}
}