// Package modules implements all the modules. // Copyright (C) 2022 Kevin Lyda package modules import ( "fmt" "math" "time" "github.com/distatus/battery" ) type battTS struct { charge float64 point time.Time } // BatteryMod module parameters for the battery module. type BatteryMod struct { name string onclick string battStats []battTS Battery int `yaml:"battery"` StatusEmp string `yaml:"status-chr"` StatusChr string `yaml:"status-chr"` StatusBat string `yaml:"status-bat"` StatusUnk string `yaml:"status-unk"` StatusFull string `yaml:"status-full"` OnError string `yaml:"on-error"` ColorOK string `yaml:"color-ok"` Color20 string `yaml:"color-20"` Color10 string `yaml:"color-10"` ColorError string `yaml:"color-error"` } // NewBattery creates a BatteryMod instance. func NewBattery(m *Module) *BatteryMod { b := &BatteryMod{ name: m.Name, onclick: m.OnClick, } if b.name == "" { b.name = "battery" } return b } // SetDefaults sets defaults. func (b *BatteryMod) SetDefaults() { if b.StatusEmp == "" { b.StatusEmp = "---" } if b.StatusChr == "" { b.StatusChr = "CHR" } if b.StatusBat == "" { b.StatusBat = "BAT" } if b.StatusUnk == "" { b.StatusUnk = "UNK" } if b.StatusFull == "" { b.StatusFull = "FULL" } if b.OnError == "" { b.OnError = "No BAT" } if b.ColorOK == "" { b.ColorOK = "#11ff11" } if b.Color20 == "" { b.Color20 = "#ffa500" } if b.Color10 == "" { b.Color10 = "#ffff00" } if b.ColorError == "" { b.ColorError = "#ff1111" } } // Name returns the name setting for the module. func (b *BatteryMod) Name() string { return b.name } // OnClick returns the on-click setting for the module. func (b *BatteryMod) OnClick() string { return b.onclick } // Render renders the module. func (b *BatteryMod) Render() string { // TODO: Alerting. now := time.Now() batt, err := battery.Get(b.Battery) if err != nil { return fmt.Sprintf(`{"name": "%s", "full_text": "%s", "color": "%s"}`, b.name, b.OnError, b.ColorError) } left := "(?)" if len(b.battStats) >= 1 { delta := now.Sub(b.battStats[0].point) if delta >= (60 * time.Second) { discharge := math.Abs(batt.Current - b.battStats[0].charge) if discharge > 0 { timeLeft := time.Duration((batt.Full-batt.Current)/discharge) * delta left = fmt.Sprintf("%dh%dm", int64(timeLeft.Hours()), int64(timeLeft.Minutes()-(timeLeft.Hours()*60))) b.battStats = b.battStats[1:] } else { left = "0h0m" } } } b.battStats = append(b.battStats, battTS{ charge: batt.Current, point: now, }) states := [...]string{ battery.Unknown: b.StatusUnk, battery.Empty: b.StatusEmp, battery.Full: b.StatusFull, battery.Charging: b.StatusChr, battery.Discharging: b.StatusBat, } color := b.ColorOK percent := 100 * (batt.Current / batt.Design) if percent < 20 { color = b.Color20 } if percent < 10 { color = b.Color10 } if b.Battery > 0 { return fmt.Sprintf(`{"name": "%s", "full_text": "%s%d %.1f%% %s", "color": "%s"}`, b.name, states[batt.State], b.Battery, percent, left, color) } return fmt.Sprintf(`{"name": "%s", "full_text": "%s %.1f%% %s", "color": "%s"}`, b.name, states[batt.State], percent, left, color) }