Skip to content

Commit 9231aa7

Browse files
tidotuarcassani
andauthored
system-monitor-graph@rcassani: Add a battery system monitor graph (#1766)
--------- Co-authored-by: rcassani <raymundo.cassani@gmail.com>
1 parent 8e59fb3 commit 9231aa7

15 files changed

Lines changed: 778 additions & 263 deletions

File tree

system-monitor-graph@rcassani/files/system-monitor-graph@rcassani/desklet.js

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ const KIB_TO_B = 1024; // 1 KiB = 1,024 B
1919
const UUID = "system-monitor-graph@rcassani";
2020
const DESKLET_PATH = imports.ui.deskletManager.deskletMeta[UUID].path;
2121

22+
// Borrowed from battery@schorschii
23+
const UPowerInterface = `<node>
24+
<interface name="org.freedesktop.UPower.Device">
25+
<property name="TimeToEmpty" type="x" access="read" />
26+
<property name="TimeToFull" type="x" access="read" />
27+
</interface>
28+
</node>`;
29+
30+
const UPowerProxy = Gio.DBusProxy.makeProxyWrapper(UPowerInterface);
31+
const UPowerBusName = "org.freedesktop.UPower";
32+
2233
Gettext.bindtextdomain(UUID, GLib.get_home_dir() + "/.local/share/locale");
2334

2435
function _(str) {
@@ -48,6 +59,7 @@ SystemMonitorGraph.prototype = {
4859
this.settings.bindProperty(Settings.BindingDirection.IN, "data-prefix-gpumem", "data_prefix_gpumem", this.on_setting_changed);
4960
this.settings.bindProperty(Settings.BindingDirection.IN, "data-prefix-network", "data_prefix_network", this.on_setting_changed);
5061
this.settings.bindProperty(Settings.BindingDirection.IN, "network-interface", "network_interface", this.on_setting_changed);
62+
this.settings.bindProperty(Settings.BindingDirection.IN, "battery-name", "battery_name", this.on_setting_changed);
5163
this.settings.bindProperty(Settings.BindingDirection.IN, "filesystem", "filesystem", this.on_setting_changed);
5264
this.settings.bindProperty(Settings.BindingDirection.IN, "filesystem-label", "filesystem_label", this.on_setting_changed);
5365
this.settings.bindProperty(Settings.BindingDirection.IN, "gpu-manufacturer", "gpu_manufacturer", this.on_setting_changed);
@@ -68,6 +80,7 @@ SystemMonitorGraph.prototype = {
6880
this.settings.bindProperty(Settings.BindingDirection.IN, "line-color-gpu", "line_color_gpu", this.on_setting_changed);
6981
this.settings.bindProperty(Settings.BindingDirection.IN, "line-color-network-down", "line_color_network_down", this.on_setting_changed);
7082
this.settings.bindProperty(Settings.BindingDirection.IN, "line-color-network-up", "line_color_network_up", this.on_setting_changed);
83+
this.settings.bindProperty(Settings.BindingDirection.IN, "line-color-battery", "line_color_battery", this.on_setting_changed);
7184

7285
// initialize desklet GUI
7386
this.setupUI();
@@ -122,6 +135,11 @@ SystemMonitorGraph.prototype = {
122135
this.net_down_speed = 0;
123136
this.net_up_speed = 0;
124137
this.net_max_scale = 1; // Auto-scaling for network graph
138+
// battery values
139+
this.battery_percent = NaN;
140+
this.battery_capacity = NaN;
141+
this.battery_status = "";
142+
this.battery_time = "";
125143

126144
// set colors
127145
switch (this.type) {
@@ -145,6 +163,9 @@ SystemMonitorGraph.prototype = {
145163
this.line_color_down = this.line_color_network_down;
146164
this.line_color_up = this.line_color_network_up;
147165
break;
166+
case "battery":
167+
this.line_color = this.line_color_battery;
168+
break;
148169
}
149170
this.first_run = false;
150171
}
@@ -296,6 +317,18 @@ SystemMonitorGraph.prototype = {
296317
text2 = "";
297318
text3 = "↓ " + down_speed_formatted + " ↑ " + up_speed_formatted;
298319
break;
320+
321+
case "battery":
322+
this.get_battery_use();
323+
value = this.battery_capacity;
324+
text1 = _("Battery");
325+
text2 = this.battery_percent + "%";
326+
let prefix = (this.battery_status == "Charging") ? "⚡ " : (this.battery_percent <= 20 ? "🪫 " : "🔋 ");
327+
text3 = (this.battery_status == "Full") ? "🔋 " + _("Fully charged") :
328+
(this.battery_status == "Not charging") ? "🔌 " + _("Not charging") :
329+
(this.battery_status == "" || this.battery_status == "Unknown") ? "" :
330+
prefix + this.battery_time + _(" hrs");
331+
break;
299332
}
300333

301334
// For non-network types, concatenate new value to the main values array
@@ -963,6 +996,58 @@ SystemMonitorGraph.prototype = {
963996
}
964997
GLib.free(contents);
965998
});
966-
}
999+
},
1000+
1001+
1002+
get_battery_use: function() {
1003+
// Sysfs directory for battery info
1004+
let battery_dir = "/sys/class/power_supply/" + this.battery_name + "/";
1005+
// D-Bus object path for the battery device in the UPower daemon
1006+
let bus_path = "/org/freedesktop/UPower/devices/battery_" + this.battery_name;
1007+
1008+
// File capacity contains the battery charge percentage, integer number from 0 to 100
1009+
Gio.file_new_for_path(battery_dir + "capacity").load_contents_async(null, (file, response) => {
1010+
try {
1011+
let [success, contents, tag] = file.load_contents_finish(response);
1012+
if (success) {
1013+
let percent = parseInt(ByteArray.toString(contents));
1014+
this.battery_percent = percent >= 100 ? 100 : percent;
1015+
this.battery_capacity = this.battery_percent / 100.0;
1016+
}
1017+
GLib.free(contents);
1018+
} catch(error) {
1019+
global.log('Battery capacity file read error: ' + error.toString());
1020+
}
1021+
});
1022+
1023+
// File status contains the battery charge status, string
1024+
Gio.file_new_for_path(battery_dir + "status").load_contents_async(null, (file, response) => {
1025+
try {
1026+
let [success, contents, tag] = file.load_contents_finish(response);
1027+
if (success) {
1028+
this.battery_status = ByteArray.toString(contents).trim();
1029+
}
1030+
GLib.free(contents);
1031+
} catch(error) {
1032+
global.log('Battery status file read error: ' + error.toString());
1033+
}
1034+
});
1035+
1036+
try {
1037+
let upower_proxy = new UPowerProxy(Gio.DBus.system, UPowerBusName, bus_path);
1038+
let time_sec = (this.battery_status == "Charging") ? upower_proxy.TimeToFull : upower_proxy.TimeToEmpty;
1039+
this.battery_time = this.formatTime(time_sec);
1040+
} catch(error) {
1041+
global.log('Battery time file open error: ' + error.toString());
1042+
}
1043+
},
1044+
1045+
formatTime: function(timeSec) {
1046+
let totalMinutes = Math.round(timeSec / 60);
1047+
let minutes = String(Math.floor(totalMinutes % 60)).padStart(2, '0');
1048+
let hours = String(Math.floor(totalMinutes / 60)).padStart(2, '0');
1049+
let result = `${hours}:${minutes}`;
1050+
return (result == "00:00") ? "--:--" : result;
1051+
}
9671052

9681053
};

