#!/bin/bash
###
### NOTE: This program is designed to run specifically with python2 and simplejson installed. It will not work without simplejson installed.
###


# Usage statement
usage() {
	echo 'Usage: ./check_eyedro -H hostname -t test [-p port] [-s secure] [-A nominalAmperage] [-V nominalLegVoltage] [-P pfCritLow:pfWarnLow] [-v verbose]'
	exit 3
}

# Values for options
HSTNAME=""
port=80
secure=""
check="none"
# Warn and crit are parsed in the following ways:
# Warn: "pfWarnLow, voltWarnLow:voltWarnHigh, ampWarnLow:ampWarnHigh, wattWarnLow:wattWarnHigh"
# Crit: "pfCritLow, voltCritLow:voltCritHigh, ampCritLow:ampCritHigh, wattCritLow:wattCritHigh"
# warn="25, 114:126, 0.8:160, 50:12000"
# crit="15, 110:127, 0.1:200, 10:19200"
nomAmp="200"
nomVolt="120"
powerFactor="15:25"
retries=3
verbose=0

# Getopts
while getopts "H:p:t:A:V:P:sv" opt

do
    case $opt in
        H)
            HSTNAME=$OPTARG # Hostname
            ;;
        p)
            port=$OPTARG # Port that web interface is on
            ;;
        t)
            check=$OPTARG # Check you want to execute
            ;;
        A)
            nomAmp=$OPTARG # Critical value
            ;;
        V)
            nomVolt=$OPTARG # Warning value
            ;;
        P)
            powerFactor=$OPTARG
            ;;
        r)
            retries=$OPTARG # Retries for curl
            ;;
        s)
            secure="s" # Whether running http/https
            ;;
        v)
            verbose=1
            ;;
        *)
            usage
            ;;
    esac
done

# List of checks
checkList="D1 CR"

# Convert check to lowercase
checkD=$check
check=$(echo $check | awk '{print tolower($0)}')
checkListLower=$(echo $checkList | awk '{print tolower($0)}')
if ! $(echo "$checkListLower" | grep -q "$check" ) ; then
    echo "UNKNOWN - Invalid check $check supplied. Valid checks: $checkList (case insensitive)"
    exit 3
fi

function vout() { if (($verbose == 1)) ; then echo "$1" ; fi }

function json() {
    vout "First index $2, second index $3." >&2
    echo $(echo "$1" | /usr/bin/python2.5 -c "import sys, simplejson as json; print json.load(sys.stdin)['data'][$2][$3]")
}

# Variables
textOut=""
dataOut=""
checkNum=""
textOK=""
textWarn=""
textCrit=""
textUnkn=""
divVal=1
uom=""
returnStat=0

# If port is defined as 80 and secure is set, change to 443.
if (($port == 80)) && [[ $secure == "s" ]] ; then
    port=443
fi

# Put all flag results to verbose output.
vout "Hostname: $HSTNAME"
vout "Port: $port"
vout "check: $check"
vout "nomAmp: $nomAmp"
vout "nomVolt: $nomVolt"
vout "powerFactor: $powerFactor" 
vout "retries: $retries"
vout "secure: $secure"

# Thresholds
## Power factor
pfCritLow=$(echo $powerFactor | cut -d':' -f1)
pfWarnLow=$(echo $powerFactor | cut -d':' -f2)
vout "pf calc done"

### Amperage Thresholds
# Low Critical is defined as 0.05% (1/2000) of nominal amperage.
# Low Warning is defined as 0.4% (1/250) of nominal amperage.
# High Warning is defined as 80% (4/5) of nominal amperage.
# High Critical is defined as 100% (1/1) of nominal amperage.
ampCritLow=$(echo  "scale=2;($nomAmp)   /2000" | bc -l)
ampWarnLow=$(echo  "scale=2;($nomAmp)   /250"  | bc -l)
ampWarnHigh=$(echo "scale=2;($nomAmp*4) /5"    | bc -l)
ampCritHigh=$(echo "scale=2;($nomAmp)   /1"    | bc -l)
vout "amp calc done"

