DNS 320L - Funplug 0.7 : Supervise Fan Speed and Case & HDD temperature with Munin

Contents[Hide]

dropcap dns320 muninWhen you run a DNS-320L NAS, as it is holding your important data secure, it may of great interest to check its important health data, like :

  • fan rotation
  • case temperature
  • harddisk temperature

This article explains how to setup your DNS-320L to report its fan rotation speed and its internal temperatures (case & hard disks) as a Munin node.

All these sensor data will then be reported to your centralised Munin console.

A pre-requisite is to have fully prepared your DNS-320 to run as a Munin node. To do so, you need to follow these articles :

  1. DNS 320 & 325 - Extend your NAS possibilities with Funplug 0.7
  2. DNS 320 & 325 - Funplug 0.7 : Install Compilation Environment
  3. DNS 320, 323 & 325 - Funplug 0.7 : Install a Munin node with Muninlite

This procedure has been tested on a DNS-320 running firmware V1.00.

Resulting Munin graph should look like this :

dns320 munin temp graph

1. How to collect data

1.1. Fan Speed

The fan embedded in the DNS-320 can run at 3 different speeds :

  • stop
  • low
  • high

Fan speed is controled by fan_control daemon.

Command fan_control can be used to read the fan state, but it only indicates if fan is still or if it rotates.

DNS 320 console
# fan_control
*** Fan Cobtrol Help Message ***
fan_control b c: for NAS booting

fan_control 0 d : [auto: high/low/stop] open debug msg
fan_control 1 d : [auto: high/low] open debug msg
fan_control 2 d : [always-high] open debug msg
fan_control 0 c : [auto: high/low/stop] close debug msg
fan_control 1 c : [auto: high/low] close debug msg
fan_control 2 c : [always-high] close debug msg
fan_control -L [value] : set Lower (THYST)
fan_control -H [value] : set Upper(TOS)
fan_control -g 0 : get current temperature
fan_control -g 1 : get Lower temperature
fan_control -g 2 : get Upper temperature
fan_control -g 3 : get fan state
fan_control -f 0 : set fan stop
fan_control -f 1 : set fan speed low
fan_control -f 2 : set fan speed high
# fan_control -g 3
fan state is 1

Fan state is :

  • 0 : fan is switched off
  • 1 : fan rotates

Every time fan_control daemon changes fan speed, it logs it in /var/log/user.log

/var/log/user.log
...
Jul 01 14:35:40 nas-fto fan_control: Set Fan Speed To "High".
Jul 02 02:30:06 nas-fto rtc: Set System Time.
Jul 02 07:00:08 nas-fto fan_control: Set Fan-Control Mode To "Auto(Off/Low/High)"
Jul 02 17:31:43 nas-fto fan_control: Fan Is Unable To Spin Or Fan Doesn't Exist
Jul 02 17:31:44 nas-fto fan_control: Set Fan Speed To "LOW".

You can clearly see that fan speed changes are logged in /var/log/user.log.

Thanks to a bug, you can also see some parasite Fan Is Unable To Spin Or Fan Doesn't Exist messages. They don't seem to be a problem as they appear mostly when fan goes from STOP to LOW state and as fan works well even with these messages.

So, we have everything to easily determine if fan is stopped or if it rotates in slow or high speed.

1.2. Case Temperature

Case temperature can also be read with fan_control tool :

DNS 320 console
# fan_control -g 0
Current temperature is 36

1.3. Disk Temperature & Description

DNS 320L can receive one or two disks.

Thanks to lsblk command, it is possible to list the connected disks :

DNS 320 console
# lsblk --nodeps --noheadings | cut -d' ' -f1 | grep "sd."
sda
sdb

Here, my DNS 320L is having two disks connected, available under /dev/sda and /dev/sdb.

It is now possible to get one of the disk temperature with smartctl tool.

DNS 320 console
# smartctl -A --device=marvell /dev/sda
smartctl version 5.38 [arm-mv5sft-linux-gnueabi] Copyright (C) 2002-8 Bruce Allen
Home page is http://smartmontools.sourceforge.net/
=== START OF READ SMART DATA SECTION ===

SMART Attributes Data Structure revision number: 16
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  1 Raw_Read_Error_Rate     0x002f   200   200   051    Pre-fail  Always       -       0
...
194 Temperature_Celsius     0x0022   118   108   000    Old_age   Always       -       32
...
200 Multi_Zone_Error_Rate   0x0008   100   253   000    Old_age   Offline      -       0

We can also use smartctl tool to get some disk details (model, serial number, capacity, ...) :

DNS 320 console
# smartctl -i --device=marvell /dev/sda
smartctl version 5.38 [arm-mv5sft-linux-gnueabi] Copyright (C) 2002-8 Bruce Allen
Home page is http://smartmontools.sourceforge.net/
=== START OF INFORMATION SECTION ===
Device Model: WDC WD20EFRX-68EUZN0
Serial Number: WD-WCC4M4FJDNX8
Firmware Version: 82.00A82
User Capacity: 2,000,398,934,016 bytes
Device is: Not in smartctl database [for details use: -P showall]
ATA Version is: 9
ATA Standard is: Exact ATA specification draft version not indicated
Local Time is: Wed May 20 18:04:00 2015 GMT
SMART support is: Available - device has SMART capability.
SMART support is: Enabled

