#! /bin/bash
MYNAME=$(basename "$0")
MYDIR=$(dirname "$0")
MYDIR=$(readlink -m "$MYDIR")
VERSION="0.0.1"
VERBOSE="true"
LOGDIR="$HOME/"
LOGFILE="$LOGDIR/${MYNAME}.log"

MQTT_CONFIG_FILE="$HOME/.pip/mqtt.conf"

export PIP_STATE="normal"

TERM_ERASE_EOL="\033[K"
TERM_HOME="\033[0;0H"
TERM_NORMAL="\033[0;39m"
TERM_BOLD="\033[1m"
TERM_INVERSE="\033[7m"
XTERM_COLOR_RED="\033[0;31m"
XTERM_COLOR_GREEN="\033[0;32m"
XTERM_COLOR_ORANGE="\033[0;33m"
XTERM_COLOR_BLUE="\033[0;34m"
XTERM_COLOR_PURPLE="\033[0;35m"
XTERM_COLOR_CYAN="\033[0;36m"
XTERM_COLOR_LIGHT_GRAY="\033[0;37m"
XTERM_COLOR_DARK_GRAY="\033[1;30m"
XTERM_COLOR_LIGHT_RED="\033[1;31m"
XTERM_COLOR_LIGHT_GREEN="\033[1;32m"
XTERM_COLOR_YELLOW="\033[1;33m"
XTERM_COLOR_LIGHT_BLUE="\033[1;34m"
XTERM_COLOR_LIGHT_PURPLE="\033[1;35m"
XTERM_COLOR_LIGHT_CYAN="\033[1;36m"
XTERM_COLOR_WHITE="\033[1;37m"

stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }

function saveState()
{
    local device
    
    while [ -n "$1" ]; do
        case "$1" in
            --device)
                device="$2"
                shift 2
                ;;

            *)
                break
                ;;
        esac
    done

    echo "device: '$device'"
}


function epoch()
{
    echo $(date +%s)
}

function timedSwitch()
{
    local name
    local operation
    local timeout=60
    local on_epoch_file
    local on_epoch

    while [ -n "$1" ]; do
        case $1 in 
            --name)
                name=$2
                on_epoch_file="/tmp/${name}.on"
                shift 2
                ;;

            --check)
                operation="check"
                shift
                ;;

            --on)
                operation="on"
                shift
                ;;

            *)  
                break
                ;;
        esac
    done
   
    #printVerbose "***      name:  $name"
    #printVerbose "*** operation: $operation"
    #printVerbose "***      file: $on_epoch_file"
    if [ -z "$name" ]; then
        printError "Name is not provided in timedSwitch()."
        return 6
    fi
    
    if [ -z "$operation" ]; then
        printError "Operation is not provided in timedSwitch()."
        return 6
    fi

    case "$operation" in
        check)
            if [ -f "$on_epoch_file" ]; then
                on_epoch=$(epoch)
                let on_epoch-=$(cat "$on_epoch_file")
                
                if [ "$on_epoch" -gt "$timeout" ]; then
                    printVerbose "TIMEOUT $name"
                    pip-pdu-control --off "$name"
                    rm -f "$on_epoch_file"
                fi
            fi
            ;;

        on)
            printVerbose "TIME ON $name"
            pip-pdu-control --on "$name"
            epoch >"$on_epoch_file"
            ;;
    esac
}

function sensorActivated()
{
    local name
    local location
    local device
    local is_pir

    while [ -n "$1" ]; do
        case $1 in 
            --name)
                name="$2"
                location="$2"
                shift 2
                ;;

            --device)
                device=$2
                shift 2
                ;;

            --pir)
                is_pir="true"
                shift
                ;;

            *)
                break
                ;;
        esac
    done
  
    if [ -n "$is_pir" ]; then
        config_file="$HOME/.pip/${device}.pir"
        if [ ! -f "$config_file" ]; then
            cat >$config_file <<EOF
#
# Configuration file for PIR sensor.
#
CONF_SENSOR_TYPE="PIR"
CONF_SENSOR_NAME="$name"
CONF_SENSOR_LOCATION="$name"
CONF_SENSOR_DEVICE="$device"

EOF
        else 
            source "$config_file"
            name="$CONF_SENSOR_NAME"
            location="$CONF_SENSOR_LOCATION"
        fi
    fi

    if [ -n "$name" ]; then
        printVerbose "ACT $name at $location."
        #printVerbose
        printVerbose "Sensor $name at $location activated."
    fi

    case "$name" in
        PIR01|PIR03)
            timedSwitch --on --name sonoff23
            ;;
        
        PIR11)
            timedSwitch --on --name sonoff23
            ;;

        PIR04)
            timedSwitch --on --name sonoff23
            ;;
    esac
}

