You are not logged in.

#1 2024-03-15 14:08:15

user11
Member
Registered: 2023-10-19
Posts: 54

custom service that runs script repeatedly without consistent time.

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

#2 2024-03-15 14:54:07

seth
Member
Registered: 2012-09-03
Posts: 51,553

Re: custom service that runs script repeatedly without consistent time.

*) 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

#3 2024-03-15 16:49:54

user11
Member
Registered: 2023-10-19
Posts: 54

Re: custom service that runs script repeatedly without consistent time.

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

#4 2024-03-15 17:00:52

seth
Member
Registered: 2012-09-03
Posts: 51,553

Re: custom service that runs script repeatedly without consistent time.

* 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

#5 2024-03-15 22:21:33

user11
Member
Registered: 2023-10-19
Posts: 54

Re: custom service that runs script repeatedly without consistent time.

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

#6 2024-03-15 22:32:59

seth
Member
Registered: 2012-09-03
Posts: 51,553

Re: custom service that runs script repeatedly without consistent time.

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.

=> https://bbs.archlinux.org/viewtopic.php?id=57855

Offline

#7 2024-03-16 04:01:12

user11
Member
Registered: 2023-10-19
Posts: 54

Re: custom service that runs script repeatedly without consistent time.

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

#8 2024-03-16 20:11:17

user11
Member
Registered: 2023-10-19
Posts: 54

Re: custom service that runs script repeatedly without consistent time.

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

#9 2024-03-16 23:13:45

seth
Member
Registered: 2012-09-03
Posts: 51,553

Re: custom service that runs script repeatedly without consistent time.

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

#10 2024-03-17 04:32:01

user11
Member
Registered: 2023-10-19
Posts: 54

Re: custom service that runs script repeatedly without consistent time.

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

Board footer

Powered by FluxBB