diff --git a/aircon.sh b/aircon.sh index fdf2fb5..4815e6b 100755 --- a/aircon.sh +++ b/aircon.sh @@ -132,6 +132,7 @@ function getzoneaction() { # populates zproblem[] and zaction[] problem="n/a" thisperfect=1 else + [[ $robtest -eq 1 ]] && echo " owner of ${zname[$idx]} is [${zowner[$idx]}]" >&2 if [[ -z ${zowner[$idx]} ]]; then pingok=1 #[[ $robtest -eq 1 ]] && echo " empty owner so no ping " @@ -190,6 +191,11 @@ function getzoneaction() { # populates zproblem[] and zaction[] zpri[$idx]="$priority" zownerhome[$idx]="$pingok" + [[ $robtest -eq 1 ]] && echo " zproblem is: ${zproblem[$idx]}" + [[ $robtest -eq 1 ]] && echo " zpri is: ${zpri[$idx]}" + [[ $robtest -eq 1 ]] && echo " zownerhome is: ${zownerhome[$idx]}" + + if [[ $problem == "owner_not_home" ]]; then # turn the zone off if [[ ${zstate[$idx]} != "close" ]]; then @@ -281,6 +287,8 @@ function getzoneaction() { # populates zproblem[] and zaction[] fi zaction[$idx]="$thisaction" zperfect[$idx]=$thisperfect + [[ $robtest -eq 1 ]] && echo " zaction is: ${zaction[$idx]}" + [[ $robtest -eq 1 ]] && echo " zperfect is: ${zperfect[$idx]}" profile "getzoneaction for idx ${zname[$idx]}" } @@ -609,7 +617,7 @@ function generate_actions() { # populates global: nairconcommands & airconcmd # gen_aircon_command zone_idx "command1 command2 etc" function gen_aircon_command() { - local idx allactions this toadd num doneset othername otherid otheridx db donemode str + local idx allactions this toadd num doneset othername otherid otherid2 otheridx db donemode str jtoadd="" id2 idx=$1 shift allactions="$*" @@ -622,49 +630,63 @@ function gen_aircon_command() { IFS=' ' read -ra tok <<< "${allactions}" for this in ${tok[@]}; do if [[ $this == *power_on* ]]; then - add_aircon_command $idx -1 "Power on system" "on" + add_aircon_command $idx -1 "Power on system" "on" '"info":{"state":"on"}' + elif [[ $this == *power_off* ]]; then - add_aircon_command $idx -1 "Power off system" "off" + add_aircon_command $idx -1 "Power off system" "off" '"info":{"state":"off"}' elif [[ $this == *set_myzone* && $airconmyzoneid != ${zid[$idx]} ]]; then [[ $idx -eq -1 ]] && continue - add_aircon_command $idx -1 "Set MyZone to ${zname[$idx]}" "myzone --zone ${zid[$idx]}" + add_aircon_command $idx -1 "Set MyZone to ${zname[$idx]}" "myzone --zone ${zid[$idx]}" "\"info\":{\"myZone\":${zid[$idx]}}" elif [[ $this == *open:* ]]; then - [[ $idx -eq -1 ]] && continue + # open vent in another zone + [[ $idx -eq -1 ]] && continue othername=$(echo "$this" | sed -e 's/^.*open://;s/ .*//') otheridx=$(getidxfromname $othername) otherid=${zid[$otheridx]} - add_aircon_command $idx $otheridx "Open vent in ${zname[$otheridx]}" "set --zone ${otherid} --state on --temp ${zsettemp[$otheridx]}" + otherid2=$(printf "z%02d" "$otherid") + add_aircon_command $idx $otheridx "Open vent in ${zname[$otheridx]}" "set --zone ${otherid} --state on --temp ${zsettemp[$otheridx]}" "\"zones\":{\"${otherid2}\":{\"state\":\"open\",\"setTemp\",${zsettemp[$otheridx]}}" elif [[ $this == *close:* ]]; then - [[ $idx -eq -1 ]] && continue + # close vent in another zone + [[ $idx -eq -1 ]] && continue othername=$(echo "$this" | sed -e 's/^.*close://;s/ .*//') otheridx=$(getidxfromname $othername) otherid=${zid[$otheridx]} - add_aircon_command $idx $otheridx "Close vent in ${zname[$otheridx]}" "set --zone ${otherid} --state off --temp ${zsettemp[$otheridx]}" + otherid2=$(printf "z%02d" "$otherid") + add_aircon_command $idx $otheridx "Close vent in ${zname[$otheridx]}" "set --zone ${otherid} --state off --temp ${zsettemp[$otheridx]}" "\"zones\":{\"${otherid2}\":{\"state\":\"close\",\"setTemp\",${zsettemp[$otheridx]}}" + elif [[ $this == *set_mode:* ]]; then str=$(echo "$this" | sed -e 's/^.*set_mode://;s/ .*//') - add_aircon_command $idx -1 "Set system mode to '$str'" "$str" + add_aircon_command $idx -1 "Set system mode to '$str'" "$str" "\"info\":{\"mode\":\"${str}\"}" elif [[ $this == *set_temp* || $this == *open_vent* || $this == *close_vent* ]]; then - [[ $idx -eq -1 ]] && continue + [[ $idx -eq -1 ]] && continue if [[ $doneset -eq 0 ]]; then + id2=$(printf "z%02d" "${zid[$idx]}") + jtoadd="\"zones\":{\"${id2}\":{" toadd="" comm="" if [[ $allactions == *open_vent* ]]; then toadd="$toadd --state on" + jtoadd="${jtoadd}\"state\":\"open\"," comm="open vent" elif [[ $allactions == *close_vent* ]]; then toadd="$toadd --state off" + jtoadd="${jtoadd}\"state\":\"close\"," comm="close vent" fi if [[ $allactions == *set_temp* ]]; then num=$(echo "$this" | sed -e 's/^.*set_temp://;s/ .*//') toadd="$toadd --temp $num" + jtoadd="${jtoadd}\"setTemp\":\"$num\"," [[ -n $comm ]] && comm="${comm} and " comm="${comm}set temperature to $num degrees" else toadd="$toadd --temp ${zsettemp[$idx]}" + jtoadd="${jtoadd}\"setTemp\":\"${zsettemp[$idx]}\"," fi if [[ -n $toadd ]]; then - add_aircon_command $idx -1 "In zone ${zname[$idx]}, $comm" "set --zone ${zid[$idx]}$toadd" + + jtoadd="${jtoadd/%,/}}}" # remove trailing comma, add closing braces + add_aircon_command $idx -1 "In zone ${zname[$idx]}, $comm" "set --zone ${zid[$idx]}$toadd" "$jtoadd" doneset=1 fi fi @@ -674,7 +696,7 @@ function gen_aircon_command() { # add_aircon_command zone_idx "comment goes here" "actual pymyair command to run" function add_aircon_command() { - local x idx otheridx comment db + local x idx otheridx comment db cmd jcmd [[ $# -le 1 ]] && return 1 @@ -684,6 +706,11 @@ function add_aircon_command() { shift comment=$1 shift + cmd="$1" + shift + jcmd="{ \"ac1\":{" + jcmd="${jcmd}$1" + jcmd="${jcmd} } }" if [[ $otheridx -ne -1 ]]; then if [[ -n $comment ]]; then @@ -702,7 +729,8 @@ function add_aircon_command() { return 1 fi done - airconcmd[$nairconcommands]="$*" + airconcmd[$nairconcommands]="$cmd" + airconjcmd[$nairconcommands]="$jcmd" airconcomment[$nairconcommands]="$comment" if [[ $idx -eq -1 ]]; then airconcmdzone[$nairconcommands]="Aircon" @@ -723,13 +751,13 @@ function add_aircon_command() { return 0 } + function addnoop() { local idx idx=$(getidxfromname "$1") zignore[$idx]=1 } - function addnomyzone() { local idx idx=$(getidxfromname "$1") @@ -1490,17 +1518,30 @@ function gen_config() { } function get_aircon_info() { + local jsoninfo url state profile "query aircon" [[ $cronmode -eq 0 && $logmode -eq 0 ]] && echo -en "${GREEN}${BOLD}>> ${PLAIN}${GREEN}Querying aircon... ${PLAIN}" - - zones=$(myair $AIRCON_IP zones | jq -r '.[] | [ .name, .state, .setTemp, .measuredTemp, .number ] | @csv' | tr -d '" ') - airconmode=$(myair $AIRCON_IP mode) + if [[ $JSONAPI -eq 1 ]]; then + url="${AIRCON_URL}/getSystemData" + jsoninfo=$(curl -s "$url" 2>/dev/null) + zones=$(echo "$jsoninfo" | jq -r '.aircons.ac1.zones[] | [ .name, .state, .setTemp, .measuredTemp, .number ] | @csv' | tr -d '" ') + state=$(echo "$jsoninfo" | jq -r '.aircons.ac1.info.state' | tr -d '" ') + if [[ $state == "off" ]]; then + airconmode="off" + else + airconmode=$(echo "$jsoninfo" | jq -r '.aircons.ac1.info.mode' | tr -d '" ') + fi + airconmyzoneid=$(echo "$jsoninfo" | jq -r '.aircons.ac1.info.myZone ' | tr -d '" ') + else + zones=$(myair $AIRCON_IP zones | jq -r '.[] | [ .name, .state, .setTemp, .measuredTemp, .number ] | @csv' | tr -d '" ') + airconmode=$(myair $AIRCON_IP mode) + airconmyzoneid=$(myair $AIRCON_IP myzone) + fi nzones=0 for line in $zones; do IFS=',' read -ra tok <<< "$line" addzone "${tok[0]}" "${tok[1]}" "${tok[2]}" "${tok[3]}" "${tok[4]}" done - airconmyzoneid=$(myair $AIRCON_IP myzone) airconmyzone=$(getnamefromid $airconmyzoneid) [[ $cronmode -eq 0 && $logmode -eq 0 ]] && echo -e "${GREEN}${BOLD}ok${PLAIN}" profile "query aircon" @@ -1691,14 +1732,68 @@ function show_proposed_commands() { [[ $count -eq 0 ]] && echo -e "${GREY}n/a${PLAIN}" } +function combine_commands() { + local x id2 basefile tfile combinejq jcmd jurl + combinejq=".[0]" + if [[ ${#airconjcmd} -eq 0 ]]; then + return 1 + fi + basefile=$(mktemp /tmp/$$.json.base.XXXXXX) + [[ -z $basefile ]] && { error "couldnt create base json file" >&2; exit 1; } + + echo -e "{\n\"aircons\": {\n\"ac1\": {\n\"info\": {\n},\n\"zones\": {\n" >${basefile} + + for x in ${zid[@]}; do + id2=$(printf "%02d" $x) + echo " \"z${id2}\": { }," >>${basefile} + done + sed -i '$s/,$//' ${basefile} + echo -e "}\n}\n}\n}\n" >> ${basefile} + + for x in ${!airconjcmd[@]}; do + tfile[$x]=$(mktemp /tmp/$$.json.$x.XXXXXX) + [[ -z ${tfile[$x]} ]] && { error "couldnt create temp file" >&2; exit 1; } + echo "${airconjcmd[$x]}" >${tfile[$x]} + combinejq="${combinejq} * .[$((x + 1))]" + done + + jcmd=$(jq -s "$combinejq" $basefile ${tfile[@]} ) + [[ $? -ne 0 ]] && { error "couldnt merge json command files " >&2; exit 1; } + [[ -z $jcmd ]] && { error "got empty merged json command" >&2; exit 1; } + jurl="${AIRCON_URL}/setAircon?json=$jcmd" + + for x in ${tfile[@]}; + do rm -f "${x}" + done + rm -f "$basefile" + + echo "$jurl" | tr -d '\n ' + return 0 +} + function run_commands() { - local x + local x tfile combinejq jcmd jurl res jqres + for x in ${!airconcmd[@]}; do + #echo RUNNING myair $AIRCON_IP ${airconcmd[$x]} + [[ -n ${airconcomment[$x]} ]] && action "${airconcomment[$x]}" - echo RUNNING myair $AIRCON_IP ${airconcmd[$x]} - myair $AIRCON_IP ${airconcmd[$x]} >/dev/null 2>&1 + if [[ $JSONAPI -eq 1 ]]; then + myair $AIRCON_IP ${airconcmd[$x]} >/dev/null 2>&1 + fi influx_insert "INSERT aircon action=\"${airconcomment[$x]}\",comment=\"${airconproblem[$x]}\"" done + + if [[ $JSONAPI -eq 1 ]]; then + jurl=$(combine_commands) + res=$(curl -s -g "$jurl" 3>/dev/null) + jqres=$(echo "$res" | jq -r '.ack' 2>/dev/null) + if [[ $jqres != "true" ]]; then + error "Myair API call failed:" + echo -e "$RED curl -s -g $jurl$PLAIN" + return 1 + fi + fi } function profile() { @@ -1801,6 +1896,7 @@ limit=$DEFAULTLIMIT profiler=0 csvfile="$DEFAULT_CSVFILE" sanitycheck=0 +JSONAPI=0 RULEFORMAT=ansi robtest=0 @@ -1820,7 +1916,7 @@ fi ALLARGS="$ALLARGS $*" -optstring="aA:bcD:f:hHi:I:k:l:Lo:pmRsSt:T:wWx:y" +optstring="aA:bcD:f:hHi:I:jk:l:Lo:pmRsSt:T:wWx:y" while getopts "$optstring" i $ALLARGS; do case "$i" in a) @@ -1829,6 +1925,12 @@ while getopts "$optstring" i $ALLARGS; do b) RULEDB=1 ;; + D) + influxhost="${OPTARG}" + ;; + f) + CONFIGFILE=${OPTARG} + ;; h) usage; exit 1; @@ -1836,19 +1938,16 @@ while getopts "$optstring" i $ALLARGS; do H) RULEFORMAT=html ;; - f) - CONFIGFILE=${OPTARG} - ;; i) AIRCON_IP=${OPTARG} ;; - D) - influxhost="${OPTARG}" - ;; I) logmode=2 influxdb="$OPTARG" ;; + j) + JSONAPI=1 + ;; A) influxdb="$OPTARG" ;; @@ -1909,6 +2008,8 @@ while getopts "$optstring" i $ALLARGS; do done shift $((OPTIND - 1)) +AIRCON_URL="http://${AIRCON_IP}:2025" + if [[ ! -e $ARPING ]]; then info "Warning: arping binary '$ARPING' not found, will use ping instead" fi @@ -1933,16 +2034,24 @@ fi if [[ $showwho -eq 0 ]]; then - if [[ -z $MYAIR ]]; then - MYAIR=$(which myair) + if [[ $JSONAPI -eq 1 ]]; then + JQ=$(which myair 2>/dev/null) if [[ $? -ne 0 ]]; then - error "Can't find pymyair executable 'myair' in path. Install it from here: https://github.com/smallsam/pymyair" + error "Can't find jq executable in path." exit 1 fi else - if [[ ! -x "$MYAIR" ]]; then - error "Specified pymyair executable '$MYAIR' not found." - exit 1 + if [[ -z $MYAIR ]]; then + MYAIR=$(which myair 2>/dev/null) + if [[ $? -ne 0 ]]; then + error "Can't find pymyair executable 'myair' in path. Install it from here: https://github.com/smallsam/pymyair" + exit 1 + fi + else + if [[ ! -x "$MYAIR" ]]; then + error "Specified pymyair executable '$MYAIR' not found." + exit 1 + fi fi fi fi