Skip to content

Instantly share code, notes, and snippets.

@Kerryliu
Last active November 17, 2024 00:37
Show Gist options
  • Save Kerryliu/c380bb6b3b69be5671105fc23e19b7e8 to your computer and use it in GitHub Desktop.
Save Kerryliu/c380bb6b3b69be5671105fc23e19b7e8 to your computer and use it in GitHub Desktop.
TrueNAS UGREEN DXP4800 Plus Status LED Guide

UGREEN DXP4800 Plus TrueNAS Status LED Guide

20240609_035951642_iOS

The following is a quick guide on getting basic status LED functionality working with TrueNAS running on the UGREEN DXP4800 Plus. Theoretically, it should work on all models (with some small revisions to the script), but I only have a DXP4800 Plus. :)

This guide is for cron job that runs a script to update the LEDs every couple minutes, but I'm sure the following can be modified for blinky LEDs as well.

Steps:

  1. Manually build or download the ugreen_leds_cli tool from https://github.com/miskcoo/ugreen_dx4600_leds_controller.
  2. Plop it somewhere on your NAS (E.g. a dataset).
  3. In the same dataset, create your .sh script that controls the LEDs. At the bottom of this gist is my modified version of meyergru's.
  4. Make the script executable: chmod +X your-script.sh.
    • You may also need to make ugreen_leds_cli executable as well.
  5. In TrueNas, navigate over to System SettingsAdvanced
  6. Under Init/Shutdown Scripts Create the following to load the i2c-dev module on boot:
    • Description: Enable i2c-dev
    • Type: Command
    • Command: modprobe i2c-dev
    • When: Pre Init
  7. Under Cron Jobs we then create a task to run every x minutes:
    • Description: Update Status LEDS
    • Command: /mnt/path/to/your/script.sh
    • Run as User: root
    • Schedule: */5 * * * * (or however often you desire)
  8. Reboot and wait a bit for your cron job to run.

Sources:

Example script:

#! /bin/bash

#set -x

SCRIPTPATH=$(dirname "$0")
echo $SCRIPTPATH

devices=(p n x x x x)
map=(power netdev disk1 disk2 disk3 disk4)

# Check network status
gw=$(ip route | awk '/default/ { print $3 }')
if ping -q -c 1 -W 1 $gw >/dev/null; then
    devices[1]=u
fi

# Map sdX1 to hardware device
declare -A hwmap
echo "Mapping devices..."
while read line; do
    MAP=($line)
    device=${MAP[0]}
    hctl=${MAP[1]}
    partitions=$(lsblk -l -o NAME | grep "^${device}[0-9]\+$")
    for part in $partitions; do
        hwmap[$part]=${hctl:0:1}
        echo "Mapped $part to ${hctl:0:1}"
    done
done <<< "$(lsblk -S -o NAME,HCTL | tail -n +2)"

# Print the hwmap for verification
echo "Hardware mapping (hwmap):"
for key in "${!hwmap[@]}"; do
    echo "$key: ${hwmap[$key]}"
done

# Check status of zpool disks
echo "Checking zpool status..."
while read line; do
    DEV=($line)
    partition=${DEV[0]}
    echo "Processing $partition with status ${DEV[1]}"
    if [[ -n "${hwmap[$partition]}" ]]; then
        index=$((${hwmap[$partition]} + 2))
        echo "Device $partition maps to index $index"
        if [ ${DEV[1]} = "ONLINE" ]; then
            devices[$index]=o
        else
            devices[$index]=f
        fi
    else
        echo "Warning: No mapping found for $partition"
    fi
done <<< "$(zpool status -L | grep -E '^\s+sd[a-h][0-9]')"

# Output the final device statuses
echo "Final device statuses:"
for i in "${!devices[@]}"; do
    echo "$i: ${devices[$i]}"
    case "${devices[$i]}" in
        p)
            "$SCRIPTPATH/ugreen_leds_cli" ${map[$i]} -color 255 255 255 -on -brightness 64
            ;;
        u)
            "$SCRIPTPATH/ugreen_leds_cli" ${map[$i]} -color 255 255 255 -on -brightness 64
            ;;
        o)
            "$SCRIPTPATH/ugreen_leds_cli" ${map[$i]} -color 0 255 0 -on -brightness 64
            ;;
        f)
            "$SCRIPTPATH/ugreen_leds_cli" ${map[$i]} -color 255 0 0 -blink 400 600 -brightness 64
            ;;
        *)
            "$SCRIPTPATH/ugreen_leds_cli" ${map[$i]} -off
            ;;
    esac
