Moinsen..
ich bin schon seit längerem interessiert an einem Lichtwecker, der durch den RPi realisiert wird.
Für alle die noch nicht wissen, was ein Lichtwecker ist:
Ein Licht, dass ca. 30 Minuten vor dem eigentlichen Zeitpunkt, zu dem man aufstehen will, einen Sonnenaufgang im Raum simuliert. Es ist mehrfach nachgewiesen, dass dies ein entspanteres aufwachen sehr begünstigt. Daher gibts dazu auch massig fertige Geräte zu kaufen. Teils ganz schön teuer. Der hohe Preis basiert häufig auf den vielen zusätzlichen Features, wie z.b. zusätzlich mp3 abspielen, Grafikdisplay etc.. etc.. Mit einem RPi wären hier kaum Grenzen für Features gesetzt.
Interessant fand ich immer die Idee, an meinem jetzigen verhalten nichts zu verändern und sowas dennoch zu nutzen. Sprich:
Ich möchte meinen jetzigen Wecker auf meinem Android Smartphone "anzapfen".
Ich habe keinen Plan von Android App Coding. Meine Kenntnisse beschränken sich auf ein paar Shellscript-Schnippsel, etwas php und google
Daher war die Idee:
Automatisiert die Weckzeit auslesen, und auf dem RPi abspeichern.
Seit kurzem bin ich damit einen Schritt weiter und kann die gesetzte Alarmzeit auswerten.
Leider kann mein Android Device kein NFC womit man die Idee ansich einfacher / effektiver umsetzen könnte.
In meinem Fall ist das WLAN am Android Device durchgehend aktiviert.. womit dies erst ermöglicht werden konnte.. Ebenso hängt mein RPi durchgehend im Heimischen Netz. Beides zusammen ergibt eine lückenlose Kommunikation, sobald ich zuhause bin.
Ein Szenario mit einer Adhoc-Verbindung zwischen Android und dem RPi um unabhängig von anderen Netzen sein zu können, wird sicherlich technisch ohne weiteres Möglich sein, ist hier aber kein Thema.
App Development erlernen ist mir für dieses Projekt eine Hausnummer zu viel.. das gibt meine Zeit einfach nicht her..
########
# Android #
########
Ziele:
- Simple Lösung ohne großen Aufwand
- Möglichst mit Boardmitteln arbeiten können damit Szenario von vielen nachspielbar ist
Mit etwas google und etwas frickeln konnte ich das ganze für das Android-Device auf ein Minimum reduzieren:
Es wird auf einem gerooteten Android die APP cron4phone und eine einzige Codezeile benötigt. Die App führt die Codezeile im eingestellten Intervall aus. Das war alles, was man auf dem Android Device erledigen muss.
Hier die Codezeile:
r=$(eval sqlite3 -column /data/data/com.android.providers.settings/databases/settings.db \'select value from system where name = \"next_alarm_formatted\"\') ; wget "0.0.0.0/test.php?p=passwqrd&t=$r"
zur Erklärung:
Das Programm "sqlite3" liest eine bestimmte Datenbank aus, in der der gesuchte Wert (die nächste Alarmzeit) steht. Anschließend wird dieser Wert in eine Variable "r" gepackt. Danach wird das Programm "wget" genutzt um einen Link zu einer Website zu öffnen und hier gleich ein paar Parameter mitzugeben.
0.0.0.0 ist hierbei der Webserver (musst du anpassen auf die IP deines Webservers/RPi)
test.php die passende php Datei an die die Parameter übergeben werden sollen
Parameter p = ein selbst gewähltes passwort
Parameter t = wird mit der Variable "r" verknüpft. Das heißt, der Inhalt der Variable (und damit die nächste Alarmzeit) wird hier eingesetzt.
Damit ist die Arbeit auf dem Android-Device komplett erledigt.
gehen wir also nun zum RPi um die Daten dort entgegen zu nehmen.. auszuwerten.. und dann entsprechend zu handeln.
#####
# RPi #
#####
Auf dem RPi rennt ein Webserver (ich nutze z.B. nginx), der die oben erwähnte Datei test.php bereitstellt. Dieses PHP-Script nimmt diese Werte (passwort und Alarmzeit) entgegen und wandelt die Alarmzeit in Unixzeit um.
Ich habe mich für die Unixzeit entschieden, weil man mit ihr als einfache Zahl viel einfacher weiterarbeiten kann. Danach schreibt das PHP-Script jeweils in eine neue Zeile für die weitere Verarbeitung in eine Text-Datei namens test.txt folgendes:
- die Weckzeit als Unixzeit
- dass Passwort
- die akutelle Zeit (ebenfalls als Unixzeit)
Sollte keine Alarmzeit am Android Device existieren konnte auch keine Alarmzeit an das PHP-Script weitergegeben werden. Das PHP-Script stellt dies fest und schreibt stattdessen eine definierte "Fake-Zeit" (z.B. 999999999 was für 09.09.2001 - 03:46:39 steht) in die test.txt und macht dennoch ein Update in Zeile drei.
damit wäre die test.php komplett fertig mit ihren Aufgaben.
Info zu den Werten die in die test.txt geschrieben werden:
Diese "Fake-Zeit" dient dazu einen klaren definierten Zustand zu haben, den wir entsprechend auswerten können. Denn ein einfaches "keine Zeit angekommen" könnte auch bedeuten, dass das Handy garnicht im WLAN ist, weil ich z.B. gerade woanders übernachte.
Und genau aus diesem Grund schreiben wir auch in die letzte Zeile die aktuelle Uhrzeit für den Zeitpunkt als das Android Device diese Daten übermittelt hat.
Wenn wir beim Auslesen diese Zeit mit dem Zeitpunkt vergleichen, wärend wir auslesen, können wir so genau feststellen, wie lange es her ist, als das Android Device das letzte mal ein Update geschickt hat. Da das Android Device dies alle 5 Minuten tun soll, würden wir hiermit einen klar definierten Wert erhalten, ob das Android Device aus/defekt/nicht anwesend ist. wir gehen einfach mal davon aus, dass das Android Device / und oder das Netzwerk nicht über Nacht kaputt gehen =)
Für den Fall, dass das Android Device runtergefahren wurde, können wir mit der oben genannten APP und einer weiteren Codezeile dies dem RPi mitteilen (to be done!)
Bleibt also bei dem Zustand, dass das letzte Update länger als 5 Minuten her ist, nur die Möglichkeit übrig, dass das Android-Device nichtmehr anwesend ist.. und kein Alarm mehr benötigt wird.
Somit können wir unterscheiden zwischen:
- Alarm ist gesetzt
- Kein Alarm ist gesetzt
- Android Device ist runtergefahren (to be done!)
- Android Device ist nicht in der nähe
####
nun haben wir die Werte die wir benötigen in einer dreizeiligen Textdatei gespeichert und diese wollen ausgewertet werden.
Sinnvoll ist es, dies automatisch geschehen zu lassen. Und zwar in einem Intervall, welches größer ist, als das vorherige. Wenn wir 15 oder 20 Minuten nehmen, haben wir garantiert, dass mehrere durchgänge zum abspeichern der Werte in die test.txt schon geschehen sind.
Als erstes prüfen wir, ob unsere Fakezeit gesetzt ist. Wenn ja, wird kein Alarm gesetzt und wir sind fertig bis zum nächsten Durchgang.
Wenn nicht die Fakezeit gesetzt wurde, muss dort eine reale Alarmzeit stehen.
Als nächstes prüfen wir, ob die Zeit in Zeile drei länger als z.B. 15 Minuten zurückliegt. Damit stellen wir fest, ob schon mehrere Intervalle kein Update vom Android-Device angekommen ist und können auch hier an dieser Stelle aussteigen und einen eventuellen Alarm deaktivieren, denn dies bedeutet ja, wir sind nicht im Heimnetz und damit nicht anwesend.
Gab es doch Intervalle, wird die Zeit aus Zeile 1 genommen und von ihr z.B. 30 Minuten (der Zeitraum wie lange der Lichtwecker den Sonnenaufgang vorher starten soll) abgezogen. Damit haben wir die Startzeit für unseren Lichtwecker ermittelt.
Da wir diese Startzeit nicht irgendwo abspeichern und ihrem Schicksal überlassen können, müssen wir bei jedem Aufruf dieses PHP-Scriptes eine erneute Prüfung auf alle Begebenheiten starten. Denn ansonsten geht uns vieleicht die Information verloren, dass der Alarm nachträglich deaktiviert oder die Alarmzeit verändert wurde.
Meine Lösung dafür geht von hinten durchs Auge. Anstatt die genaue Startzeit auch zum starten zu nutzen, wird überprüft ob die Zeit zwischen der Startzeit und der aktuellen Zeit kleiner oder größer ist, als das Intervall der Überprüfung selbst. Wenn nicht, passiert nichts weiter. Sollte die Zahl kleiner sein, stehen wir im letzten Intervall vor der eigentlichen Startzeit und können den Licktwecker starten.
Ich würde behaupten, bei einem Lichtwecker kommt es nicht auf wenige Minuten an. Und wir können so Extra-Code um z.B. einen Cronjob zu schreiben und diesen gegebenfalls wieder zu löschen, etc.. vermeiden.
Durch weitere simple Mathematik ist es auch möglich, den Lichtwecker nach einer selbst festgelegten Zeit automatisch zu deaktivieren (z.b. 20 minuten nach der eigentlichen Weckzeit (also in dem Rechenbeispiel 50 Minuten nach der Startzeit)).
Den entsprechenden Code habe ich unten unter "test2.php" stehen.. er ist nicht ausgereift.. und sicherlich zu verbessern.. es ist nur eine Momentaufnahme.. ich Bastel da noch weiter..
Jetzt bleibt nur die Frage, ob mein Ansatz/meine Idee am Ende überhaupt praktikabel ist.
Das ganze habe ich bisher nur auf meinem Motorola Moto G mit Cyanogenmod testen können.
Vieleicht hat ja wer Zeit und Lust das ganze mit seinem gerooteten Android Device zu verifizieren?
todo:
(Stand 2014.11.15_01:40)
- Abfrage Passwort
- Codezeile bei Ausschalten des Android Device (+ Verarbeitung nach Auswertung)
- Schaltung für Sonnenaufgang (z.B. RGB-LED Strip oder TIP142 + 12V halogen)
- LED zu Anzeige ob "scharf geschaltet" und/oder Taster zur Aktivierung eines Displays
- mp3 Ausgabe wärend Sonnenaufgang (z.B. leichtes Meeresrauschen oder entferntes Vogelgezwitscher, etc..)
- Eventuell Display zur Anzeige von Daten wie z.B. Wetterprognose, Uhrzeit, whatever (dafü liegt hier noch ein Pearl DPF)
- Lösung finden was passieren soll bei snooze (wie erkennen, dass snooze?)
#### Update: 2014_11_12 23:20 Uhr
test.php
<?php
// version: 0.6
//set filename
$filename = 'test.txt';
//###reformat time to unix timestamp format
//table for reformating german shortcuts of weekdays to english shortcuts accepted by strtotime()
$trans=array("Mo." => "Mon.", "Di." => "Tue", "Mi." => "Wed", "Do." => "Thu", "Fr." => "Fri", "Sa." => "Sat", "So." => "Sun");
//get time
$time=substr(htmlspecialchars($_GET["t"]), -5);
//get day and reformat
$newday=strtr(substr(htmlspecialchars($_GET["t"]), 0, 3), $trans);
//convert to unix timestamp format
if (empty($time)) {
$waketime=999999999;
}else{
$waketime=strtotime("$newday $time");
}
//set content to be stored (waketime, password, current time)
$content = $waketime."\n".htmlspecialchars($_GET["p"])."\n".date("U")."\n";
//open file
if (!$handle = fopen($filename, "w")) {
print "can´t open $filename";
exit;
}
//write to file
if (!fwrite($handle, $content)) {
print "can´t write to $filename";
exit;
}
fclose($handle);
?>
Alles anzeigen
test2.php
<?php
// Version: 0.3
$sunrisetime=1800; // how many seconds before alarmtime should sunrise start
$lines = file('test.txt'); // read file and put each line into array
$calc=date("U") - $lines[2]; //calculate current time minus time, when last time the file was written -> aka how long ago was file set
if ( $lines[0] == 999999999 ){
echo "no alarm is set" ;
if ( $calc > 1200 ) {
echo " and you are not at home";
}
exit;
}
echo "last write is ".$calc." seconds ago\n";
$alarmset=$lines[0] + 1; //add one second to workaround integer/bolean problem or something like this..
$sunrisestart=$lines[0] - $sunrisetime; // calculate time to beginn sunrise
$lasting=$sunrisestart - date("U"); //how many seconds from now till start of sunrise
if ( $calc > 1200 ){
echo "i´ll delete Alarm, you are not at home\n";
} else {
echo "Alarm is set to ".date('D F j, Y, G:i', $alarmset)."\n";
echo "Sunrise starts ".date('D F j, Y, G:i', $sunrisestart)." this is in ".gmdate("H:i:s", $lasting)."\n";
}
echo $lasting;
if ( $lasting < 350 AND $lasting > 0 ){
shell_exec("sudo /usr/share/nginx/www/send 11101 3 1"); // Needs "www-data ALL=NOPASSWD: /usr/share/nginx/www/send" in /etc/sudoers to work!
}
if ( $lasting < 0 ){
shell_exec("sudo /usr/share/nginx/www/send 11101 3 0");
}
?>
Alles anzeigen