#!/bin/bash
#
# NAME
# ----
# - xymon_cbw_temp.sh
#
# DESCRIPTION
# -----------
# - Simple Bash shell script to monitor from 1 to 4 temperature readings
#   from a ControlByWeb 4-temp/2-relay module OR the X-300 8-temperature
#   plus thermostat module and report status and temperature readings 
#   back to a Xymon server for logging, graphing and alerting
#

# - The most current version of this script may be
#   found at http://www.revpol.com/xymon_cbw_temp_script
#
# - Instructions to integrate the output of this script to be monitored
#   and graphed by a Xymon server may also be found at the above URL
#
# - If you find this script useful, I'd love to know. Send me an email!
#
# William A. Arlofski
# Reverse Polarity, LLC
# 860-824-2433 Office
# http://www.revpol.com/
#
# HISTORY
# ------
# - 20100308 - Initial version release
# - 20100318 - Minor modifications to work with the 
#              X-300 (8-temp & thermostat) Module
#            - Increased the curl timeout from 3 to 10 seconds
#
###############################################################################
#
# Copyright (C) 2010 William A. Arlofski - waa-at-revpol-dot-com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# or visit http://www.gnu.org/licenses/gpl.txt
#
###############################################################################
#
# Set some variables
# ------------------
# Local System Binaries
# ---------------------
GREP="/bin/grep"
TR="/usr/bin/tr"
CURL="/usr/bin/curl"

# Location/device specific variables
# ----------------------------------
#
# FQDN or IP address of the ControlByWeb
# temperature monitor to pull data from
# and user login and password
# (User should be blank)
#---------------------------------------
HOST="host.example.com"
USER=""
PASS=""

# Define the temperature zone(s) to monitor
# -----------------------------------------
# Format is as follows:
#
# ZONE="Sensor#:TestType:Location:WarnTmp1:CritTmp1:[WarnTmp2:CritTmp2] \
# [ Sensor#:TestType:Location:WarnTmp:CritTmp:[WarnTmp2:CritTmp2] ...]"
#
# Where the fields are as follows:
# - Sensor   : The sensor number from 1 to 4
# - TestType : The type of test: UP, DOWN, RANGE, IGNORE.
#              If TestType is RANGE, WarnTmp2 and CritTmp2 are required
#              If TestType is IGNORE, then only Sensor:TestType:Location are required
# - Location : The name of the location - Must match your Xymon definitions
# - WarnTmp1 : The value at which to set test COLOR and alert to yellow for UP or DOWN tests
#              For RANGE test types, this value is used as if the test were a DOWN test
# - CritTmp1 : The value at which to set test COLOR and alert to red for UP or DOWN tests
#              For RANGE test types, this value is used as if the test were a DOWN test
# - WarnTmp2 : Only used for RANGE type tests. The value at which to set test COLOR
#              to yellow as temperature increases
# - CritTmp2 : Only used for RANGE type tests. The value at which to set test COLOR
#              to red as temperature increases
#
#
# The ControlByWeb temperature monitor
# supports up to four temperature sensors
# and reports the temperature as XX.Y in
# either Celsius or Fahrenheit
# ---------------------------------------
ZONES="1:UP:ServerRoom:78.0:80.0          \
       2:IGNORE:Outside                   \
       3:RANGE:Office:70.0:65.0:80.0:82.0 \
       4:DOWN:Basement:36.0:32.0"


###############################################################################
# --------------------------------------------------
# Nothing should need to be modified below this line
# --------------------------------------------------
###############################################################################
#
# ----------------------------
# Set required Xymon variables
# ----------------------------
COLUMN="cbwtemp"
COLOR="green"
MSG=""

# ----------------
# Set up functions
# ----------------
#
# Get the four sensor temperature outputs from the
# "state.xml" page from ControlByWeb temperature monitor
# ------------------------------------------------------
getdata() {
        TEMPS=`"$CURL" -s -m 10 -u "$USER:$PASS" "$HOST/state.xml"`
        # If the device returns no data, or is offline, or does not respond,
        # or if curl fails for any reason, then just fail and exit the script.
        # Xymon will alert purple indicating that it has not seen data for this
        # test after 20 minutes (default). I suppose we COULD instead force a
        # yellow alert for all temps for this device during this condition...
        # ---------------------------------------------------------------------
        if [ "$?" != "0" ] || [ -z "$TEMPS" ] ; then
         exit 1
        fi
}

# Separate zone components:
# - Skip all temperature values for IGNORE test types
# - Assign WarnTmp2 and CrtTmp2 for RANGE test types
# ---------------------------------------------------
parsezone () {
        sensornum=`echo "$zone" | cut -d':' -f1`
        testtype=`echo "$zone"  | cut -d':' -f2 | "$TR" [a-z] [A-Z]`
        location=`echo "$zone"  | cut -d':' -f3`
        if [ ! "$testtype" == "IGNORE" ] ; then
          warntemp1=`echo "$zone" | cut -d':' -f4`
          crittemp1=`echo "$zone" | cut -d':' -f5`
          if [ "$testtype" == "RANGE" ] ; then
            warntemp2=`echo "$zone" | cut -d':' -f6`
            crittemp2=`echo "$zone" | cut -d':' -f7`
          fi
        fi
}

# Pull current zone's temperature reading out of xml tags
# -------------------------------------------------------
getcurtemp () {
        # Each of the four temperatures is represented
        # as a line  [-][Y]YY.Z
        # where X is the sensor number from 1 to 4,
        # Y is the temp in degrees, and Z is the tenths
        # We only want the numeric portion including the
        # negative (hyphen) symbol between the tags for
        # the current sensor we are looping for
        # ----------------------------------------------
        
	curtemp=`echo "$TEMPS" \
        | grep -Eo "sensor$sensornum.*sensor$sensornum" \
        | grep -Eo [-]*[0-9]\{2,3\}\.[0-9]`

}

# Test for temperature RISING and set the test's CURCOLOR
# Set the main COLOR variable for the Xymon report if necessary
# -------------------------------------------------------------
testup() {
        # Is current temp greater than the critical temp?
        # -----------------------------------------------
        if [ `echo "$curtemp" | "$TR" -d .` -ge `echo "$crittemp1" | "$TR" -d .` ] ; then
          CURCOLOR="red"
          # Now, since red is the most critical color, just set
          # the main status color for this report to red too
          # ---------------------------------------------------
          COLOR="red"

           # Is current temp greater than the warning temp?
           # ----------------------------------------------
           elif [ `echo "$curtemp" | "$TR" -d .` -ge `echo "$warntemp1" | "$TR" -d .` ] ; then
            CURCOLOR="yellow"

            # Set main status color to yellow only if it is not already worse (red)
            # ---------------------------------------------------------------------
            if [ "$COLOR" != "red" ] ; then
              COLOR="yellow"
            fi
        fi
}

# Test for temperature DECREASING and set the test's CURCOLOR
# Set the main COLOR variable for the Xymon report if necessary
# -------------------------------------------------------------
testdown() {
        # Is current temp less than the critical temp?
        # --------------------------------------------
        if [ `echo "$curtemp" | "$TR" -d .` -le `echo "$crittemp1" | "$TR" -d .` ] ; then
          CURCOLOR="red"
          # Now, since red is the most critical color, just set
          # the main status color for this report to red too
          # ---------------------------------------------------
          COLOR="red"

           # Is current temp less than the warning temp?
           # -------------------------------------------
           elif [ `echo "$curtemp" | "$TR" -d .` -le `echo "$warntemp1" | "$TR" -d .` ] ; then
            CURCOLOR="yellow"

            # Set main status color to yellow only if it is not already worse (red)
            # ---------------------------------------------------------------------
            if [ "$COLOR" != "red" ] ; then
              COLOR="yellow"
            fi
        fi
}

# Test for temperature being within the defined RANGE
# and set the test's CURCOLOR
# Set the main COLOR variable for the Xymon report if necessary
# -------------------------------------------------------------
testrange() {
        # Is the current temp is outside of the high and low critical levels?
        # -------------------------------------------------------------------
        if [ `echo "$curtemp" | "$TR" -d .` -le `echo "$crittemp1" | "$TR" -d .` ] \
        || [ `echo "$curtemp" | "$TR" -d .` -ge `echo "$crittemp2" | "$TR" -d .` ] ; then
          CURCOLOR="red"
          # Now, since red is the most critical color, just set
          # the main status color for this report to red too
          # ---------------------------------------------------
          COLOR="red"

        # Is the current temp is outside of the high and low warning levels?
        # ------------------------------------------------------------------
        elif [ `echo "$curtemp" | "$TR" -d .` -le `echo "$warntemp1" | "$TR" -d .` ] \
          || [ `echo "$curtemp" | "$TR" -d .` -ge `echo "$warntemp2" | "$TR" -d .` ] ; then
            CURCOLOR="yellow"

            # Set main status color to yellow only if it is not already worse (red)
            # ---------------------------------------------------------------------
            if [ "$COLOR" != "red" ] ; then
              COLOR="yellow"
            fi
        fi
}

###########################################################
# -----------
# Main Script
# -----------

# Look at this poor lonely function call :)
# -----------------------------------------
getdata
#echo $TEMPS
# Loop through the defined zones
# ------------------------------
for zone in $ZONES; do
 CURCOLOR="green"
 parsezone
 getcurtemp
 # Determine if this is an UP or DOWN test
 # ---------------------------------------
 case "$testtype" in

        UP )
          testup
          ;;

        DOWN )
          testdown
          ;;

        RANGE )
          testrange
          ;;

        IGNORE )
          # Do not test anything. Just append
          # the $CURCOLOR (green), $location
          # and $curtemp values to the Xymon
          # Server report for this "zone"
          ;;

        * )
          exit 1
          ;;
 esac

 # Build the text of the status message
 # that will be sent to the Xymon Server
 # -------------------------------------
 MSG="${MSG}
 &$CURCOLOR $location : $curtemp"

done


# Send final report to Xymon Server
# ---------------------------------
$BB $BBDISP "status $MACHINE.$COLUMN $COLOR `date`
${MSG}
"
###########################################################