### Voltage Thresholds
# For Service Entrance
# Low Critical is defined as 91.7% of nominal voltage
# Low Warning is defined as 95% of nominal voltage
# High Warning is defined as 105% of nominal voltage
# High Critical is defined as 105.8% of nominal voltage
voltCritLow=$(echo  "scale=2;($nomVolt *  917) /1000" | bc -l)
voltWarnLow=$(echo  "scale=2;($nomVolt *  950) /1000" | bc -l)
voltWarnHigh=$(echo "scale=2;($nomVolt * 1050) /1000" | bc -l)
voltCritHigh=$(echo "scale=2;($nomVolt * 1058) /1000" | bc -l)
vout "volt calc done"

### Wattage Thresholds
# Wattage thresholds are defined as the amperage thresholds multiplied
# by the nominal voltage.
wattCritLow=$(echo  "scale=2;$ampCritLow *$nomVolt" | bc -l)
wattWarnLow=$(echo  "scale=2;$ampWarnLow *$nomVolt" | bc -l)
wattWarnHigh=$(echo "scale=2;$ampWarnHigh*$nomVolt" | bc -l)
wattCritHigh=$(echo "scale=2;$ampCritHigh*$nomVolt" | bc -l)
vout "watt calc done"

# Verbose output for thresholds
vout "Thresholds: "
vout "Power Factor: $pfCritLow $pfWarnLow"
vout "Voltage: $voltCritLow $voltWarnLow $voltWarnHigh $voltCritHigh"
vout "Amperage: $ampCritLow $ampWarnLow $ampWarnHigh $ampCritHigh"
vout "Wattage: $wattCritLow $wattWarnLow $wattWarnHigh $wattCritHigh"


# Grab the results json from the device
results=""
tries=1

# Shorthand for URL
site="http${secure}://$HSTNAME:$port/getdata"

# If running verbose, don't add silent flag.
silent=""
if (($verbose == 0)) ; then silent="-s" ; fi

# Grab the results. Try $retries time, with a max time of 5s per retry and 3s in between each, give it 5s to connect.
results=$(curl --retry-delay 3 --retry-max-time 5 --retry $retries --connect-timeout 5 $silent $site)

# If we don't get anything for results, error out.
if ! [[ $results ]] ; then
    echo "UNKNOWN - Curl timeout when polling $site"
    exit 3
fi

# Verbose out the JSON results.
vout "Raw JSON: $results"

# Parse JSON based on text.
if [[ $check == "cr" ]] ; then
    pfA=$(json "$results" "2" "0")
    voltA=$(json "$results" "2" "1")
    ampA=$(json "$results" "2" "2")
    wattA=$(json "$results" "2" "3")
    pfB=$(json "$results" "3" "0")
    voltB=$(json "$results" "3" "1")
    ampB=$(json "$results" "3" "2")
    wattB=$(json "$results" "3" "3")
elif [[ $check == "d1" ]] ; then
    pfA=$(json "$results" "0" "0")
    voltA=$(json "$results" "0" "1")
    ampA=$(json "$results" "0" "2")
    wattA=$(json "$results" "0" "3")
    pfB=$(json "$results" "1" "0")
    voltB=$(json "$results" "1" "1")
    ampB=$(json "$results" "1" "2")
    wattB=$(json "$results" "1" "3")
else
    echo "UNKNOWN: Check $check is not a valid check. Valid checks: $checkList"
    exit 3
fi

# Verbose out raw values
vout "Parsed values (raw):"
vout "L1: $pfA $voltA $ampA $wattA"
vout "L2: $pfB $voltB $ampB $wattB"

