Um ein Fritz!DECT 200, welche eine Außenbeleuchtung steuern soll, so anzusprechen, wie ich es mir vorgestellt habe, brauche ich eine automatisierte Steuerung. Die von AVM mitgelieferten Einstellmöglichkeiten auf der Fritz!Box sind schon recht umfangreich, bilden aber leider genau meinen Anwendungsfall nicht ab.
- Schalte morgens ab 07:00 Uhr bis Sonnenaufgang die Außenbeleuchtung ein. Falls der Sonnenaufgang vor 07:00 Uhr war, schalte die Beleuchtung nicht ein.
- Schalte abends ab Sonnenuntergang bis 23:00 Uhr die Außenbeleuchtung ein. Falls der Sonnenuntergang nach 23:00 Uhr war (ich weiß, ist hier nicht möglich, aber die Schaltzeit könnte ja auch früher sein), schalte die Beleuchtung nicht ein.
- „Gäste-Schaltung“: Wenn nach 23:00 Uhr (und nach Sonnenuntergang) der Schalter manuell betätigt wurde, dann spende für 10-20 Minuten Licht, schalte danach das Licht wieder aus. (Prüfe alle 10 Minuten den Stand, wenn er zweimal hintereinander „eingeschaltet“ ist, obwohl laut Zeitplan eigentlich „ausgeschaltet“ sein sollte, schalte ab.)
Die erste Herausforderung für ein solches Skript ist zunächst, den korrekten Zeitpunkt des Sonnenaufgangs bzw. -untergangs zu berechnen. Dazu muss man wissen, dass natürlich die Dämmmerung vom Wetter abhängig ist, aber der Erdtag auch gar nicht exakt 24 Stunden lang ist, sondern sich nur „im Jahresmittel“ ausgleicht. Das führt zu Abweichungen, welche man – zumindest bis 2027 – recht exakt berechnen kann.
Das nachfolgende Skript berechnet für den aktuellen Tag die Zeitpunkte und gibt diese gerundet auf Minuten aus. Man sollte vorher seine Position in den Variablen posLaenge
und posBreite
korrigieren, denn 51°/10° ist grob in der Mitte Deutschlands, zwischen der westlichsten Stadt Deutschlands Isenbruch/Selfkant (51.05°, 5.866944°) und der östlichsten Stadt Deutschlands Neißeaue (51.247°, 14.975°) liegen ca. 35 Minuten.
Das Skript nutzt für die detaillierten Berechnungen bc, welches auf dem eingesetzten Unix-System vorhanden sein sollte. Da bc kein arccos(x) kann, musste ich mir mit der Umrechnung helfen.
Wer das Skript übrigens alle Vorberechnungen erledigen lässt, um darauf später zurückzugreifen, sollte das per übergebene Datum wie date --date="+1year"
immer mit einer Uhrzeit nach 3 Uhr nachts versehen, damit die Berechnung der Winter- bzw. Sommerzeit mit greift. Sonst findet die Berechnung einen Tag zu spät statt. Die Uhren werden ja um 2 bzw. 3 Uhr nachts umgestellt, nicht bereits um Mitternacht.
#!/bin/bash # Unsere Position posLaenge="10.0" posBreite="51.0" # Notwendige Vorberechnungen zoneinfo=$(date +%z) # Zeitzone T=`date +%j` # Tag im Jahr pi="3.14159265358979323844" # pi=`echo "4*a(1)" | bc -l` rad=$(echo "${pi}/180" | bc -l) h=$(echo "-(5/6)*(${rad})" | bc -l) # Höhe des Sonnenmittelpunkts bei Aufgang: Radius+Refraktion BreiteRAD=$(echo "${posBreite}*${rad}" | bc -l) # Welcher Tag ist heute? echo "Heute ist $(date +%d.%m.%y), der $(date +%j). Tag im Jahr" echo -n "Wir nutzen die Zeitzone $(date +%Z), dies entspricht $(date +%z) und damit " echo "${zoneinfo:0:3}" sonnendekl=`echo "0.409526325277017*s(0.0169060504029192*(${T}-80.0856919827619))" | bc -l` sonnendeklDEG=$(echo "${sonnendekl} / ${rad}" | bc -l) arccosint=$(echo "(s(${h})-s(${BreiteRAD})*s(${sonnendekl}))/(c(${BreiteRAD})*c(${sonnendekl}))" | bc -l) arccosintsign=${arccosint:0:1} if [ ${arccosintsign} == "-" ]; then usesign="+" else usesign="-" fi arc2cosint=$(echo "(${arccosint}) * (${arccosint})" | bc -l) acoszeit=$(echo "${pi}/2 ${usesign} a(sqrt(${arc2cosint} / (1 - (${arc2cosint}) ) ) ) " | bc -l) zeitdiff=$(echo "12*${acoszeit}/${pi}" | bc -l) # KORREKT! zeitgleich=$(echo "-0.170869921174742*s(0.0336997028793971 * ${T} + 0.465419984181394) - 0.129890681040717*s(0.0178674832556871*${T} - 0.167936777524864)" | bc -l) aufgang=$(echo "12-(${zeitdiff})-(${zeitgleich})-(${posLaenge}/15)${zoneinfo:0:3}" | bc -l) untergang=$(echo "12+(${zeitdiff})-(${zeitgleich})-(${posLaenge}/15)${zoneinfo:0:3}" | bc -l) if [ ${aufgang:1:1} == "." ]; then # Ist ein einstelliges Ergebnis der Form x.xxxx, wir brauchen noch eine 0 vorne aufgang=$(echo 0${aufgang}) fi # Fuer unsere Breitengrade ueberfluessig, nur der Vollstaendigkeit halber: #if [ ${untergang:1:1} == "." ]; then # Ist ein einstelliges Ergebnis der Form x.xxxx, wir brauchen noch eine 0 vorne # untergang=$(echo 0${untergang}) #fi # Umrechnung in Stunden (trivial) und Minuten (runden!) AufgangMinute=$(echo "(${aufgang} - ${aufgang:0:2}) * 60" | bc | xargs printf "%02.0f\n") if [ ${AufgangMinute} == "60" ]; then AufgangMinute="00" AufgangStunde=$(echo "${aufgang:0:2} + 1" | bc | xargs printf "%02.0f") else AufgangStunde=${aufgang:0:2} fi echo "Aufgang (hh:mm): ${AufgangStunde}:${AufgangMinute}" # Immer ein zweistelliges Ergebnis UntergangMinute=$(echo "(${untergang} - ${untergang:0:2}) * 60" | bc | xargs printf "%02.0f\n") if [ ${UntergangMinute} == "60" ]; then UntergangMinute="00" UntergangStunde=$(echo "${untergang:0:2} + 1" | bc | xargs printf "%02.0f") else UntergangStunde=${untergang:0:2} fi echo "Untergang (hh:mm): ${UntergangStunde}:${UntergangMinute}" # Immer ein zweistelliges Ergebnis