每分钟运行 udev 脚本(显示 Dualshock 4 电池电量)

每分钟运行 udev 脚本(显示 Dualshock 4 电池电量)

我创建了一个简单的脚本,根据电池状态更改 Dualshock 4 Gamecontroller LED 颜色条(使用答案https://gaming.stackexchange.com/questions/336934/how-to-set-default-color-and-brightness-of-leds-of-the-dualshock-4-controller-on和电池电量状态https://wiki.gentoo.org/wiki/Sony_DualShock):

#!/bin/bash

function float_to_int() { 
  echo $1 | cut -d. -f1    # or use -d, if decimals separator is ,
}

LED=$(echo "$1" | egrep -o '[[:xdigit:]]{4}:[[:xdigit:]]{4}:[[:xdigit:]]{4}\.[[:xdigit:]]{4}')

[[ -z "$LED" || ! -d "/sys/class/leds/$LED:global" ]] && exit

BRIGHTNESS=0.2

POWER=$(cat "/sys/class/power_supply/sony_controller_battery_$2/capacity")

GREEN=$(float_to_int $(echo "($POWER*255/100*$BRIGHTNESS)" | bc -l))
RED=$(float_to_int $(echo "((255 - $POWER*255/100)*$BRIGHTNESS)" | bc -l))
BLUE=0

echo $RED > /sys/class/leds/$LED:red/brightness
echo $GREEN > /sys/class/leds/$LED:green/brightness
echo $BLUE > /sys/class/leds/$LED:blue/brightness

我在 /etc/udev/rules.d/10-local.rules 下创建了一个非常简单的 udev 规则,一旦连接控制器就运行此脚本。

ACTION=="add", SUBSYSTEM=="input", ATTRS{uniq}=="XX:XX:XX:XX:XX:XX" RUN+="/usr/local/bin/ds4led '%p' XX:XX:XX:XX:XX:XX"

到目前为止,这工作得很好。我现在需要的是让这个脚本每分钟左右运行一次(否则电池状态将不会更新)。

我尝试了几种方法来实现这一目标:

在 do-while 循环中运行整个脚本

while :
do
    // CODE
    sleep 60
done

-> 这适用于显示电池状态,但控制器本身不再可用

在后台的 do-while 循环中运行整个脚本

为此,我使用了括号和&符号语法:

(
while :
do
    // CODE
    sleep 60
done
) &

-> 这原则上是有效的,控制器是可用的。但是,一旦控制器断开连接,脚本就会继续运行,并抛出错误,此外,令我烦恼的是该脚本的多个实例不断运行。

解决方案?

如何解决多个实例不断运行,控制器断线脚本仍继续运行的问题?

当然,我可以编写一个额外的脚本,在删除控制器时运行,从而从一开始就终止仍在运行的脚本。但在这一点上,这个解决方案显得非常不优雅。难道没有一种简单的方法可以让这个脚本每分钟运行一次吗?我想从这个脚本中生成一个每分钟运行一次的 cronjob,并在控制器拔下插头后立即停止,但这似乎也不是那么优雅。

答案1

我相信您正在尝试解决错误的问题。子系统udev会报告设备何时连接(如果您小心的话,还会报告设备何时断开连接)。另一方面,cron子系统会定期运行一个进程。

因此,将两者放在一起并用于udev启用或禁用允许cron脚本执行其操作的切换。

在一个简单的层面上,它可能是这样的(不,我不特别推荐一个标志文件,/tmp除非你用权限和所有权来保护它)

乌德夫

ACTION=="add" [...] RUN+="touch /tmp/.ds4led_on"

计划任务脚本

#!/bin/bash
#
[[ -f "/tmp/.ds4led_on" ]] || exit 0

# ...Code to perform the update...

答案2

在 roaima 的回答的帮助下,我终于成功了:

我创建了 3 个不同的脚本/usr/local/bin

DS4LED

#!/bin/bash

function float_to_int() {
  echo $1 | cut -d. -f1    # or use -d, if decimals separator is ,
}

function setrgb() {
    LED=$(echo "$1" | egrep -o '[[:xdigit:]]{4}:[[:xdigit:]]{4}:[[:xdigit:]]{4}\.[[:xdigit:]]{4}')

    [[ -z "$LED" || ! -d "/sys/class/leds/$LED:global" ]] && exit

    BRIGHTNESS=0.2

    POWER=$(cat "/sys/class/power_supply/sony_controller_battery_$2/capacity")

    GREEN=$(float_to_int $(echo "($POWER*255/100*$BRIGHTNESS)" | bc -l))
    RED=$(float_to_int $(echo "((255 - $POWER*255/100)*$BRIGHTNESS)" | bc -l))
    BLUE=0

    echo $RED > /sys/class/leds/$LED:red/brightness
    echo $GREEN > /sys/class/leds/$LED:green/brightness
    echo $BLUE > /sys/class/leds/$LED:blue/brightness
}

if [ "$#" -ne 2 ]
then
    while read -r line; do
        linesplit=($line)

        LEDINPUT=${linesplit[0]}
        POWERINPUT=${linesplit[1]}

        setrgb $LEDINPUT $POWERINPUT
     done < /tmp/ds4led
else
    setrgb $1 $2
fi

ds4led_write

#!/bin/bash

/usr/local/bin/ds4led $1 $2
echo $1 $2 >> /tmp/ds4led

ds4led_删除

#!/bin/bash

sed "\!$1!d" /tmp/ds4led --in-place

我的/etc/udev/rules.d/20-ds4.rules文件:

ACTION=="add", KERNEL=="event28", ATTRS{uniq}=="00:1f:e2:e5:c3:2e" RUN+="/usr/local/bin/ds4led_write '%p' 00:1f:e2:e5:c3:2e"
ACTION=="remove", KERNEL=="event28", ATTRS{uniq}=="00:1f:e2:e5:c3:2e" RUN+="/usr/local/bin/ds4led_remove '%p'"

sudo crontab -e

* * * * * /usr/local/bin/ds4led

解释:

每当连接 Dualshock 4 控制器时,其序列号和电池标识符都会写入文件中/tmp/ds4led。在连接上,ds4led直接使用这些标识符直接调用脚本,以立即将 RGB 条设置为正确的颜色。此后,每分钟都会运行一个 crontab,检查该文件下/tmp/ds4led是否有连接的设备并执行 RGB 条过程。每当控制器断开连接时,其在文件中的条目就会被删除。

udev 规则: 由于由于我的粗过滤器,dualshock 4 控制器的每次连接都会生成大约 8 个 udev 触发器,因此我试图找到一个每个连接仅触发一次的 udev 事件。总共,每个设备都会触发:

/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input67 00:1f:e2:e5:c3:2e
/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input68 00:1f:e2:e5:c3:2e
/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input66 00:1f:e2:e5:c3:2e
/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input67/mouse3 00:1f:e2:e5:c3:2e
/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input66/js0 00:1f:e2:e5:c3:2e
/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input68/event27 00:1f:e2:e5:c3:2e
/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input66/event28 00:1f:e2:e5:c3:2e
/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:054C:09CC.0013/input/input67/event26 00:1f:e2:e5:c3:2e

我只是选择“event28”作为过滤器,因为它只会出现一次,并且与控制器的实际操纵杆部分有关(不要忘记每个 Dualshock 控制器都包含触摸板和其他模拟设备)。但是,我不确定“event28”到底是什么。

相关内容