2. Munin Node Plugin

Now that we know how to collect data, everything is ready to create and declare the munin node plugin.

I won't explain how to create a Munin node plugin as it is very welle explained on official How to write Munin plugins article.

Plugin provides fan speed and temperatures on the same graph.

All temperatures are in Celcius.

Fan speed is visualize with following values :

  • 20 : Off
  • 24 : Low speed
  • 28 : High speed

As DNS-320L can receive one or two disks, the plugin auto-detect the disks and publish them accordingly.

Disks are published as sda1 and sda2 and model, serial number and capacity are provided to help in the real disk determination.

/ffp/share/munin/plugins-extra/dns320_temperature
#!/ffp/bin/bash 
# ----------------------------------------------
# Muninlite plugin for DNS-320

# Used to supervise :
#  * fan speed
#  * case temperature
#  * hdd temperature
#
# This script needs the following utilities to run :
#  * fan_control
#  * smartctl
#  * lsblk
#
# To install muninlite on DNS-320, please check :
#  http://bernaerts.dyndns.org/nas/71-dns325-ffp07/319-dns325-dns323-ffp7-munin-node-muninlite
#
# 28/04/2015, V1.0 - Creation by N. Bernaerts
# 02/05/2015, V1.1 - Handle fan speed from user.log
# 03/05/2015, V1.2 - Handle error where temperature case is read as 0
# 03/05/2015, V1.3 - Do not check idle drive (thanks to John Kari)
# ----------------------------------------------

# -------------------------------------------------------
#  Initialisation
# -------------------------------------------------------

# log file
LOG_FILE="/var/log/user.log"

# define warning and critical temperature levels
CASE_WARNING="45"
CASE_CRITICAL="50"
DISK_WARNING="45"
DISK_CRITICAL="50"

# define display value for 3 fan states (stop, low & high)
FAN_STOP="20"
FAN_LOW="24"
FAN_HIGH="28"

# get nas name
NAS_IP=$(hostname)

# -------------------------------------------------------
#  Disk array initialisation
# -------------------------------------------------------

# load array all disks available on the system
ARR_DISK=($(lsblk --nodeps --noheadings | cut -d' ' -f1 | grep "sd."))

# -------------------------------------------------------
#   Configuration call
# -------------------------------------------------------

if [ "$1" = "config" ]; then

  # -------------------------------
  #    NAS general infos
  # -------------------------------

  echo "host_name $NAS_IP"
  echo "graph_title Temperature & Fan speed"
  echo "graph_vlabel Degree Celsius"
  echo "graph_category temperature"
  echo "graph_info Temperature Levels & Fan speed"
  echo "graph_scale no"
  echo "graph_args --lower-limit $FAN_STOP --upper-limit ${DISK_CRITICAL} --rigid"

  # -------------------------------
  #    Fan speed
  # -------------------------------

  echo "fan.label Fan"
  echo "fan.info Fan speed (off:$FAN_STOP, low:$FAN_LOW, high:$FAN_HIGH)"
  echo "fan.colour c0c0c0"
  echo "fan.draw AREA"

  # -------------------------------
  #    Case internal temperature
  # -------------------------------

  echo "case.label Internal case"
  echo "case.info Internal Case Sensor"
  echo "case.colour 00ff00"
  echo "case.warning :${CASE_WARNING}"
  echo "case.critical :${CASE_CRITICAL}"

  # -------------------------------
  #    Hard drives temperature
  # -------------------------------

  for DISK in "${ARR_DISK[@]}"
  do
    # init text
    DISK_INFO="Idle"
    
    # check disk state
    DISK_STATE=$(hdparm -C /dev/${DISK} | grep "state.*" | sed 's/.*[=:  ]//')
    
    # if disk is not idle
    if [ "${DISK_STATE}" = "active/idle" ]
    then
      # get disk capacity
      DISK_SIZE=$(smartctl -i --device=marvell /dev/${DISK} | grep "^User Capacity" | sed 's/^.*:\([0-9 ,]*\)bytes.*$/\1/' | tr -d " ," | sed 's/\(.*\).\{9\}/\1/')

      # if disk is present, get its full characteristics
      if [ "${DISK_SIZE}" != "" ]
      then
        DISK_MODEL=$(smartctl -i --device=marvell /dev/${DISK} | grep "^Device Model" | sed 's/^.*:[ ]*\(.*\)$/\1/')
        DISK_SERIAL=$(smartctl -i --device=marvell /dev/${DISK} | grep "^Serial Number" | sed 's/^.*:[ ]*\(.*\)$/\1/')
        DISK_INFO="${DISK_SIZE} Gb, model ${DISK_MODEL}, s/n ${DISK_SERIAL}"
      fi
    fi

    # display disk1 configuration
    echo "${DISK}.label /dev/${DISK}"
    echo "${DISK}.info ${DISK_INFO}"
    echo "${DISK}.warning :${DISK_WARNING}"
    echo "${DISK}.critical :${DISK_CRITICAL}"
  done

