diff --git a/awesome/src/theme/user_variables.lua b/awesome/src/theme/user_variables.lua index efac15f..eb5357e 100644 --- a/awesome/src/theme/user_variables.lua +++ b/awesome/src/theme/user_variables.lua @@ -8,11 +8,39 @@ local home = os.getenv("HOME") -- If you want different default programs, wallpaper path or modkey; edit this file. 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 -- City ID is also from there weather_secrets = { - key = "e71b00168ca7219563dde4514a425b14", - city_id = "2864118", + key = "", + city_id = "", unit = "metric" -- "metric" or "imperial" }, diff --git a/awesome/src/widgets/battery.lua b/awesome/src/widgets/battery.lua index 6ed2c55..909955e 100644 --- a/awesome/src/widgets/battery.lua +++ b/awesome/src/widgets/battery.lua @@ -1,21 +1,28 @@ +---@diagnostic disable: undefined-field -------------------------------- -- This is the battery widget -- -------------------------------- + -- Awesome Libs local awful = require("awful") local color = require("src.theme.colors") local dpi = require("beautiful").xresources.apply_dpi local gears = require("gears") +local lgi = require("lgi") local naughty = require("naughty") -local watch = awful.widget.watch +local upower_glib = lgi.require("UPowerGlib") local wibox = require("wibox") + require("src.core.signals") -- Icon directory path local icondir = awful.util.getdir("config") .. "src/assets/icons/battery/" --- Returns the battery widget -return function() +---Returns the battery widget +---@return wibox.widget +return function(battery_kind) + + -- Battery wibox.widget local battery_widget = wibox.widget { { { @@ -58,145 +65,171 @@ return function() 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 }, - text = "", mode = "inside", preferred_alignments = "middle", margins = dpi(10) } - local get_battery_info = function() - awful.spawn.easy_async_with_shell( - [[ upower -i $(upower -e | grep BAT) | grep "time to " ]], - function(stdout) - if stdout == nil or stdout == '' then - battery_tooltip:set_text('No Battery Found') - return - end - local rem_time = "" - if stdout:match("hour") then - rem_time = "Hours" - else - rem_time = "Minutes" - 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() + ---Sets the battery information for the widget + ---@param device UPowerGlib.Device battery + local function set_battery(device) + local battery_percentage = math.floor(device.percentage + 0.5) + local battery_status = upower_glib.DeviceState[device.state]:lower() + local battery_temp = device.temperature - local last_battery_check = os.time() - local notify_critical_battery = true + local battery_time = 1 + + if device.time_to_empty ~= 0 then + battery_time = device.time_to_empty + else + battery_time = device.time_to_full + end + + battery_time = math.floor(battery_time / 3600) .. "h, " .. math.floor((battery_time / 60) % 60) .. "m" + + if battery_temp == 0.0 then + battery_temp = "NaN" + else + battery_temp = math.floor(battery_temp + 0.5) .. "°C" + end + + if not battery_percentage then + return + end + + battery_widget:get_children_by_id("battery_layout")[1].spacing = dpi(5) + battery_widget:get_children_by_id("label")[1].visible = true + battery_widget:get_children_by_id("label")[1].text = battery_percentage .. '%' + + tooltip.markup = "Battery Status: " + .. battery_status .. "\nRemaining time: " + .. battery_time .. "\nTemperature: " + .. battery_temp .. "" + + local icon = 'battery' + + if battery_status == 'fully-charged' or battery_status == 'charging' and battery_percentage == 100 then + icon = icon .. '-' .. 'charging.svg' + naughty.notification { + 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 + elseif battery_percentage > 0 and battery_percentage < 10 and battery_status == 'discharging' then + icon = icon .. '-' .. 'alert.svg' + naughty.notification { + title = "Battery warning", + message = "Battery is running low!\n" .. battery_percentage .. "% left", + urgency = "critical", + icon = icondir .. icon, + timeout = 60 + } + battery_widget:get_children_by_id("icon")[1].image = gears.surface.load_uncached(gears.color.recolor_image(icondir .. icon, "#212121")) + return + end + + if battery_percentage > 0 and battery_percentage < 10 then + icon = icon .. '-' .. battery_status .. '-' .. 'outline' + elseif battery_percentage >= 10 and battery_percentage < 20 then + icon = icon .. '-' .. battery_status .. '-' .. '10' + elseif battery_percentage >= 20 and battery_percentage < 30 then + icon = icon .. '-' .. battery_status .. '-' .. '20' + elseif battery_percentage >= 30 and battery_percentage < 40 then + icon = icon .. '-' .. battery_status .. '-' .. '30' + elseif battery_percentage >= 40 and battery_percentage < 50 then + icon = icon .. '-' .. battery_status .. '-' .. '40' + elseif battery_percentage >= 50 and battery_percentage < 60 then + icon = icon .. '-' .. battery_status .. '-' .. '50' + elseif battery_percentage >= 60 and battery_percentage < 70 then + icon = icon .. '-' .. battery_status .. '-' .. '60' + elseif battery_percentage >= 70 and battery_percentage < 80 then + icon = icon .. '-' .. battery_status .. '-' .. '70' + elseif battery_percentage >= 80 and battery_percentage < 90 then + icon = icon .. '-' .. battery_status .. '-' .. '80' + elseif battery_percentage >= 90 and battery_percentage < 100 then + icon = icon .. '-' .. battery_status .. '-' .. '90' + end + + battery_widget:get_children_by_id("icon")[1].image = gears.surface.load_uncached(gears.color.recolor_image(icondir .. icon .. '.svg', "#212121")) + awesome.emit_signal("update::battery_widget", battery_percentage, icondir .. icon .. ".svg") - 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 - local update_battery = function(status) - awful.spawn.easy_async_with_shell( - [[sh -c "upower -i $(upower -e | grep BAT) | grep percentage | awk '{print \$2}' |tr -d '\n%'"]], - function(stdout) - local battery_percentage = tonumber(stdout) + ---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 "" - if not battery_percentage then - return - end + battery_widget.device = get_device_from_path(device_path) or upower_glib.Client():get_display_device() - battery_widget.container.battery_layout.spacing = dpi(5) - battery_widget.container.battery_layout.label.visible = true - battery_widget.container.battery_layout.label:set_text(battery_percentage .. '%') + battery_widget.device.on_notify = function(device) + battery_widget:emit_signal("upower::update", device) + end - local icon = 'battery' + -- 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 - if status == 'fully-charged' or status == 'charging' and battery_percentage == 100 then - icon = icon .. '-' .. 'charging' - battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached( - gears.color.recolor_image(icondir .. icon .. '.svg', "#212121"))) - return - end - - if battery_percentage > 0 and battery_percentage < 10 and status == 'discharging' then - icon = icon .. '-' .. 'alert' - if (os.difftime(os.time(), last_battery_check) > 300 or notify_critical_battery) then - last_battery_check = os.time() - notify_critical_battery = false - battery_warning() - end - battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached( - gears.color.recolor_image(icondir .. icon .. '.svg', "#212121"))) - return - end - - if battery_percentage > 0 and battery_percentage < 10 then - icon = icon .. '-' .. status .. '-' .. 'outline' - elseif battery_percentage >= 10 and battery_percentage < 20 then - icon = icon .. '-' .. status .. '-' .. '10' - elseif battery_percentage >= 20 and battery_percentage < 30 then - icon = icon .. '-' .. status .. '-' .. '20' - elseif battery_percentage >= 30 and battery_percentage < 40 then - icon = icon .. '-' .. status .. '-' .. '30' - elseif battery_percentage >= 40 and battery_percentage < 50 then - icon = icon .. '-' .. status .. '-' .. '40' - elseif battery_percentage >= 50 and battery_percentage < 60 then - icon = icon .. '-' .. status .. '-' .. '50' - elseif battery_percentage >= 60 and battery_percentage < 70 then - icon = icon .. '-' .. status .. '-' .. '60' - elseif battery_percentage >= 70 and battery_percentage < 80 then - icon = icon .. '-' .. status .. '-' .. '70' - elseif battery_percentage >= 80 and battery_percentage < 90 then - icon = icon .. '-' .. status .. '-' .. '80' - elseif battery_percentage >= 90 and battery_percentage < 100 then - icon = icon .. '-' .. status .. '-' .. '90' - end - - battery_widget.container.battery_layout.icon_margin.icon_layout.icon:set_image(gears.surface.load_uncached( - gears.color.recolor_image(icondir .. icon .. '.svg', "#212121"))) - awesome.emit_signal("update::battery_widget", battery_percentage, icondir .. icon .. ".svg") - 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 - Hover_signal(battery_widget, color["Purple200"], color["Grey900"]) + for _, device in ipairs(get_device_path()) do + attach_to_device(device) + end battery_widget:connect_signal( - 'button::press', - function() - awful.spawn("xfce4-power-manager-settings") - 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"))) + "upower::update", + function(widget, device) + if upower_glib.DeviceKind[battery_widget.device.kind] == battery_kind then + set_battery(device) end - update_battery(status) end )