# Convert raw to SI
pfA=$(echo "scale=2;$pfA/10" | bc -l) # Convert units to percent
voltA=$(echo "scale=2;$voltA/100" | bc -l) # Centivolt to volt
ampA=$(echo "scale=2;$ampA/1000" | bc -l) # Milliamp to amp
pfB=$(echo "scale=2;$pfB/10" | bc -l)
voltB=$(echo "scale=2;$voltB/100" | bc -l)
ampB=$(echo "scale=2;$ampB/1000" | bc -l)
# Watts don't get converted as they're already SI

# Verbose out SI values
vout "Parsed values (SI):"
vout "L1: $pfA% ${voltA}V ${ampA}A ${wattA}W"
vout "L2: $pfB% ${voltB}V ${ampB}A ${wattB}W"

# Long string of checking blocks. No real better way to do it, unfortunately.
# Adds checks that meet critera to respective string. If OK, don't do anything.
if (( $(echo "$pfA < $pfCritLow" | bc) )) ; then
    textCrit+="L1 PF; "  
elif (( $(echo "$pfA < $pfWarnLow" | bc) )) ; then
    textWarn+="L1 PF; "
elif (( $(echo "$pfA >= $pfWarnLow" | bc) )) ; then
    :
else
    textUnkn+="L1 PF; "
fi

if (( $(echo "$voltA >= $voltWarnLow" | bc) )) && (( $(echo "$voltA <= $voltWarnHigh" | bc) )) ; then
    :
elif (( $(echo "$voltA < $voltCritLow" | bc) )) || (( $(echo "$voltA > $voltCritHigh" | bc) )) ; then
    textCrit+="L1 Voltage; "
elif (( $(echo "$voltA < $voltWarnLow" | bc) )) || (( $(echo "$voltA > $voltWarnHigh" | bc) )) ; then
    textWarn+="L1 Voltage; "
else
    textUnkn+="L1 Voltage; "
fi

if (( $(echo "$ampA >= $ampWarnLow" | bc) )) && (( $(echo "$ampA <= $ampWarnHigh" | bc) )) ; then
    :
elif (( $(echo "$ampA < $ampCritLow" | bc) )) || (( $(echo "$ampA > $ampCritHigh" | bc) )) ; then
    textCrit+="L1 Amperage; "
elif (( $(echo "$ampA < $ampWarnLow" | bc) )) || (( $(echo "$ampA > $ampWarnHigh" | bc) )) ; then
    textWarn+="L1 Amperage; "
else
    textUnkn+="L1 Amperage; "
fi

if (( $(echo "$wattA >= $wattWarnLow" | bc) )) && (( $(echo "$wattA <= $wattWarnHigh" | bc) )) ; then
    :
elif (( $(echo "$wattA < $wattCritLow" | bc) )) || (( $(echo "$wattA > $wattCritHigh" | bc) )) ; then
    textCrit+="L1 Wattage; "
elif (( $(echo "$wattA < $wattWarnLow" | bc) )) || (( $(echo "$wattA > $wattWarnHigh" | bc) )) ; then
    textWarn+="L1 Wattage; "
else
    textUnkn+="L1 Wattage; "
fi

if (( $(echo "$pfB < $pfCritLow" | bc) )) ; then
    textCrit+="L2 PF; "  
elif (( $(echo "$pfB < $pfWarnLow" | bc) )) ; then
    textWarn+="L2 PF; "
elif (( $(echo "$pfB >= $pfWarnLow" | bc) )) ; then
    :
else
    textUnkn+="L2 PF; "
fi

if (( $(echo "$voltB >= $voltWarnLow" | bc) )) && (( $(echo "$voltB <= $voltWarnHigh" | bc) )) ; then
    :
elif (( $(echo "$voltB < $voltCritLow" | bc) )) || (( $(echo "$voltB > $voltCritHigh" | bc) )) ; then
    textCrit+="L2 Voltage; "
elif (( $(echo "$voltB < $voltWarnLow" | bc) )) || (( $(echo "$voltB > $voltWarnHigh" | bc) )) ; then
    textWarn+="L2 Voltage; "
else
    textUnkn+="L2 Voltage; "
fi

