Google bietet viele seiner Services für normale Anwender kostenlos an. Eine beliebte Anwendung ist die Google Maps API, welche neben der Routenplanung auch den aktuellen Verkehr kennt. Wer aus mehreren Strecken zum Ziel wählen kann, wird sicher wissen, dass je nach Verkehrslage / Stau eine andere schneller ist.
In diesem Tutorial nutzen wir auf dem ESP8266 Google Maps API, um die voraussichtliche Streckenzeit abzufragen und auf einem LCD (Liquid Crystal Display) anzeigen lassen.
Zubehör
Für dieses Tutorial wirst du folgende Teile benötigen:
- ESP8266 (bspw. ESP-01 oder aber das NodeMCU Development Board)
- HD44780 Display (20×04 Zeichen)
- PCF8574 I2C Display Adapter
- I2C Logik Level Konverter
- Breadboard (optional)
- ggf. Lötutensilien
- Jumper Kabel (ebay)
Falls du dich entscheidest maximal zwei Strecken anzeigen zu lassen, würde auch ein kleineres Display (16×02 Zeichen) ausreichen.
Vorbereitung – Strecken auswählen
Um die Daten einer Strecke über die Google Maps API abfragen zu können, brauchen wir die Start-, End- und Zwischenpunkte. Diese können entweder als Text („Hauptstraße X, Stadt Y“) oder im Idealfall als Breiten- und Lägenkoordinate verfübar sein.
Die Korrdinaten bekommen wir ganz einfach über Google Maps, klicken per Rechtsklick auf einen Punkt und anschließend „Was ist hier?“. In meinem Beispiel wähle ich folgende:
- Start: Alexanderplatz, Berlin (52.520490, 13.413232)
- Ziel: Olympiastadion, Berlin (52.513226, 13.239923)
Nun könnte es verschiedene Routen geben, die (je nach Verkehrslage) unterschiedlich lange dauern. Daher erstellen wir zwei Beispielrouten, die über verschiedene Zwischenpunkte führen:
- Über die Siegessäule (52.515109, 13.350030).
- Über die Mollstraße (52.525538, 13.419398), dann am Leopoldplatz (52.546504, 13.359172) vorbei.
Zeigt man die entsprechenden Routen in Google Maps an, sehen diese folgendermaßen aus:
Natürlich kannst du auch noch weitere Routen erstellen, aber für dieses Beispiel sollen zwei genügen.
Das Ziel ist es nun per aktueller Abfrage die geschätzte Zeit (anhand der aktuellen Verkehrlage) zu bekommen, um dann die beste Route wählen zu können.
Google Maps API Key für ESP8266 bekommen
Um die Schnittstelle nutzen zu können, benötigen wir einen API Schlüssel. Diesen bekommen wir ganz einfach von Google selbst. Die Nutzung ist bis zu einem Kontigent von 2500 Abfragen am Tag kostenlos. Um den Google Maps API Schlüssel zu erhalten, führen wir folgende Schritte aus:
- Öffnen der Google API Console.
- Neues Projekt erstellen.
- „Google Maps JavaScript API“ auswählen und API Schlüssel kopieren.
Um den Schlüssel zu überprüfen können wir folgende URL im Browser aufrufen (DEIN_API_KEY
muss entsprechend durch den gerade kopieren Schlüssel ersetzt werden):
https://maps.googleapis.com/maps/api/directions/json?origin=Berlin&destination=Hamburg&key=DEIN_API_KEY
Du solltest auf der Seite nun JSON Code angezeigt bekommen. Die Ausgabe sollte hiermit (o.ä.) beginnen:
{ "geocoded_waypoints" : [ { "geocoder_status" : "OK", "place_id" : "ChIJAVkDPzdOqEcRcDteW0YgIQQ", "types" : [ "locality", "political" ] }, { ...
Falls dein API Key ungültig ist, würde eine solche Ausgabe erscheinen:
{ "error_message" : "The provided API key is invalid.", "routes" : [], "status" : "REQUEST_DENIED" }
In diesem Fall musst du deinen Schlüssel überprüfen oder ggf. einen neuen erstellen.
Auf der Dokumentationsseite findest du viele Optionen, die genutzt werden können. In diesem Tutorial nutzen wir vor allem auf die Streckenberechnung, aber auch andere Komponenten können genutzt werden.
Wer bereits einen Anwendungsfall sehen möchte, kann sich diese URL ansehen. Dabei muss wieder dein API Schlüssel eingesetzt werden. Ich habe hierbei die Streckeninformationen der zweiten Strecke anzeigen lassen:
https://maps.googleapis.com/maps/api/directions/json?origin=52.520490,13.413232&destination=52.513226,13.2399238&waypoints=52.525538,13.419398|52.546504,13.359172&key=DEIN_API_KEY
Im Gegensatz zum vorherigen Beispiel habe ich hier drei Parameter genutzt:
- origin: Längen- und Breitenkoordinaten (mit Komma getrennt aber ohne Leerzeichen)
- destination: Längen- und Breitenkoordinaten (mit Komma getrennt aber ohne Leerzeichen)
- waypoints: Koordinaten, da jedoch mehrere Zwischenpunkte angegeben wurden, werden diese mit einem senkrechten Strich („|“) voneinander getrennt.
Unter dem Punkt „routes“ -> „0“ -> „legs“ befinden sich mehrere Kindknoten (0,1,2). Jeder Knoten hat u.a. zwei Knoten („distance“ und „duration“), in denen die für uns interessanten Informationen vorhanden sind. Zusammenaddiert ergeben sich die Dauer und Länge der gesamten Strecke.
ESP8266 Vorbereitung
Um die folgenden Skripte auf dem ESP8266 nutzen zu können, erstellen wir uns eine Custom NodeMCU Firmware. Folgende Module müssen zusätzlich ausgewählt werden: Bit, HTTP, IC, SJSON.
Wähle außerdem den Punkt „TLS/SSL“ aus, da die Google Maps API nur über SSL erreichbar ist.
Nachdem die Firmware auf den ESP8266 übertragen wurde, können wir mit den weiteren Vorkehrungen fortfahren.
Schließe dein HD44780 LC Display mit aufgelötetem Controller gemäß diesem Tutorial an und teste es ggf. In der verlinkten Anleitung wird die Bibliothek zum Steuern des LC Displays erstellt. Dafür muss die Adresse zunächst ausgelesen werden. Ich gehe davon aus, dass diese Schritte bearbeitet wurden, bevor zum nächsten Schritt dieses Tutorials fortgefahren wird.
ESP8266 Google Maps Routenabfrage
Wir verbinden uns mittels ESPlorer mit dem NodeMCU und erstellen eine neue Datei („esp8266_google_maps_traffic.lua“) mit diesem Inhalt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
local lcd = require("i2clcdpcf") local json = require('sjson') local SSID = "XXXXXXXXXXXXXX" local SSID_PASSWORD = "XXXXXXXXXXXXXX" local API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" local ROUTES = { { name = "Stecke 1", origin = "52.520490,13.413232", destination = "52.513226,13.2399238", waypoints = { "52.515109,13.350030" } }, { name = "Stecke 2", origin = "52.520490,13.413232", destination = "52.513226,13.2399238", waypoints = { "52.525538,13.419398", "52.546504,13.359172" } } } local SIGNAL_MODE = wifi.PHYMODE_N INTERVAL = 60 -- seconds LCD_LENGTH = 20 function wait_for_wifi_conn ( ) tmr.alarm (1, 1000, 1, function ( ) if wifi.sta.getip ( ) == nil then print ("Waiting for Wifi connection") else tmr.stop (1) print ("ESP8266 mode is: " .. wifi.getmode ( )) print ("The module MAC address is: " .. wifi.ap.getmac ( )) print ("Config done, IP is " .. wifi.sta.getip ( )) end end) end function concat(str) local len = string.len(str) if len > LCD_LENGTH then return string.sub(str, LCD_LENGTH) else local p = string.rep(" ", LCD_LENGTH - len) return str .. p end end function main(key) route = ROUTES[key] local waypoints = "" for k,w in pairs(route["waypoints"]) do waypoints = waypoints .. w .. "|" end local url = "https://tutorials-raspberrypi.de/wp-content/uploads/scripts/maps.php?" .. "origin=" .. route["origin"] .. "&destination=" .. route["destination"] .. "&waypoints=" .. waypoints .. "&mode=driving&departure_time=now&key=" .. API_KEY http.get(url, nil, function(code, data) print(key) if (code >= 0) then local tab = json.decode(data) local text = "n.v." if tab["routes"][1]["duration"] ~= nil then local val = tonumber(tab["routes"][1]["duration"]) local mins = math.floor(val/60 + 0.5) local hours = (mins - (mins%60)) / 60 mins = mins%60 if hours > 0 then text = string.format("%dh %dmin", hours, mins) else text = string.format("%dmin", mins) end end route["text"] = concat( route["name"] .. ": " .. text ) if (key < table.getn(ROUTES)) then main(key+1) else lcd.begin(4,3) lcd.setBacklight(1) for k, r in pairs(ROUTES) do lcd.setCursor(0, k-1) lcd.print(r["text"]) end end end end) end -- Configure the ESP as a station (client) wifi.setmode(wifi.STATION) wifi.setphymode(SIGNAL_MODE) wifi.sta.config {ssid=SSID, pwd=SSID_PASSWORD} wifi.sta.autoconnect(1) -- Hang out until we get a wifi connection before the httpd server is started. wait_for_wifi_conn ( ) tmr.alarm(2, INTERVAL * 1000, tmr.ALARM_AUTO, function () main(1) end) |
Hier musst du dementsprechend deinen WLAN Namen, das Passwort, den Google Maps API Key und deine Routen eintragen. Sofern öfters als alle 60 Sekunden abgefragt werden soll, kannst du dies auch einstellen.
Leider hat der NodeMCU das Problem, dass er keine größeren Ausgaben verwerten kann (zu geringer Speicher), weshalb wir nur das nötigste gefiltert erkennen müssen. Dazu kannst du entweder auf deinem eigenen Webserver das PHP Skript laufen lassen, oder einfach meinen Service nehmen. Hierfür müssen nur die gleichen Parameter wie beim Google API Service angegeben werden:
https://tutorials-raspberrypi.de/wp-content/uploads/scripts/maps.php?....
Als letzten Schritt erstellen wir noch eine init.lua, in der wir das eigentliche Skript aufrufen, sodass dieses beim Booten des ESP8266 automatisch gestartet wird.
1 |
dofile("esp8266_google_maps_traffic.lua") |
6 Kommentare
Gutes Tutorial, nur leider funktioniert der Link zum Display-Tutorial nicht.
Tut mir leid, hier der aktualisierte Link: NodeMCU ESP8266: HD44780 LCD Display per I2C steuern
Ich hatte eigentlich gedacht, dass technisch Bewanderte wissen, dass es entweder „LC Display“ oder einfach nur „LCD“ heißt, aber NICHT „LCD-Display“.
Das ist doppelt doppelt gemoppelt. 😉
Stimmt schon, aber Leute, die sich nicht mit der Materie beschäftigen wissen häufig nicht wofür „LCD“ genau steht und suchen daher eher nach „LCD Displays“. Umgangsprachlich ähnlich mit „HIV Virus“. Man verzeihe mir den nicht ganz formellen Fachjargon 🙂
Da muss ich widersprechen: selbst auf den „Grabbeltischen“ in den Billigläden mit 5 oder weniger Buchstaben liegen schon seit Jahren immer häufiger Geräte mit „LC Display“. Und ich bin überzeugt davon, dass die durchschnittliche Intelligenz deren Kunden um Zehnerpotenzen geringer ist als die der Leser von Foren wie diesem, die sich mit der Materie beschäftigen.
Was die Suchfunktion angeht: wer einfach nur nach „LCD Display“ ohne Anführungszeichen in eine Suchmaschine eingibt, führt automatisch eine Suche nach „LCD ODER DISPLAY“ durch. Und ich glaube, die meisten Sucher tippen eh nur „LCD“ als Suchbegriff ein.
Daher würde ich als Autor eines Artikels in der Überschrift einfach nur „LCD“ benutzen, und im Artikel in der Einleitung einen kurzen Satz schreiben wie:
„Ein LCD (liquid crystal display), manchmal auch LC-Display genannt, kann…“
Damit sind die Suchmaschinen gefüttert, und jede(r) Suchende findet den Artikel.
Stimmt, da gebe ich dir Recht. Ich habe den Artikel mal angepasst 😉