[GH-ISSUE #82] upower module #8479

Closed
opened 2026-05-23 03:52:20 +01:00 by JakeStanger · 10 comments
Owner

Originally created by @dchinmay2 on GitHub (Mar 17, 2023).
Original GitHub issue: https://github.com/JakeStanger/ironbar/issues/82

upower: https://upower.freedesktop.org/

can be used to listen to device events like charger connected/battery level changed instead of polling.
I want to implement this feature and am planning to use the upower-dbus crate

Originally created by @dchinmay2 on GitHub (Mar 17, 2023). Original GitHub issue: https://github.com/JakeStanger/ironbar/issues/82 upower: https://upower.freedesktop.org/ can be used to listen to device events like charger connected/battery level changed instead of polling. I want to implement this feature and am planning to use the `upower-dbus` crate
Author
Owner

@JakeStanger commented on GitHub (Mar 17, 2023):

That'd be fantastic, a battery module is something I've been meaning to add to the backlog for some time. Go for it!

<!-- gh-comment-id:1473718701 --> @JakeStanger commented on GitHub (Mar 17, 2023): That'd be fantastic, a battery module is something I've been meaning to add to the backlog for some time. Go for it!
Author
Owner

@dchinmay2 commented on GitHub (Mar 17, 2023):

Thanks, this is what I have now: https://paste.sr.ht/~p00f/7061bf6067959b1c9b61f405665c9f377baed807

When I connect/disconnect the charger, the properties get printed on the terminal

{"BatteryLevel": OwnedValue(U32(1)), "HasHistory": OwnedValue(Bool(false)), "UpdateTime": OwnedValue(U64(1679089599)), "Capacity": OwnedValue(F64(0.0)), "Voltage": OwnedValue(F64(0.0)), "ChargeCycles": OwnedValue(I32(0)), "IconName": OwnedValue(Str(Str(Owned("battery-full-charging-symbolic")))), "Type": OwnedValue(U32(2)), "Serial": OwnedValue(Str(Str(Owned("")))), "PowerSupply": OwnedValue(Bool(true)), "EnergyEmpty": OwnedValue(F64(0.0)), "Energy": OwnedValue(F64(31.83)), "Model": OwnedValue(Str(Str(Owned("")))), "TimeToEmpty": OwnedValue(I64(0)), "HasStatistics": OwnedValue(Bool(false)), "Luminosity": OwnedValue(F64(0.0)), "WarningLevel": OwnedValue(U32(1)), "Percentage": OwnedValue(F64(78.0)), "TimeToFull": OwnedValue(I64(0)), "EnergyFull": OwnedValue(F64(40.46)), "IsRechargeable": OwnedValue(Bool(false)), "Online": OwnedValue(Bool(false)), "Technology": OwnedValue(U32(0)), "Vendor": OwnedValue(Str(Str(Owned("")))), "Temperature": OwnedValue(F64(0.0)), "EnergyFullDesign": OwnedValue(F64(0.0)), "IsPresent": OwnedValue(Bool(true)), "NativePath": OwnedValue(Str(Str(Owned("")))), "State": OwnedValue(U32(5)), "EnergyRate": OwnedValue(F64(0.0))}

This is a HashMap which has properties of the battery like percentage, time to full/empty, whether it is charging, etc

I'm having trouble implementing into_widget, can you help me here?

<!-- gh-comment-id:1474442426 --> @dchinmay2 commented on GitHub (Mar 17, 2023): Thanks, this is what I have now: https://paste.sr.ht/~p00f/7061bf6067959b1c9b61f405665c9f377baed807 When I connect/disconnect the charger, the properties get printed on the terminal ``` {"BatteryLevel": OwnedValue(U32(1)), "HasHistory": OwnedValue(Bool(false)), "UpdateTime": OwnedValue(U64(1679089599)), "Capacity": OwnedValue(F64(0.0)), "Voltage": OwnedValue(F64(0.0)), "ChargeCycles": OwnedValue(I32(0)), "IconName": OwnedValue(Str(Str(Owned("battery-full-charging-symbolic")))), "Type": OwnedValue(U32(2)), "Serial": OwnedValue(Str(Str(Owned("")))), "PowerSupply": OwnedValue(Bool(true)), "EnergyEmpty": OwnedValue(F64(0.0)), "Energy": OwnedValue(F64(31.83)), "Model": OwnedValue(Str(Str(Owned("")))), "TimeToEmpty": OwnedValue(I64(0)), "HasStatistics": OwnedValue(Bool(false)), "Luminosity": OwnedValue(F64(0.0)), "WarningLevel": OwnedValue(U32(1)), "Percentage": OwnedValue(F64(78.0)), "TimeToFull": OwnedValue(I64(0)), "EnergyFull": OwnedValue(F64(40.46)), "IsRechargeable": OwnedValue(Bool(false)), "Online": OwnedValue(Bool(false)), "Technology": OwnedValue(U32(0)), "Vendor": OwnedValue(Str(Str(Owned("")))), "Temperature": OwnedValue(F64(0.0)), "EnergyFullDesign": OwnedValue(F64(0.0)), "IsPresent": OwnedValue(Bool(true)), "NativePath": OwnedValue(Str(Str(Owned("")))), "State": OwnedValue(U32(5)), "EnergyRate": OwnedValue(F64(0.0))} ``` This is a HashMap which has properties of the battery like percentage, time to full/empty, whether it is charging, etc I'm having trouble implementing `into_widget`, can you help me here?
Author
Owner

@dchinmay2 commented on GitHub (Mar 17, 2023):

What are the associated types SendMessage and ReceiveMessage in the Module trait? I believe SendMessage is what the controller sends to the bar to draw? And then into_widget draws from the message whenever there is a message? Is that correct?

<!-- gh-comment-id:1474444156 --> @dchinmay2 commented on GitHub (Mar 17, 2023): What are the associated types `SendMessage` and `ReceiveMessage` in the `Module` trait? I believe `SendMessage` is what the controller sends to the bar to draw? And then `into_widget` draws from the message whenever there is a message? Is that correct?
Author
Owner

@JakeStanger commented on GitHub (Mar 17, 2023):

So the separation of controller/widget is really there for organisation, rather than functionality (at the moment at least anyway). With the current implementation, you could actually technically get away with doing all the rendering in the controller, or all the logic in into_widget.

SendMessage is pretty much what you described. The idea is the controller sends data to the widget/popup, and this is the type used to denote that. into_widget isn't called every time you send a message, instead you need to use context.widget_rx and attach a callback to that. You can then do the necessary UI updates when you receive an update.

ReceiveMessage is used to send events from the UI back to the controller, for example when a button is clicked. The controller can listen to its rx to receive these and fire off any necessary logic (ie send command to client, run script...)

I'd recommend having a look at the clock module implementation as the simplest example. Although from your current implementation, it looks like you're pretty much there :)

