web-dev-qa-db-ja.com

udevスクリプトを毎分実行します(Dualshock 4のバッテリーレベルを表示します)

バッテリーの状態に基づいてDualshock4ゲームコントローラーの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"

これは今のところ完全に機能します。今必要なのは、このスクリプトを1分ごとに実行することです(そうしないと、バッテリーの状態が更新されません)。

私はこれを達成するためにいくつかの方法を試しました:

do-whileループでスクリプト全体を実行する

while :
do
    // CODE
    sleep 60
done

->これはバッテリーの状態を表示するために機能しますが、コントローラー自体は使用できなくなります

スクリプト全体をバックグラウンドでdo-whileループで実行する

そのために、角かっことアンパサンド構文を使用しました。

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

->これは原則として機能し、コントローラーは使用可能です。しかし、コントローラーが切断されるとすぐに、スクリプトは実行を続行し、エラーを吐き出します。さらに、このスクリプトの複数のインスタンスが常に実行されていることに悩まされます。

解決策?

複数のインスタンスが常に実行され、コントローラーが切断されている場合でもスクリプトが実行を続行するという問題をどのように解決できますか?

確かに、コントローラーを削除して実行する追加のスクリプトを作成して、まだ実行中のスクリプトを最初から強制終了することができます。しかし、現時点では、この解決策は非常に不法なようです。このスクリプトを毎分実行する簡単な方法はありませんか?毎分実行され、コントローラーのプラグが抜かれるとすぐに停止するこのスクリプトからcronジョブを生成することを考えましたが、これもそれほどエレガントではないようです。

4
Jonas Dedden

あなたは間違った問題を解決しようとしていると思います。 udevサブシステムは、デバイスが接続されたとき(注意している場合は、デバイスが切断されたとき)を報告します。一方、cronサブシステムは定期的にプロセスを実行します。

したがって、2つを組み合わせ、udevを使用して、cronスクリプトがそのアクションを実行できるようにするトグルを有効または無効にします。

些細なレベルでは、次のようなものになる可能性があります(いいえ、権限と所有権で保護しない限り、/tmpのフラグファイルは特にお勧めしません)

Udev

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

Cronスクリプト

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

# ...Code to perform the update...
3
roaima

Roaimaの答えの助けを借りて、私はついにそれを機能させました:

/usr/local/binで3つの異なるスクリプトを作成しました。

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_remove

#!/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バー手順を実行します。コントローラが切断されるたびに、ファイル内のそのエントリが削除されます。

dev-rules:デュアルショック4コントローラーのすべての接続は、粗いフィルターのために約8つのudevトリガーを生成したため、接続ごとに1回だけトリガーされる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」を選択したのは、これが1回だけ表示され、コントローラの実際のジョイスティック部分と関係があるためです(すべてのデュアルショックコントローラはタッチパッドと追加のエミュレートされたデバイスで構成されていることを忘れないでください)。しかし、「event28」が実際に何であるかはわかりません。

0
Jonas Dedden