if (( $(echo "$ampB >= $ampWarnLow" | bc) )) && (( $(echo "$ampB <= $ampWarnHigh" | bc) )) ; then
    :
elif (( $(echo "$ampB < $ampCritLow" | bc) )) || (( $(echo "$ampB > $ampCritHigh" | bc) )) ; then
    textCrit+="L2 Amperage; "
elif (( $(echo "$ampB < $ampWarnLow" | bc) )) || (( $(echo "$ampB > $ampWarnHigh" | bc) )) ; then
    textWarn+="L2 Amperage; "
else
    textUnkn+="L2 Amperage; "
fi

if (( $(echo "$wattB >= $wattWarnLow" | bc) )) && (( $(echo "$wattB <= $wattWarnHigh" | bc) )) ; then
    :
elif (( $(echo "$wattB < $wattCritLow" | bc) )) || (( $(echo "$wattB > $wattCritHigh" | bc) )) ; then
    textCrit+="L2 Wattage; "
elif (( $(echo "$wattB < $wattWarnLow" | bc) )) || (( $(echo "$wattB > $wattWarnHigh" | bc) )) ; then
    textWarn+="L2 Wattage; "
else
    textUnkn+="L2 Wattage; "
fi

# Convert check to uppercase for display purposes.
checkD=$(echo $checkD | awk '{print toupper($0)}')
avg_pf=$(echo "scale=2;($pfA+$pfB)/2" | bc -l)
avg_volt=$(echo "scale=2;($voltA+$voltB)/2" | bc -l)
avg_amp=$(echo "scale=2;($ampA+$ampB)/2" | bc -l)
avg_watt=$(echo "scale=2;($wattA+$wattB)/2" | bc -l)


# Add the results to the text output.
textOut+="$avg_pf% PF : ${avg_volt}V : ${avg_amp}A : ${avg_watt}W"

# Add the results to the data output.
dataOut+="L1_pf=$pfA%;$pfWarnLow:101;$pfCritLow:105; "
dataOut+="L1_voltage=$voltA;$voltWarnLow:$voltWarnHigh;$voltCritLow:$voltCritHigh; "
dataOut+="L1_amperage=$ampA;$ampWarnLow:$ampWarnHigh;$ampCritLow:$ampCritHigh; "
dataOut+="L1_wattage=$wattA;$wattWarnLow:$wattWarnHigh;$wattCritLow:$wattCritHigh; "
dataOut+="L2_pf=$pfB%;$pfWarnLow:101;$pfCritLow:105; "
dataOut+="L2_voltage=$voltB;$voltWarnLow:$voltWarnHigh;$voltCritLow:$voltCritHigh; "
dataOut+="L2_amperage=$ampB;$ampWarnLow:$ampWarnHigh;$ampCritLow:$ampCritHigh; "
dataOut+="L2_wattage=$wattB;$wattWarnLow:$wattWarnHigh;$wattCritLow:$wattCritHigh; "

# If we have a critical, unknown, or warning, we want to add the devices
# that have thrown that to their respective flags. Otherwise, just OK.
if [[ $textCrit ]] || [[ $textUnkn ]] || [[ $textWarn ]] ; then
    if [[ $textCrit ]] ; then
        outString+="CRITICAL - $textCrit - "
    fi
    if [[ $textUnkn ]] ; then
        outString+="UNKNOWN - $textUnkn - "
    fi
    if [[ $textWarn ]] ; then
        outString+="WARNING - $textWarn - "
    fi
else
    outString+="OK - "
fi

# Returnstat is based on whether or not there's anything in the text of
# each text block.
if [[ $textCrit ]] ; then
    returnStat=2
elif [[ $textUnkn ]] ; then
    returnStat=3
elif [[ $textWarn ]] ; then
    returnStat=1
else
    returnStat=0
fi

# Compile out string
outString+="   "
outString+=$textOut
outString+=" | "
outString+=$dataOut

# Echo and exit.
echo $outString
exit $returnStat

