Files
community-plugins/battery-threshold/service.luau
T
Damian D'SouzaandGitHub 253668025d Fix/battery threshold setup (#136)
* refactor(battery-threshold): change setup to run script in terminal via sudo

* chore(battery-threshold): update dependencies

* docs(battery-threshold): update threshold.txt location description

* chore(battery-threshold): bump version
2026-07-28 21:12:15 -04:00

223 lines
6.4 KiB
Luau

--!nonstrict
local function get_batteries(): { string }
local batteries = {}
local files, _ = noctalia.listDir("/sys/class/power_supply")
if files then
for _, name in files do
local path = "/sys/class/power_supply/" .. name
if noctalia.fileExists(path .. "/charge_control_end_threshold") then
table.insert(batteries, path)
end
end
end
return batteries
end
local function get_active_battery(): string?
local configured = noctalia.getConfig("battery_device")
if
typeof(configured) == "string"
and configured ~= ""
and noctalia.fileExists(configured .. "/charge_control_end_threshold")
then
return configured
end
local list = get_batteries()
return list[1]
end
local function shell_quote(str: string): string
return "'" .. string.gsub(str, "'", "'\\''") .. "'"
end
local function check_writable(path: string, callback: (boolean) -> ())
noctalia.runAsync("test -w " .. shell_quote(path), function(res)
callback(res.exitCode == 0)
end)
end
local data_dir, data_dir_err = noctalia.pluginDataDir()
if not data_dir or data_dir_err then
noctalia.log(
"Failed to get plugin data directory: "
.. tostring(data_dir_err or "unknown error")
)
end
local THRESHOLD_FILE_PATH: string? = if data_dir
then data_dir .. "/threshold.txt"
else nil
local function set_threshold(value: number)
local battery = get_active_battery()
if not battery then
return
end
local threshold_file = battery .. "/charge_control_end_threshold"
local v = math.floor(value + 0.5)
if v < 40 then
v = 40
end
if v > 100 then
v = 100
end
noctalia.log("Setting charge threshold to " .. tostring(v) .. "% on " .. battery)
local ok, err = noctalia.writeFile(threshold_file, tostring(v) .. "\n")
if ok then
noctalia.state.set("current_threshold", v)
if THRESHOLD_FILE_PATH then
local save_ok, save_err =
noctalia.writeFile(THRESHOLD_FILE_PATH, tostring(v))
if not save_ok then
noctalia.log(
"Failed to write saved threshold to "
.. THRESHOLD_FILE_PATH
.. ": "
.. tostring(save_err)
)
end
end
else
noctalia.log("Failed to write threshold: " .. tostring(err))
noctalia.notifyError(
noctalia.tr("notification.error-title"),
noctalia.tr("notification.error-msg", { file = threshold_file })
)
end
end
local function check_status()
local battery = get_active_battery()
if not battery then
noctalia.state.set("is_available", false)
noctalia.state.set("is_writable", false)
noctalia.state.set("current_threshold", 0)
noctalia.state.set("battery_model_name", "")
return
end
noctalia.state.set("is_available", true)
local model_name = ""
local content, err = noctalia.readFile(battery .. "/model_name")
if content and not err then
model_name = noctalia.string.trim(content)
end
noctalia.state.set("battery_model_name", model_name)
local threshold_file = battery .. "/charge_control_end_threshold"
local threshold_content = noctalia.readFile(threshold_file)
local current_val = 0
if threshold_content then
current_val = tonumber(noctalia.string.trim(threshold_content)) or 0
noctalia.state.set("current_threshold", current_val)
end
check_writable(threshold_file, function(writable)
noctalia.state.set("is_writable", writable)
if writable then
local saved_val = nil
if THRESHOLD_FILE_PATH and noctalia.fileExists(THRESHOLD_FILE_PATH) then
local saved_content, read_err = noctalia.readFile(THRESHOLD_FILE_PATH)
if saved_content and not read_err then
saved_val = tonumber(noctalia.string.trim(saved_content))
elseif read_err then
noctalia.log(
"Failed to read saved threshold from "
.. THRESHOLD_FILE_PATH
.. ": "
.. tostring(read_err)
)
end
end
if not saved_val then
local config_val = noctalia.getConfig("charge_threshold")
if typeof(config_val) == "number" then
saved_val = config_val
end
end
if saved_val and saved_val >= 40 and saved_val <= 100 then
if saved_val ~= current_val then
set_threshold(saved_val)
end
end
end
end)
end
local function run_setup()
local user = noctalia.getenv("USER")
if not user or user == "" then
noctalia.log("Could not get USER environment variable")
return
end
local plugin_dir = noctalia.pluginDir()
if not plugin_dir then
noctalia.log("Could not get plugin directory")
return
end
local rules_script = plugin_dir .. "/setup_rules.sh"
local cmd =
string.format("bash %s %s", shell_quote(rules_script), shell_quote(user))
noctalia.log("Launching setup script in terminal: " .. cmd)
local launched = noctalia.runInTerminal(cmd)
if launched then
noctalia.log("Setup script launched in terminal")
else
noctalia.log("Failed to launch terminal for setup script")
noctalia.notifyError(
noctalia.tr("notification.setup-title"),
noctalia.tr("notification.setup-fail")
)
end
noctalia.state.set("run_setup_request", false)
end
noctalia.state.watch("run_setup_request", function(val)
if val == true then
run_setup()
end
end)
noctalia.state.watch("set_threshold_request", function(val)
if val then
local num = tonumber(val)
if num then
set_threshold(num)
end
end
end)
function onIpc(event, payload)
if event == "set" then
if payload then
local val = tonumber(payload)
if val and val >= 40 and val <= 100 then
set_threshold(val)
end
end
elseif event == "setup" then
run_setup()
end
end
function onConfigChanged()
check_status()
end
check_status()