<!-- gh-comment-id:1474500645 --> @JakeStanger commented on GitHub (Mar 17, 2023): So the separation of controller/widget is really there for organisation, rather than functionality (at the moment at least anyway). With the current implementation, you could actually technically get away with doing all the rendering in the controller, or all the logic in `into_widget`. `SendMessage` is pretty much what you described. The idea is the controller sends data to the widget/popup, and this is the type used to denote that. `into_widget` isn't called every time you send a message, instead you need to use `context.widget_rx` and attach a callback to that. You can then do the necessary UI updates when you receive an update. `ReceiveMessage` is used to send events from the UI back to the controller, for example when a button is clicked. The controller can listen to its `rx` to receive these and fire off any necessary logic (ie send command to client, run script...) I'd recommend having a look at the `clock` module implementation as the simplest example. Although from your current implementation, it looks like you're pretty much there :)
Author
Owner

@dchinmay2 commented on GitHub (Mar 17, 2023):

Should the initial setup in spawn_controller be blocking or nonblocking (lines 36-44)?

I tried making everything nonblocking:
https://paste.sr.ht/~p00f/b6d7aa744218ae9466a5f96a2d89213db0c76a5c

but it crashed:
https://paste.sr.ht/~p00f/d373ae7c7fdaad64fdf1919534e05a80b009b7ca

<!-- gh-comment-id:1474506267 --> @dchinmay2 commented on GitHub (Mar 17, 2023): Should the initial setup in spawn_controller be blocking or nonblocking (lines 36-44)? I tried making everything nonblocking: https://paste.sr.ht/~p00f/b6d7aa744218ae9466a5f96a2d89213db0c76a5c but it crashed: https://paste.sr.ht/~p00f/d373ae7c7fdaad64fdf1919534e05a80b009b7ca
Author
Owner

@JakeStanger commented on GitHub (Mar 17, 2023):

Non-blocking/async is preferable, as the controller runs on the main GTK thread, so will otherwise block the UI for all bars/widgets.

The channels will error if you try to send but there is no open receiver. If you stick:

context.widget_rx.attach(None, |_| Continue(true));

inside into_widget, it should resolve that error (I think). And then you can obvs add your logic inside the callback.

<!-- gh-comment-id:1474508412 --> @JakeStanger commented on GitHub (Mar 17, 2023): Non-blocking/async is preferable, as the controller runs on the main GTK thread, so will otherwise block the UI for all bars/widgets. The channels will error if you try to send but there is no open receiver. If you stick: ```rs context.widget_rx.attach(None, |_| Continue(true)); ``` inside `into_widget`, it should resolve that error (I think). And then you can obvs add your logic inside the callback.
Author
Owner

@dchinmay2 commented on GitHub (Mar 17, 2023):

Nice, thanks

<!-- gh-comment-id:1474513806 --> @dchinmay2 commented on GitHub (Mar 17, 2023): Nice, thanks
Author
Owner

@yavko commented on GitHub (May 1, 2023):

I can't use the module and the docs don't appear on the wiki, I don't know why, and I'm on latest commit.
image

<!-- gh-comment-id:1529481384 --> @yavko commented on GitHub (May 1, 2023): I can't use the module and the docs don't appear on the wiki, I don't know why, and I'm on latest commit. ![image](https://user-images.githubusercontent.com/15178513/235428818-f6e328b7-2308-4e2c-9e03-4c5b36628223.png)
Author
Owner

@JakeStanger commented on GitHub (May 1, 2023):

I forgot to add the sidebar link on the wiki, that's there now. There's only two reasons I can see that it wouldn't show up there for you:

a) You're not actually on the latest commit
b) The feature flag is not enabled (it is by default, but I also forgot to stick this in the docs)

<!-- gh-comment-id:1529669168 --> @JakeStanger commented on GitHub (May 1, 2023): I forgot to add the sidebar link on the wiki, that's there now. There's only two reasons I can see that it wouldn't show up there for you: a) You're not actually on the latest commit b) The feature flag is not enabled (it is by default, but I also forgot to stick this in the docs)
Author
Owner

@yavko commented on GitHub (May 1, 2023):

b) The feature flag is not enabled (it is by default, but I also forgot to stick this in the docs)

Wait, yeah that would be why...

<!-- gh-comment-id:1529771683 --> @yavko commented on GitHub (May 1, 2023): > b) The feature flag is not enabled (it is by default, but I also forgot to stick this in the docs) Wait, yeah that would be why...
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
JakeStanger/ironbar#8479
No description provided.