Nach langer Pause habe ich nun endlich mal wieder ein wenig Zeit gefunden, mich mit der Optimierung meiner FHEM Konfiguration zu beschäftigen. Ich hoffe, dass ich nun auch die zahlreichen Kommentare bei meinen übrigen FHEM-Beiträgen beantworten bzw. entsprechende Lösungen hier in weiteren Artikeln zeitnah präsentieren kann.
Eines der größten Ärgernisse meiner aktuellen SmartHome-Lösung war der Umstand, dass die Google Maps Auswertung bezüglich der Fahrzeiten – insbesondere unter Einbeziehung der aktuellen Verkehrslage – schon lange nicht mehr funktionierte. Irgendwann hat Google den Aufbau der Webseite geändert, so dass ich keine sinnvolle Lösung mehr gefunden habe, die Infos mittels regulärer Ausdrücke zu extrahieren. Auch in dem entsprechenden FHEM Forums-Beitrag hatte keiner eine passende Lösung.
Nun habe ich mich entschieden, dass Problem mit der verfügbaren Google Maps API zu lösen, wodurch ich nun unabhängig von Änderungen auf der entsprechenden Webseite bin. Nachfolgend werde ich Schritt für Schritt beschreiben, wie man die entsprechende API kostenfrei nutzen kann und wie ich die Informationen in meine FTUI-Lösung von FHEM eingebunden habe.
API Key von Google beziehen
Voraussetzung für die Nutzung der Google Maps Funktion in Verbindung mit den aktuellen Verkehrsinformationen ist ein sogenannter API-Key. Diesen Schlüssel kann man sich in Google Developer Console, die in erster Linie für Entwickler gedacht ist, die die Google Produkte zum Beispiel in ihren eigenen Apps nutzen wollen.
Bei der Nutzung der Google API hat man in der Regel die Möglichkeit, eine begrenzte Anzahl von Aufrufen kostenfrei zu nutzen. Dieses Kontingent sollte für die Nutzung in einer privaten Smarthome-Umgebung völlig ausreichend sein. Damit nun auch die etwas weniger erfahrenen FHEM-User an einen solchen API-Key gelangen gibt es nun eine ausführliche und bebilderte Schritt für Schritt Anleitung. Dadurch wird der Artikel zwar extrem lang, hilft aber hoffentlich allen Lesern.
- Aufruf der Developer Console
Für den Aufruf der Developer Console benötigt man natürlich einen Google Account, den man sich zuvor erstellen muß, sofern man nicht bereits Nutzer von Gmail ist. Zur Console gelangt man dann über diesen Link. - Aufruf der Funktion „Google API verwenden“
- Google Maps Distance API aufrufen
In der Übersicht der APIs wählen wir nun die „Google Maps Distance API“ aus. - API aktivieren
Nun muß die API noch aktiviert werden und man kann sich über den Reiter „Kontingente“ seine kostenlosen Kontingente (Aufrufe) für die API ansehen. Hierbei wird man auch noch aufgefordert, ein Projekt anzulegen.
- „Zugangsdaten“ links im Menü auswählen
Im Bereich der Zugangsdaten klickt man auf „Anmeldedaten“ sowie auf „Anmeldedaten hinzufügen“. Hier wird dann ein Dialog angezeigt, wo man den benötigten Key auswählen kann. Wir brauchen einen Browser Key und wählen diesen aus.
Damit haben wir nun unseren benötigten API-Key und können diesen zum Beispiel direkt für die weitere Verwendung in FHEM kopieren.
Google Maps API mittels HTTPMOD Modul in FHEM integrieren
Zur Nutzung von Fahrzeiten innerhalb FHEM eignet sich das Modul HTTPMOD. Damit kann ein Aufruf einer Webseiten-URL integriert werden und mittels regulärer Ausdrücke ausgewertet werden. Auf die konkrete Beschreibung des Moduls gehe ich an dieser Stelle nicht ein.
HTTPMOD Definition
Die Definition für den Aufruf der von uns benötigten Google Maps Funktion sieht demnach wie folgt aus:
define FahrzeitKoelnBonn HTTPMOD https://maps.googleapis.com/maps/api/distancematrix/json?origins=KOELN,STRASSE+NR&destinations=BONN,STRASSE+NR&mode=driving&language=de-DE&departure_time=now&key=EIGENER_API_KEY 3600
Die Beschreibung zur API und der möglichen Parameter, die man nutzen kann, findet man hier bei Google. Wichtig ist, dass man neben dem API Key den Parameter „departure_time“ verwendet. Nur dann wird auch die Fahrzeit in Verbindung mit der aktuellen Verkehrslage ausgegeben. Bei der Verwendung der Funktion habe ich mich für die Ausgabe als json-Format entschieden. Es besteht auch die Möglichkeit einer xml-Ausgabe. Mit dem Wert 3600 am Ende wird die Fahrzeit im Abstand von einer Stunde aktualisiert.
Die Ausführung der Google Maps Funktion sollte in etwa folgendes Ergebnis zurück geben, welches dann anschließend innerhalb FHEM ausgewertet werden kann:
{ "destination_addresses" : [ "Bonn, Deutschland" ], "origin_addresses" : [ "Köln, Deutschland" ], "rows" : [ { "elements" : [ { "distance" : { "text" : "28,9 km", "value" : 28887 }, "duration" : { "text" : "36 Minuten", "value" : 2130 }, "duration_in_traffic" : { "text" : "35 Minuten", "value" : 2075 }, "status" : "OK" } ] } ], "status" : "OK" }
Auswertung der API Rückgabe
Für die Anzeige der Informationen zum Beispiel in einer FTUI Oberfläche legen wir nun noch entsprechende Readings in unserer HTTPMOD Definition an. Ich verwende zwei Readings – eines für die normale Zeit und eines für die „Verkehrs-Zeit“. Die Definitionen inklusive der regulären Ausdrücke zur Ermittlung der konkreten Zeiten sieht wie folgt aus:
attr FahrzeitKoelnBonn reading01Expr GoogleExpr($val) attr FahrzeitKoelnBonn reading01Name Standard attr FahrzeitKoelnBonn reading01Regex (?s)duration.* "(.* Minuten).*duration_in attr FahrzeitKoelnBonn reading02Expr GoogleExpr($val) attr FahrzeitKoelnBonn reading02Name Verkehr attr FahrzeitKoelnBonn reading02Regex (?s)duration_in.*"(.* Minuten) attr FahrzeitKoelnBonn stateFormat Normal:Standard Aktuell:Verkehr
Da die Ausgabe der Fahrzeiten von Google ein wenig ungünstig ist, wenn man nur die reine Angabe in Form von „hh:mm“ benötigt, habe ich noch eine kleine Funktion zur Formatierung der Zeiten geschrieben. Die Ausgabe von Google ist zum Beispiel „30 Minuten“ oder „1 Stunde 25 Minuten“. Der Aufruf der Funktion geschieht über die Readings-Definition „reading01Expr“ im obigen Beispiel. Die Funktion dazu sieht wie folgt aus:
sub GoogleExpr($) { my ($traffic) = @_; #zunächst die Minuten ermitteln $traffic =~ /([\d]+) Minuten?/; my $Std_Min = $1; my $Std_Std = "0"; #falls Stunden angegeben sind, diese nun ermitteln if($traffic =~ /([\d]+) Stunden?/) { $Std_Std = $1; } return sprintf("%02d:%02d",$Std_Std,$Std_Min); }
In der obigen Definition der Attribute ist auch noch eine „StateFormat“ zu finden. Damit kann man die konkrete Ausgabe für die genutzten Readings nochmals festlegen.
Darstellung der Fahrzeiten mittels FTUI Oberfläche
Die Darstellung der Fahrzeiten mittels der von mir genutzten FTUI Oberfläche konnte man in den Screenshots aus meinen letzten FHEM-Beiträgen schon sehen. Hier nun nochmals der entsprechende Auszug aus der index.html.
<li EIGENE DEFINTION> <header> <div data-type="label" class="large">Fahrzeiten</div> </header> <table class="calls" width="100%"> <tr class="darker"> <th>Ziel</th> <th>Normal</th> <th>Aktuell</th> </tr> <tr> <td> <div data-type="label" class="cell">Bonn:</div> </td> <td> <div data-type="label" data-device="FahrzeitKoelBonn" data-part="Normal:(.*).*Aktuell.*"></div> </td> <td> <div data-type="label" data-device="FahrzeitKoelnBonn" data-part=".*Aktuell:(.*).*"></div> </td> </tr> <tr>WEITERE FAHRZEITEN</tr> </table> </li>
Moin,
schöne Idee mit der Google Maps Distance API. Ich habe bei meinen Beispielen nur leider erkannt, das Google einem immer die schnellste Strecke zurückliefert. Wenn es also, mit Umwegen, eine durch den Verkehr schnellere Strecke gibt, bekommt man diese zurück. Eine Möglichkeit sich genau eine bestimmte Strecke zurückliefern zu lassen, habe ich nicht entdeckt. Hast du diese Erkenntnis auch schon gemacht? Oder stört dich das weiter nicht?
Ein Auswahl für bestimmte Strecken oder den Ausschluß von Strecken gibt es meines Wissens nicht. Vielleicht hilft der Parameter TRAFFIC_MODEL hier auch weiter. Mann kann diesen auf buest_guess (Standard). optimistic oder pessimistic einstellen.
Hallo Jürgen,
auf der Suche nach Anregungen für mein eigenes Smarthome Projekt bin ich über deine(n) Artikel gestolpert. Die Idee mit dem Abfallkalender finde ich klasse und habe sie auch schon bei mir im Projekt umgesetzt. Danke dafür. 🙂
Die Sache mit den Fahrzeiten klingt auch interessant – auch, wenn ich noch nicht weiß, ob ich das wirklich gebrauchen kann. Beim Lesen des Artikels ist mir jedoch aufgefallen, dass du bei Bild 6 zwar den API-Key maskiert hast, allerdings nur im offensichtlichen Teil der Grafik. Schau mal rechts unten am Bildrand. 😉
Viele Grüße und weiterhin viel Spaß mit der ganzen Technik
Oliver
Danke für den Hinweis! Habe ich direkt mal geändert und werde mir wohl nun besser noch einen neuen Schlüssel generieren 😉
Hallo Jürgen,
ich noch mal. 🙂 Wollte mich dann doch an der Verkehrsinfo versuchen – und hänge leider fest. Bei der HTTPMOD Definition ist mir ein kleiner Fehler aufgefallen. Dort hast du ein Semikolon drin, das da wohl nicht hingehört. Soweit konnte ich mir noch helfen.
Aber bei der Ausgabe der Fahrtzeiten scheitere ich derzeit leider noch kläglich. Ich bekomme die Werte 00:01 und 00:02 zurück geliefert. Mit Perl kenne ich mich nicht so gut aus, dass ich auf den ersten Blick den Fehler entdecke. Und wie ich in FHEM debuggen kann, weiß ich ehrlich gesagt auch grad nicht. Könntest du mich etwas in die richtige Richtung schubsen? 😉
Oliver
Danke erstmal, zu dem Hinweis des fehlerhaften Semikolons, welches ich nun aus der HTTPMOD Definition entfernt habe. Bei der weiteren Durchsicht ist mir noch aufgefallen, dass in der Funktion „GoogleExpr“ eine Code-Zeile hinter eine Kommentarzeile gerutscht ist. Das habe ich nun auch entsprechend angepasst. Vielleicht war das schon das Problem.
Wenn du auch meine Funktion der GoogleExpr nutzt, dann kannst du dort auf jeden Fall die Parameter und berechnete Zwischenwerte ins Logfile schreiben lassen. So mache ich es auch meistens. Ich nutze hierzu oft Aufrufe in der Form:
Log3 undef, 3, „Diese Variabe testen:“.$variable.“ evtl. weitere variablen „.$variable2;
Im Logfile sollten dann entsprechende Einträge zu finden sein, mit denen man in der Regel schon einen Schritt weiter kommt.
@Oliver: Der Fehler mit 00:01 und 00:02 liegt in folgender Zeile der Subroutine
my $traffic = @_
ersetze die durch
my ($traffic) = @_
und voila.
@Jürgen: Super Modul und tolle Ideen hast du 🙂
Vielen Dank für den Hinweis. Das kommt davon, wenn man den Code beim Übertragen in die Beschreibung nochmal anpasst. Zunächst hatte ich eine Routine mit zwei Parametern, von denen einer nicht mehr gebraucht wurde. Da habe ich dann wohl etwas zu viel weggelöscht. Bin auch nicht wirklich der Perl-Profi und meine praktischen Programmiererfahrungen liegen schon einen Weile zurück ;-).
Danke euch beiden. Hatte parallel auch noch im FHEM Forum gestöbert und dort auch einiges zu dem Thema gefunden. Inzwischen hab ich tatsächlich ne lauffähige Version und sehe die Daten auch in der Tablet UI Oberfläche. Werde später mal noch versuchen, die Entfernungsangaben zu parsen und unterzubringen. Macht auf jeden Fall sehr viel Spaß! 🙂
Hi,
als erstes mal ein großes Lob an die tollen Anleitungen, die im Vergleich zu vielen anderen, sofort funktionieren 🙂
Hast du eine Idee wie man einrichten könnte das er unter Tablet-UI die aktuell benötigte Zeit farblich kennzeichnet?
Normalzeit= 15 min
Aktuell= 15 min – grün
Aktuell= 18 min – orange
Aktuell= 22 min – rot
evtl. durch einen Bereich, sprich
15-17 min = grün
18-21 min = orange
22-x min = rot
oder mit % ?!
Grüße David
Hallo,
was ist denn der Unterschied zur dieser Lösung?
http://forum.fhem.de/index.php?topic=38463.0
Hallo David,
die farbliche Darstellung müsste mit den Label-Optionen „data-colors“ und „data-limits“ umsetzbar sein. Bei data-colors wird ein Array mit Farbcodes angegeben und bei data-limits die entsprechenden Werte. Habe ich noch nicht ausgetestet, kann ich aber bei Gelegenheit mal probieren.
Hallo Jürgen,
soviel ich sehe, kann man das Reading nicht numerisch auswerten. Ich würde mir gerne eine Email schicken, sobald ein bestimmter Schwellenwert überschritten wird. Hast Du da eine Idee?
VG
Christian
Ich habe es leider noch nicht testen können, wäre aber davon ausgegangen, dass mein Vorschlag grundsätzlich funktioniert.
Mails habe ich mit fhem noch nicht versendet, aber mit pushbullet kann man Nachrichten recht gut versenden. Bei mir landen solche Nachrichten dann sogar auf meiner Pebble Smartwatch.
Für die Ermittlung der Zeitdifferenz könnte ich mir (ungetestet) folgende Varianten vorstellen:
– mit einem notify welches auf Veränderungen der erzeugten Readings im HTTPMOD reagiert und dann die Differenz aus Standard- und Verkehrs-Zeit ermittelt
– falls das mit dem notify nicht funktioniert könnte man die GoogleExpr-Funktion so anpassen, dass beide Zeiten übergeben und dann in der Funktion die Differenz ermittelt wird. Hierbei bin ich mir aber nicht sicher, ob bei dem Aufruf der Funktion – der ja für jedes Attribut durchgeführt wird – der jeweils benötigte Wert schon vorhanden ist.
Ich habe das Thema auf meiner ToDo-Liste, da ich die Idee hatte, die Weckzeit in Abhängigkeit von der Verkehrslage anzupassen. Allerdings kann ich nicht versprechen, das zeitnah auszuprobieren.
Hallo Jürgen,
bei der Formatierung der Attribute ist was schief gelaufen: Die Attribute reading02Name und reading02Regex stehen in einer Zeile. Wenn sich das ein Anfänger zeilenweise per Cut&Paste in die Config holt, hat er ’ne Weile Spaß, bis er es findet 🙂
Ansonsten finde ich das eine ziemlich coole Idee, das API hätte ich im Leben nicht allein gefunden. Danke fürs zeigen.
Schönen Gruß
Kai
Danke für den Hinweis.
Hallo Leute irgendwie holt das Teil keine Daten und aktualisiert auch nichts. Bei Eingabe im Browser wird das erwartetet Ergebnis wie oben dargestellt zurückgegeben. Die Angabe des Aktualisierungsintervalls funktioniert jedoch nicht. Was mache ich denn da falsch?
Gruß Matthias
Ohne die Konfiguration deines HTTPMOD zu sehen, kann man schlecht sagen, wass du falsch machst. Was steht z.B. bei deinen Eigenschaften von „Triggertime_fmt“, „buf“, „code“. In „buf“ sollte die Rückgabe der Webseite zu finden sein. bei „code“ die Rückmeldung der Webseite: 200 heißt fehlerfrei ausgeführt. „Triggertime_fmt“ sollte die letzte Ausführung des Abrufs anzeigen.
Ach ja, welchen Wert hast du denn für das Aktualisierungsintervall angegeben?
Das war der richtige Tip, die Werte waren aktuell nicht belegt da augenscheinlich ein ungültiger Abruf erfolgte, das lag an den „+“ Zeichen die man auch dann verwenden muss, wenn im Straßennamen ein Leerzeichen enthalten ist. Also anstelle von Leerzeichen.
Ich hatte diesbezüglich deine Vorlage wohl falsch verstanden.
Nun funktioniert es einwandfrei.
Super Seite hier und du machst dir viele Mühe. Weiter so!!
DANKE!
Hi,
zu erst danke für deine super Anleitung. Ich habe es bis zu den Readings auch umgesetzt bekommen. Aus den Rückmeldungen des Moduls HTTPMOD kann ich auch erkennen, dass es soweit funktioniert. Allerdings kann ich die Attribute „reading01Expr GoogleExpr($val)“ usw. nicht setzen… entweder bin ich noch nicht so weit es zu verstehen oder es hat sich etwas mit der 5.7 verändert. Es gibt folgende Fehlermeldung:
Invalid Expression GoogleExpr($val)
Kann hier jemand helfen ?
Anmerkung zum Beitrag (Dator23 25. Januar 2016 at 14:17):
Fehler gefunden:
Variable musste erst die Sub in der Utilitys definiert werden.
Moin,
ich würde die aktuelle Fahrzeit in Tablet UI auch gerne einfärben, besteht die Möglichkeit die Readings anzupassen, dass nur Minuten angezeigt werden, so dass aus 00:45 einfach 45 als Reading wird.
Damit könnte ein Notify rechnen und die Labels einfärben.
Viele Grüße
Manuel
Hallo Manuel, man müsste wahrscheinlich nur die Funktion GoogleExpr entsprechend ändern. Nachfolgend ein Ansatz, allerdings ohne dass ich diesen auf Funktionsfähigkeit getestet habe.
Hallo Jürgen,
ich weiß nicht, ob es „schön“ ist, aber ich habe die Einfärbung bzw. die Möglichkeit mit der Fahrzeit zu rechnen über ein weiteres Reading gelöst.
reading03Name duration_in_traffic
reading03Regex „duration_in_traffic“\s*:\s*{\s*[„\w\s:,]+“value“\s*:\s*(\d+)\s*}
Dadurch wird nun die Fahrzeit in Sekunden angegeben und damit kann dann gerechnet werden.
Viele Grüße
Manuel
Hallo
Ich glaube ich bin etwas zu doof.
Ich habe alles so wie du es angibst in meine index.html eingefügt name natürlich angepasst.
So und jetzt zeigt er mir keine Zahlen an 🙁
Fahrzeiten
Ziel
Normal
Aktuell
REWE:
Anmerkung in der normalen ansicht bekomme ich ergebnisse zurück geliefert nur eben in der tablet ui nicht.
Ohne den Code in deiner INdex.html zu kennen, kann ich leider nicht erkennen, woran das Problem liegt. Wenn du Code hier als Kommentar hinterlassen möchtest, dann muss dieser mit [ code ] hier der Text [ /code ] eingeschlossen werden (In den eckigen Klammern ohne die Leerzeichen. Die habe ich nur verwendet, damit das Formatierungskürzel sichtbar ist).
@Michael: Ich habe ebenfalls das gleiche Problem.
Folgendes bekomme ich von Google zurück:
Die Attributes habe ich genau so übernommen wie im Post.
in der ftui habe ich folgendes stehen:
Funktioniert bei mir leider auch nicht..
Irgendwas mit den Attributes ist glaub ich nicht ganz korrekt bei mir.. Weiß aber auch nicht …
Muß ich mir nochmal genauer anschauen, ob ich im Text evtl. einen Fehler habe oder ob das Problem woanders liegt.
Moin, hab das selbe Problem wie Dator23, mir ist allerdings nicht ganz klar, wie ich die Variable in der Sub in der Utilitys definiert kann?! Kann mri jemand helfen?
Danek und VG
Chris
Das Problem ist wahrscheinlich auf die neue Version von HTTPMOD zurück zu führen. Dort wird der Ausruck „readingNNExpr“ nicht mehr unterstützt. Solange man die Definition mit der alten VErsion vorgenommen hat, scheint es noch zu funktionieren. Ich habe mir die notwendigen Anpassungen noch nicht genauer angesehen, werde meine Definition aber demnächst mal umstellen, damit ich die notwendigen Änderungen im Text ergänzen kann.
Versucht bitte mal statt reading01Expr den Ausdruck reading01OExpr zu verwenden – also einfach ein „O“ bei allen Expr-Ausdrücken einbauen. Wahrscheinlich sollte es damit schon funktionieren.
Moin, danke, aber das klappt auch nicht. tatsächlich habe ich nur ein Problem mit der Variable GoogleExpr($val) – die kennt er wohl nicht. gibt immer zurück:
Invalid Expression GoogleExpr($val)
muss ich da in der 99_myutils was ändern?
Danke und LG
Chris
Hi Chris. Hast du eine Lösung? Habe das gleiche Problem… Grüße
Habe auch das Problem wie Chris und Kruse, auch wenn Dator23 ja schon eine Lösung hatte: „Variable musste erst die Sub in der Utilitys definiert werden.“
Was immer das grammatikalisch und technisch bedeuten mag. Ich wundere mich immer, wenn hier Leute schreiben, dass bei ihnen ein Skript funktioniert, wenn es bei vielen anderen aber nicht so ist. Und noch besser, wenn Lösungen gepostet werden, die keiner versteht. Bei einem Forum oder Blog wäre es doch praktisch, Erklärungen nachvollziehbar zu beschreiben. Dann hätten alle was davon.