]> git.madduck.net Git - etc/awesome.git/blob - widgets/bat.lua

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

battery: magnitude differences check added; closes #199 #203
[etc/awesome.git] / widgets / bat.lua
1
2 --[[
3                                                                                                                         
4          Licensed under GNU General Public License v2 
5           * (c) 2013,      Luke Bonham                
6           * (c) 2010-2012, Peter Hofmann              
7                                                                                                                         
8 --]]
9
10 local newtimer     = require("lain.helpers").newtimer
11 local first_line   = require("lain.helpers").first_line
12
13 local naughty      = require("naughty")
14 local wibox        = require("wibox")
15
16 local math         = { floor  = math.floor, min = math.min }
17 local string       = { format = string.format }
18 local tonumber     = tonumber
19 local tostring     = tostring
20
21 local setmetatable = setmetatable
22
23 -- Battery infos
24 -- lain.widgets.bat
25
26 local function worker(args)
27     local bat       = {}
28     local args      = args or {}
29     local timeout   = args.timeout or 30
30     local batteries = args.batteries or (args.battery and {args.battery}) or {"BAT0"}
31     local ac        = args.ac or "AC0"
32     local notify    = args.notify or "on"
33     local settings  = args.settings or function() end
34
35     bat.widget = wibox.widget.textbox('')
36
37     bat_notification_low_preset = {
38         title   = "Battery low",
39         text    = "Plug the cable!",
40         timeout = 15,
41         fg      = "#202020",
42         bg      = "#CDCDCD"
43     }
44
45     bat_notification_critical_preset = {
46         title   = "Battery exhausted",
47         text    = "Shutdown imminent",
48         timeout = 15,
49         fg      = "#000000",
50         bg      = "#FFFFFF"
51     }
52
53     bat_now = {
54         status    = "N/A",
55         ac_status = "N/A",
56         perc      = "N/A",
57         time      = "N/A",
58         watt      = "N/A"
59     }
60
61     bat_now.n_status = {}
62     for i = 1, #batteries do
63         bat_now.n_status[i] = "N/A"
64     end
65
66     function update()
67         local sum_rate_current      = 0
68         local sum_rate_voltage      = 0
69         local sum_rate_power        = 0
70         local sum_energy_now        = 0
71         local sum_energy_full       = 0
72         local sum_energy_percentage = 0
73         --local pspath                = "/sys/class/power_supply/"
74         local pspath = "/home/luke/Download/"
75
76         for i, battery in ipairs(batteries) do
77             local bstr    = pspath .. battery
78             local present = first_line(bstr .. "/present")
79
80             if tonumber(present) == 1 then
81                 -- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW]
82                 local rate_current      = tonumber(first_line(bstr .. "/current_now"))
83                 local rate_voltage      = tonumber(first_line(bstr .. "/voltage_now"))
84                 local rate_power        = tonumber(first_line(bstr .. "/power_now"))
85
86                 -- energy_now(P)[uWh], charge_now(I)[uAh]
87                 local energy_now        = tonumber(first_line(bstr .. "/energy_now") or
88                                           first_line(bstr .. "/charge_now"))
89
90                 -- energy_full(P)[uWh], charge_full(I)[uAh]
91                 local energy_full       = tonumber(first_line(bstr .. "/energy_full") or
92                                           first_line(bstr .. "/charge_full"))
93
94                 local energy_percentage = tonumber(first_line(bstr .. "/capacity")) or
95                                           math.floor((energy_now / energy_full) * 100)
96
97                 bat_now.n_status[i] = first_line(bstr .. "/status") or "N/A"
98
99                 sum_rate_current      = sum_rate_current + (rate_current or 0)
100                 sum_rate_voltage      = sum_rate_voltage + rate_voltage
101                 sum_rate_power        = sum_rate_power + (rate_power or ((rate_voltage * rate_current) / 1e6))
102                 sum_energy_now        = sum_energy_now + (energy_now or 0)
103                 sum_energy_full       = sum_energy_full + energy_full
104                 sum_energy_percentage = sum_energy_percentage + energy_percentage
105             end
106         end
107
108         bat_now.status = bat_now.n_status[1]
109         bat_now.ac_status = tonumber(first_line(string.format("%s%s/online", pspath, ac))) or "N/A"
110
111         if bat_now.status ~= "N/A" then
112             -- update {perc,time,watt} iff battery not full and rate > 0
113             if bat_now.status ~= "Full" and (sum_rate_current > 0 or sum_rate_power > 0) then
114                 local sum_rpc = sum_rate_power or sum_rate_current
115                 local enr = 0
116                 local m1 = tostring(sum_rpc):len()
117                 local m2 = 0
118
119                 if bat_now.status == "Charging" then
120                     enr = sum_energy_full - sum_energy_now
121                     m2 = tostring(sum_energy_full):len()
122                 else -- Discharging
123                     enr = sum_energy_now
124                     m2 = tostring(enr):len()
125                 end
126
127                 -- solve magnitude differences, which may be caused
128                 -- by file discrepancies
129                 magnitude_diff = m1 - m2
130                 if magnitude_diff > 0 then
131                     sum_rpc = sum_rpc / 10^magnitude_diff
132                 elseif magnitude_diff < 0 then
133                     enr = enr / 10^(magnitude_diff * -1)
134                 end
135
136                 local rate_time = enr / sum_rpc
137                 local hours     = math.floor(rate_time)
138                 local minutes   = math.floor((rate_time - hours) * 60)
139
140                 bat_now.perc    = tonumber(string.format("%d", math.min(100, sum_energy_percentage / #batteries)))
141                 bat_now.time    = string.format("%02d:%02d", hours, minutes)
142                 bat_now.watt    = tonumber(string.format("%.2f", sum_rate_power / 1e6))
143             elseif bat_now.status == "Full" then
144                 bat_now.perc    = 100
145                 bat_now.time    = "00:00"
146                 bat_now.watt    = 0
147             end
148         end
149
150         widget = bat.widget
151         settings()
152
153         -- notifications for low and critical states
154         if notify == "on" and bat_now.perc and bat_now.status == "Discharging" then
155             if bat_now.perc <= 5 then
156                 bat.id = naughty.notify({
157                     preset = bat_notification_critical_preset,
158                     replaces_id = bat.id
159                 }).id
160             elseif bat_now.perc <= 15 then
161                 bat.id = naughty.notify({
162                     preset = bat_notification_low_preset,
163                     replaces_id = bat.id
164                 }).id
165             end
166         end
167     end
168
169     newtimer(battery, timeout, update)
170
171     return setmetatable(bat, { __index = bat.widget })
172 end
173
174 return setmetatable({}, { __call = function(_, ...) return worker(...) end })