function printWarning()
{
    local date_string=$(date "+%Y-%m-%d %H:%M:%S")
    local log_file="$HOME/.pip/warnings.log"

    echo -n "$date_string "     >&2
    printf "${XTERM_COLOR_RED}" >&2
    echo -en "$*"               >&2
    printf "${TERM_NORMAL}\n"   >&2
    

    echo -n  "$date_string "    >>$log_file
    echo -en "$*"               >>$log_file
    echo     ""                 >>$log_file
}

#
# $*: the message
#
# Prints all the arguments but only if the program is in the verbose mode.
#
function printVerbose()
{
    local datestring=$(date "+%Y-%m-%d %H:%M:%S")

    if [ "$VERBOSE" == "true" ]; then
        echo -e "$datestring $*" >&2
    fi

    if [ "$LOGFILE" ]; then
        echo -e "$datestring DEBUG $MYNAME($$) $*" >>"$LOGFILE"
    fi
}

function change_state()
{
    local new_state="$1"

    if [ "$new_state" == "$PIP_STATE" ]; then
        return 0
    fi

    printf "State %s -> %s\n" "$PIP_STATE" "$new_state"
    case "$new_state" in 
        night)
            printVerbose "Changing $PIP_STATE mode to $new_state mode now."
            pip-pdu-control --on  --group=safety_lights
            pip-pdu-control --off --group=main_lights
            pip-pdu-control --off --group=safety_lights
            pip-pdu-control --on  sonoff11
            ;;

        party)
            printVerbose "Changing $PIP_STATE mode to $new_state mode now."
            pip-pdu-control --on  --group=safety_lights
            pip-pdu-control --off --group=main_lights
            ;;
    esac

    PIP_STATE="$new_state"
}

