Rewrote the Battery widget to work with dbus. Widget also supports to report battery states for every device possible

This commit is contained in:
Rene Kievits
2022-05-31 20:48:25 +02:00
parent 0e22af5a87
commit dbc7708f58
2 changed files with 186 additions and 125 deletions

View File

@@ -8,11 +8,39 @@ local home = os.getenv("HOME")
-- If you want different default programs, wallpaper path or modkey; edit this file. -- If you want different default programs, wallpaper path or modkey; edit this file.
user_vars = { user_vars = {
-- The battery that should be displayed in the battery widget.
--[[
You can choose from one of these values (default is internal battery):
"UNKNOWN"
"LINE_POWER"
"TABLET"
"COMPUTER"
"GAMING_INPUT"
"LAST"
"BATTERY"
"UPS"
"MONITOR"
"MOUSE"
"KEYBOARD"
"PDA"
"PHONE"
"MEDIA_PLAYER"
More information at: https://lazka.github.io/pgi-docs/UPowerGlib-1.0/enums.html#UPowerGlib.DeviceKind.KEYBOARD
]]
battery_kind = "BATTERY",
-- Here you can specify a battery to use. e.g. "/org/freedesktop/UPower/devices/battery_BAT0"
-- Default is nil (use the internal battery)
battery_path = nil,
-- This is opened when clicked on the battery icon, set it to whatever you like
energy_manager = "xfce4-power-manager-settings",
-- Uses the openweather api https://home.openweathermap.org/api_keys -- Uses the openweather api https://home.openweathermap.org/api_keys
-- City ID is also from there -- City ID is also from there
weather_secrets = { weather_secrets = {
key = "e71b00168ca7219563dde4514a425b14", key = "",
city_id = "2864118", city_id = "",
unit = "metric" -- "metric" or "imperial" unit = "metric" -- "metric" or "imperial"
}, },

View File

@@ -1,21 +1,28 @@
---@diagnostic disable: undefined-field
-------------------------------- --------------------------------
-- This is the battery widget -- -- This is the battery widget --
-------------------------------- --------------------------------
-- Awesome Libs -- Awesome Libs
local awful = require("awful") local awful = require("awful")
local color = require("src.theme.colors") local color = require("src.theme.colors")
local dpi = require("beautiful").xresources.apply_dpi local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears") local gears = require("gears")
local lgi = require("lgi")
local naughty = require("naughty") local naughty = require("naughty")
local watch = awful.widget.watch local upower_glib = lgi.require("UPowerGlib")
local wibox = require("wibox") local wibox = require("wibox")
require("src.core.signals") require("src.core.signals")
-- Icon directory path -- Icon directory path
local icondir = awful.util.getdir("config") .. "src/assets/icons/battery/" local icondir = awful.util.getdir("config") .. "src/assets/icons/battery/"
-- Returns the battery widget ---Returns the battery widget
return function() ---@return wibox.widget
return function(battery_kind)
-- Battery wibox.widget
local battery_widget = wibox.widget { local battery_widget = wibox.widget {
{ {
{ {
@@ -58,145 +65,171 @@ return function()
widget = wibox.container.background widget = wibox.container.background
} }
local battery_tooltip = awful.tooltip { -- Color change on mouse over
Hover_signal(battery_widget, color["Purple200"], color["Grey900"])
-- Open an energy manager on click
battery_widget:connect_signal(
'button::press',
function()
awful.spawn(user_vars.energy_manager)
end
)
---Gets every enery device path
---@return table string battery device paths
local function get_device_path()
local paths = upower_glib.Client():get_devices()
local path_table = {}
for _, path in ipairs(paths) do
table.insert(path_table, path:get_object_path())
end
return path_table
end
---Takes a path and returns the glib object
---@param path string battery device path
---@return UPowerGlib.Device battery battery device object
local function get_device_from_path(path)
local devices = upower_glib.Client():get_devices()
for _, device in ipairs(devices) do
if device:get_object_path() == path then
return device
end
end
end
local tooltip = awful.tooltip {
objects = { battery_widget }, objects = { battery_widget },
text = "",
mode = "inside", mode = "inside",
preferred_alignments = "middle", preferred_alignments = "middle",
margins = dpi(10) margins = dpi(10)
} }
local get_battery_info = function() ---Sets the battery information for the widget
awful.spawn.easy_async_with_shell( ---@param device UPowerGlib.Device battery
[[ upower -i $(upower -e | grep BAT) | grep "time to " ]], local function set_battery(device)
function(stdout) local battery_percentage = math.floor(device.percentage + 0.5)
if stdout == nil or stdout == '' then local battery_status = upower_glib.DeviceState[device.state]:lower()
battery_tooltip:set_text('No Battery Found') local battery_temp = device.temperature
return
end local battery_time = 1
local rem_time = ""
if stdout:match("hour") then if device.time_to_empty ~= 0 then
rem_time = "Hours" battery_time = device.time_to_empty
else else
rem_time = "Minutes" battery_time = device.time_to_full
end
local bat_time = stdout:match("%d+,%d") or stdout:match("%d+.%d") or ""
if stdout:match("empty") then
battery_tooltip:set_text("Remaining battery time: " .. bat_time .. " " .. rem_time)
elseif stdout:match("time to full") then
battery_tooltip:set_text("Battery fully charged in: " .. bat_time .. " " .. rem_time)
end
end
)
end
get_battery_info()
local last_battery_check = os.time()
local notify_critical_battery = true
local battery_warning = function()
naughty.notification {
icon = gears.color.recolor_image(icondir .. "battery-alert.svg", color["White"]),
app_name = "System notification",
title = "Battery is low",
message = "Battery is almost empty",
urgency = "critical"
}
end end
local update_battery = function(status) battery_time = math.floor(battery_time / 3600) .. "h, " .. math.floor((battery_time / 60) % 60) .. "m"
awful.spawn.easy_async_with_shell(
[[sh -c "upower -i $(upower -e | grep BAT) | grep percentage | awk '{print \$2}' |tr -d '\n%'"]], if battery_temp == 0.0 then
function(stdout) battery_temp = "NaN"
local battery_percentage = tonumber(stdout) else
battery_temp = math.floor(battery_temp + 0.5) .. "°C"
end
if not battery_percentage then if not battery_percentage then
return return
end end
battery_widget.container.battery_layout.spacing = dpi(5) battery_widget:get_children_by_id("battery_layout")[1].spacing = dpi(5)
battery_widget.container.battery_layout.label.visible = true battery_widget:get_children_by_id("label")[1].visible = true
battery_widget.container.battery_layout.label:set_text(battery_percentage .. '%') battery_widget:get_children_by_id("label")[1].text = battery_percentage .. '%'
tooltip.markup = "<span foreground='#64ffda'>Battery Status:</span> <span foreground='#90caf9'>"
.. battery_status .. "</span>\n<span foreground='#64ffda'>Remaining time:</span> <span foreground='#90caf9'>"
.. battery_time .. "</span>\n<span foreground='#64ffda'>Temperature:</span> <span foreground='#90caf9'>"
.. battery_temp .. "</span>"
local icon = 'battery' local icon = 'battery'
if status == 'fully-charged' or status == 'charging' and battery_percentage == 100 then if battery_status == 'fully-charged' or battery_status == 'charging' and battery_percentage == 100 then
icon = icon .. '-' .. 'charging' icon = icon .. '-' .. 'charging.svg'
battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached( naughty.notification {
gears.color.recolor_image(icondir .. icon .. '.svg', "#212121"))) title = "Battery notification",
message = "Battery is fully charged",
icon = icondir .. icon,
timeout = 5
}
battery_widget:get_children_by_id("icon")[1].image = gears.surface.load_uncached(gears.color.recolor_image(icondir .. icon, "#212121"))
return return
end elseif battery_percentage > 0 and battery_percentage < 10 and battery_status == 'discharging' then
icon = icon .. '-' .. 'alert.svg'
if battery_percentage > 0 and battery_percentage < 10 and status == 'discharging' then naughty.notification {
icon = icon .. '-' .. 'alert' title = "Battery warning",
if (os.difftime(os.time(), last_battery_check) > 300 or notify_critical_battery) then message = "Battery is running low!\n" .. battery_percentage .. "% left",
last_battery_check = os.time() urgency = "critical",
notify_critical_battery = false icon = icondir .. icon,
battery_warning() timeout = 60
end }
battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached( battery_widget:get_children_by_id("icon")[1].image = gears.surface.load_uncached(gears.color.recolor_image(icondir .. icon, "#212121"))
gears.color.recolor_image(icondir .. icon .. '.svg', "#212121")))
return return
end end
if battery_percentage > 0 and battery_percentage < 10 then if battery_percentage > 0 and battery_percentage < 10 then
icon = icon .. '-' .. status .. '-' .. 'outline' icon = icon .. '-' .. battery_status .. '-' .. 'outline'
elseif battery_percentage >= 10 and battery_percentage < 20 then elseif battery_percentage >= 10 and battery_percentage < 20 then
icon = icon .. '-' .. status .. '-' .. '10' icon = icon .. '-' .. battery_status .. '-' .. '10'
elseif battery_percentage >= 20 and battery_percentage < 30 then elseif battery_percentage >= 20 and battery_percentage < 30 then
icon = icon .. '-' .. status .. '-' .. '20' icon = icon .. '-' .. battery_status .. '-' .. '20'
elseif battery_percentage >= 30 and battery_percentage < 40 then elseif battery_percentage >= 30 and battery_percentage < 40 then
icon = icon .. '-' .. status .. '-' .. '30' icon = icon .. '-' .. battery_status .. '-' .. '30'
elseif battery_percentage >= 40 and battery_percentage < 50 then elseif battery_percentage >= 40 and battery_percentage < 50 then
icon = icon .. '-' .. status .. '-' .. '40' icon = icon .. '-' .. battery_status .. '-' .. '40'
elseif battery_percentage >= 50 and battery_percentage < 60 then elseif battery_percentage >= 50 and battery_percentage < 60 then
icon = icon .. '-' .. status .. '-' .. '50' icon = icon .. '-' .. battery_status .. '-' .. '50'
elseif battery_percentage >= 60 and battery_percentage < 70 then elseif battery_percentage >= 60 and battery_percentage < 70 then
icon = icon .. '-' .. status .. '-' .. '60' icon = icon .. '-' .. battery_status .. '-' .. '60'
elseif battery_percentage >= 70 and battery_percentage < 80 then elseif battery_percentage >= 70 and battery_percentage < 80 then
icon = icon .. '-' .. status .. '-' .. '70' icon = icon .. '-' .. battery_status .. '-' .. '70'
elseif battery_percentage >= 80 and battery_percentage < 90 then elseif battery_percentage >= 80 and battery_percentage < 90 then
icon = icon .. '-' .. status .. '-' .. '80' icon = icon .. '-' .. battery_status .. '-' .. '80'
elseif battery_percentage >= 90 and battery_percentage < 100 then elseif battery_percentage >= 90 and battery_percentage < 100 then
icon = icon .. '-' .. status .. '-' .. '90' icon = icon .. '-' .. battery_status .. '-' .. '90'
end end
battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached( battery_widget:get_children_by_id("icon")[1].image = gears.surface.load_uncached(gears.color.recolor_image(icondir .. icon .. '.svg', "#212121"))
gears.color.recolor_image(icondir .. icon .. '.svg', "#212121")))
awesome.emit_signal("update::battery_widget", battery_percentage, icondir .. icon .. ".svg") awesome.emit_signal("update::battery_widget", battery_percentage, icondir .. icon .. ".svg")
end
)
end end
Hover_signal(battery_widget, color["Purple200"], color["Grey900"]) ---This function attaches a device path to the dbus interface
---It will only display on a widget if the user specified a device kind
---This device will then be filtered out and sent information to the widget itself
---The rest will only report in the background to other widgets e.g. Bluetooth devices
---Will report to the bluetooth widget.
---@param path string device path /org/freedesktop/...
local function attach_to_device(path)
local device_path = user_vars.battery_path or path or ""
battery_widget.device = get_device_from_path(device_path) or upower_glib.Client():get_display_device()
battery_widget.device.on_notify = function(device)
battery_widget:emit_signal("upower::update", device)
end
-- Check which device kind the user wants to display
-- If there are multiple then the first is used
if upower_glib.DeviceKind[battery_widget.device.kind] == battery_kind then
set_battery(battery_widget.device)
end
-- The delayed call will fire every time awesome finishes its main event loop
gears.timer.delayed_call(battery_widget.emit_signal, battery_widget, "upower::update", battery_widget.device)
end
for _, device in ipairs(get_device_path()) do
attach_to_device(device)
end
battery_widget:connect_signal( battery_widget:connect_signal(
'button::press', "upower::update",
function() function(widget, device)
awful.spawn("xfce4-power-manager-settings") if upower_glib.DeviceKind[battery_widget.device.kind] == battery_kind then
set_battery(device)
end end
)
battery_widget:connect_signal(
"mouse::enter",
function()
get_battery_info()
end
)
watch(
[[sh -c "upower -i $(upower -e | grep BAT) | grep state | awk '{print \$2}' | tr -d '\n'"]],
5,
function(widget, stdout)
local status = stdout:gsub('%\n', '')
if status == nil or status == '' then
battery_widget.container.battery_layout.spacing = dpi(0)
battery_widget.container.battery_layout.label.visible = false
battery_tooltip:set_text('No battery found')
battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached(
gears.color.recolor_image(icondir .. 'battery-off' .. '.svg', "#212121")))
end
update_battery(status)
end end
) )