1分ごとにudevスクリプトを実行する(Dualshock 4バッテリー残量表示)

1分ごとに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プロセスを定期的に実行します。

したがって、2つの組み合わせを使用して、スクリプトがそのタスクを実行できるようにするトグルを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_delete

#!/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ストリップを正しい色にすぐに設定します。その後、1分ごとに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」が正確に何であるかよくわかりません。

関連情報