system-monitor-graph@rcassani/files/system-monitor-graph@rcassani/po/ca.po

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgstr ""
88
"Project-Id-Version: \n"
99
"Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-desklets/"
1010
"issues\n"
11-
"POT-Creation-Date: 2025-08-27 21:38-0400\n"
11+
"POT-Creation-Date: 2026-03-19 16:11+0200\n"
1212
"PO-Revision-Date: 2025-09-29 04:41+0200\n"
1313
"Last-Translator: Daniel <d3vf4n@tutanota.com>\n"
1414
"Language-Team: \n"
@@ -20,82 +20,99 @@ msgstr ""
2020
"X-Generator: Poedit 3.6\n"
2121

2222
#. settings-schema.json->type->options
23-
#. desklet.js:183
23+
#. desklet.js:204
2424
msgid "CPU"
2525
msgstr "CPU"
2626

27-
#. desklet.js:194 desklet.js:212 desklet.js:232 desklet.js:273 desklet.js:547
27+
#. desklet.js:215 desklet.js:233 desklet.js:253 desklet.js:294 desklet.js:580
2828
msgid "GB"
2929
msgstr "GB"
3030

31-
#. desklet.js:197 desklet.js:215 desklet.js:235 desklet.js:276 desklet.js:561
31+
#. desklet.js:218 desklet.js:236 desklet.js:256 desklet.js:297 desklet.js:594
3232
msgid "GiB"
3333
msgstr "GiB"
3434

3535
#. settings-schema.json->type->options
36-
#. desklet.js:199
36+
#. desklet.js:220
3737
msgid "RAM"
3838
msgstr "RAM"
3939

