diff --git a/helpers.lua b/helpers.lua index bbe6da1..e7807e5 100644 --- a/helpers.lua +++ b/helpers.lua @@ -31,6 +31,7 @@ -- along with Vicious. If not, see . -- {{{ Grab environment +local ipairs = ipairs local pairs = pairs local rawget = rawget local require = require @@ -273,13 +274,33 @@ function helpers.sysctl_async(path_table, parse) path = table.concat(path, " ") spawn.with_line_callback("sysctl " .. path, { - stdout = function(line) - if not string.find(line, "sysctl: unknown oid") then - local key, value = string.match(line, "(.+): (.+)") - ret[key] = value + stdout = function (line) + local separators = { + freebsd = ": ", + 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, - output_done = function() parse(ret) end + output_done = function () parse(ret) end }) end -- }}} diff --git a/widgets/bat_openbsd.lua b/widgets/bat_openbsd.lua index 689e836..fe7665d 100644 --- a/widgets/bat_openbsd.lua +++ b/widgets/bat_openbsd.lua @@ -18,68 +18,77 @@ -- along with Vicious. If not, see . -- {{{ Grab environment +local pairs = pairs local tonumber = tonumber -local math = { floor = math.floor, modf = math.modf } +local table = { + insert = table.insert +} -local helpers = require"vicious.helpers" -local spawn = require"vicious.spawn" +local math = { + floor = math.floor, + modf = math.modf +} + +local helpers = require("vicious.helpers") -- }}} -local STATES = { [0] = "↯", -- not charging - [1] = "-", -- discharging - [2] = "!", -- critical - [3] = "+", -- charging - [4] = "N/A", -- unknown status - [255] = "N/A" } -- unimplemented by the driver +local bat_openbsd = {} +function bat_openbsd.async(format, warg, callback) + local battery_id = warg or "bat0" -return helpers.setasyncall{ - async = function (format, warg, callback) - local filter = "hw.sensors.acpi" .. (warg or "bat0") - local pattern = filter .. ".(%S+)=(%S+)" - local bat_info = {} + local fields = { + charging_rate = ("hw.sensors.acpi%s.power0"):format(battery_id), + last_full_capacity = ("hw.sensors.acpi%s.watthour0"):format(battery_id), + remaining_capacity = ("hw.sensors.acpi%s.watthour3"):format(battery_id), + 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( - ("sysctl -a | grep '^%s'"):format(filter), - { 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)] + local sysctl_args = {} + for _, v in pairs(fields) do table.insert(sysctl_args, v) end - -- battery capacity in percent - local percent = tonumber( - bat_info.watthour3 / bat_info.watthour0 * 100) + local battery = {} + helpers.sysctl_async(sysctl_args, function (ret) + for k, v in pairs(fields) do + -- discard the description that comes after the values + battery[k] = tonumber(ret[v]:match("(.-) ")) + end - local time - if tonumber(bat_info.power0) < 1 then - time = "∞" - else - local raw_time = bat_info.watthour3 / bat_info.power0 - local hours, hour_fraction = math.modf(raw_time) - local minutes = math.floor(60 * hour_fraction) - time = ("%d:%0.2d"):format(hours, minutes) - end + local states = { + [0] = "↯", -- not charging + [1] = "-", -- discharging + [2] = "!", -- critical + [3] = "+", -- charging + [4] = "N/A", -- unknown status + [255] = "N/A" -- unimplemented by the driver + } + local state = states[battery.state] - -- calculate wear level from (last full / design) capacity - local wear = "N/A" - 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 + local charge = tonumber(battery.remaining_capacity + / battery.last_full_capacity * 100) - -- dis-/charging rate as presented by battery - local rate = bat_info.power0 + local remaining_time + 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: - -- * battery state symbol (↯, -, !, + or N/A) - -- * remaining_capacity (in percent) - -- * remaining_time, by battery - -- * wear level (in percent) - -- * present_rate (in Watts) - callback{state, percent, time, wear, rate} - end }) - end } + local wear = math.floor(battery.last_full_capacity, + battery.design_capacity) + + -- Pass the following arguments to callback function: + -- * battery state symbol (↯, -, !, + or N/A) + -- * remaining capacity (in percent) + -- * remaining time, as reported by the battery + -- * wear level (in percent) + -- * present_rate (in Watts/hour) + return callback({ state, charge, remaining_time, + wear, battery.charging_rate }) + end) +end + +return helpers.setasyncall(bat_openbsd)