Make helpers.sysctl_async cross-platform & let bat_openbsd use it (#93)

This commit is contained in:
Enric Morales 2019-10-16 16:05:32 +02:00 committed by Nguyễn Gia Phong
parent ee970d0c68
commit 1277889978
2 changed files with 89 additions and 59 deletions

View File

@ -31,6 +31,7 @@
-- along with Vicious. If not, see <https://www.gnu.org/licenses/>. -- along with Vicious. If not, see <https://www.gnu.org/licenses/>.
-- {{{ Grab environment -- {{{ Grab environment
local ipairs = ipairs
local pairs = pairs local pairs = pairs
local rawget = rawget local rawget = rawget
local require = require local require = require
@ -273,13 +274,33 @@ function helpers.sysctl_async(path_table, parse)
path = table.concat(path, " ") path = table.concat(path, " ")
spawn.with_line_callback("sysctl " .. path, { spawn.with_line_callback("sysctl " .. path, {
stdout = function(line) stdout = function (line)
if not string.find(line, "sysctl: unknown oid") then local separators = {
local key, value = string.match(line, "(.+): (.+)") freebsd = ": ",
ret[key] = value linux = " = ",
openbsd = "="
}
local pattern = ("(.+)%s(.+)"):format(separators[helpers.getos()])
local key, value = string.match(line, pattern)
ret[key] = value
end,
stderr = function (line)
local messages = {
openbsd = { "level name .+ in (.+) is invalid" },
linux = { "cannot stat /proc/sys/(.+):",
"permission denied on key '(.+)'" },
freebsd = { "unknown oid '(.+)'" }
}
for _, error_message in ipairs(messages[helpers.getos()]) do
local key = line:match(error_message)
if key then
key = key:gsub("/", ".")
ret[key] = "N/A"
end
end end
end, end,
output_done = function() parse(ret) end output_done = function () parse(ret) end
}) })
end end
-- }}} -- }}}

View File

@ -18,68 +18,77 @@
-- along with Vicious. If not, see <https://www.gnu.org/licenses/>. -- along with Vicious. If not, see <https://www.gnu.org/licenses/>.
-- {{{ Grab environment -- {{{ Grab environment
local pairs = pairs
local tonumber = tonumber local tonumber = tonumber
local math = { floor = math.floor, modf = math.modf } local table = {
insert = table.insert
}
local helpers = require"vicious.helpers" local math = {
local spawn = require"vicious.spawn" floor = math.floor,
modf = math.modf
}
local helpers = require("vicious.helpers")
-- }}} -- }}}
local STATES = { [0] = "", -- not charging local bat_openbsd = {}
[1] = "-", -- discharging function bat_openbsd.async(format, warg, callback)
[2] = "!", -- critical local battery_id = warg or "bat0"
[3] = "+", -- charging
[4] = "N/A", -- unknown status
[255] = "N/A" } -- unimplemented by the driver
return helpers.setasyncall{ local fields = {
async = function (format, warg, callback) charging_rate = ("hw.sensors.acpi%s.power0"):format(battery_id),
local filter = "hw.sensors.acpi" .. (warg or "bat0") last_full_capacity = ("hw.sensors.acpi%s.watthour0"):format(battery_id),
local pattern = filter .. ".(%S+)=(%S+)" remaining_capacity = ("hw.sensors.acpi%s.watthour3"):format(battery_id),
local bat_info = {} design_capacity = ("hw.sensors.acpi%s.watthour4"):format(battery_id),
state = ("hw.sensors.acpi%s.raw0"):format(battery_id)
}
spawn.with_line_callback_with_shell( local sysctl_args = {}
("sysctl -a | grep '^%s'"):format(filter), for _, v in pairs(fields) do table.insert(sysctl_args, v) end
{ stdout = function (line)
for key, value in line:gmatch(pattern) do
bat_info[key] = value
end
end,
output_done = function ()
-- current state
local state = STATES[tonumber(bat_info.raw0)]
-- battery capacity in percent local battery = {}
local percent = tonumber( helpers.sysctl_async(sysctl_args, function (ret)
bat_info.watthour3 / bat_info.watthour0 * 100) for k, v in pairs(fields) do
-- discard the description that comes after the values
battery[k] = tonumber(ret[v]:match("(.-) "))
end
local time local states = {
if tonumber(bat_info.power0) < 1 then [0] = "", -- not charging
time = "" [1] = "-", -- discharging
else [2] = "!", -- critical
local raw_time = bat_info.watthour3 / bat_info.power0 [3] = "+", -- charging
local hours, hour_fraction = math.modf(raw_time) [4] = "N/A", -- unknown status
local minutes = math.floor(60 * hour_fraction) [255] = "N/A" -- unimplemented by the driver
time = ("%d:%0.2d"):format(hours, minutes) }
end local state = states[battery.state]
-- calculate wear level from (last full / design) capacity local charge = tonumber(battery.remaining_capacity
local wear = "N/A" / battery.last_full_capacity * 100)
if bat_info.watthour0 and bat_info.watthour4 then
local l_full = tonumber(bat_info.watthour0)
local design = tonumber(bat_info.watthour4)
wear = math.floor(l_full / design * 100)
end
-- dis-/charging rate as presented by battery local remaining_time
local rate = bat_info.power0 if battery.charging_rate < 1 then
remaining_time = ""
else
local raw_time = battery.remaining_capacity / battery.rate
local hours, hour_fraction = math.modf(raw_time)
local minutes = math.floor(60 * hour_fraction)
remaining_time = ("%d:%0.2d"):format(hours, minutes)
end
-- Pass the following arguments to callback function: local wear = math.floor(battery.last_full_capacity,
-- * battery state symbol (↯, -, !, + or N/A) battery.design_capacity)
-- * remaining_capacity (in percent)
-- * remaining_time, by battery -- Pass the following arguments to callback function:
-- * wear level (in percent) -- * battery state symbol (↯, -, !, + or N/A)
-- * present_rate (in Watts) -- * remaining capacity (in percent)
callback{state, percent, time, wear, rate} -- * remaining time, as reported by the battery
end }) -- * wear level (in percent)
end } -- * present_rate (in Watts/hour)
return callback({ state, charge, remaining_time,
wear, battery.charging_rate })
end)
end
return helpers.setasyncall(bat_openbsd)