ledcontrol: update for upcoming changes

Signed-off-by: AuxXxilium <info@auxxxilium.tech>
This commit is contained in:
AuxXxilium 2024-10-24 18:28:38 +02:00
parent 5cd825ad13
commit ebf5d5ca84
5 changed files with 430 additions and 3 deletions

View File

@ -0,0 +1,314 @@
#!/usr/bin/bash
# function for removing lockfile
exit-ugreen-diskiomon() {
if [[ -f "/var/run/ugreen-diskiomon.lock" ]]; then
rm "/var/run/ugreen-diskiomon.lock"
fi
kill $smart_check_pid 2>/dev/null
kill $zpool_check_pid 2>/dev/null
kill $disk_online_check_pid 2>/dev/null
}
# trap exit and remove lockfile
trap 'exit-ugreen-diskiomon' EXIT
# check if script is already running
if [[ -f "/var/run/ugreen-diskiomon.lock" ]]; then
echo "ugreen-diskiomon already running!"
exit 1
fi
touch /var/run/ugreen-diskiomon.lock
# use variables from config file (unRAID specific)
if [[ -f /boot/config/plugins/ugreenleds-driver/settings.cfg ]]; then
source /boot/config/plugins/ugreenleds-driver/settings.cfg
fi
# load environment variables
if [[ -f /etc/ugreen-leds.conf ]]; then
source /etc/ugreen-leds.conf
fi
# led-disk mapping (see https://github.com/miskcoo/ugreen_dx4600_leds_controller/pull/4)
MAPPING_METHOD=${MAPPING_METHOD:=ata} # ata, hctl, serial
led_map=(disk1 disk2 disk3 disk4 disk5 disk6 disk7 disk8)
# hctl, $> lsblk -S -x hctl -o hctl,serial,name
# NOTE: It is reported that the order below should be adjusted for each model.
# Please check the disk mapping section in https://github.com/miskcoo/ugreen_dx4600_leds_controller/blob/master/README.md.
hctl_map=("0:0:0:0" "1:0:0:0" "2:0:0:0" "3:0:0:0" "4:0:0:0" "5:0:0:0" "6:0:0:0" "7:0:0:0")
# serial number, $> lsblk -S -x hctl -o hctl,serial,name
serial_map=(${DISK_SERIAL})
# ata number, $> ls /sys/block | egrep ata\d
ata_map=("ata1" "ata2" "ata3" "ata4" "ata5" "ata6" "ata7" "ata8")
if which dmidecode > /dev/null; then
product_name=$(dmidecode --string system-product-name)
case "${product_name}" in
DXP6800*) # tested on DXP6800 Pro
echo "Found UGREEN DXP6800 series"
hctl_map=("2:0:0:0" "3:0:0:0" "4:0:0:0" "5:0:0:0" "0:0:0:0" "1:0:0:0")
ata_map=("ata3" "ata4" "ata5" "ata6" "ata1" "ata2")
;;
DX4600*) # tested on DX4600 Pro
echo "Found UGREEN DX4600 series"
;;
DX4700*)
echo "Found UGREEN DX4700 series"
;;
DXP2800*) # see issue #19
echo "Found UGREEN DXP2800 series"
;;
DXP4800*)
echo "Found UGREEN DXP4800 series"
;;
DXP8800*) # tested on DXP8800 Plus
echo "Found UGREEN DXP8800 series"
# using the default mapping
;;
*)
if [[ "${MAPPING_METHOD}" == "hctl" || "${MAPPING_METHOD}" == "ata" ]]; then
echo -e "\033[0;31mUsing the default HCTL order. Please check it maps to your disk slots correctly."
echo -e "If you confirm that the HCTL order is correct, or find it is different, you can "
echo -e "submit an issue to let us know, so we can update the script."
echo -e "Please read the disk mapping section in the link below for more details. "
echo -e " https://github.com/miskcoo/ugreen_dx4600_leds_controller/blob/master/README.md\033[0m"
fi
;;
esac
elif [[ "${MAPPING_METHOD}" == "hctl" || "${MAPPING_METHOD}" == "ata" ]]; then
echo -e "\033[0;31minstalling the tool `dmidecode` is suggested; otherwise the script cannot detect your device and adjust the hctl/ata_map\033[0m"
fi
declare -A devices
# set monitor SMART information to true by default if not running unRAID
if [[ -f /etc/unraid-version ]]; then
CHECK_SMART=false
else
CHECK_SMART=${CHECK_SMART:=true}
fi
# polling rate for smartctl. 360 seconds by default
CHECK_SMART_INTERVAL=${CHECK_SMART_INTERVAL:=360}
# refresh interval from disk leds
LED_REFRESH_INTERVAL=${LED_REFRESH_INTERVAL:=0.1}
# whether to check zpool health
CHECK_ZPOOL=${CHECK_ZPOOL:=false}
# polling rate for checking zpool health. 5 seconds by default
CHECK_ZPOOL_INTERVAL=${CHECK_ZPOOL_INTERVAL:=5}
# polling rate for checking disk online. 5 seconds by default
CHECK_DISK_ONLINE_INTERVAL=${CHECK_DISK_ONLINE_INTERVAL:=5}
COLOR_DISK_HEALTH=${COLOR_DISK_HEALTH:="255 255 255"}
COLOR_DISK_UNAVAIL=${COLOR_DISK_UNAVAIL:="255 0 0"}
COLOR_ZPOOL_FAIL=${COLOR_ZPOOL_FAIL:="255 0 0"}
COLOR_SMART_FAIL=${COLOR_SMART_FAIL:="255 0 0"}
BRIGHTNESS_DISK_LEDS=${BRIGHTNESS_DISK_LEDS:="255"}
{ lsmod | grep ledtrig_oneshot > /dev/null; } || { modprobe -v ledtrig_oneshot && sleep 2; }
function disk_enumerating_string() {
if [[ $MAPPING_METHOD == ata ]]; then
ls -ahl /sys/block | sed 's/\/$//' | awk '{
if (match($0, /ata[0-9]+/)) {
ata = substr($0, RSTART, RLENGTH);
if (match($0, /[^\/]+$/)) {
basename = substr($0, RSTART, RLENGTH);
print basename, ata;
}
}
}'
elif [[ $MAPPING_METHOD == hctl || $MAPPING_METHOD == serial ]]; then
lsblk -S -o name,${MAPPING_METHOD},tran | grep sata
else
echo Unsupported mapping method: ${MAPPING_METHOD}
exit 1
fi
}
echo Enumerating disks based on $MAPPING_METHOD...
declare -A dev_map
while read line
do
blk_line=($line)
key=${blk_line[1]}
val=${blk_line[0]}
dev_map[${key}]=${val}
echo $MAPPING_METHOD ${key} ">>" ${dev_map[${key}]}
done <<< "$(disk_enumerating_string)"
# initialize LEDs
declare -A dev_to_led_map
for i in "${!led_map[@]}"; do
led=${led_map[i]}
if [[ -d /sys/class/leds/$led ]]; then
echo oneshot > /sys/class/leds/$led/trigger
echo 1 > /sys/class/leds/$led/invert
echo 100 > /sys/class/leds/$led/delay_on
echo 100 > /sys/class/leds/$led/delay_off
echo "$COLOR_DISK_HEALTH" > /sys/class/leds/$led/color
echo "$BRIGHTNESS_DISK_LEDS" > /sys/class/leds/$led/brightness
# find corresponding device
_tmp_str=${MAPPING_METHOD}_map[@]
_tmp_arr=(${!_tmp_str})
if [[ -v "dev_map[${_tmp_arr[i]}]" ]]; then
dev=${dev_map[${_tmp_arr[i]}]}
if [[ -f /sys/class/block/${dev}/stat ]]; then
devices[$led]=${dev}
dev_to_led_map[$dev]=$led
else
# turn off the led if no disk installed on this slot
echo 0 > /sys/class/leds/$led/brightness
echo none > /sys/class/leds/$led/trigger
fi
else
# turn off the led if no disk installed on this slot
echo 0 > /sys/class/leds/$led/brightness
echo none > /sys/class/leds/$led/trigger
fi
fi
done
# construct zpool device mapping
declare -A zpool_ledmap
if [ "$CHECK_ZPOOL" = true ]; then
echo Enumerating zpool devices...
while read line
do
zpool_dev_line=($line)
zpool_dev_name=${zpool_dev_line[0]}
zpool_scsi_dev_name="unknown"
# zpool_dev_state=${zpool_dev_line[1]}
case "$zpool_dev_name" in
sd*)
# remove the trailing partition number
zpool_scsi_dev_name=$(echo $zpool_dev_name | sed 's/[0-9]*$//')
;;
dm*)
# find the underlying block device of the encrypted device
dm_slaves=($(ls /sys/block/${zpool_dev_name}/slaves))
zpool_scsi_dev_name=${dm_slaves[0]}
;;
*)
echo Unsupported zpool device type ${zpool_dev_name}.
;;
esac
# if the detected scsi device can be found in the mapping array
#echo zpool $zpool_dev_name ">>" $zpool_scsi_dev_name ">>" ${dev_to_led_map[${zpool_scsi_dev_name}]}
if [[ -v "dev_to_led_map[${zpool_scsi_dev_name}]" ]]; then
zpool_ledmap[$zpool_dev_name]=${dev_to_led_map[${zpool_scsi_dev_name}]}
echo "zpool device" $zpool_dev_name ">>" $zpool_scsi_dev_name ">> LED:"${zpool_ledmap[$zpool_dev_name]}
fi
done <<< "$(zpool status -L | egrep ^\\s*\(sd\|dm\))"
function zpool_check_loop() {
while true; do
while read line
do
zpool_dev_line=($line)
zpool_dev_name=${zpool_dev_line[0]}
zpool_dev_state=${zpool_dev_line[1]}
# TODO: do something if the pool is unhealthy?
if [[ -v "zpool_ledmap[${zpool_dev_name}]" ]]; then
led=${zpool_ledmap[$zpool_dev_name]}
if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then
continue;
fi
if [[ "${zpool_dev_state}" != "ONLINE" ]]; then
echo "$COLOR_ZPOOL_FAIL" > /sys/class/leds/$led/color
echo Disk failure detected on /dev/$dev at $(date +%Y-%m-%d' '%H:%M:%S)
fi
# ==== To recover from an error, you should restart the script ====
## case "${zpool_dev_state}" in
## ONLINE)
## # echo "$COLOR_DISK_HEALTH" > /sys/class/leds/$led/color
## ;;
## *)
## echo "255 0 0" > /sys/class/leds/$led/color
## ;;
## esac
fi
done <<< "$(zpool status -L | egrep ^\\s*\(sd\|dm\))"
sleep ${CHECK_ZPOOL_INTERVAL}s
done
}
zpool_check_loop &
zpool_check_pid=$!
fi
# check disk health if enabled
if [ "$CHECK_SMART" = true ]; then
(
while true; do
for led in "${!devices[@]}"; do
if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then
continue;
fi
dev=${devices[$led]}
if [[ -z $(smartctl -H /dev/${dev} | grep PASSED) ]]; then
echo "$COLOR_SMART_FAIL" > /sys/class/leds/$led/color
echo Disk failure detected on /dev/$dev at $(date +%Y-%m-%d' '%H:%M:%S)
continue
fi
done
sleep ${CHECK_SMART_INTERVAL}s
done
) &
smart_check_pid=$!
fi
# check disk online status
(
while true; do
for led in "${!devices[@]}"; do
dev=${devices[$led]}
if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then
continue;
fi
if [[ ! -f /sys/class/block/${dev}/stat ]]; then
echo "$COLOR_DISK_UNAVAIL" > /sys/class/leds/$led/color 2>/dev/null
echo Disk /dev/$dev went offline at $(date +%Y-%m-%d' '%H:%M:%S)
continue
fi
done
sleep ${CHECK_DISK_ONLINE_INTERVAL}s
done
) &
disk_online_check_pid=$!
# monitor disk activities
declare -A diskio_data_rw
while true; do
for led in "${!devices[@]}"; do
# if $dev does not exist, diskio_new_rw="", which will be safe
diskio_new_rw="$(cat /sys/block/${devices[$led]}/stat 2>/dev/null)"
if [ "${diskio_data_rw[$led]}" != "${diskio_new_rw}" ]; then
echo 1 > /sys/class/leds/$led/shot
fi
diskio_data_rw[$led]=$diskio_new_rw
done
sleep ${LED_REFRESH_INTERVAL}s
done