#
# $2: '{"RfReceived":{"Sync":9220,"Low":350,"High":1020,"Data":"7ECCE6","RfKey":"None"}}'
#   : '{"Time":"1970-01-01T10:20:19","Uptime":11,"Vcc":3.208,"Wifi":{"AP":1,"SSId":"pipas","RSSI":68,"APMac":"AC:22:05:DA:77:0F"}}'
#   : 
#
function process_message()
{
    local topic="$1"
    local message="$2"
    local data=$(echo "$message" | jq -r '."RfReceived"."Data"' 2>/dev/null)
    local mac=$(echo "$message" | jq -r '."Wifi"."ApMac"' 2>/dev/null)
    local device=$(echo "$topic" | awk -F/ '{print $2}')
    local file
    local name
    local directory

    printVerbose "-------------------------------------------------"
    printVerbose "    topic: '$topic'"
    printVerbose "  message: '$message'"
    if [[ $topic == stat/*/POWER ]] || [[ $topic == stat/*/POWER1 ]]; then
        name=$(echo "$topic" | cut -d'/' -f 2)
        config_file="$HOME/.pip/${name}.pdu"
        if [ ! -f "$config_file" ]; then
            printVerbose "--> $name"
cat >$config_file <<EOF
#
# PDU configuration file created by $MYNAME $VERSION.
# Discovered through mqtt as
#     topic: '$topic'
#   message: '$message'
#
CONF_PDU_NAME="$name"

CONF_PDU_SERVER="???.???.???.???"
CONF_PDU_URL="http://\$CONF_PDU_SERVER"
CONF_PDU_STANDARD="tasmota"
CONF_PDU_CATEGORY="pending"
CONF_PDU_MQTT="yes"
EOF
        fi
    fi

    for file in $HOME/.pip/*.pdu; do
        name=$(basename "$file" .pdu)
        if [ "$topic" == "stat/$name/POWER" ]; then
            directory="$HOME/.pip.measurements"

            [ ! -d "$directory" ] && mkdir "$directory"
            echo "$message" >"$directory/${name}.state"
            break
        fi
    done

    #if echo "$topic" | grep -q 'tele/.*/LWT'; then
    #    echo "TELEMETRY:"
    #    saveState \
    #        --device "$(echo "$topic" | sed 's#^tele/\(.*\)/LWT$#\1#')"
    #fi

    if [ "$message" == "OFF" ]; then
        # Topic: "stat/sonoffXX/POWER"
        #if [ "$device" != "sonoff21" ]; then
            printVerbose "OFF $device"
        #fi
        #pip-pdu-control --off sonoff4ch01_02
    elif [ "$message" == "ON" ]; then
        # Topic: "stat/sonoffXX/POWER"
        printVerbose "ON  $device"
        #pip-pdu-control --on sonoff4ch01_02
    elif [ "$topic" == "tele/sonoff_rf_bridge_01/RESULT" ]; then 
        #echo " device : sonoff_rf_bridge_01"
        
        case "$data" in 
            D2D49E)
                sensorActivated --pir --name "PIR01" --device "$data"
                ;;

            D4500E)
                sensorActivated --pir --name "PIR02" --device "$data"
                ;;

            D250DE)
                sensorActivated --pir --name "PIR03" --device "$data"
                ;;

            D40BBE)
                sensorActivated --pir --name "PIR04" --device "$data"
                ;;

            D4102E)
                sensorActivated --pir --name "PIR05" --device "$data"
                ;;

            D3E00E)
                sensorActivated --pir --name "PIR06" --device "$data"
                ;;

            EA080E)
                sensorActivated --pir --name "PIR10" --device "$data"
                ;;

            E885DE)
                sensorActivated --pir --name "PIR11" --device "$data"
                ;;
            
            E591AE)
                sensorActivated --pir --name "PIR12" --device "$data"
                ;;

            EB7E1E)
                sensorActivated --pir --name "PIR13" --device "$data"
                ;;

            EC6DFE)
                sensorActivated --pir --name "PIR14" --device "$data"
                ;;

            7D5503)
                printVerbose "message : button 1"
                pip-pdu-control --on tasmota02
                ;;

            7D5530)
                printVerbose "message : button 2"
                pip-pdu-control --off tasmota02
                ;;

            7D550C)
                printVerbose "message : button 3"
                pip-pdu-control --off sonoff11
                ;;

            7D550F)
                printVerbose "message : button 4"
                pip-pdu-control --on sonoff11
                ;;

            7D5533)
                printVerbose "message : button 5"
                change_state "night"
                ;;


            7D55FC)
                printVerbose "message : button 14"
                pip-pdu-control --toggle tasmota01
                ;;

            7D55FF)
                printVerbose "message : button 15"
                pip-pdu-control --toggle sonoff11
                ;;

            7D553C)
                printVerbose "message : button 6"
                change_state "party"
                ;;
            
            7D553F)
                printVerbose "message : button 7"
                pip-pdu-control --off sonoff21
                pip-pdu-control --off orvibo04
                ;;


            BD5AD8)
                # Light switch
                printVerbose "message : switch 01"
                #pip-pdu-control --off sonoff21
                pip-pdu-control --toggle tasmota01
                ;;
            #
            # Another remote controller.
            #
            592EB8)
                printVerbose "Button A"
                pip-pdu-control --on sonoff11
                pip-pdu-control --on sonoff19
                ;;

            592EB4)
                printVerbose "Button B"
                pip-pdu-control --off sonoff11
                pip-pdu-control --off sonoff19
                ;;

            592EB2)
                printVerbose "Button C"
                ;;

            592EB1)
                printVerbose "Button D"
                ;;


            #
            # Door opening sensors.
            #
            7ECCE6)
                printVerbose "message : door open 01"
                ;;

            C3CD19)
                printVerbose "message : door open 02"
                ;;

            7CFEE1)
                #3E7F70)
                printVerbose "message : door open 10"
                pip-pdu-control --on sonoff21
                ;;

            #
            # Water alarms.
            #
            4492A9)
                printWarning "Water alarm 01."
                ;;

            1576A9)
                printWarning "Water alarm 02."
                ;;

            7541E9)
                printWarning "Water alarm 03."
                ;;

            4541E9)
                printWarning "Water alarm 04."
                ;;

            *)
                echo "UNHANDLED RF"
                echo "message : '$message'"
                echo "   data : '$data'"
                echo "    mac : '$mac'"
        esac
    elif [ "$topic" == "/sonofftouch01/button/state" ]; then
        # A sonoff touch 1
        if [ "$message" == "0" ]; then
            pip-pdu-control --off sonoff21
        else 
            pip-pdu-control --on  sonoff21
        fi
    else
        if false; then
            echo "UNHANDLED"
            echo "  topic : '$topic'"
            echo "message : '$message'"
            echo "   data : '$data'"
            echo "    mac : '$mac'"
        fi
    fi

    timedSwitch --check --name sonoff10
    timedSwitch --check --name sonoff23
}

printVerbose "Core system process is starting now."

MQTT_SERVER="192.168.0.5"
MQTT_SERVER="mqtt"
MQTT_PORT=1883
MQTT_USER=pipas
MQTT_PASSWORD=p

if [ -f "$MQTT_CONFIG_FILE" ]; then
    printVerbose "Loading '$MQTT_CONFIG_FILE'..."
    source "$MQTT_CONFIG_FILE"
else
    printVerbose "Creating '$MQTT_CONFIG_FILE'..."
    cat >"$MQTT_CONFIG_FILE" <<EOF
#
# Config file autogenerated by $MYNAME $VERSION.
# Change this file to represent the settings, it will not beoverwritten.
#
MQTT_SERVER="$MQTT_SERVER"
MQTT_PORT=$MQTT_PORT
MQTT_USER=$MQTT_USER
MQTT_PASSWORD=$MQTT_PASSWORD

EOF
fi 

while read msg; do
    topic=$(echo "$msg" | awk '{print $1}')
    message=$(echo "$msg" | awk '{print $2}')
    process_message "$topic" "$message"
    #echo "msg: '$msg'";
done < <(mosquitto_sub \
    -h "$MQTT_SERVER" \
    -u "$MQTT_USER" \
    -P "$MQTT_PASSWORD" \
    -t '#' -v -q 1)

