battery-widget: Sanitize total charge computation

The code to parse the output of `acpi -i` is fragile as it does not
guarantee that the same number of battery status and capacities are
read. This causes a wrong computation of the total charge level when
batteries of status "Unknown" are reported.

For instance, this is what `acpi -i` reports with a Wacom Intuos S
attached to a Thinkpad T460s:

  $ acpi -i
  Battery 0: Unknown, 0%, rate information unavailable
  Battery 1: Not charging, 98%
  Battery 1: design capacity 1857 mAh, last full capacity 1513 mAh = 81%
  Battery 2: Not charging, 98%
  Battery 2: design capacity 2051 mAh, last full capacity 1711 mAh = 83%

Fix the code by guaranteeing that for each battery status parsed there
is also a capacity, which is zero if no capacity can be parsed. This
effectively causes the exclusion of such batteries when computing the
total charge level.
This commit is contained in:
Stefan Huber 2022-12-30 13:04:06 +01:00
parent 0aba2f2e13
commit ed355dbf46
1 changed files with 15 additions and 3 deletions

View File

@ -125,12 +125,21 @@ local function worker(user_args)
local battery_info = {} local battery_info = {}
local capacities = {} local capacities = {}
for s in stdout:gmatch("[^\r\n]+") do for s in stdout:gmatch("[^\r\n]+") do
-- Match a line with status and charge level
local status, charge_str, _ = string.match(s, '.+: ([%a%s]+), (%d?%d?%d)%%,?(.*)') local status, charge_str, _ = string.match(s, '.+: ([%a%s]+), (%d?%d?%d)%%,?(.*)')
if status ~= nil then if status ~= nil then
-- Enforce that for each entry in battery_info there is an
-- entry in capacities of zero. If a battery has status
-- "Unknown" then there is no capacity reported and we treat it
-- as zero capactiy for later calculations.
table.insert(battery_info, {status = status, charge = tonumber(charge_str)}) table.insert(battery_info, {status = status, charge = tonumber(charge_str)})
else table.insert(capacities, 0)
local cap_str = string.match(s, '.+:.+last full capacity (%d+)') end
table.insert(capacities, tonumber(cap_str))
-- Match a line where capacity is reported
local cap_str = string.match(s, '.+:.+last full capacity (%d+)')
if cap_str ~= nil then
capacities[#capacities] = tonumber(cap_str) or 0
end end
end end
@ -144,6 +153,9 @@ local function worker(user_args)
-- this is arbitrary, and maybe another metric should be used -- this is arbitrary, and maybe another metric should be used
end end
-- Adds up total (capacity-weighted) charge and total capacity.
-- It effectively ignores batteries with status "Unknown" as we
-- treat them with capacity zero.
charge = charge + batt.charge * capacities[i] charge = charge + batt.charge * capacities[i]
capacity = capacity + capacities[i] capacity = capacity + capacities[i]
end end