Compare commits
No commits in common. "88a0886681321a22dc6e4c568a219c6d5e7b3242" and "cf5581657ba2a9eb8fedb2f6f3468730a4b18f13" have entirely different histories.
88a0886681
...
cf5581657b
7 changed files with 17 additions and 146 deletions
|
|
@ -91,7 +91,6 @@ programs.nova-shell.modules = {
|
||||||
weather.interval = 3600000; # refresh interval in ms (default 1h)
|
weather.interval = 3600000; # refresh interval in ms (default 1h)
|
||||||
temperature.warm = 55; # °C threshold for warm color
|
temperature.warm = 55; # °C threshold for warm color
|
||||||
temperature.hot = 75; # °C threshold for hot color
|
temperature.hot = 75; # °C threshold for hot color
|
||||||
temperature.device = "x86_pkg_temp"; # pin to a specific thermal zone (default: system max)
|
|
||||||
battery.warning = 30; # % for warning notification
|
battery.warning = 30; # % for warning notification
|
||||||
battery.critical = 10; # % for critical blink + notification
|
battery.critical = 10; # % for critical blink + notification
|
||||||
cpu.interval = 2000; # polling interval in ms
|
cpu.interval = 2000; # polling interval in ms
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,7 @@ QtObject {
|
||||||
property var temperature: ({
|
property var temperature: ({
|
||||||
enable: true,
|
enable: true,
|
||||||
warm: 80,
|
warm: 80,
|
||||||
hot: 90,
|
hot: 90
|
||||||
device: ""
|
|
||||||
})
|
})
|
||||||
property var gpu: ({
|
property var gpu: ({
|
||||||
enable: true
|
enable: true
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,7 @@ QtObject {
|
||||||
readonly property Connections _notifConn: Connections {
|
readonly property Connections _notifConn: Connections {
|
||||||
target: root.notification
|
target: root.notification
|
||||||
function onClosed() {
|
function onClosed() {
|
||||||
if (root.state !== "dismissed")
|
M.NotifService.dismiss(root.id);
|
||||||
M.NotifService.dismiss(root.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ QtObject {
|
||||||
|
|
||||||
// ── Temperature ──────────────────────────────────────────────────────
|
// ── Temperature ──────────────────────────────────────────────────────
|
||||||
property int tempCelsius: 0
|
property int tempCelsius: 0
|
||||||
property var tempHistory: [] // 150 samples @ 4s each ≈ 10 min
|
property var tempHistory: [] // 150 samples @ 4s each ≈ 10 min
|
||||||
property var tempDevices: [] // [{name, celsius}] sorted hottest-first
|
|
||||||
|
|
||||||
// ── GPU ──────────────────────────────────────────────────────────────
|
// ── GPU ──────────────────────────────────────────────────────────────
|
||||||
property bool gpuAvailable: false
|
property bool gpuAvailable: false
|
||||||
|
|
@ -96,8 +95,6 @@ QtObject {
|
||||||
root.tempCelsius = ev.celsius;
|
root.tempCelsius = ev.celsius;
|
||||||
const th = root.tempHistory.concat([ev.celsius]);
|
const th = root.tempHistory.concat([ev.celsius]);
|
||||||
root.tempHistory = th.length > 150 ? th.slice(th.length - 150) : th;
|
root.tempHistory = th.length > 150 ? th.slice(th.length - 150) : th;
|
||||||
if (ev.devices)
|
|
||||||
root.tempDevices = ev.devices;
|
|
||||||
} else if (ev.type === "gpu") {
|
} else if (ev.type === "gpu") {
|
||||||
root.gpuAvailable = true;
|
root.gpuAvailable = true;
|
||||||
root.gpuVendor = ev.vendor;
|
root.gpuVendor = ev.vendor;
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,7 @@ M.BarSection {
|
||||||
|
|
||||||
readonly property int _warm: M.Modules.temperature.warm || 80
|
readonly property int _warm: M.Modules.temperature.warm || 80
|
||||||
readonly property int _hot: M.Modules.temperature.hot || 90
|
readonly property int _hot: M.Modules.temperature.hot || 90
|
||||||
readonly property string _deviceFilter: M.Modules.temperature.device || ""
|
readonly property int _temp: M.SystemStats.tempCelsius
|
||||||
|
|
||||||
// If a device filter is set, use that device's temp; otherwise fall back to system max
|
|
||||||
readonly property int _temp: {
|
|
||||||
if (_deviceFilter !== "") {
|
|
||||||
const dev = M.SystemStats.tempDevices.find(d => d.name === _deviceFilter);
|
|
||||||
if (dev)
|
|
||||||
return dev.celsius;
|
|
||||||
}
|
|
||||||
return M.SystemStats.tempCelsius;
|
|
||||||
}
|
|
||||||
|
|
||||||
property color _stateColor: _temp > _hot ? M.Theme.base08 : _temp > _warm ? M.Theme.base0A : root.accentColor
|
property color _stateColor: _temp > _hot ? M.Theme.base08 : _temp > _warm ? M.Theme.base0A : root.accentColor
|
||||||
Behavior on _stateColor {
|
Behavior on _stateColor {
|
||||||
|
|
@ -267,57 +257,6 @@ M.BarSection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per-device breakdown
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width - 16
|
|
||||||
height: 1
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: M.Theme.base03
|
|
||||||
visible: M.SystemStats.tempDevices.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: M.SystemStats.tempDevices
|
|
||||||
delegate: Item {
|
|
||||||
required property var modelData
|
|
||||||
width: hoverPanel.contentWidth
|
|
||||||
height: 22
|
|
||||||
|
|
||||||
readonly property bool _isActive: root._deviceFilter === modelData.name
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 8
|
|
||||||
anchors.rightMargin: 8
|
|
||||||
color: _isActive ? Qt.rgba(root.accentColor.r, root.accentColor.g, root.accentColor.b, 0.12) : "transparent"
|
|
||||||
radius: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 12
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
text: modelData.name
|
|
||||||
color: _isActive ? root.accentColor : M.Theme.base04
|
|
||||||
font.pixelSize: M.Theme.fontSize - 2
|
|
||||||
font.family: M.Theme.fontFamily
|
|
||||||
elide: Text.ElideRight
|
|
||||||
width: parent.width - 80
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 12
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
text: modelData.celsius + "\u00B0C"
|
|
||||||
color: root._tempColor(modelData.celsius)
|
|
||||||
font.pixelSize: M.Theme.fontSize - 2
|
|
||||||
font.family: M.Theme.fontFamily
|
|
||||||
font.bold: _isActive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: 1
|
width: 1
|
||||||
height: 4
|
height: 4
|
||||||
|
|
|
||||||
|
|
@ -141,14 +141,6 @@ in
|
||||||
default = 90;
|
default = 90;
|
||||||
description = "Temperature threshold for hot state (°C).";
|
description = "Temperature threshold for hot state (°C).";
|
||||||
};
|
};
|
||||||
device = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
description = ''
|
|
||||||
Thermal zone device name to use for the primary temperature reading
|
|
||||||
(e.g. "x86_pkg_temp", "acpitz"). Leave empty to use the system maximum.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
battery = moduleOpt "battery" {
|
battery = moduleOpt "battery" {
|
||||||
warning = lib.mkOption {
|
warning = lib.mkOption {
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,25 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub fn read_temp_celsius() -> Option<i32> {
|
||||||
pub struct ThermalDevice {
|
let mut max: Option<i32> = None;
|
||||||
pub name: String,
|
|
||||||
pub celsius: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_thermal_devices() -> Vec<ThermalDevice> {
|
|
||||||
let mut by_name: HashMap<String, i32> = HashMap::new();
|
|
||||||
|
|
||||||
for i in 0.. {
|
for i in 0.. {
|
||||||
let temp_path = format!("/sys/class/thermal/thermal_zone{i}/temp");
|
let path = format!("/sys/class/thermal/thermal_zone{i}/temp");
|
||||||
let type_path = format!("/sys/class/thermal/thermal_zone{i}/type");
|
match fs::read_to_string(&path) {
|
||||||
|
Ok(s) => {
|
||||||
let temp_str = match fs::read_to_string(&temp_path) {
|
if let Ok(millic) = s.trim().parse::<i32>() {
|
||||||
Ok(s) => s,
|
let c = millic / 1000;
|
||||||
|
max = Some(max.map_or(c, |m: i32| m.max(c)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
};
|
|
||||||
|
|
||||||
let millic: i32 = match temp_str.trim().parse() {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
let celsius = millic / 1000;
|
|
||||||
|
|
||||||
let name = fs::read_to_string(&type_path)
|
|
||||||
.map(|s| s.trim().to_string())
|
|
||||||
.unwrap_or_else(|_| format!("zone{i}"));
|
|
||||||
|
|
||||||
// Keep the highest temp seen for each device type
|
|
||||||
let entry = by_name.entry(name).or_insert(celsius);
|
|
||||||
if celsius > *entry {
|
|
||||||
*entry = celsius;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
max
|
||||||
let mut devices: Vec<ThermalDevice> = by_name
|
|
||||||
.into_iter()
|
|
||||||
.map(|(name, celsius)| ThermalDevice { name, celsius })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Sort descending by temp so the hottest shows first
|
|
||||||
devices.sort_by(|a, b| b.celsius.cmp(&a.celsius));
|
|
||||||
devices
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_temp(out: &mut impl Write) {
|
pub fn emit_temp(out: &mut impl Write) {
|
||||||
let devices = read_thermal_devices();
|
if let Some(c) = read_temp_celsius() {
|
||||||
if devices.is_empty() {
|
let _ = writeln!(out, "{{\"type\":\"temp\",\"celsius\":{c}}}");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let max = devices.iter().map(|d| d.celsius).max().unwrap_or(0);
|
|
||||||
|
|
||||||
let devices_json: Vec<String> = devices
|
|
||||||
.iter()
|
|
||||||
.map(|d| {
|
|
||||||
format!(
|
|
||||||
"{{\"name\":{},\"celsius\":{}}}",
|
|
||||||
json_str(&d.name),
|
|
||||||
d.celsius
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let _ = writeln!(
|
|
||||||
out,
|
|
||||||
"{{\"type\":\"temp\",\"celsius\":{max},\"devices\":[{}]}}",
|
|
||||||
devices_json.join(",")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_str(s: &str) -> String {
|
|
||||||
let escaped = s.replace('\\', "\\\\").replace('"', "\\\"");
|
|
||||||
format!("\"{escaped}\"")
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue