From fac2ee9c1122e4497ff467a3cdc9289a00fffded Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Thu, 26 Sep 2013 01:20:29 -0400 Subject: [PATCH 1/3] added basic tp_smapi battery widget for thinkpads with hover-expandable status --- widgets/contrib/tpbat/init.lua | 152 ++++++++++++++++++++++++++++++++ widgets/contrib/tpbat/smapi.lua | 99 +++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 widgets/contrib/tpbat/init.lua create mode 100644 widgets/contrib/tpbat/smapi.lua diff --git a/widgets/contrib/tpbat/init.lua b/widgets/contrib/tpbat/init.lua new file mode 100644 index 0000000..673b66c --- /dev/null +++ b/widgets/contrib/tpbat/init.lua @@ -0,0 +1,152 @@ +--[[ + tpbat.lua + Battery status widget for ThinkPad laptops that use SMAPI + lain.widgets.contrib.tpbat + + More on tp_smapi: http://www.thinkwiki.org/wiki/Tp_smapi + + Licensed under GNU General Public License v2 + * (c) 2013, Conor Heine + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local newtimer = require("lain.helpers").newtimer +local first_line = require("lain.helpers").first_line +local beautiful = require("beautiful") +local naughty = require("naughty") +local wibox = require("wibox") +local smapi = require("lain.widgets.contrib.tpbat.smapi") -- Ugly :( + +local string = { format = string.format } +local math = { floor = math.floor } +local tostring = tostring +local setmetatable = setmetatable + +-- ThinkPad SMAPI-enabled battery info widget +local tpbat = { } + +local tpbat_notification = nil + +function tpbat:hide() + if tpbat_notification ~= nil then + naughty.destroy(tpbat_notification) + tpbat_notification = nil + end +end + +function tpbat:show(t_out) + tpbat:hide() + + local bat = self.bat + if bat == nil or not bat:installed() then return end + + local mfgr = bat:get('manufacturer') or "no_mfgr" + local model = bat:get('model') or "no_model" + local chem = bat:get('chemistry') or "no_chem" + local status = bat:get('state') or "nil" + local time = bat:remaining_time() + local msg = "\t" + + if status ~= "idle" and status ~= "nil" then + if time == "N/A" then + msg = "...Calculating time remaining..." + else + msg = time .. (status == "charging" and " until charged" or " remaining") + end + else + msg = "On AC Power" + end + + local str = string.format("%s : %s %s (%s)\n", bat.name, mfgr, model, chem) + str = str .. string.format("\n%s \t\t\t %s", status:upper(), msg) + + tpbat_notification = naughty.notify({ + preset = { fg = beautiful.fg_normal }, + text = str, + timeout = t_out + }) +end + +function tpbat.register(args) + local args = args or {} + local timeout = args.timeout or 30 + local battery = args.battery or "BAT0" + local settings = args.settings or function() end + + tpbat.bat = smapi:battery(battery) -- Create a new battery + local bat = tpbat.bat + + tpbat.widget = wibox.widget.textbox('') + + if bat:get('state') == nil then + local n = naughty.notify({ + title = "SMAPI Battery Warning: Unable to read battery state!", + text = "This widget is intended for ThinkPads. Is tp_smapi installed? Check your configs & paths.", + position = "top_right", + timeout = 15, + fg="#202020", + bg="#cdcdcd", + ontop = true + }) + end + + function update() + bat_now = { + status = "Not present", + perc = "N/A", + time = "N/A", + watt = "N/A" + } + + if bat:installed() + then + bat_now.status = bat:status() + bat_now.perc = bat:percent() + bat_now.time = bat:remaining_time() + -- bat_now.watt = string.format("%.2fW", (VOLTS * AMPS) / 1e12) + + -- notifications for low and critical states + if bat_now.perc <= 5 + then + tpbat.id = naughty.notify({ + text = "shutdown imminent", + title = "battery nearly exhausted", + position = "top_right", + timeout = 15, + fg="#000000", + bg="#ffffff", + ontop = true, + replaces_id = tpbat.id + }).id + elseif bat_now.perc <= 15 + then + tpbat.id = naughty.notify({ + text = "plug the cable", + title = "battery low", + position = "top_right", + timeout = 15, + fg="#202020", + bg="#cdcdcd", + ontop = true, + replaces_id = tpbat.id + }).id + end + + bat_now.perc = tostring(bat_now.perc) + end + + widget = tpbat.widget -- 'widget' needed in rc.lua (following convention) + settings() + end + + newtimer("tpbat", timeout, update) + + widget:connect_signal('mouse::enter', function () tpbat:show(0) end) + widget:connect_signal('mouse::leave', function () tpbat:hide() end) + + return tpbat.widget +end + +return setmetatable(tpbat, { __call = function(_, ...) return tpbat.register(...) end }) diff --git a/widgets/contrib/tpbat/smapi.lua b/widgets/contrib/tpbat/smapi.lua new file mode 100644 index 0000000..6024fa9 --- /dev/null +++ b/widgets/contrib/tpbat/smapi.lua @@ -0,0 +1,99 @@ +--[[ + smapi.lua + Interface with thinkpad battery information + + Licensed under GNU General Public License v2 + * (c) 2013, Conor Heine + +--]] + +local first_line = require("lain.helpers").first_line + +local string = { format = string.format } +local tonumber = tonumber +local setmetatable = setmetatable + +local smapi = {} + +local apipath = "/sys/devices/platform/smapi" + +-- Most are readable values, but some can be written to (not implemented, yet?) +local readable = { + barcoding = true, + charging_max_current = true, + charging_max_voltage = true, + chemistry = true, + current_avg = true, + current_now = true, + cycle_count = true, + design_capacity = true, + design_voltage = true, + dump = true, + first_use_date = true, + force_discharge = false, + group0_voltage = true, + group1_voltage = true, + group2_voltage = true, + group3_voltage = true, + inhibit_charge_minutes = false, + installed = true, + last_full_capacity = true, + manufacture_date = true, + manufacturer = true, + model = true, + power_avg = true, + power_now = true, + remaining_capacity = true, + remaining_charging_time = true, + remaining_percent = true, + remaining_percent_error = true, + remaining_running_time = true, + remaining_running_time_now = true, + serial = true, + start_charge_thresh = false, + state = true, + stop_charge_thresh = false, + temperature = true, + voltage = true, +} + +function smapi:battery(name) + local bat = {} + + bat.name = name + bat.path = apipath .. "/" .. name + + function bat:get(item) + return self.path ~= nil and readable[item] and first_line(self.path .. "/" .. item) or nil + end + + function bat:installed() + return self:get("installed") == "1" + end + + function bat:status() + return self:get('state') + end + + -- Remaining time can either be time until battery dies or time until charging completes + function bat:remaining_time() + local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time' + local mins_left = self:get(time_val) + + if mins_left:find("^%d+") == nil then + return "N/A" + end + + local hrs = mins_left / 60 + local min = mins_left % 60 + return string.format("%02d:%02d", hrs, min) + end + + function bat:percent() + return tonumber(self:get("remaining_percent")) + end + + return setmetatable(bat, {__metatable = false, __newindex = false}) +end + +return smapi \ No newline at end of file From af7558fb163bc37923bd62a88abc5213f3bb5a29 Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Thu, 26 Sep 2013 01:30:39 -0400 Subject: [PATCH 2/3] fixed formatting to follow contrib style --- widgets/contrib/tpbat/init.lua | 24 +++--- widgets/contrib/tpbat/smapi.lua | 130 ++++++++++++++++---------------- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/widgets/contrib/tpbat/init.lua b/widgets/contrib/tpbat/init.lua index 673b66c..d46697a 100644 --- a/widgets/contrib/tpbat/init.lua +++ b/widgets/contrib/tpbat/init.lua @@ -65,7 +65,7 @@ function tpbat:show(t_out) tpbat_notification = naughty.notify({ preset = { fg = beautiful.fg_normal }, text = str, - timeout = t_out + timeout = t_out }) end @@ -80,17 +80,17 @@ function tpbat.register(args) tpbat.widget = wibox.widget.textbox('') - if bat:get('state') == nil then - local n = naughty.notify({ - title = "SMAPI Battery Warning: Unable to read battery state!", - text = "This widget is intended for ThinkPads. Is tp_smapi installed? Check your configs & paths.", - position = "top_right", - timeout = 15, - fg="#202020", - bg="#cdcdcd", - ontop = true - }) - end + if bat:get('state') == nil then + local n = naughty.notify({ + title = "SMAPI Battery Warning: Unable to read battery state!", + text = "This widget is intended for ThinkPads. Is tp_smapi installed? Check your configs & paths.", + position = "top_right", + timeout = 15, + fg="#202020", + bg="#cdcdcd", + ontop = true + }) + end function update() bat_now = { diff --git a/widgets/contrib/tpbat/smapi.lua b/widgets/contrib/tpbat/smapi.lua index 6024fa9..3291cc2 100644 --- a/widgets/contrib/tpbat/smapi.lua +++ b/widgets/contrib/tpbat/smapi.lua @@ -19,81 +19,81 @@ local apipath = "/sys/devices/platform/smapi" -- Most are readable values, but some can be written to (not implemented, yet?) local readable = { - barcoding = true, - charging_max_current = true, - charging_max_voltage = true, - chemistry = true, - current_avg = true, - current_now = true, - cycle_count = true, - design_capacity = true, - design_voltage = true, - dump = true, - first_use_date = true, - force_discharge = false, - group0_voltage = true, - group1_voltage = true, - group2_voltage = true, - group3_voltage = true, - inhibit_charge_minutes = false, - installed = true, - last_full_capacity = true, - manufacture_date = true, - manufacturer = true, - model = true, - power_avg = true, - power_now = true, - remaining_capacity = true, - remaining_charging_time = true, - remaining_percent = true, - remaining_percent_error = true, - remaining_running_time = true, - remaining_running_time_now = true, - serial = true, - start_charge_thresh = false, - state = true, - stop_charge_thresh = false, - temperature = true, - voltage = true, + barcoding = true, + charging_max_current = true, + charging_max_voltage = true, + chemistry = true, + current_avg = true, + current_now = true, + cycle_count = true, + design_capacity = true, + design_voltage = true, + dump = true, + first_use_date = true, + force_discharge = false, + group0_voltage = true, + group1_voltage = true, + group2_voltage = true, + group3_voltage = true, + inhibit_charge_minutes = false, + installed = true, + last_full_capacity = true, + manufacture_date = true, + manufacturer = true, + model = true, + power_avg = true, + power_now = true, + remaining_capacity = true, + remaining_charging_time = true, + remaining_percent = true, + remaining_percent_error = true, + remaining_running_time = true, + remaining_running_time_now = true, + serial = true, + start_charge_thresh = false, + state = true, + stop_charge_thresh = false, + temperature = true, + voltage = true, } function smapi:battery(name) - local bat = {} + local bat = {} - bat.name = name - bat.path = apipath .. "/" .. name - - function bat:get(item) - return self.path ~= nil and readable[item] and first_line(self.path .. "/" .. item) or nil - end + bat.name = name + bat.path = apipath .. "/" .. name + + function bat:get(item) + return self.path ~= nil and readable[item] and first_line(self.path .. "/" .. item) or nil + end - function bat:installed() - return self:get("installed") == "1" - end + function bat:installed() + return self:get("installed") == "1" + end - function bat:status() - return self:get('state') - end + function bat:status() + return self:get('state') + end - -- Remaining time can either be time until battery dies or time until charging completes - function bat:remaining_time() - local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time' - local mins_left = self:get(time_val) + -- Remaining time can either be time until battery dies or time until charging completes + function bat:remaining_time() + local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time' + local mins_left = self:get(time_val) - if mins_left:find("^%d+") == nil then - return "N/A" - end - - local hrs = mins_left / 60 - local min = mins_left % 60 - return string.format("%02d:%02d", hrs, min) - end + if mins_left:find("^%d+") == nil then + return "N/A" + end + + local hrs = mins_left / 60 + local min = mins_left % 60 + return string.format("%02d:%02d", hrs, min) + end - function bat:percent() - return tonumber(self:get("remaining_percent")) - end + function bat:percent() + return tonumber(self:get("remaining_percent")) + end - return setmetatable(bat, {__metatable = false, __newindex = false}) + return setmetatable(bat, {__metatable = false, __newindex = false}) end return smapi \ No newline at end of file From 64ab76a6b70caea7a3d764b0ef613d17f9f0fe35 Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Thu, 26 Sep 2013 01:49:37 -0400 Subject: [PATCH 3/3] fixed brace style to match project's --- widgets/contrib/tpbat/init.lua | 12 ++++++++---- widgets/contrib/tpbat/smapi.lua | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/widgets/contrib/tpbat/init.lua b/widgets/contrib/tpbat/init.lua index d46697a..1bb6a9b 100644 --- a/widgets/contrib/tpbat/init.lua +++ b/widgets/contrib/tpbat/init.lua @@ -30,7 +30,8 @@ local tpbat = { } local tpbat_notification = nil function tpbat:hide() - if tpbat_notification ~= nil then + if tpbat_notification ~= nil + then naughty.destroy(tpbat_notification) tpbat_notification = nil end @@ -49,8 +50,10 @@ function tpbat:show(t_out) local time = bat:remaining_time() local msg = "\t" - if status ~= "idle" and status ~= "nil" then - if time == "N/A" then + if status ~= "idle" and status ~= "nil" + then + if time == "N/A" + then msg = "...Calculating time remaining..." else msg = time .. (status == "charging" and " until charged" or " remaining") @@ -80,7 +83,8 @@ function tpbat.register(args) tpbat.widget = wibox.widget.textbox('') - if bat:get('state') == nil then + if bat:get('state') == nil + then local n = naughty.notify({ title = "SMAPI Battery Warning: Unable to read battery state!", text = "This widget is intended for ThinkPads. Is tp_smapi installed? Check your configs & paths.", diff --git a/widgets/contrib/tpbat/smapi.lua b/widgets/contrib/tpbat/smapi.lua index 3291cc2..59b916b 100644 --- a/widgets/contrib/tpbat/smapi.lua +++ b/widgets/contrib/tpbat/smapi.lua @@ -80,8 +80,9 @@ function smapi:battery(name) local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time' local mins_left = self:get(time_val) - if mins_left:find("^%d+") == nil then - return "N/A" + if mins_left:find("^%d+") == nil + then + return "N/A" end local hrs = mins_left / 60