# -------------------------------------------------------
#    Normal call : Read Data
# -------------------------------------------------------

else

  # read internal case temperature (handle read errors reporting 0)
  TEMP_CASE=$(fan_control -g 0 | grep " is " | sed 's/^.*is \([0-9]*\)$/\1/')
  [ "${TEMP_CASE}" = "0" ] && TEMP_CASE="U"

  # publish case temperature
  echo "case.value ${TEMP_CASE}"

  # read fan state
  FAN_STATE=$(fan_control -g 3 | sed 's/^.*is \([0-9]*\).*$/\1/')

  # if fan rotates, get speed from last user.log record
  if [ "${FAN_STATE}" == "1" ]
  then
    FAN_SPEED=$(cat ${LOG_FILE} | grep "Fan Speed" | tail -n 1 - | sed 's/^.*\"\(.*\)\".*$/\1/')
    [ "${FAN_SPEED}" == "High" ] && FAN_STATE=2
  fi

  # publish fan speed
  case ${FAN_STATE} in
    0) echo "fan.value ${FAN_STOP}" ;;
    1) echo "fan.value ${FAN_LOW}" ;;
    2) echo "fan.value ${FAN_HIGH}" ;;
    *) echo "fan.value U" ;;
  esac

  for DISK in "${ARR_DISK[@]}"
  do
    # check disk state
    DISK_STATE=$(hdparm -C /dev/${DISK} | grep "state.*" | sed 's/.*[=:  ]//')

    # if disk is not idle
    if [ "${DISK_STATE}" = "active/idle" ]
    then
      # read hard disk 1 temperature
      TEMP_DISK=$(smartctl -A --device=marvell /dev/${DISK} | grep "^194.*" | sed 's/^.*- *\([0-9]*\).*$/\1/g')

      # publish disk temperature
      echo "${DISK}.value ${TEMP_DISK}"
    fi
  done
  
fi

2.1. Installation

To install the plugin, you just need to download it from my GitHub repository with these commands :

DNS 320 console
# wget --no-check-certificate -O /ffp/share/munin/plugins-extra/dns320_temperature https://raw.githubusercontent.com/NicolasBernaerts/munin-plugin/master/dns320_temperature
# chmod +x /ffp/share/munin/plugins-extra/dns320_temperature

The new plugin is now ready to be used. You can easily test it :

DNS 320 console
# /ffp/share/munin/plugins-extra/dns320_temperature config
host_name DNS320
graph_title Temperature & Fan speed
graph_vlabel Degree Celsius
graph_category temperature
graph_info Temperature Levels & Fan speed
graph_scale no
graph_args --lower-limit 20 --upper-limit 50 --rigid
fan.label Fan
fan.info Fan speed (off:20, low:24, high:28)
fan.colour c0c0c0
fan.draw AREA
case.label Internal case
case.info Internal Case Sensor
case.colour 00ff00
case.warning :45
case.critical :50
sda.label /dev/sda (2000 Gb)
sda.info 2000 Gb, model WDC WD20EFRX-68EUZN0, s/n WD-WCC4M4FJDNX8
sda.warning :45
sda.critical :50
sdb.label /dev/sdb (2000 Gb)
sdb.info 2000 Gb, model WDC WD20EFRX-68EUZN0, s/n WD-WCC4M4JHEVE8
sdb.warning :45
sdb.critical :50
# /ffp/share/munin/plugins-extra/dns320_temperature
case.value 36
fan.value 24
sda.value 37
sdb.value 36

2.2. Declaration

 It's now time to declare the plugin to Muninlite node.

As explained in DNS 320, 323 & 325 - Funplug 0.7 : Install a Munin node with Muninlite, this is simply done by creating symbolic links in /ffp/share/munin/plugins-enabled pointing to the new dns320_temperature plugin scripts.

DNS 320 console
# ln -s /ffp/share/munin/plugins-extra/dns320_temperature /ffp/share/munin/plugins-enabled/dns320_temperature

You can now test your Munin node installation :

DNS 320 console
# telnet localhost 4949
# munin node at DNS320
list
cpu dns320_temperature dns32x_df memory rsync_synchro uptime
quit
Connection closed by foreign host

Your new munin node plugin is in the list. It should be fully operationnal.

It should appear after few minutes on the Munin supervision server where DNS-320 munin node has been declared.

Your NAS health is now under control   :-)

 

Hope it helps.

Signature Technoblog

This article is published "as is", without any warranty that it will work for your specific need.
If you think this article needs some complement, or simply if you think it saved you lots of time & trouble,
just let me know at This email address is being protected from spambots. You need JavaScript enabled to view it.. Cheers !

icon linux icon debian icon apache icon mysql icon php icon piwik icon googleplus