done
@re-do-ne
Copy link

re-do-ne commented Jul 3, 2024

Thanks for this!

The example script didn't seem to work as expected on my 6800 Pro, so I took some inspiration from it and the diskiomon script (mainly for the HCTL mappings):

#!/bin/bash

SCRIPTPATH=$(dirname "${0}")

if ! [[ -f "${SCRIPTPATH}/ugreen_leds_cli" ]]; then
  echo "Ugreen LED CLI not found"
  exit 1
fi

# LED to HCTL mapping, specific for the 6800 Pro model
declare -A led_map=(
    ["disk1"]="2:0:0:0"
    ["disk2"]="3:0:0:0"
    ["disk3"]="4:0:0:0"
    ["disk4"]="5:0:0:0"
    ["disk5"]="0:0:0:0"
    ["disk6"]="1:0:0:0"
)

# Map to hold the desired LED color and status
declare -A led_status

# Initialize all LEDs to off
led_status["power"]="-off"
led_status["netdev"]="-off"
for key in "${!led_map[@]}"; do
    led_status[$key]="-off"
done

# Check network status
check_network_connectivity() {
    gw=$(ip route | awk '/default/ { print $3 }')
    if ping -q -c 1 -W 1 "${gw}" >/dev/null; then
        return 0
    else
        return 1
    fi
}

# Get the currently active disks and their names
active_disks=$(lsblk -S -o name,hctl,tran | grep sata | awk '{print $1,$2}')

# Set LED status for power
led_status["power"]="-color 255 255 255 -on -brightness 64"

# Check network connectivity and set netdev LED accordingly
if check_network_connectivity; then
    led_status["netdev"]="-color 0 0 255 -on -brightness 64"  # Blue for connected
else
    led_status["netdev"]="-color 255 0 0 -on -brightness 64"  # Red for not connected
fi

# Set LED status for active disks based on SMART status
while read -r disk_info; do
    disk_name=$(awk '{print $1}' <<< "${disk_info}")
    hctl=$(awk '{print $2}' <<< "${disk_info}")
    led_name=$(for key in "${!led_map[@]}"; do [[ ${led_map[$key]} == "${hctl}" ]] && echo "${key}"; done)

    if [[ -n "${led_name}" ]]; then
        # Check the SMART status
        smart_status=$(smartctl -H "/dev/${disk_name}" | grep "SMART overall-health self-assessment test result" | awk '{print $6}')

        # Set LED color based on SMART status
        case "${smart_status^^}" in
            "PASSED")
                led_status[$led_name]="-color 0 255 0 -on -brightness 64"  # Green for good
                ;;
            "FAILED")
                led_status[$led_name]="-color 255 0 0 -on -brightness 64"  # Red for bad
                ;;
            *)
                led_status[$led_name]="-color 255 255 0 -on -brightness 64"  # Yellow for unknown
                ;;
        esac
    fi
done <<< "${active_disks}"

# Function to check zpool status and update LED status accordingly
check_zpool_status() {
    # Get zpool status with -PL for detailed device paths
    zpool_status=$(zpool status -PL)
    unhealthy_volumes=()

    while read -r line; do
        if [[ "${line}" =~ "/dev/" ]]; then
            zdevice=$(awk '{print $1}' <<< "${line}")
            zstatus=$(awk '{print $2}' <<< "${line}")
            
            if [[ "${zstatus^^}" != "ONLINE" ]]; then
                unhealthy_volumes+=("${zdevice}")
            fi
        fi
    done <<< "${zpool_status}"

    # Blink LEDs for disks in pools with errors
    for partition in "${unhealthy_volumes[@]}"; do
        parent_disk=$(lsblk -no pkname "${partition}")
        hctl=$(lsblk -S -o name,hctl | grep "^${parent_disk} " | awk '{print $2}')
        led_name=$(for key in "${!led_map[@]}"; do [[ ${led_map[$key]} == "${hctl}" ]] && echo "${key}"; done)

        if [[ -n "${led_name}" ]]; then
            led_status[$led_name]="${led_status[$led_name]} -blink 500 500"
        fi
    done
}

