diff --git a/a.html b/a.html new file mode 100644 index 0000000..84ff8fa --- /dev/null +++ b/a.html @@ -0,0 +1,20 @@ +- Only operate the aircon in cool mode
+- Close vent in Study if [robsphone] isn't online
+- Close vent in Rob&Beth if [robsphone bethsphone] aren't online
+- Close vent in Brendan if [brendansphone bethsphone] aren't online
+- Close vent in Media if [lg-wifi] isn't online
+- Close vent in Ben/Sewing if [bensipad] isn't online
+- From Mon to Fri between 08:30 and 18:00, Close vent in Ben/Sewing if [brendansphone] isn't online
+- Prevent Nursery from being the MyZone
+- Prevent Ben/Sewing from being the MyZone
+- From Mon to Tue between 08:30 and 16:30, Force the vent in Nursery to be closed
+- Force the vent in Nursery to be closed
+- From Sat to Sun, Ignore Study temperature when deciding what to do
+- Between 06:00 and 23:59, Keep temperature of Family between 20-23 degrees
+- Between 20:00 and 07:00, Keep temperature of Brendan between 20-23 degrees
+- Keep temperature of Media between 18-23 degrees
+- Keep temperature of Rob&Beth between 20-23 degrees
+- From Mon to Fri between 08:30 and 17:30, Keep temperature of Study between 20-22 degrees
+- Between 20:00 and 07:00, Keep temperature of Ben/Sewing between 20-23 degrees
+- From Mon to Fri between 08:30 and 17:30, Keep temperature of Ben/Sewing between 20-23 degrees
+ diff --git a/aircon.sh b/aircon.sh index 82e5a6f..5438adc 100755 --- a/aircon.sh +++ b/aircon.sh @@ -70,7 +70,7 @@ function usage() { echo " -S[H] Show configured rules in human-readable format" echo " (HTML if -H given, otherwise ANSI)." echo " -w List which people are available then exit." - echo " -W List zone owners' devices are available then exit." + echo " -W List zone-owning devices are available then exit." echo " -t num Specify degrees below min temperature before taking action." echo " -T num Specify degrees above max temperature before taking action." echo " -y Actually run commands/db inserts. By default, commands are just displayed." @@ -117,7 +117,7 @@ function getzoneaction() { # populates zproblem[] and zaction[] else if [[ -z ${zowner[$idx]} ]]; then pingok=1 - elif canping "${zowner[$idx]}"; then + elif canping ${zowner[$idx]}; then pingok=1 else pingok=0 @@ -151,6 +151,7 @@ function getzoneaction() { # populates zproblem[] and zaction[] #info "${zname[$idx]} priority is $priority" zproblem[$idx]="$problem" zpri[$idx]="$priority" + zownerhome[$idx]="$pingok" if [[ $problem == "owner_not_home" ]]; then # turn the zone off @@ -337,6 +338,7 @@ function generate_actions() { # populates global: nairconcommands & airconcmd for x in ${!zname[@]}; do getzoneaction $x +#echo "zoneignore for ${zname[$x]} is ${zignore[$x]}" >/dev/stderr done # pass 1 @@ -637,6 +639,7 @@ function add_aircon_command() { airconcmdzone[$nairconcommands]="${zname[$idx]}" airconcmdotherzone[$nairconcommands]="${zname[$otheridx]}" airconproblem[$nairconcommands]="${zname[$idx]} is ${zproblem[$idx]/_/ }" +ooooooooooo #if [[ $otheridx -ne -1 ]]; then # airconcomment[$nairconcommands]="${airconcomment[$nairconcommands]}, update nearby zone ${zname[$otheridx]}" #fi @@ -672,8 +675,12 @@ function addforcevent() { [[ $idx == $nforcevents ]] && nforcevents=$((nforcevents + 1)) } -function addtemprange() { - local x idx +function addtemprange() { # [-s] idx min-max -s means 'set zwanttemp+zwantmin+zwantmax too' + local x idx doset=0 + if [[ $1 == "-s" ]]; then + doset=1 + shift + fi idx=$ntempranges for x in ${!tr_zonename[@]}; do if [[ ${tr_zonename[$x]} == "$1" ]]; then @@ -681,9 +688,36 @@ function addtemprange() { break; fi done + tr_zonename[$idx]="$1" tr_range[$idx]="$2" + + if [[ $doset -eq 1 ]]; then + local wanttemp zidx + wanttemp=$(gettemprange "$1") + zidx=$(getidxfromname "$1") + if [[ $wanttemp == "n/a" ]]; then + zwanttemp[$zidx]="n/a" + zwantmin[$zidx]="-99" + zwantmax[$zidx]="99" + else + zwanttemp[$zidx]="$wanttemp" + zwantmin[$zidx]="${wanttemp%-*}" + zwantmax[$zidx]="${wanttemp#*-}" + fi + fi + + + + + + [[ $idx == $ntempranges ]] && ntempranges=$((ntempranges + 1)) + + + + + } function addadj() { @@ -721,9 +755,13 @@ function addperson() { [[ $idx == $npeople ]] && npeople=$((npeople + 1)) } -function addowner() { - local z h local x idx db +function addowner() { # zone "host1 host2 ..." + local z h local x idx db doset=0 db=0 + if [[ $1 == "-s" ]]; then + doset=1 + shift + fi z="$1" shift @@ -745,21 +783,28 @@ function addowner() { fi [[ $db -eq 1 ]] && info " hosts val is: ${ownerhost[$idx]}" [[ $idx == $nowners ]] && nowners=$((nowners + 1)) + + if [[ $doset -eq 1 ]]; then + local zidx + zidx=$(getidxfromname "$z") + zowner[$zidx]="${ownerhost[$idx]}"; + #zownerperson[$zidx]=$(getownerperson "$z"); # may be overwritten later + fi } # getownerperson zone_name # returns name of person who owns zone -function getownerperson() { - local x retval - retval="" - for x in ${!ownerzone[@]}; do - if [[ ${ownerzone[$x]} == "$1" ]]; then - retval="${ownerperson[$x]}" - break - fi - done - echo "$retval" -} +#function getownerperson() { +# local x retval +# retval="" +# for x in ${!ownerzone[@]}; do +# if [[ ${ownerzone[$x]} == "$1" ]]; then +# retval="${ownerperson[$x]}" +# break +# fi +# done +# echo "$retval" +#} # getowner zone_name # returns devices associated woth zone @@ -832,6 +877,7 @@ function load_config() { db=0 rv=0 while read line; do + ok=1 # default to okay line=${line%%#*} # remove comments if [[ -n ${line// } ]]; then # time based options @@ -847,7 +893,7 @@ function load_config() { if [[ $ok -eq 1 ]]; then IFS=' ' read -ra tok <<< "$line" if [[ ${tok[0]} == "temp" ]]; then - addtemprange ${tok[1]} ${tok[2]} + addtemprange -s ${tok[1]} ${tok[2]} elif [[ ${tok[0]} == "constant" ]]; then constant=${tok[1]} elif [[ ${tok[0]} == "adj" ]]; then @@ -859,7 +905,7 @@ function load_config() { elif [[ ${tok[0]} == "force" ]]; then addforcevent ${tok[1]} ${tok[2]} elif [[ ${tok[0]} == "owner" ]]; then - addowner ${tok[1]} ${tok[@]:2} + addowner -s ${tok[1]} ${tok[@]:2} elif [[ ${tok[0]} == "person" ]]; then addperson ${tok[1]} ${tok[@]:2} elif [[ ${tok[0]} == "modelock" ]]; then @@ -975,11 +1021,14 @@ function processtimeconditions() { fi done + [[ $db -eq 1 ]] && info " ok=$ok nonmatches=$nonmatches" + if [[ $ok -eq 0 || $nonmatches -gt 0 ]]; then rv=1 else rv=0 fi + [[ $db -eq 1 ]] && info " returning $rv" return $rv } @@ -1052,6 +1101,7 @@ function parse_config() { local cond allconds x local db fileok=1 linenum show=0 local config_human line_human errstr + local ign="" thisignored=0 oneof if [[ -n $1 ]]; then show=$1 @@ -1065,6 +1115,7 @@ function parse_config() { ok=1 active_cols line=${line%%#*} # remove comments + thisignored=0 line_human="" if [[ ! -z ${line// } ]]; then # time based options @@ -1081,11 +1132,14 @@ function parse_config() { fi fi + IFS=' ' read -ra tok <<< "$line" if [[ ${tok[0]} == "temp" ]]; then local min max min=${tok[2]%-*} max=${tok[2]#*-} + [[ $ign == *\ ${tok[1]}* ]] && thisignored=1 # zone is being ignored + [[ $thisignored -eq 1 ]] && inactive_cols line_human="${line_human}Keep temperature of ${roomc}${tok[1]}${linec} between ${minc}${min}${linec}-${maxc}${max}${linec} degrees" elif [[ ${tok[0]} == "constant" ]]; then true @@ -1097,6 +1151,7 @@ function parse_config() { line_human="${line_human}Prevent ${roomc}${tok[1]}${linec} from being the MyZone" elif [[ ${tok[0]} == "noop" || ${tok[0]} == "ignore" ]]; then line_human="${line_human}Ignore ${roomc}${tok[1]}${linec} temperature when deciding what to do" + ign="${ign} ${tok[1]}" elif [[ ${tok[0]} == "force" ]]; then if [[ $VALID_ZONE_STATES == *\ ${tok[2]}\ * ]]; then local adj @@ -1110,13 +1165,16 @@ function parse_config() { elif [[ ${tok[0]} == "owner" ]]; then local devices verb devices="${devc}${tok[@]:2}${linec}" - devices="${devbc}[${linec}${devices}${devbc}]${linec}" if [[ ${#tok[@]} -eq 3 ]]; then verb="isn't" + oneof="" + devices="${devbc}${linec}${devices}${devbc}${linec}" else verb="aren't" + oneof=" one of" + devices="${devbc}(${linec}${devices}${devbc})${linec}" fi - line_human="${line_human}${statec}Close${linec} vent in ${roomc}${tok[1]}${linec} if $devices $verb online" + line_human="${line_human}${statec}Close${linec} vent in ${roomc}${tok[1]}${linec} if${oneof} $devices $verb online" elif [[ ${tok[0]} == "modelock" ]]; then if [[ $VALID_MODES == *\ ${tok[1]}\ * ]]; then local col @@ -1136,7 +1194,9 @@ function parse_config() { fi if [[ -n $line_human ]]; then if [[ $ok -eq 0 ]]; then - line_human="${plainc}${inactc} ${linec}${line_human}" + line_human="${plainc}${inactc}[out-of-hours] ${linec}${line_human}" + elif [[ $thisignored -eq 1 ]]; then + line_human="${plainc}${inactc}[ignored] ${linec}${line_human}" fi config_human="${config_human}- ${linec}${line_human}${plainc}$nl" fi @@ -1175,7 +1235,8 @@ function canping() { thisrv=1 else arp -d $ip >/dev/null 2>&1 - ping -c1 -w1 -n -q $ip >/dev/null 2>&1 & + #ping -c1 -w1 -n -q $ip >/dev/null 2>&1 & + arping -c10 -W0.1 -w2 -C1 -q ${ip} 2>/dev/null sleep 0.3 mac=$(arp -n $ip) mac=$(echo "$mac" | egrep -v "Host|xpired" | awk '{print $2}') @@ -1205,17 +1266,18 @@ function addzone() { zproblem[$nzones]="n/a" zaction[$nzones]="n/a" zactionfail[$nzones]=0 - zowner[$nzones]=$(getowner "$name") - zownerperson[$nzones]=$(getownerperson "$name") + zowner[$nzones]=$(getowner "$name") # devices which 'own' the zone - may be overwritten later + #zownerperson[$nzones]=$(getownerperson "$name") # may be overwritten later + zownerhome[$nzones]=1 #info "zone $name owner is [${zowner[$nzones]}]" zignore[$nzones]=0 znomyzone[$nzones]=0 zpri[$nzones]=0 wanttemp=$(gettemprange "$name") if [[ $wanttemp == "n/a" ]]; then - zwanttemp[$nzones]="n/a" - zwantmin[$nzones]="-99" - zwantmax[$nzones]="99" + zwanttemp[$nzones]="n/a" # default - this will be overridden in load_config + zwantmin[$nzones]="-99" # default - this will be overridden in load_config + zwantmax[$nzones]="99" # default - this will be overridden in load_config else zwanttemp[$nzones]="$wanttemp" zwantmin[$nzones]="${wanttemp%-*}" @@ -1288,6 +1350,7 @@ function gen_config() { function get_aircon_info() { 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) nzones=0 @@ -1303,10 +1366,11 @@ function get_aircon_info() { function show_aircon_status() { local zonestr zonecol settempcol actioncol thiswantcol thisstate thisstateform - local thisformat x powercol lockcol + local actualtempformat x powercol lockcol actionstr local FORMAT1 FORMAT2 FORMATHOT FORMATCOLD FORMATOK CLOSEDFORM OPENFORM + local ownercol ownerform - FORMAT1="${BOLD}%-16s%-7s%-8s%-7s%-7s%s${PLAIN}" + FORMAT1="${BOLD}%-16s%-9s%-8s%-7s%-7s%-7s%s${PLAIN}" FORMAT2="${UNDERLINE}${FORMAT1}${PLAIN}" FORMATHOT="${RED}%-7s${PLAIN}" FORMATCOLD="${CYAN}%-7s${PLAIN}" @@ -1327,15 +1391,15 @@ function show_aircon_status() { echo - printf "$FORMAT1\n" "" "Valid" "" "Set" "Actual" "Proposed " - printf "$FORMAT2\n" "Zone" "Temp" "State" "Temp" "Temp" "Action " + printf "$FORMAT1\n" "" "Valid" "" "Set" "Actual" "Owner" "Proposed " + printf "$FORMAT2\n" "Zone" "Temp" "State" "Temp" "Temp" "Home" "Action " for x in ${!zname[@]}; do if [[ ${zproblem[$x]} == "too_hot" ]]; then - thisformat="${FORMATHOT}" + actualtempformat="${FORMATHOT}" elif [[ ${zproblem[$x]} == "too_cold" ]]; then - thisformat="${FORMATCOLD}" + actualtempformat="${FORMATCOLD}" else - thisformat="${FORMATOK}" + actualtempformat="${FORMATOK}" fi if [[ ${airconmode} == "off" ]]; then thisstateform="${CLOSEDFORM}" @@ -1353,6 +1417,13 @@ function show_aircon_status() { else thiswantcol="$PLAIN" fi + + # override + if [[ ${zignore[$x]} -eq 1 ]]; then + thiswant="ignore" + thiswantcol="$GREY" + fi + if [[ ${zactionfail[$x]} -eq 1 || ${zaction[$x]} == "n/a" ]]; then actioncol="$GREY" else @@ -1376,7 +1447,23 @@ function show_aircon_status() { zonestr="${zname[$x]} (C)" fi - printf "$zonecol%-16s$PLAIN$thiswantcol%-7s$PLAIN$thisstateform$settempcol%-7s$PLAIN$thisformat$actioncol%s$PLAIN\n" "${zonestr}" "${thiswant}" "${thisstate}" "${zsettemp[$x]}" "${ztemp[$x]}" "${zaction[$x]}" + if [[ -z ${zowner[$x]} ]]; then + ownercol="$GREY" + ownerstr="n/a" + elif [[ ${zownerhome[$x]} -eq 1 ]]; then + ownercol="$PLAIN" + ownerstr="yes" + else + ownercol="$GREY" + ownerstr="no" + fi + + actionstr="${zaction[$x]}" + #if [[ ${zaction[$x]} == "n/a" && ${zignore[$x]} -eq 1 ]]; then + # actionstr="${actionstr} (zone ignored)" + #fi + + printf "$zonecol%-16s$PLAIN$thiswantcol%-9s$PLAIN$thisstateform$settempcol%-7s$PLAIN${actualtempformat}${ownercol}%-7s${PLAIN}$actioncol%s$PLAIN\n" "${zonestr}" "${thiswant}" "${thisstate}" "${zsettemp[$x]}" "${ztemp[$x]}" "$ownerstr" "${actionstr}" done } @@ -1399,12 +1486,21 @@ function show_analysis() { [[ $what == "close" ]] && what="${what}d" echo "- ${zname[$x]} is forced $what" else - if [[ $constant == ${zname[$x]} ]]; then - append=" (constant zone)" + if [[ ${zownerhome[$x]} -ne 1 ]]; then + if [[ ${zowner[$x]} == *\ * ]]; then + append1=", but (${zowner[$x]}) aren't online" + else + append1=", but ${zowner[$x]} isn't online" + fi else - append="" + append1="" fi - echo "- ${zname[$x]} is ${zproblem[$x]/_/ }${append}" + if [[ $constant == ${zname[$x]} ]]; then + append2=" (constant zone)" + else + append2="" + fi + echo "- ${zname[$x]} is ${zproblem[$x]/_/ }${append1}${append2}" fi count=$((count + 1)) fi @@ -1558,7 +1654,6 @@ csvfile="$DEFAULT_CSVFILE" sanitycheck=0 RULEFORMAT=ansi - # check for config file option first if [[ $* == *-f\ * ]]; then cf=$(echo "$*" | sed -e 's/.*-f //;s/ .*//') @@ -1670,18 +1765,9 @@ if [[ $makeconfig -eq 1 ]]; then exit $rv fi -if [[ -e $CONFIGFILE ]]; then - if [[ $sanitycheck -ge 1 ]]; then - parse_config $sanitycheck - exit $? - elif ! load_config; then - error "Config load failed" - exit 1 - fi -else - error "Config file $CONFIGFILE doesn't exist." - exit 1 -fi + + + if [[ $showwho -eq 0 ]]; then if [[ -z $MYAIR ]]; then @@ -1698,6 +1784,25 @@ if [[ $showwho -eq 0 ]]; then fi fi + + +# Must do this BEFORE parsing the config file, otherwise +# we can't resolve zone names. +get_aircon_info + +if [[ -e $CONFIGFILE ]]; then + if [[ $sanitycheck -ge 1 ]]; then + parse_config $sanitycheck + exit $? + elif ! load_config; then + error "Config load failed" + exit 1 + fi +else + error "Config file $CONFIGFILE doesn't exist." + exit 1 +fi + # ping all hosts in background to populate arp table for x in ${devices}; do ping -c1 -w1 -n -q $ip >/dev/null 2>&1 & @@ -1717,7 +1822,7 @@ if [[ $showwho -eq 1 ]]; then echo printf "$TFORMAT" "Person" "Availability" for x in ${!pname[@]}; do - if canping "${pdev[$x]}"; then + if canping ${pdev[$x]}; then thisform="$HFORMAT" str="At home" else @@ -1742,7 +1847,7 @@ elif [[ $showwho -eq 2 ]]; then echo printf "$TFORMAT" "Devices" "Availability" for x in $alldevs; do - if canping "${x}"; then + if canping ${x}; then thisform="$HFORMAT" str="Available" else @@ -1756,9 +1861,6 @@ elif [[ $showwho -eq 2 ]]; then fi - -get_aircon_info - if [[ $logmode -eq 1 ]]; then now=$(date +'%d/%m/%Y %H:%M:%S') if [[ ! -e $csvfile ]]; then @@ -1786,7 +1888,7 @@ elif [[ $logmode -eq 2 ]]; then done for x in ${!pname[@]}; do - canping "${pdev[$x]}" && ishome=1 || ishome=0 + canping ${pdev[$x]} && ishome=1 || ishome=0 influx_insert "INSERT attendance,person=${pname[$x]} value=$ishome" done [[ $airconmode == "off" ]] && pw=0 || pw=1 diff --git a/aircon_grafana.png b/aircon_grafana.png new file mode 100755 index 0000000..4b167aa Binary files /dev/null and b/aircon_grafana.png differ diff --git a/b.html b/b.html new file mode 100644 index 0000000..8f5bfa0 --- /dev/null +++ b/b.html @@ -0,0 +1,2 @@ +strikedstill striked
+what about now