4040
#. settings-schema.json->type->options
41-
#. desklet.js:217
41+
#. desklet.js:238
4242
msgid "Swap"
4343
msgstr "Swap"
4444

45-
#. desklet.js:240
45+
#. desklet.js:261
4646
msgid "free of"
4747
msgstr "lliure de"
4848

49-
#. desklet.js:256
49+
#. desklet.js:277
5050
msgid "GPU Usage"
5151
msgstr "Ús de GPU"
5252

53-
#. desklet.js:278
53+
#. desklet.js:299
5454
msgid "GPU Memory"
5555
msgstr "Memòria de la GPU"
5656

5757
#. settings-schema.json->type->options
58-
#. desklet.js:290
58+
#. desklet.js:311
5959
msgid "Network"
6060
msgstr "Xarxa"
6161

62-
#. desklet.js:518 desklet.js:541
62+
#. settings-schema.json->type->options
63+
#. desklet.js:324
64+
msgid "Battery"
65+
msgstr ""
66+
67+
#. desklet.js:327
68+
msgid "Fully charged"
69+
msgstr ""
70+
71+
#. desklet.js:328
72+
msgid "Not charging"
73+
msgstr ""
74+
75+
#. desklet.js:330
76+
msgid " hrs"
77+
msgstr ""
78+
79+
#. desklet.js:551 desklet.js:574
6380
msgid "b"
6481
msgstr "b"
6582

66-
#. desklet.js:520 desklet.js:555 desklet.js:569
83+
#. desklet.js:553 desklet.js:588 desklet.js:602
6784
msgid "B"
6885
msgstr "B"
6986

70-
#. desklet.js:533
87+
#. desklet.js:566
7188
msgid "Gb"
7289
msgstr "Gb"
7390

74-
#. desklet.js:536
91+
#. desklet.js:569
7592
msgid "Mb"
7693
msgstr "Mb"
7794

78-
#. desklet.js:539
95+
#. desklet.js:572
7996
msgid "Kb"
8097
msgstr "Kb"
8198

82-
#. desklet.js:550
99+
#. desklet.js:583
83100
msgid "MB"
84101
msgstr "MB"
85102

86-
#. desklet.js:553
103+
#. desklet.js:586
87104
msgid "KB"
88105
msgstr "KB"
89106

90-
#. desklet.js:564
107+
#. desklet.js:597
91108
msgid "MiB"
92109
msgstr "MiB"
93110

94-
#. desklet.js:567
111+
#. desklet.js:600
95112
msgid "KiB"
96113
msgstr "KiB"
97114

98-
#. desklet.js:844 desklet.js:882
115+
#. desklet.js:877 desklet.js:915
99116
msgid "Error executing nvidia-smi command."
100117
msgstr "Error executant l'ordre nvidia-smi."
101118

@@ -194,6 +211,15 @@ msgstr ""
194211
"Deixeu-ho en blanc per a monitorar totes les interfícies. Per exemple: eth0, "
195212
"wlan0, enp0s3"
196213

214+
#. settings-schema.json->battery-name->description
215+
#, fuzzy
216+
msgid "Name of battery name to monitor"
217+
msgstr "Interfície de xarxa a monitorar"
218+
219+
#. settings-schema.json->battery-name->tooltip
220+
msgid "Check battery name in /sys/class/power_supply/ Examples: BAT0, BAT1"
221+
msgstr ""
222+
197223
#. settings-schema.json->filesystem->description
198224
msgid "Filesystem to monitor"
199225
msgstr "Sistema de fitxers a monitorar"
@@ -350,6 +376,7 @@ msgstr "Color de la línia de la CPU"
350376
#. settings-schema.json->line-color-gpu->tooltip
351377
#. settings-schema.json->line-color-network-down->tooltip
352378
#. settings-schema.json->line-color-network-up->tooltip
379+
#. settings-schema.json->line-color-battery->tooltip
353380
msgid "RGB or RGBA. Alpha is ignored"
354381
msgstr "RGB o RGBA. El canal alpha s'ignora"
355382

@@ -377,6 +404,11 @@ msgstr "Color de la línia de la velocitat de baixada"
377404
msgid "Line color Network Upload"
378405
msgstr "Color de la línia de la velocitat de pujada"
379406

407+
#. settings-schema.json->line-color-battery->description
408+
#, fuzzy
409+
msgid "Line color Battery"
410+
msgstr "Color de la línia de la memòria d'intercanvi (Swap)"
411+
380412
#. settings-schema.json->midline-color->description
381413
msgid "Grid color"
382414
msgstr "Color de la graella"

0 commit comments

Comments
 (0)