diff --git a/index.js b/index.js index 850e6e2..8bee65a 100644 --- a/index.js +++ b/index.js @@ -10,7 +10,7 @@ const { app } = require("electron"); global.ARGS = global.ARGS || {}; if (!process.env.DISPLAY) { - console.error(`$DISPLAY variable not set to run the GUI application, are you connected via SSH?`); + console.error(`\n$DISPLAY variable not set to run the GUI application, are you connected via SSH?`); console.error(`If you have installed the service use:`); console.error(` systemctl --user start touchkio.service`); console.error(`Alternatively export the variables first:`); diff --git a/js/hardware.js b/js/hardware.js index 26b285b..c1abca4 100644 --- a/js/hardware.js +++ b/js/hardware.js @@ -9,6 +9,11 @@ global.HARDWARE = global.HARDWARE || { status: null, session: {}, support: {}, + battery: { + level: { + path: null, + }, + }, display: { status: { path: null, @@ -41,6 +46,8 @@ const init = async () => { // Init globals HARDWARE.session.user = sessionUser(); HARDWARE.session.type = sessionType(); + HARDWARE.battery.level.path = getBatteryLevelPath(); + HARDWARE.support.batteryLevel = HARDWARE.battery.level.path !== null; HARDWARE.display.status.path = getDisplayStatusPath(); HARDWARE.support.displayStatus = HARDWARE.display.status.path !== null; HARDWARE.display.brightness.path = getDisplayBrightnessPath(); @@ -70,8 +77,9 @@ const init = async () => { console.log("Processor Usage:", getProcessorUsage()); console.log("Processor Temperature:", getProcessorTemperature()); - // Show display infos - console.log(`\nDisplay Status [${HARDWARE.display.status.path}]:`, getDisplayStatus()); + // Show hardware infos + console.log(`\nBattery Level [${HARDWARE.battery.level.path}]:`, getBatteryLevel()); + console.log(`Display Status [${HARDWARE.display.status.path}]:`, getDisplayStatus()); console.log(`Display Brightness [${HARDWARE.display.brightness.path}]:`, getDisplayBrightness(), "\n"); // Check for keyboard visibility @@ -309,6 +317,39 @@ const getProcessorTemperature = () => { return null; }; +/** + * Gets the current battery power level path using `/sys/class/power_supply`. + * + * @returns {string|null} The battery power level path or null if nothing was found. + */ +const getBatteryLevelPath = () => { + const power = "/sys/class/power_supply"; + for (const supply of fs.readdirSync(power)) { + const capacityFile = path.join(power, supply, "capacity"); + if (!fs.existsSync(capacityFile)) { + continue; + } + return path.join(power, supply); + } + return null; +}; + +/** + * Gets the current battery power level using `/sys/class/power_supply/.../capacity`. + * + * @returns {number|null} The battery power level in percentage or null if nothing was found. + */ +const getBatteryLevel = () => { + if (!HARDWARE.support.batteryLevel) { + return null; + } + const capacity = fs.readFileSync(`${HARDWARE.battery.level.path}/capacity`, "utf8").trim(); + if (capacity) { + return parseFloat(capacity); + } + return null; +}; + /** * Gets the current display status path using `/sys/class/drm`. * @@ -406,8 +447,8 @@ const getDisplayBrightnessMax = () => { if (!HARDWARE.support.displayBrightness) { return null; } - const max = execSyncCommand("cat", [`${HARDWARE.display.brightness.path}/max_brightness`]); - if (max !== null) { + const max = fs.readFileSync(`${HARDWARE.display.brightness.path}/max_brightness`, "utf8").trim(); + if (max) { return parseInt(max, 10); } return null; @@ -422,10 +463,10 @@ const getDisplayBrightness = () => { if (!HARDWARE.support.displayBrightness) { return null; } - const brightness = execSyncCommand("cat", [`${HARDWARE.display.brightness.path}/brightness`]); - if (brightness !== null) { - const max = HARDWARE.display.brightness.max; - return Math.round((parseInt(brightness, 10) / max) * 100); + const brightness = fs.readFileSync(`${HARDWARE.display.brightness.path}/brightness`, "utf8").trim(); + if (brightness) { + const max = HARDWARE.display.brightness.max || 1; + return Math.max(1, Math.min(Math.round((parseInt(brightness, 10) / max) * 100), 100)); } return null; }; @@ -720,6 +761,8 @@ module.exports = { getMemoryUsage, getProcessorUsage, getProcessorTemperature, + getBatteryLevelPath, + getBatteryLevel, getDisplayStatusPath, getDisplayStatus, setDisplayStatus, diff --git a/js/integration.js b/js/integration.js index 7e7dd49..f9abd2a 100644 --- a/js/integration.js +++ b/js/integration.js @@ -77,6 +77,7 @@ const init = async () => { initMemoryUsage(); initProcessorUsage(); initProcessorTemperature(); + initBatteryLevel(); initPackageUpgrades(); initHeartbeat(); initLastActive(); @@ -134,6 +135,7 @@ const update = async () => { updateMemoryUsage(); updateProcessorUsage(); updateProcessorTemperature(); + updateBatteryLevel(); }; /** @@ -692,6 +694,35 @@ const updateProcessorTemperature = () => { publishState("processor_temperature", processorTemperature); }; +/** + * Initializes the battery level sensor. + */ +const initBatteryLevel = () => { + if (!HARDWARE.support.batteryLevel) { + return; + } + const root = `${INTEGRATION.root}/battery_level`; + const config = { + name: "Battery Level", + unique_id: `${INTEGRATION.node}_battery_level`, + state_topic: `${root}/state`, + value_template: "{{ (value | float) | round(0) }}", + unit_of_measurement: "%", + icon: "mdi:battery-medium", + device: INTEGRATION.device, + }; + publishConfig("sensor", config); + updateBatteryLevel(); +}; + +/** + * Updates the battery level sensor via the mqtt connection. + */ +const updateBatteryLevel = () => { + const batteryLevel = hardware.getBatteryLevel(); + publishState("battery_level", batteryLevel); +}; + /** * Initializes the package upgrades sensor. */