You are not logged in.
1 - service:
[Unit]
Description=Warnings for battery
[Service]
ExecStart=/home/user/.local/bin/custom/battery-warn
2 - service's timer:
[Unit]
Description=Timer for battery warn
[Timer]
OnBootSec=0.2s
OnUnitActiveSec=0.2s
AccuracySec=1us
Unit=battery-warn-c.service
[Install]
WantedBy=timers.target
3 - service's script:
#!/bin/sh
for battery in /sys/class/power_supply/BAT?*; do
[ -n "${capacity+x}" ] && printf " "
case "$(cat "$battery/status" 2>&1)" in
"Full") status="Full" ;;
"Discharging") status="Discharging" ;;
"Charging") status="Charging" ;;
"Not charging") status="Not charging" ;;
*) exit 1 ;;
esac
capacity="$(cat "$battery/capacity" 2>&1)"
if ! grep -Fxq 'true' /tmp/has_noti; then
if [ "$status" = "Not charging" ] || [ "$status" = "Full" ]; then
id=$(/home/user/.local/bin/notify/notify+ --expire-time=0 --print-id "$capacity% charged" "unplug it")
echo 'true' > /tmp/has_noti
echo 'true' > /tmp/has_noti_is_charged
echo $id > /tmp/has_noti_id
elif [ "$status" = "Discharging" ] && [ "$capacity" -le 5 ]; then
id=$(/home/user/.local/bin/notify/notify+ --expire-time=0 --print-id "low battery" "charge it")
echo 'true' > /tmp/has_noti
echo $id > /tmp/has_noti_id
fi
elif grep -Fxq 'true' /tmp/has_noti; then
if grep -Fxq 'true' /tmp/has_noti_is_charged && [ ! "$status" = "¬" ] && [ ! "$status" = "Full" ]; then
notify+ --close=$(cat /tmp/has_noti_id)
echo 'false' > /tmp/has_noti
echo 'false' > /tmp/has_noti_is_charged
elif [ "$status" = "Charging" ] && [ "$capacity" -le 5 ]; then
/home/user/.local/bin/notify/notify+ --close=$(cat /tmp/has_noti_id)
echo 'false' > /tmp/has_noti
fi
fi
done
4 - erros shown in "journalctl -e"
Mar 15 10:58:52 host systemd[1]: Failed to start Warnings for battery.
Mar 15 10:58:52 host systemd[3223]: battery-warn-c.service: Start request repeated too quickly.
Mar 15 10:58:52 host systemd[3223]: battery-warn-c.service: Failed with result 'start-limit-hit'.
Mar 15 10:58:52 host systemd[3223]: Failed to start Warnings for battery.
Mar 15 10:58:53 host systemd[1]: battery-warn-c.service: Start request repeated too quickly.
Mar 15 10:58:53 host systemd[1]: battery-warn-c.service: Failed with result 'start-limit-hit'.
Mar 15 10:58:53 host systemd[1]: Failed to start Warnings for battery.
Mar 15 10:58:53 host systemd[3223]: battery-warn-c.service: Start request repeated too quickly.
Mar 15 10:58:53 host systemd[3223]: battery-warn-c.service: Failed with result 'start-limit-hit'.
Mar 15 10:58:53 host systemd[3223]: Failed to start Warnings for battery.
5 - The service fails a lot of the times, and eventually (about 3 to 5 seconds) succeeds.
Last edited by user11 (2024-03-15 14:11:58)
Offline
*) exit 1 ;;
will have the process "fail" and also you're trying to spawn that 5 tiems per second.
Before I try to understand what you're trying to achieve (did you copy that script from somewhere?), what's the actual plan here?
https://en.wikipedia.org/wiki/XY_problem
Get notified reg. the battery status?
Are you looking for a udev rule?
https://wiki.archlinux.org/title/Laptop#Battery_state
Offline
did you copy that script from somewhere
the majority of the script I wrote.
the only part I copied was:
for battery in /sys/class/power_supply/BAT?*; do
[ -n "${capacity+x}" ] && printf " "
case "$(cat "$battery/status" 2>&1)" in
"Full") status="Full" ;;
"Discharging") status="Discharging" ;;
"Charging") status="Charging" ;;
"Not charging") status="Not charging" ;;
*) exit 1 ;;
esac
what's the actual plan here
Send a notification whenever one of these two is true:
1 - the battery is full while it's still trying to be charged
2 - the battery is below 5% while it's not charging
I wanted to make these notifications persist only till I plug the charger in the case of the below 5% battery while uncharging case or till I unplug the case for the the full while still trying to charge case, without constantly sending notifications.
I forgot to mention that I took another "notify-send" from the internet, which has a flag to kill the notification using its id.
I have been using this script in my status bar, I assigned the frequency to update it to one second, and it works as it is intended to work, but I wish to use this as a systemd service instead.
Offline
* You want to use a udev rule, not poll the status at 5Hz
* Udev rule or systemd service, you'll have to import the relevant DBUS/X11 context, https://gist.github.com/AladW/de1c5676d93d05a5a0e1
* "OnUnitActiveSec=0.2s" is maybe wayyyyy too often - you might trigger the script in parallel
Offline
I spent about 2 hours trying to make it work with udev, but couldn't make it.
"OnUnitActiveSec=0.2s" is maybe wayyyyy too often
I tested with five seconds and I still got the "too quickly" warnings.
you'll have to import the relevant DBUS/X11 context
I believe I don't know how to do it, couldn't find anything in the internet to guide me in this regard.
Offline
couldn't find anything in the internet
I posted a link to function that does that (it fetches the environment from xinit, you'll have to use a different process depending on how you start the session)
I spent about 2 hours trying to make it work with udev, but couldn't make it.
Offline
I posted a link to function that does that
I had tried that, but for some reason the "tty$(fgconsole)" in the script gave me
Couldn't get a file descriptor referring to the console.
Now I went after another way to replace it (get the active VT name):
head -n 1 /sys/devices/virtual/tty/tty0/active
It doesn't output any warning/error, although I'm considerably unsure if this is a correct substitution.
I used it in the script, but didn't see any difference. With udev the notifications just doesn't pop out, even though it shows that the rule is executed:
Mar 16 00:32:54 host sudo[225019]: user : PWD=/home/user ; USER=root ; COMMAND=/usr/bin/tee /etc/udev/rules.d/99-lowbat.rules
Maybe the "USER=root" is the problem?
This is the rule (I simplified it with a simple script to test):
SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", ATTR{capacity}=="[0-100]", RUN+="/home/user/.local/bin/custom/test-script a"
The simplified script is:
#!/bin/bash
pid=$(pgrep -t $(head -n 1 /sys/devices/virtual/tty/tty0/active) xinit)
pid=$(pgrep -P $pid -n)
import_environment() {
(( pid )) && for var; do
IFS='=' read key val < <(grep -E -z "$var" /proc/$pid/environ)
printf -v "$key" %s "$val"
[[ ${!key} ]] && export "$key"
done
}
import_environment XAUTHORITY USER DISPLAY
notify-send a
Offline
I managed a way:
1 - Service
[Unit]
Description=Warnings for battery
[Service]
ExecStart=/home/user/.local/bin/custom/battery-warn
Restart=on-failure
RestartSec=1s
[Install]
WantedBy=default.target
2 - Script
#!/bin/sh
while :
do
for battery in /sys/class/power_supply/BAT?*; do
[ -n "${capacity+x}" ] && printf " "
case "$(cat "$battery/status" 2>&1)" in
"Full") status="Full" ;;
"Discharging") status="Discharging" ;;
"Charging") status="Charging" ;;
"Not charging") status="Not charging" ;;
*) exit 0 ;;
esac
capacity="$(cat "$battery/capacity" 2>&1)"
if ! grep -Fxq 'true' /tmp/has_noti; then
if [ "$status" = "Not charging" ] || [ "$status" = "Full" ]; then
id=$(/home/user/.local/bin/notify/notify+ --expire-time=0 --print-id "$capacity% charged" "unplug it")
echo 'true' > /tmp/has_noti
echo 'true' > /tmp/has_noti_is_charged
echo $id > /tmp/has_noti_id
elif [ "$status" = "Discharging" ] && [ "$capacity" -le 5 ]; then
id=$(/home/user/.local/bin/notify/notify+ --expire-time=0 --print-id "low battery" "charge it")
echo 'true' > /tmp/has_noti
echo $id > /tmp/has_noti_id
fi
elif grep -Fxq 'true' /tmp/has_noti; then
if grep -Fxq 'true' /tmp/has_noti_is_charged && [ ! "$status" = "Not charging" ] && [ ! "$status" = "Full" ]; then
/home/user/.local/bin/notify/notify+ --close=$(cat /tmp/has_noti_id)
echo 'false' > /tmp/has_noti
echo 'false' > /tmp/has_noti_is_charged
elif [ "$status" = "Charging" ] && [ "$capacity" -le 5 ]; then
/home/user/.local/bin/notify/notify+ --close=$(cat /tmp/has_noti_id)
echo 'false' > /tmp/has_noti
fi
fi
done
sleep 0.25
done
This is the "notify+" I use in the code: https://github.com/vlevit/notify-send.sh/tree/master
Regarding udev, I believe I would not like to use it, since it sends one signal for each time the battery level varies by 1, which make the case of pluging in and then immediately pluging out when with a low level of battery is uncomfortable, I'd have to wait for the battery level to decrease from 5% to 4% for the notification to pop up again for example (this situation is nonsensical to care about, but I want to make everything rigorous).
Last edited by user11 (2024-03-17 04:08:25)
Offline
You get events for plugging the charger?
Maybe the "USER=root" is the problem?
Yes.
pid=$(pgrep -t $(head -n 1 /sys/devices/virtual/tty/tty0/active) xinit)
Do you start your session using xinit?
Couldn't get a file descriptor referring to the console.
fgconsole
But you can straight up ask tty0 for the active console, yes.
This is the "notify+" I use
Looks like a wrapper around gdbus, are you running the service as a --user service?
Offline
You get events for plugging the charger?
When the status is "Not charging", the charger is plugged while the battery is can't charge anymore, then, when I unplug it, the script gets to know that it has been unplugged.
(reason: I have stated "echo 'true' > /tmp/has_noti_is_charged" when the "full battery" notification is sent, so when "if grep -Fxq 'true' /tmp/has_noti_is_charged && [ ! "$status" = "Not charging" ] && [ ! "$status" = "Full" ]" happens (when the battery is not "Not charging" while at the same time existing a "full battery" notification, which means I unplugged the charger), the notification gets closed)
For the "low battery level" case is similar.
Do you start your session using xinit?
Yes, through "~/.config/x11/xinitrc"
are you running the service as a --user service?
Yes.
Last edited by user11 (2024-03-17 04:34:57)
Offline