View File

@ -0,0 +1,88 @@
#!/usr/bin/bash
# function for removing lockfile
exit-ugreen-netdevmon() {
if [[ -f "/var/run/ugreen-netdevmon.lock" ]]; then
rm "/var/run/ugreen-netdevmon.lock"
fi
}
# trap exit and remove lockfile
trap 'exit-ugreen-netdevmon' EXIT
# check if script is already running
if [[ -f "/var/run/ugreen-netdevmon.lock" ]]; then
echo "ugreen-netdevmon already running!"
exit 1
fi
touch /var/run/ugreen-netdevmon.lock
{ lsmod | grep ledtrig_netdev > /dev/null; } || { modprobe -v ledtrig_netdev && sleep 2; }
# load environment variables
if [[ -f /etc/ugreen-leds.conf ]]; then
source /etc/ugreen-leds.conf
fi
COLOR_NETDEV_NORMAL=${COLOR_NETDEV_NORMAL:="255 255 255"}
COLOR_NETDEV_GATEWAY_UNREACHABLE=${COLOR_NETDEV_GATEWAY_UNREACHABLE:="255 0 0"}
BRIGHTNESS_NETDEV_LED=${BRIGHTNESS_NETDEV_LED:="255"}
CHECK_NETDEV_INTERVAL=${CHECK_NETDEV_INTERVAL:=60}
CHECK_GATEWAY_CONNECTIVITY=${CHECK_GATEWAY_CONNECTIVITY:=false}
CHECK_LINK_SPEED=${CHECK_LINK_SPEED:=false}
led="netdev"
netdev_name=$1
echo netdev > /sys/class/leds/$led/trigger
echo $netdev_name > /sys/class/leds/$led/device_name
echo 1 > /sys/class/leds/$led/link
echo ${NETDEV_BLINK_TX:=1} > /sys/class/leds/$led/tx
echo ${NETDEV_BLINK_RX:=1} > /sys/class/leds/$led/rx
echo ${NETDEV_BLINK_INTERVAL:=200} > /sys/class/leds/$led/interval
echo $COLOR_NETDEV_NORMAL > /sys/class/leds/$led/color
echo $BRIGHTNESS_NETDEV_LED > /sys/class/leds/$led/brightness
function set_netdev_normal_color() {
color=$COLOR_NETDEV_NORMAL
if [[ $CHECK_LINK_SPEED == true ]]; then
case $(cat /sys/class/net/$netdev_name/speed) in
100) color=${COLOR_NETDEV_LINK_100:=$COLOR_NETDEV_NORMAL};;
1000) color=${COLOR_NETDEV_LINK_1000:=$COLOR_NETDEV_NORMAL};;
2500) color=${COLOR_NETDEV_LINK_2500:=$COLOR_NETDEV_NORMAL};;
10000) color=${COLOR_NETDEV_LINK_10000:=$COLOR_NETDEV_NORMAL};;
esac
fi
echo $color > /sys/class/leds/$led/color
}
if [[ $CHECK_GATEWAY_CONNECTIVITY == false && $CHECK_LINK_SPEED == false ]]; then
exit 0
fi
gw_conn=1
while true; do
if [[ $CHECK_GATEWAY_CONNECTIVITY == true ]]; then
gw=$(ip route | awk '/default/ { print $3 }')
if ping -q -c 1 -W 1 $gw >/dev/null; then
gw_conn=1
else
gw_conn=0
fi
fi
if [[ $gw_conn == 1 ]]; then
set_netdev_normal_color
else
echo $COLOR_NETDEV_GATEWAY_UNREACHABLE > /sys/class/leds/$led/color
fi
sleep ${CHECK_NETDEV_INTERVAL}s
done

View File

@ -0,0 +1,21 @@
#!/usr/bin/bash
set -e
{ lsmod | grep i2c-dev ; } || modprobe -v i2c-dev
{ lsmod | grep led-ugreen ; } || modprobe -v led-ugreen
i2c_dev=$(i2cdetect -l | grep "SMBus I801 adapter" | grep -Po "i2c-\d+")
if [ $? = 0 ]; then
echo "Found I2C device /dev/${i2c_dev}"
dev_path=/sys/bus/i2c/devices/$i2c_dev/${i2c_dev/i2c-/}-003a
if [ ! -d $dev_path ]; then
echo "led-ugreen 0x3a" > /sys/bus/i2c/devices/${i2c_dev}/new_device
elif [ "$(cat $dev_path/name)" != "led-ugreen" ]; then
echo "ERROR: the device ${i2c_dev/i2c-/}-003a has been registered as $(cat $dev_path/name)"
exit 1
fi
else
echo "I2C device not found!"
fi

View File

@ -13,13 +13,17 @@ if [ "${1}" = "late" ]; then
cp -vf /usr/bin/ledcontrol.sh /tmpRoot/usr/bin/ledcontrol.sh
cp -vf /usr/bin/ugreen_leds_cli /tmpRoot/usr/bin/ugreen_leds_cli
cp -vf /usr/bin/ugreen-diskiomon /tmpRoot/usr/bin/ugreen-diskiomon
cp -vf /usr/bin/ugreen-netdevmon /tmpRoot/usr/bin/ugreen-netdevmon
cp -vf /usr/bin/ugreen-probe-leds /tmpRoot/usr/bin/ugreen-probe-leds
cp -vf /usr/bin/led.conf /tmpRoot/usr/bin/led.conf
cp -vf /usr/bin/modules/i2c-algo-bit.ko /tmpRoot/usr/bin/modules/i2c-algo-bit.ko
cp -vf /usr/lib/modules/i2c-i801.ko /tmpRoot/usr/lib/modules/i2c-i801.ko
cp -vf /usr/lib/modules/i2c-smbus.ko /tmpRoot/usr/lib/modules/i2c-smbus.ko
modprobe i2c-algo-bit
modprobe i2c-i801
modprobe i2c-smbus
insmod i2c-algo-bit
insmod i2c-i801
insmod i2c-smbus
rm -f "/tmpRoot/usr/lib/systemd/system/multi-user.target.wants/ledcontrol.service"
rm -f "/tmpRoot/usr/lib/systemd/system/ledcontrol.service"