-
Notifications
You must be signed in to change notification settings - Fork 21
/
handler.go
311 lines (259 loc) · 8.8 KB
/
handler.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
package main
import (
"errors"
"fmt"
"net/http"
"github.com/distatus/battery"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
func getConfig(c *gin.Context) {
c.IndentedJSON(http.StatusOK, config)
}
func setConfig(c *gin.Context) {
var cfg Config
if err := c.BindJSON(&cfg); err != nil {
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
if cfg.Limit < 10 || cfg.Limit > 100 {
err := fmt.Errorf("limit must be between 10 and 100, got %d", cfg.Limit)
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
config = cfg
if err := saveConfig(); err != nil {
logrus.Errorf("saveConfig failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
logrus.Infof("set config: %#v", cfg)
// Immediate single maintain loop, to avoid waiting for the next loop
maintainLoopForced()
c.IndentedJSON(http.StatusCreated, "ok")
}
func getLimit(c *gin.Context) {
c.IndentedJSON(http.StatusOK, config.Limit)
}
func setLimit(c *gin.Context) {
var l int
if err := c.BindJSON(&l); err != nil {
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
if l < 10 || l > 100 {
err := fmt.Errorf("limit must be between 10 and 100, got %d", l)
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
if l-config.LowerLimitDelta < 10 {
err := fmt.Errorf("limit must be at least %d, got %d", 10+config.LowerLimitDelta, l)
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
config.Limit = l
if err := saveConfig(); err != nil {
logrus.Errorf("saveConfig failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
logrus.Infof("set charging limit to %d", l)
var msg string
charge, err := smcConn.GetBatteryCharge()
if err != nil {
msg = fmt.Sprintf("set upper/lower charging limit to %d%%/%d%%", l, l-config.LowerLimitDelta)
} else {
msg = fmt.Sprintf("set upper/lower charging limit to %d%%/%d%%, current charge: %d%%", l, l-config.LowerLimitDelta, charge)
if charge > config.Limit {
msg += ". Current charge is above the limit, so your computer will use power from the wall only. Battery charge will remain the same."
}
}
if l >= 100 {
msg = "set charging limit to 100%. batt will not control charging anymore."
}
// Immediate single maintain loop, to avoid waiting for the next loop
maintainLoopForced()
c.IndentedJSON(http.StatusCreated, msg)
}
func setPreventIdleSleep(c *gin.Context) {
var p bool
if err := c.BindJSON(&p); err != nil {
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
config.PreventIdleSleep = p
if err := saveConfig(); err != nil {
logrus.Errorf("saveConfig failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
logrus.Infof("set prevent idle sleep to %t", p)
c.IndentedJSON(http.StatusCreated, "ok")
}
func setDisableChargingPreSleep(c *gin.Context) {
var d bool
if err := c.BindJSON(&d); err != nil {
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
config.DisableChargingPreSleep = d
if err := saveConfig(); err != nil {
logrus.Errorf("saveConfig failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
logrus.Infof("set disable charging pre sleep to %t", d)
c.IndentedJSON(http.StatusCreated, "ok")
}
func setAdapter(c *gin.Context) {
var d bool
if err := c.BindJSON(&d); err != nil {
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
if d {
if err := smcConn.EnableAdapter(); err != nil {
logrus.Errorf("enablePowerAdapter failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
logrus.Infof("enabled power adapter")
} else {
if err := smcConn.DisableAdapter(); err != nil {
logrus.Errorf("disablePowerAdapter failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
logrus.Infof("disabled power adapter")
}
c.IndentedJSON(http.StatusCreated, "ok")
}
func getAdapter(c *gin.Context) {
enabled, err := smcConn.IsAdapterEnabled()
if err != nil {
logrus.Errorf("getAdapter failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.IndentedJSON(http.StatusOK, enabled)
}
func getCharging(c *gin.Context) {
charging, err := smcConn.IsChargingEnabled()
if err != nil {
logrus.Errorf("getCharging failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.IndentedJSON(http.StatusOK, charging)
}
func getBatteryInfo(c *gin.Context) {
batteries, err := battery.GetAll()
if err != nil {
logrus.Errorf("getBatteryInfo failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
if len(batteries) == 0 {
logrus.Errorf("no batteries found")
c.IndentedJSON(http.StatusInternalServerError, "no batteries found")
_ = c.AbortWithError(http.StatusInternalServerError, errors.New("no batteries found"))
return
}
bat := batteries[0] // All Apple Silicon MacBooks only have one battery. No need to support more.
if bat.State == battery.Discharging {
bat.ChargeRate = -bat.ChargeRate
}
c.IndentedJSON(http.StatusOK, bat)
}
func setLowerLimitDelta(c *gin.Context) {
var d int
if err := c.BindJSON(&d); err != nil {
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
if d < 0 {
err := fmt.Errorf("lower limit delta must be positive, got %d", d)
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
if config.Limit-d < 10 {
err := fmt.Errorf("lower limit delta must be less than limit - 10, got %d", d)
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
config.LowerLimitDelta = d
if err := saveConfig(); err != nil {
logrus.Errorf("saveConfig failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
ret := fmt.Sprintf("set lower limit delta to %d, current upper/lower limit is %d%%/%d%%", d, config.Limit, config.Limit-config.LowerLimitDelta)
logrus.Info(ret)
c.IndentedJSON(http.StatusCreated, ret)
}
func setControlMagSafeLED(c *gin.Context) {
// Check if MasSafe is supported first. If not, return error.
if !smcConn.CheckMagSafeExistence() {
logrus.Errorf("setControlMagSafeLED called but there is no MasSafe LED on this device")
err := fmt.Errorf("there is no MasSafe on this device. You can only enable this setting on a compatible device, e.g. MacBook Pro 14-inch 2021")
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
var d bool
if err := c.BindJSON(&d); err != nil {
c.IndentedJSON(http.StatusBadRequest, err.Error())
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}
config.ControlMagSafeLED = d
if err := saveConfig(); err != nil {
logrus.Errorf("saveConfig failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
logrus.Infof("set control MagSafe LED to %t", d)
c.IndentedJSON(http.StatusCreated, fmt.Sprintf("ControlMagSafeLED set to %t. You should be able to see the effect in a few minutes.", d))
}
func getCurrentCharge(c *gin.Context) {
charge, err := smcConn.GetBatteryCharge()
if err != nil {
logrus.Errorf("getCurrentCharge failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.IndentedJSON(http.StatusOK, charge)
}
func getPluggedIn(c *gin.Context) {
pluggedIn, err := smcConn.IsPluggedIn()
if err != nil {
logrus.Errorf("getCurrentCharge failed: %v", err)
c.IndentedJSON(http.StatusInternalServerError, err.Error())
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.IndentedJSON(http.StatusOK, pluggedIn)
}