# Check zpool status and update LEDs
check_zpool_status

# Apply the desired LED colors and statuses
for led in "${!led_status[@]}"; do
    ${SCRIPTPATH}/ugreen_leds_cli $led ${led_status[$led]}
done

@Weingartens
Copy link

Below a working version for the DXP8800 Plus model:

#!/bin/bash

SCRIPTPATH=$(dirname "${0}")

if ! [[ -f "${SCRIPTPATH}/ugreen_leds_cli" ]]; then
  echo "Ugreen LED CLI not found"
  exit 1
fi

# LED to HCTL mapping, specific for the 6800 Pro model
declare -A led_map=(
    ["disk1"]="2:0:0:0"
    ["disk2"]="3:0:0:0"
    ["disk3"]="4:0:0:0"
    ["disk4"]="5:0:0:0"
    ["disk5"]="0:0:0:0"
    ["disk6"]="1:0:0:0"
    ["disk7"]="6:0:0:0"
    ["disk8"]="7:0:0:0"
)

# Map to hold the desired LED color and status
declare -A led_status

# Initialize all LEDs to off
led_status["power"]="-off"
led_status["netdev"]="-off"
for key in "${!led_map[@]}"; do
    led_status[$key]="-off"
done

# Check network status
check_network_connectivity() {
    gw=$(ip route | awk '/default/ { print $3 }')
    if ping -q -c 1 -W 1 "${gw}" >/dev/null; then
        return 0
    else
        return 1
    fi
}

# Get the currently active disks and their names
active_disks=$(lsblk -S -o name,hctl,tran | grep sata | awk '{print $1,$2}')

# Set LED status for power
led_status["power"]="-color 255 255 255 -on -brightness 64"

# Check network connectivity and set netdev LED accordingly
if check_network_connectivity; then
    led_status["netdev"]="-color 0 0 255 -on -brightness 64"  # Blue for connected
else
    led_status["netdev"]="-color 255 0 0 -on -brightness 64"  # Red for not connected
fi

# Set LED status for active disks based on SMART status
while read -r disk_info; do
    disk_name=$(awk '{print $1}' <<< "${disk_info}")
    hctl=$(awk '{print $2}' <<< "${disk_info}")
    led_name=$(for key in "${!led_map[@]}"; do [[ ${led_map[$key]} == "${hctl}" ]] && echo "${key}"; done)

    if [[ -n "${led_name}" ]]; then
        # Check the SMART status
        smart_status=$(smartctl -H "/dev/${disk_name}" | grep "SMART overall-health self-assessment test result" | awk '{print $6}')

        # Set LED color based on SMART status
        case "${smart_status^^}" in
            "PASSED")
                led_status[$led_name]="-color 0 255 0 -on -brightness 64"  # Green for good
                ;;
            "FAILED")
                led_status[$led_name]="-color 255 0 0 -on -brightness 64"  # Red for bad
                ;;
            *)
                led_status[$led_name]="-color 255 255 0 -on -brightness 64"  # Yellow for unknown
                ;;
        esac
    fi
done <<< "${active_disks}"

# Function to check zpool status and update LED status accordingly
check_zpool_status() {
    # Get zpool status with -PL for detailed device paths
    zpool_status=$(zpool status -PL)
    unhealthy_volumes=()

    while read -r line; do
        if [[ "${line}" =~ "/dev/" ]]; then
            zdevice=$(awk '{print $1}' <<< "${line}")
            zstatus=$(awk '{print $2}' <<< "${line}")
            
            if [[ "${zstatus^^}" != "ONLINE" ]]; then
                unhealthy_volumes+=("${zdevice}")
            fi
        fi
    done <<< "${zpool_status}"

    # Blink LEDs for disks in pools with errors
    for partition in "${unhealthy_volumes[@]}"; do
        parent_disk=$(lsblk -no pkname "${partition}")
        hctl=$(lsblk -S -o name,hctl | grep "^${parent_disk} " | awk '{print $2}')
        led_name=$(for key in "${!led_map[@]}"; do [[ ${led_map[$key]} == "${hctl}" ]] && echo "${key}"; done)

        if [[ -n "${led_name}" ]]; then
            led_status[$led_name]="${led_status[$led_name]} -blink 500 500"
        fi
    done
}

