Skip to content

Commit

Permalink
add battery widget (taken from https://github.com/coleifer/mastodon/b…
Browse files Browse the repository at this point in the history
  • Loading branch information
ghedamat committed Apr 11, 2014
1 parent 10b9e77 commit 7b8dabd
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 16 deletions.
124 changes: 110 additions & 14 deletions i3status/power.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
package i3status

import (
"bytes"
"errors"
"fmt"
"os/exec"
"strconv"
"strings"
"time"
)

const (
Charging = "charging"
Discharging = "discharging"
Charged = "charged"
BATTERY_DISCHARGING = iota
BATTERY_CHARGING
BATTERY_FULL
)

type BatteryInfo struct {
PercentRemaining float64
SecondsRemaining float64
Consumption float64
status int
}

type PowerWidget struct {
BaseWidget
}
Expand All @@ -26,13 +33,25 @@ func NewPowerWidget() *PowerWidget {
return &w
}

func (w *PowerWidget) execCommand() string {
var out bytes.Buffer
cmd := exec.Command("acpi", "-b")
cmd.Stdout = &out
cmd.Run()
str, _ := out.ReadString('\n')
return str
func (w *PowerWidget) getStatus() (string, string) {
bi, _ := readBatteryInfo(0)

bar := MakeBar(bi.PercentRemaining, 20)
remaining := HumanDuration(int64(bi.SecondsRemaining))
prefix := "BAT"
color := "#ffffff"
if bi.IsCharging() {
prefix = "CHR"
} else if bi.IsFull() {
prefix = "FULL"
} else {
if bi.PercentRemaining < 10 {
color = "#ff0000"
} else if bi.PercentRemaining < 30 {
color = "#ffff00"
}
}
return fmt.Sprintf("%s %s %s %0.1f%%", prefix, remaining, bar, bi.PercentRemaining), color
}

func (w *PowerWidget) basicLoop() {
Expand All @@ -41,8 +60,7 @@ func (w *PowerWidget) basicLoop() {
msg.Color = "#ffffff"
msg.Instance = strconv.Itoa(w.Instance)
for {
str := w.execCommand()
msg.FullText = fmt.Sprintf("%s", str)
msg.FullText, msg.Color = w.getStatus()
w.Output <- *msg
time.Sleep(5000 * time.Millisecond)
}
Expand All @@ -52,3 +70,81 @@ func (w *PowerWidget) Start() {
go w.basicLoop()
go w.readLoop()
}

// stolen from https://github.com/coleifer/mastodon/blob/master/battery.go
func (batteryInfo *BatteryInfo) IsCharging() bool {
return batteryInfo.status == BATTERY_CHARGING
}

func (batteryInfo *BatteryInfo) IsFull() bool {
return batteryInfo.status == BATTERY_FULL
}

func readBatteryInfo(battery int) (*BatteryInfo, error) {
rawInfo := make(map[string]string)
batteryInfo := new(BatteryInfo)

path := fmt.Sprintf("/sys/class/power_supply/BAT%d/uevent", battery)
if !FileExists(path) {
return batteryInfo, errors.New("Battery not found")
}
callback := func(line string) bool {
data := strings.Split(string(line), "=")
rawInfo[data[0]] = data[1]
return true
}
ReadLines(path, callback)

var remaining, presentRate, voltage, fullDesign float64
var wattAsUnit bool
batteryInfo.status = BATTERY_DISCHARGING

if rawInfo["POWER_SUPPLY_STATUS"] == "Charging" {
batteryInfo.status = BATTERY_CHARGING
} else if rawInfo["POWER_SUPPLY_STATUS"] == "Full" {
batteryInfo.status = BATTERY_FULL
}

/* Convert to float shorthand */
pf := func(keys ...string) float64 {
for _, key := range keys {
if _, ok := rawInfo[key]; ok {
f, _ := strconv.ParseFloat(rawInfo[key], 64)
return f
}
}
return 0.
}

/* Read values from file */
remaining = pf("POWER_SUPPLY_ENERGY_NOW", "POWER_SUPPLY_CHARGE_NOW")
presentRate = pf("POWER_SUPPLY_CURRENT_NOW", "POWER_SUPPLY_POWER_NOW")
voltage = pf("POWER_SUPPLY_VOLTAGE_NOW")
fullDesign = pf("POWER_SUPPLY_CHARGE_FULL_DESIGN", "POWER_SUPPLY_ENERGY_FULL_DESIGN")
_, wattAsUnit = rawInfo["POWER_SUPPLY_ENERGY_NOW"]

if !wattAsUnit {
presentRate = (voltage / 1000.0) * (presentRate / 1000.0)
remaining = (voltage / 1000.0) * (remaining / 1000.0)
fullDesign = (voltage / 1000.0) * (fullDesign / 1000.0)
}

if fullDesign == 0 {
return batteryInfo, errors.New("Battery full design missing")
}

batteryInfo.PercentRemaining = (remaining / fullDesign) * 100

var remainingTime float64
if presentRate > 0 {
if batteryInfo.status == BATTERY_CHARGING {
remainingTime = (fullDesign - remaining) / presentRate
} else if batteryInfo.status == BATTERY_DISCHARGING {
remainingTime = remaining / presentRate
}
batteryInfo.SecondsRemaining = remainingTime * 3600
}
batteryInfo.Consumption = presentRate / 1000000.0

return batteryInfo, nil
}
53 changes: 53 additions & 0 deletions i3status/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// this has been stolen form
// https://github.com/coleifer/mastodon/blob/master/utils.go
package i3status

import (
"bufio"
"bytes"
"fmt"
"io"
"os"
)

func ReadLines(fileName string, callback func(string) bool) {
fin, err := os.Open(fileName)
if err != nil {
fmt.Fprintf(os.Stderr, "The file %s does not exist!\n", fileName)
return
}
defer fin.Close()

reader := bufio.NewReader(fin)
for line, _, err := reader.ReadLine(); err != io.EOF; line, _, err = reader.ReadLine() {
if !callback(string(line)) {
break
}
}
}

func FileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}

func MakeBar(percent float64, bar_size int) string {
var bar bytes.Buffer
cutoff := int(percent * .01 * float64(bar_size))
bar.WriteString("[")
for i := 0; i < bar_size; i += 1 {
if i <= cutoff {
bar.WriteString("#")
} else {
bar.WriteString(" ")
}
}
bar.WriteString("]")
return bar.String()
}

func HumanDuration(n int64) string {
hours := n / 3600
minutes := (n % 3600) / 60
return fmt.Sprintf("%d:%02d", hours, minutes)
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func main() {
b.Add(i3status.NewPowerWidget())
b.Add(i3status.NewOnOffWidget())
b.Add(i3status.NewI3statusWidget())
b.Add(i3status.NewEchoWidget())
//b.Add(i3status.NewEchoWidget())

for {
m := <-b.Output
Expand Down
2 changes: 1 addition & 1 deletion test/power_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestPowerWidgetHasMessage(t *testing.T) {
w.Start()
Convey("output message is available", func() {
msg := <-c
So(msg.FullText, ShouldContainSubstring, "Battery")
So(msg.FullText, ShouldContainSubstring, "BAT")
})
})
})
Expand Down

0 comments on commit 7b8dabd

Please sign in to comment.