Im Internet of Things / Internet der Dinge ist das Datensammeln eines der Hauptbestandteile zur Analyse. Ein Problem, dass der Raspberry Pi hat ist, dass er selbst in seiner günstigsten Wifi-fähigen Form (Raspberry Pi Zero) durch seinen Preis nicht für das massenhafte Auslesen an Daten geeignet ist. Der ESP8266 NodeMCU hingegen sehr wohl! Dieser kostet nur wenige Euro und kann selbst mit einem kleinen Akku über Monate hinweg mit Strom versorgt werden.
In diesem Tutorial wollen wir zwischen Raspberry Pi und dem ESP8266 NodeMCU Daten senden – und zwar in beide Richtungen. Damit wollen wir den günstigen ESP8266 als „Außenstation“ für unsere Projekte verwenden, wobei der Raspberry Pi als Herzstück agiert und alle Daten sammelt bzw. speichert.
Zubehör
Um dieses Tutorial nachbauen zu können, benötigst du folgendes:
- Raspberry Pi
- mind. 1x ESP8266 NodeMCU
Der ESP Mikrocontroller wird per Lua programmiert, welches im Grunde eine sehr einfache Sprache ist.
Darüber hinaus nutzen wir folgendes, um die Verbindung „sichtbar“ zu machen:
Bei Interesse gehe ich in weiteren Tutorials auf die Nutzung anderer Sensoren (DHT11 / DHT22 bspw.) mit dem ESP8266 ein. In diesem Tutorial steht die Verbindung im Vordergrund und daher ist der Aufbau bzw. die Nutzung eines Buttons relativ simpel.
Hast du vorher noch nicht mit einem ESP8266 gearbeitet, solltest du dir dieses Tutorial zunächst ansehen: Einführung & Programmierung des ESP8266 NodeMCU Boards
Vorbereitung: Node.JS Server
Damit der Raspberry Pi Daten per WLAN empfangen kann, brauchen wir einen Webserver. Hierfür kann z.B. Apache2 dienen, allerdings nutzen wir in diesem Tutorial Node.JS, da dies eine Reihe einfach zu nutzender Erweiterungen hat, welche u.a. auch die GPIOs steuern können.
Wichtig: Falls du noch keinen Node.js Server auf deinem Raspberry Pi installiert hast, so starte mit dem ersten Abschnitt von diesem Tutorial (Link).
Sofern du die übertragenen Daten z.B. per MySQL speichern möchtest, so kannst du das NPM Package „node-mysql“ nutzen. Dafür ist eine bereits bestehende Installation von MySQL auf dem Raspberry Pi nötig. Wie dies am einfachsten funktioniert, ist hier gezeigt.
In weiteren Tutorials wird die Thematik noch genauer besprochen.
Aufbau am ESP8266 NodeMCU
Bevor wir die Software aufspielen, nehmen wir das Breadboard zur Hand und erstellen den Testaufbau. Dabei wollen wir sowohl auf Eingaben reagieren (Taster) als auch auf übermittelte Werte vom Raspberry Pi (LED leuchten lassen).
Der Taster wird an GND sowie die andere Seite an GPIO5 / D2 angeschlossen.
Statt einen Button könntest du auch ein Magnetrelais o.ä. nutzen, wie wir es hier bereits für den Raspberry Pi besprochen haben. Die Funktionsweise ist die gleiche.
Vom Raspberry Pi Daten an den ESP8266 senden
Um Befehle an den ESP8266 zu senden, nutzen wir diesen als Server, an den wir HTTP Anfragen senden. Dabei wird die interne IP Adresse des Heimnetzwerks genutzt (192.18.x.x). Diese HTTP Anfragen können entweder direkt per Terminal (curl), per Python (urllib) oder noch einfacher durch Aufruf per Browser gesendet werden.
Im ersten Schritt richten wir also den ESP8266 Server ein, welcher die LED schaltet. Öffne dazu das Programm, mit dem du den Lua Code überträgst (ich nutze den ESPlorer, wie hier erklärt). Folgender Code muss übertragen werden:
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 |
-- Your Wifi connection data local SSID = "xxxxxxxxxx" local SSID_PASSWORD = "xxxxxxxxxxx" local LED_PIN = 3 -- GPIO0 local function connect (conn, data) local data conn:on ("receive", function (cn, req_data) data = get_http_req (req_data) -- print data for k, v in pairs( data ) do if k ~= "GET" then print(k, "=",v) else print(k, ":") for j, w in pairs( v ) do print(" ", j, " = ", w) end end end -- check if LED parameter contained if data["GET"]["led"] ~= nil then if data["GET"]["led"] == "on" or data["GET"]["led"] == "1" then -- turn LED on gpio.write(LED_PIN, gpio.HIGH) cn:send ("LED was turned ON") elseif data["GET"]["led"] == "off" or data["GET"]["led"] == "0" then -- turn LED off gpio.write(LED_PIN, gpio.LOW) cn:send ("LED was turned OFF") else cn:send ("Invalid Input") end else cn:send ("Invalid Input") end -- Close the connection for the request cn:on("sent",function(cn) cn:close() end) end) end 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 get_http_req(request) local t = {} local buf = ""; local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP"); if(method == nil)then _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP"); end local _GET = {} if (vars ~= nil)then for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do _GET[k] = v end end t["METHOD"] = method t["PATH"] = path t["GET"] = _GET return t end -- setup GPIO gpio.mode(LED_PIN, gpio.OUTPUT) -- Configure the ESP as a station (client) wifi.setmode (wifi.STATION) wifi.sta.config (SSID, SSID_PASSWORD) wifi.sta.autoconnect (1) -- Hang out until we get a wifi connection before the httpd server is started. wait_for_wifi_conn ( ) -- Create the httpd server svr = net.createServer (net.TCP, 30) -- Server listening on port 80, call connect function if a request is received svr:listen (80, connect) |
Den Namen deines WLANs und das Passwort musst du natürlich anpassen. Falls du möchtest, dass der Code auch direkt nach Neustart ausgeführt wird, erstelle eine Datei mit dem Namen „init.lua“ mit folgendem Inhalt und übertrage diese Datei ebenfalls auf den ESP8266:
1 |
dofile("receive_esp8266.lua") |
Nun kannst du eine der oberen Möglichkeiten ausprobieren. Solange der ESP noch seriell verbunden ist, wirst du die IP Adresse ablesen können (bspw. bei mir: „Config done, IP is 192.168.1.53„). Öffne nun deinen Browser und hänge an die IP Adresse den Zusatz /?led=on an.
Ebenso kannst du mit off die LED wieder ausschalten. Möglich wäre hier noch eine Passwortabfrage über einen Parameter, damit nicht jeder die Aktion auslösen kann.
Um vom Raspberry Pi diese Abfrage abzusenden, kannst du curl benutzen. Gib dazu folgendes im Terminal ein:
curl 192.168.1.53/?led=off
Übrigens: Falls du per Node.JS auch HTTP-Requests senden möchtest, geht dies mit der http-Bibliothek.
Vom ESP8266 NodeMCU Daten an den Raspberry Pi senden
Starten wir mit dem Raspberry Pi. Zunächst finden wir die interne / lokale IP Adresse heraus:
ifconfig -a
Das zeigt u.a. so etwas an:
... wlan0 Link encap:Ethernet HWaddr b8:27:eb:6f:37:fd inet addr:192.168.1.80 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::5c5d:4000:b4d5:bb75/64 Scope:Link ...
In meinem Fall ist die IP Adresse des Raspberry Pi’s 192.168.1.80, welche gleich für das ESP8266 Lua Skript benötigt wird.
In dem kommenden Skript nutze ich Express und einen JSON Body Parser. Falls diese Pakete noch nicht installiert sind, geht dies einfach mit:
npm install express body-parser
Nun erstellen wir das Node.js Skript:
sudo nano rpi_esp826_server.js
Dieses bekommt folgenden Inhalt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
var express = require('express'); var app = express(); var bodyParser = require('body-parser'); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.post('/esp8266_trigger', function(req, res){ if (req.body.hasOwnProperty("ip") && req.body.ip != "") { console.log(req.body.ip + " was triggered"); res.json({"success": true}); } else { res.json({"error": "IP has to be sent"}); } }); app.listen(8000); |
Speichere (STRG+O) und kehre zurück zum Terminal (STRG+X). Hier startest du nun den Server per Node:
node rpi_esp826_server.js
ESP8266 Skript
Um nun vom ESP8266 auch HTTP Request an den Raspberry Pi senden zu können, brauchen wir dessen http-Library. Diese ist nicht auf der Standard-Firmware enthalten und muss durch eine Custom-Firmware aufgespielt werden. Gehe dazu auf diese Seite und wähle die entsprechenden Module, die enthalten sein sollen.
Nach Angabe deiner Email bekommst du innerhalb von wenigen Minuten den Downloadlink (Spam Ordner prüfen). Das Aufspielen der Firmware haben wir bereits im vorherigen Tutorial besprochen.
Nun spielen wir folgendes Skript wieder per ESPFlasher auf den NodeMCU:
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 |
local SSID = "xxxxxxxxxxxxxxx" local SSID_PASSWORD = "xxxxxxxxxxxxxxx" local BUTTON_PIN = 1 -- GPIO5 local RASPBERRY_PI_URL = "http://192.168.1.80:8000/esp8266_trigger" 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 transmit_msg() end -- Configure the ESP as a station (client) wifi.setmode (wifi.STATION) wifi.sta.config (SSID, SSID_PASSWORD) wifi.sta.autoconnect (1) -- Hang out until we get a wifi connection before the httpd server is started. wait_for_wifi_conn ( ) do gpio.mode(BUTTON_PIN, gpio.INT, gpio.PULLUP) local function pin1cb(level, pulse) if level == 0 then -- send http request to Raspberry Pi local post_data = '{"ip": "'..wifi.sta.getip()..'"}' http.post(RASPBERRY_PI_URL, 'Content-Type: application/json\r\n', post_data, function(code, data) if (code < 0) then print("HTTP request failed") else print(code, data) end end) -- sleep 1 sec --node.dsleep(1 * 1000000) end end gpio.trig(BUTTON_PIN, "both", pin1cb) end |
Im oberen Teil des Skripts musst du wieder die Daten deines WLANs anpassen sowie die URL des Raspberry Pi’s. In meinem Fall ist dies also http://192.168.1.80:8000/esp8266_trigger
(Port und Route wurden im Raspberry Pi Node.JS Skript definiert).
Nachdem du es übertragen hast, kannst du den Taster drücken und auf den Log in der Raspberry Pi Konsole achten. Hier siehst du, sobald Daten eingingen.
Wie du siehst ist es nicht sehr schwer Daten auszutauschen. Wir können somit eine bidirektionale Verbindung aufbauen und z.B. bestimmte Sensoren oder Module auslesen und diese Daten übertragen.
Als nächstes ist geplant, dass wir mehrere ESP8266 mit Sensoren (DHT11 o.ä.) ausstatten und die Werte immer wieder an den Raspberry Pi senden, welcher diese in einer lokalen SQL Datenbank sammelt.
31 Kommentare
Sehr geil!
Habe schon mit meinem Pi Dank Deiner Anleitungen die komplette Steuerung meines Terrariums realisiert siehe https://goo.gl/iKyFQG . Licht an/aus, UV-Lampe an/aus, Heizung an/aus, Befeuchter an/aus alles per Funksteckdose und abhängig von Werten die mit dem DHT22 gemessen werden. Sehr geil wäre wenn ich den Pi nicht direkt in die Nähe des Terra stellen müsste und das ganze per WLan machen könnte. Freue mich schon auf das Tutorial mit Sensoren. Darf ich mir gleich danach ein Tut für die Funkdosen wünschen?
Viele Grüße
Ben
Hey Ben,
ein Tutorial mit dem ESP8266 und Funksteckdosen steht schon auf der ToDo Liste und kommt mit Sicherheit 🙂
Hi Ben,
ich bin z.Z. an einer sehr ähnlichen Steuerung, allerdings für ein Gewächshaus. Dein Interface beinhaltet aber bereits Komponenten die ich 1:1 wiederverwenden könnte.
Wärst du bereit mir den aktuellen Code deines Projekts zur Verfügung zu stellen?
LG
Dave
Super Anleitung! Das macht diese Plattform so wertvoll. Danke!
Hallo Felix,
super Anleitung! Ich habe bei mir das Problem, das die Taster mehrere Events auslösen beim Drücken. Entprellen via Hardware habe ich jetzt schon versucht, allerdings ohne Erfolg. Bei Magnetschaltern (Tür) wird das wahrscheinlich noch mehr sein. Hast Du dafür evtl. eine Lösung?
PS: Der Taster wird an GND sowie die andere Seite an GPIO5 / D2 angeschlossen. <- GPIO5 ist bei mir D1 😛
Du könntest einen „Cooldown“ (sleep) setzen, sobald eine Event ausgelöst wurde (bspw. 500ms warten, bevor das nächste erkannt wird). Oder bspw. nur auf Flanken (Pull up/down) reagieren.
Hallo Felix,
vielen Dank für deine tollen Tutorials.
Habe mir sofort den ESP8266 samt Board bestellt.
Die Idee ist unser Gewächshaus zu überwachen und bei Frostgefahr zu heizen.
Erhard
Vielleicht kannst du ja einige Ideen hiervon übernehmen 🙂
Éin „Guten Morgen“ in die Runde,
bin ganz neu hier und habe bisher nur wenig Erfahrung mit dem Raspi. Für ein aktuelles Projekt möchte ca. 1.900 verschiedene Relais-Ausgänge ansteuern können – nach Möglichkeit mit nur einem Pi. Ich finde aber aber biosher nicht den passenden GPIO-Expander. Ich bräuchte z.B. einen 16bit-Expander, aber dann für 255 Teilnehmer an einem Bus. Das was ich bisher gefunden hatte, ist immer nur mit 3 Bits addressierbar – also 8 Teilnehmer am Bus – hat jemand von Euch eine gute Idee, wie ich das lösen könnte? Eventuell wäre ja die Idee aus dem heutigen Tutorial adaptierbar?
LG
Alexander Koch
Hallo,
Das hört sich groß an.
Tipp: Codesys auf den rpi (50€).
Ethercat Feldbus. SPS (iec) programmieren.
Aber: teuer…
Hallo Felix,
auch von mir herzlichen Dank für Deine Projekte.
Zu dem aktuellen habe ich folgende Frage:
Was bedeutet der Zusatz „esp8266_trigger“ in der Zeile:
local RASPBERRY_PI_URL = „http://192.168.1.80:8000/esp8266_trigger“
MfG
Juergen B.
Das ist einfach eine URL, die ich gesetzt habe. Du kannst hier auch deinen Namen o.ä. verwenden.
Da ich bei einem Jugend forscht Wettbewerb auch den Raspberry Pi mittels Wifi steuern habe ich eine Frage:
Ich möchte den Besuchern auf diesem Wettbewerb die Möglichkeit geben mittels dem Raspberry Pi selber Dinge zu steuern. Deswegen frage ich mich nun ob es mit dem Raspberry Pi möglich ist, dass sich schnell hintereinander verschiedene vorher nicht näher bekannte Endgeräte verbinden?
Ich würde mich sehr über eine Antwort freuen:D
Ein Webserver würde sich anbieten, über den sich die Geräte verbinden (verschiedene Websessions bspw.).
Guten Tag,
Zitat: „Als nächstes ist geplant, dass wir mehrere ESP8266 mit Sensoren (DHT11 o.ä.) ausstatten und die Werte immer wieder an den Raspberry Pi senden, welcher diese in einer lokalen SQL Datenbank sammelt.“
Wurde das bereits realisiert oder kommt es noch?
Vielen Dank!
WG
ESP8266 Wetterstation Außenposten für den Raspberry Pi
Hallo Felix,
super Tutorial welches ich in den nächsten Tagen bestimmt nachbauen werde jedoch habe ich noch eine Frage dazu.
Ich möchte gerne meinen Reed-Schalter Status vom ESP8266 an den Raspberry Pi 3 senden der wiederum eine LED schalten soll, wie müsste das Raspberry Skript dazu aussehen um die eingegangenen Daten zu verarbeiten?
Des Weiteren möchte ich gerne mehrere ESP-Module einsetzen und die Daten an den RPi senden…. Endergebnis soll wie in diesem Link:
https://www.computerhilfen.de/info/smart-home-display-zum-selberbauen.html
Ich würde mich freuen wenn Du mir die weitere Verarbeitung der empfangenen Daten erklären könntest, aktuell würde ich aus deinem Tutorial raus erkennen das im Log ein Status angezeigt wird oder?
Gruß Katsche
Demnächst kommt ein Tutorial bzgl MQTT mit Pi+ESP, das die Kommunikation noch weiter vereinfacht.
Hallo Felix,
ich würde gerne mehrere Node-MCU’s Daten an einen RPi senden lassen. Und zwar auch außerhalb des heimischen W-Lan-Netzes.
Gibt es eine Möglichkeit, dass der RPi als W-Lan-Router dient? Ich hab das Tutorial mit den 2,4 Ghz-Modulen gesehen. Geht das auch ohne diese Module? Also, dass der NodeMcu die Daten direkt an den Raspi schickt?
Besten Dank im Voraus.
Grüße
Alex
Dazu müsstest du deinen Port zuhause freigeben und ggf. einen dDNS Service nutzen, falls du keine statische IP hast.
Das hab ich nicht gemeint. Ich meine, wenn ich Raspi und ESP unterwegs wohin mitnehme und die sich dann Daten untereinander schicken können, ohne dass ein externer W-Lan-Router da ist, bzw. ohne Internet. Nur die Beiden „Geräte“
Dann wirst du allerdings eine andere Übertragungsmethode brauchen (433 MHz Funk vielleicht?)
Ich wollte auf zusätzliche Gerätschaften möglichst verzichten um es einfacher zu halten.
Ich könnte einen alten W-Lan-Router (also ohne Internetzugang) als Hotspot nehmen.
Oder könnte man aus dem Rpi einen W-Lan-Router (praktisch als Switch) oder sowas machen?
Hallo Felix,
ich würde gerne eine Waage realisieren die das Gewicht per SMS versendet.
Leider reicht mein Plan nicht bis zum Wiegepunkt
Gruß
und Danke für die tollen Anleitungen
Hallo Felix
bin daran, eine automatisierte Garten-Bewässerung aufzubauen, als „Zentrale“ PI mit Node-Server sowie die „Aussenstellen“ insgesamt 3 für die Betätigung der Ventile und messen der Bodenfeuchte
für diese Aussenstellen habe ich ESP8266 (Sparkfun) vorgesehen
meine Frage, für die ersten Versuche mit dem ESP zu kommunizieren habe ich das IDE von Arduino benutzt. der script vom Tutorial wird damit vermutlich nicht funktionieren?!
den ESPlorer (LUA) zu installieren gelingt mir leider nicht (Fehlermeldung)
gibt es da nähere Angaben? verwende MAC OS10.13.4
besten Dank
Hi Felix,
ich habe die customized Firmware erfolgreich draufgespielt. Sobald ich nun aber mittels ESPlorer das LUA Skript drauffspielen will, fängt sobald ich versuche mittels ESPlorer mit dem ESP8266 zu verbinden die blaue LED an wie wild zu blinken und im ESPlorer werden permanent Hyroglyphen ausgegeben… Habe die Baudrate von 9600 nicht verändert. Wenn ich eine andere versuche geschieht aber auch das gleiche. Woran kann das liegen?
Hi,
ich bin Neuling und möchte mir eine Fotobox bauen, die per Button die Kamera am Raspberry Pi 3 auslöst. Mit Kabeln funktioniert das ganze bereits und nun möchte ich das ganze per WLan gestalten. Wenn ich jetzt richtig bin, müsste ich nur den NodeMCU abändern. Wie würde ich das ganze abändern, wenn der Raspberry lediglich einen gpio auf pullup setzt, wenn der Button gedrückt wird und sonst den status pulldown hat?
Wäre für deine/eure Hilfe dankbar.
Hallo,
habe obiges Lua-script auf den ESP geladen und erhalte im Esplorer folgende Fehlermeldung:
wlan1.lua:93: bad argument #1 to ‚config‘ (config table not found!)
stack traceback:
[C]: in function ‚config‘
wlan1.lua:93: in main chunk
[C]: in function ‚dofile‘
stdin:1: in main chunk
> finde den Fehler nicht! Weiß jemand was dazu?
Hallo Hajo, hast du das Problem schon gelöst? ich hänge an der selben stelle.
Hallo,
erst Mal danke für die vielen guten Tutorials! Ich habe den LUA Code etwas anpassen müssen bis er auf meiner aktuelle LUA Version läuft.
NodeMCU 3.0.0.0 built on nodemcu-build.com provided by frightanic.com
branch: master
commit: 71a182caa7841cbb478ed90ede526dc881943c80
release:
release DTS: 202001061321
SSL: false
build type: integer
LFS: 0x0
modules: ads1115,file,gpio,i2c,net,node,tmr,uart,wifi,wifi_monitor
build 2020-01-12 10:33 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)
lua: cannot open init.lua
> dofile(„receive_esp8266.lua“)
WiFi: nil
> ESP8266 mode is: 1
The module MAC address is: a6:cf:12:bf:25:11
Config done, IP is 192.168.11.95
Das Starten des Moduls funktioniert nun. Beim Aufruf der URL entsteht folgender Fehler den ich nicht finde:
PANIC: unprotected error in call to Lua API (receive_esp8266.lua:117: attempt to index global ‚conn‘ (a nil value))
ets Jan 8 2013,rst cause:2, boot mode:(3,6)
load 0x40100000, len 27812, room 16
tail 4
chksum 0x6e
load 0x3ffe8000, len 2572, room 4
tail 8
chksum 0x66
load 0x3ffe8a0c, len 8, room 0
tail 8
chksum 0x43
csum 0x43
Bin für jede Hilfe dankbar
Grüße
Holger
Hallo,
noch ein kleiner Hinweis zum Anschluss der LED. Diese sollte unbedingt mit einem Vorwiderstand betrieben werden. 470 Ohm – 1 KOhm sollte ein guter Wert sein.
Gruß Armin