# Check zpool status and update LEDs
check_zpool_status

# Apply the desired LED colors and statuses
for led in "${!led_status[@]}"; do
    ${SCRIPTPATH}/ugreen_leds_cli $led ${led_status[$led]}
done

@supramx6
Copy link

supramx6 commented Aug 20, 2024

I consider my self a noob when it comes to TrueNAS and scripts but I actually got this to work without too much fuss. Thank you KerryLiu and re-do-ne! My UGreen 6800 looks so much better without the rotating LEDs!

@Adrian-Grimm
Copy link

Adrian-Grimm commented Sep 4, 2024

Same here - tested it now since 7 weeks and covered many cases - everything is working so reliable and smooth with a 5 min. cron update CLI call 👍🏻 (DXP6800 TrueNAS Dragonfish)

@republicandaddy
Copy link

republicandaddy commented Sep 21, 2024

Thanks to all of you for this. The KITT lights were driving me crazy...lol.

@Weingartens using your script is great for my 8800, but one question. I'm horrible at coding, but I think I see it's set to blink green if there's a problem with the drive, correct?

I ask because my Drive 1 light is blinking green, but TrueNAS doesn't show any smart errors or zfs pool issues, so I'm not sure what I might have done wrong. I'm running 8 spinning NAS drives (mostly Seagate) and an 8800 Plus.

Thought I'd add....6 disks are setup as one pool, 2 are in a mirror pool and the third is a hot spare. The hot spare is set to power down after 10 minutes of inactivity, but all others are always on. Could bay 1 have the hot spare in it and thus be powered down (hence flashing)? I didn't label my disks and can't seem to figure out how to know which one (sda, sdb, etc) is in which bay without shutting down removing one and booting up 7 times to label them all....so...here I am...lol.

Any thoughts?

EDIT/UPDATE: Nevermind.... I shutdown my 8800 and pulled each drive after taking a screenshot of serial numbers and drive names. Then labeled each bay with the corresponding drive name. This lead me to the answer. The drive in bay 1 is the hot spare for the mirrored pool. I'm assuming since it's not a full member of the pool, it shows flashing on the LEDs. That works for me.

Cheers!

@nderscore
Copy link

@republicandaddy

The script was not built with spares in mind and treats any status besides ONLINE as being "unhealthy". An unused spare should have a status of AVAIL, so you should be able to update this line:

            if [[ "${zstatus^^}" != "ONLINE" ]]; then

Like this:

            if [[ "${zstatus^^}" != "ONLINE" && "${zstatus^^}" != "AVAIL" ]]; then

Then the LED for your spare slot will not blink.

@HansBethe
Copy link

Thank you very much for these instructions! It worked for me.

I had to set ownership and group of the shell script and ugreen_leds_cli to the root user. Than I did chmod +X your-script.sh under the root
user in the Truenas shell. I enabled the root user password.

I had to change the zpool command to /sbin/zpool because sbin is not in the PATH definition.

The instruction is difficult for somebody without Unix knowledge.

@Fuergrissa1
Copy link

Guide is not working or i am to dumb for the steps: Downloaded the file placed it into a smb folder. Created the script, which i copied from below. Tried it in the terminal with the command you wrote here: chmod +X your-script.sh. Copied it in the same folder. Then implemented the 6 & 7 restarted but nothing happened. Maybe im not into depth of truenas scale but dont know what i did wrong.

Might have the same issue as I do. I copy/pasted the script on my windows machine before copying to the NAS. When I ran the script with the -x parameter to debug there was an error about the windows style EOL marker '/r'. From the shell in TrueNAS I ran the following to correct the issue:

sed -i 's/\r$//' /mnt/pool_name/dataset_name/LED.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment