Update: afwezigheidsdetectie

Sinds vandaag werkt het script voor afwezigheidsdetectie met zowel (geroote)Toon als Hue. Er zijn een ook aantal aanpassingen gemaakt zoals het toevoegen van absolute paden naar bestanden voor gebruik met cron.

Het script bestaat uit drie bestanden:

  • daemon.sh – het script zelf
  • devices – lijst met mac-adressen van telefoons
  • lights – lijst met unieke ids van Hue-lampen

Belangrijk is om voor Hue een unieke API-key aan te maken. Dit kan via de clip API debugger (check voor meer informatie de site van Philips Hue).

Bij mij draait het bestand elke vijf minuten via Cron en wordt uitvoer opgeslagen naar een log-bestand, waarvan de uitvoer als volgt is:

Zoeken naar apparaten, dit duurt een paar minuutjes...
Apparaat offline: xx:xx:xx:xx:xx:xx
Apparaat offline: xx:xx:xx:xx:xx:xx
Apparaat offline: xx:xx:xx:xx:xx:xx
Apparaat offline: xx:xx:xx:xx:xx:xx
Geen apparaten online, actie ondernemen...
Toon ingesteld op 'Weg'
Hue instellen...
Uitschakelen: Badkamer spot 1 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Badkamer spot 2 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Badkamer spot 3 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Hal boven spot 1 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Hal boven spot 2 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Hal boven spot 3 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Plafonniere (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Plafonniere hal (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Plafonnière (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Keuken (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Keuken spot 1 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Keuken spot 2 (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Tv hoek (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Zithoek (xx:xx:xx:xx:xx:xx:xx:xx-xx)
Uitschakelen: Plafonnière (xx:xx:xx:xx:xx:xx:xx:xx-xx)

Het script ziet er nu als volgt uit:

#!/bin/bash
# Script door Dennis Bor

# IP van Toon
toonIP="192.168.0.58"

# IP van Hue
hueIP="192.168.0.87"

# API-key van Hue
hueAPIKey="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# pad naar het script
path="/home/dennis/home_automation/"

# pad naar arp
arpPath="/usr/sbin/"

# Array met mac adressen
# Als geen van deze apparaten gevonden wordt in het lokale
# netwerk, dan zal er geschakeld worden.
deviceArray=()

# itereer door bestand 'devices' waarin
# per regel een mac-adres van een apparaat opgegeven
# kan worden
while read line; do

	# geen lege regel?
	if [[ $line != "" ]]; then

		# voeg het apparaat toe aan de array
		deviceArray+=("$line")
	fi

done < "$path"devices


# Boolean waarin opgeslagen wordt of er tenminste een
# van de gespecificeerde apparaten online is. Standaard false
deviceFound=false

# Toon informatie
echo "Zoeken naar apparaten, dit duurt een paar minuutjes..."

# Leeg de arp cache
ipResult=`ip -s -s neigh flush all`

# Wacht drie minuten
sleep 3m

# Haal de arp table op
arpResult=`"$arpPath"arp -a`

# Itereer door alle gespecificeerde mac adressen
for macIterator in "${deviceArray[@]}"
do

	# huidige adres in de arp tabel?
	if [[ $arpResult == *"$macIterator"* ]]; then

		# ja

		# toon informatie
		echo "Apparaat online: $macIterator"

		# stel de boolean in op true
		deviceFound=true

	# huidige adres niet in de arp tabel
	else

		# nee

		# toon informatie
		echo "Apparaat offline: $macIterator"

	fi
done

# Geen apparaten online?
if [[ $deviceFound == false ]]; then

	# nee

	# toon informatie
	echo "Geen apparaten online, actie ondernemen..."

	# schakel programma Toon in op Weg
	# gebruik curl, parse de uitvoer als JSON en sla de waarde van 'result' op
	# de waarde wordt bij de tweede call overschreven; als de laatste faalt,
	# dan moet de eerste ook gefaald zijn en andersom
	result=`curl -s "http://$toonIP/happ_thermstat?action=changeSchemeState&state=0"`
	result=`curl -s "http://$toonIP/happ_thermstat?action=changeSchemeState&state=2&temperatureState=3" | jq -r '.result'`

	# waarde van result 'ok'?
	# dat betekent dat Toon het gekozen programma geacvtiveerd heeft
	if [[ $result == "ok" ]]; then

		# toon informatie
		echo "Toon ingesteld op 'Weg'"

	# waarde van result ongelijk aan 'ok'? dit kan alles zijn, van een ander resultaat tot
	# verbindingsproblemen, etc.
	else

		# toon informatie
		echo "Kan toon niet instellen op 'Weg'"
	fi

	# toon informatie
	echo "Hue instellen..."

	# haal alle lampen op
	result=`curl -s "http://$hueIP/api/$hueAPIKey/lights"`

	# array keys uit de json array van Hue halen. helaas gebruikt Hue geen
	# array met indices, maar met keys. van lampen die verwijderd worden
	# vervalt het id.
	arrayKeys=`echo "$result" | jq -r 'keys | .[]'`
	
	# nieuwe array om alle keys in op te slaan
	arrayIDs=()

	# itereer door alle array keys
	for key in ${arrayKeys//\\n/ }
	do
		# voeg de key toe aan de array
		arrayIDs+=("$key")

	done

	# inhoud van bestand 'lights' opslaan in de variabele. Bij alle lampen van Hue
	# wordt gecontroleerd of ze in deze lijst voorkomen, voordat ze uitgeschakeld worden.
	# hierdoor blijft het mogelijk om bepaalde verlichting te laten branden (bijvoorbeeld
	# tuinverlichting)
	lightsToSwitchOff=`cat "$path"lights`

	# itereer door alle IDs
	for lightIterator in "${arrayIDs[@]}"
	do

		# unieke id van de lamp ophalen. in het betand 'lights' kun je een lijst aanleggen
		# van unieke ids van lampen die uitgeschakeld moeten worden
		currentUniqueId=`echo "$result" | jq --arg value $lightIterator -r '.[$value].uniqueid'`
		
		# komt het huidige unieke id voor in de lijst met ids?
		if [[ $lightsToSwitchOff == *"$currentUniqueId"* ]]; then

			# ja
			
			# lamp naam ophalen zodat deze getoond kan worden
			currentName=`echo "$result" | jq --arg value $lightIterator -r  '.[$value].name'`
			
			# toon informatie
			echo "Uitschakelen: $currentName ($currentUniqueId)"
			
			# schakel de lamp uit
			toonResult=`curl -s -X PUT -H "Content-Type: application/json" -d '{"on":false}' "http://$hueIP/api/$hueAPIKey/lights/$lightIterator/state"`

		fi
	done

# Tenminste een apparaat online?
else

	# ja

	 # toon informatie
     echo "Een of meer apparaten online, thermostaat herstellen..."

	# hervat het programma van toon
	# gebruik curl, parse de uitvoer als JSON en sla de waarde van 'result' op
	result=`curl -s "http://$toonIP/happ_thermstat?action=changeSchemeState&state=1" | jq -r '.result'`

	# waarde van result 'ok'?
        # dat betekent dat Toon het programma hersteld heeft
        if [[ $result == "ok" ]]; then

                # toon informatie
                echo "Toon hervat programma"

        # waarde van result ongelijk aan 'ok'? dit kan alles zijn, van een ander resultaat tot
        # verbindingsproblemen, etc.
        else

                # toon informatie
                echo "Kan het programma op Toon niet hervatten"
        fi

	# toon informatie
	echo "Klaar..."

fi

En nu maar testen. Vooral het detecteren van iPhones lijkt (nog) niet helemaal vlekkeloos te verlopen: ofwel ze blijven te lang in de cache staan, of ze worden niet verwijderd.