Liebe Maker Freunde,
sind Sie schon mal in die Verlegenheit gekommen, kein WLAN zur Verfügung zu haben oder einen Micro-Controller nutzen zu wollen, der kein WLAN hat? Dann kommen sogenannte Ethernet Shields oder Boards zum Einsatz, die dem Micro-Controller Zugriff auf das Netzwerk ermöglichen.
Mit diesem ersten Teil meiner zweiteiligen Reihe möchte ich ein solches Ethernet Board, den ENC28J60, vorstellen und auch gleich mit einem praktischen Beispiel verknüpfen: einer Temperatur- und Luftfeuchte-Messung in meinem Rechenzentrum, inklusive Alarmierung per E-Mail, sollten die Schwellwerte überschritten werden.
Im zweiten Teil dann werden wir die Schaltung um einen besseren Temperatur- und Luftfeuchtesensor ergänzen, ein OLED Display zur lokalen Anzeige mit einbringen und das Ganze dann in ein selbstgedrucktes 3D-Gehäuse packen.
Benötigte Hardware
Anzahl | Bauteil | Anmerkung |
---|---|---|
1 | Arduino Nano | |
1 | ENC28J60 Ethernet Modul | |
1 | DHT11 Breakout Board | |
1 | Breadboard | |
Dupont Kabel M/M und M/F |
Der Aufbau
Das Pin Mapping der beiden Module
ENC28J60 Modul Arduino Nano
5V 5V
GND GND
SCK PIN 13
SO PIN 12
ST PIN 11
CS PIN 10
RST RESET
Der erste Sketch
Erforderliche Bibliothek
Wir erstellen nun unseren ersten Sketch (Sketch = Programm für den Arduino). Bevor wir diesen Sketch jedoch erstellen und ausführen können, müssen wir in unserer Arduino Entwicklungsumgebung die passende Bibliothek zum Ansteuern des ENC28J60 Netzwerk Moduls einbinden.
Dies können wir direkt aus der Arduino IDE heraus machen, indem wir im Menüpunkt „Sketch => Bibliothek einbinden“ => „Bibliothek verwalten“ den Suchbegriff ENC28J60 eingeben:
Die Software
Das hier abgebildete Programm basiert auf dem EtherCard Beispielprogramm getDHCPandDNS. Es initialisiert den ENC28J60 Ethernet Adapter und weist ihm eine MAC-Adresse zu. Anschließend wird mittels DHCP versucht, eine IP Adresse für das Netzwerk zu beziehen, ebenso wie das Default Gateway und die Adresse des DNS Servers. Das alles passiert in der setup() Routine. In der anschließenden Hauptroutine loop() geht der Ethernet Adapter „auf Empfang“ und gibt empfangene IP-Pakete auf dem seriellen Monitor aus.
// 2020-07-11 ENC28J60 V1 - Basis Setup// (c) Markus Pohle @Creative Commons BY-NC-SA
// https://en.wikipedia.org/wiki/File:Cc-by-nc-sa_icon.svg
//
// ENC28J60 Grundinstallation, Basis Sketch, Pingen des Default GW
//
// Sketch inspiriert von: getDHCPandDNS (c) 2011 <jc@wippler.nl>
#include <EtherCard.h>
#define SS 10 // Slave Select Pin Nummer
uint8_t Ethernet::buffer[700]; // Paket Buffer Grüße ist 512 Byte
byte mymac[] = { 0xaa,0xbb,0xcc,0xdd,0xee,0xff };// Hier wird die Hardware MAC Adresse definiert
static BufferFiller bfill; // used as cursor while filling the buffer
void setup()
{
Serial.begin(9600); // Öffne serielle Schnittsatelle
while (!Serial)
{ // Warte auf seriellen Port
}
Serial.println("Warte auf ENC28J60 Startup.");
delay(6000);
Serial.println("Initialisierung des Ethernet Controllers");
if (ether.begin(sizeof Ethernet::buffer, mymac, SS) == 0)
{
Serial.println( "Fehler: ENC28J60 konnte nicht initalisiert werden...");
while (true);
}
Serial.println("Hole DHCP Adresse.");
if (ether.dhcpSetup())
{
ether.printIp("IP Adresse: ", ether.myip);
ether.printIp("Netmask: ", ether.netmask);
ether.printIp("GW IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);
}
else
{
ether.printIp("Das holen einer DHCP Adresse ist fehlgeschlagen...");
while (true);
}
}
void loop()
{
word len = ether.packetReceive(); // Paket Listener
word pos = ether.packetLoop(len);
if (len)
{
Serial.print("IP Packet erhalten. Groesse:");
Serial.print(len);
Serial.print(" Bytes. Daten Offset:");
Serial.print(pos);
Serial.println(" Bytes. IP Daten:");
for (int x = 0; x < len; x++)
{
char StrC =Ethernet::buffer[x];
Serial.print(StrC);
}
Serial.println("");
}
}
Nachdem der Sketch in die Arduino IDE geladen und von dieser erfolgreich kompiliert wurde, kann er in den Nano übertragen und ausgeführt werden. Öffnet man dann die serielle Konsole und stellt die Baud-Rate, wie im Sketch definiert, auf 9600 ein, so kann man folgende Ausgabe sehen:
- Initialisierung des Ethernet Controllers
- Holen der IP Adresse per DHCP
- Netzmaske, Gateway und DNS werden gesetzt
- IP Pakete werden empfangen und angezeigt
In dem folgenden Video kann man sehen, wie der Netzwerk Adapter initialisiert wird, sich seine IP Adresse und die weiteren Netzwerk Informationen per DHCP holt und anschließend die eingehenden Datenpakete über die serielle Konsole ausgibt.
Als Datenpakete werden ICMP Ping Pakete aus einer Konsole an die IP-Adresse des Ethernet Controllers gesendet.
Der Sensor - DHT11
Zum Einsatz kommt bei mir ein DHT11 Sensor auf einem Breakout Modul (Stichwort: 10k Pullup Widerstand schon verbaut) von Kuman. Dieses ist aber baugleich zum Modul von AZ-Delivery. Beim DHT11 handelt es sich um einen einfach „gestrickten“ Temperatur- und Luftfeuchte-Sensor. Der Sensor hat die folgenden Specs:
- Temperatur Bereich: 0° bis 50° C mit einer Genauigkeit von +- 2°C
- Luftfeuchte Bereich: 20 – 90 % rel. mit einer Genauigkeit von +- 5%
- Versorgungsspannung: 3.3 bis 5 V
- Sampling Rate: 1Hz
- Auflösung: 8 Bit
Details zur Funktionsweise des Sensors können ganz wunderbar auf der folgenden Seite nachgelesen werden:
https://lastminuteengineers.com/dht11-dht22-arduino-tutorial/
Sensor - Pinout und Anschluss
Da der DHT11 Sensor kompatibel mit 5 V Micro-Controllern ist, kann er direkt an den Arduino Nano angeschlossen werden. Die Stromaufnahme des DHT11 liegt im Standby Betrieb (also zwischen den Messungen) im µA Bereich und während einer Messung bei maximal 2.5 mA – also kein Problem für die Anschlüsse des Arduino.
Ich empfehle das Breakout Board, weil hier bereits der Pull-Up-Resistor von 10 kOhm verbaut ist. Ansonsten müssten Sie diesen Widerstand zusätzlich zwischen den Kontakten für DATA und VCC (5V) anschließen. Achten Sie in jedem Fall auf die Beschriftung der Boards, da es hier unterschiedliche Ausführungen gibt.
1=VCC, 2=DATA, 3=nc, 4=GND
DHT 11 Arduino Nano
VCC 5 Volt
GND GND
DATA D2
Die Library
SimpleDHT - die erste Ernüchterung
Um den Sensor auslesen zu können, braucht es wieder eine Library. Bei meinen ersten Versuchen nahm ich dazu die SimpleDHT Library (die Installation der Library erfolgt analog zur Installation der EtherCard Library über den Library Manager in der Arduino IDE).
Um den DHT11 Sensor auszulesen, bedarf es gerade einmal 18 Zeilen Code (ohne die Kommentare) – die Ergebnisse der Messung werden dabei auf den seriellen Monitor ausgegeben.
Hier erfolgte dann bereits die erste Ernüchterung (auf eine weitere Ernüchterung im Kontext des DHT11 kommen wir im zweiten Teil dieses Blog Artikels noch zu sprechen): der DHT liefert bei Nutzung der SimpleDHT Library „nur“ ganzzahlige Ergebnisse zurück.
Das könnte man jetzt ignorieren, schließlich wollen wir keine Präsisionsmessung durchführen (was mit der Genauigkeit des DHT11 ja auch gar nicht ginge), sondern nur einen Temperatur-Schwellwert überwachen… aber: Nö 🙂 Wir wollen ja schließlich zeigen, was geht, oder auch eben nicht.
DHT Sensor Library - by Adafruit
Damit wir die von Adafruit bereit gestellte Library zum Auslesen des DHT11 nutzen können, müssen wir diese ebenfalls über den Library Manager installieren. Eventuell kommt es dabei zu einer Meldung hinsichtlich Abhängigkeiten von anderen Libraries. Diese dann bitte mitinstallieren.
Anschließend öffnen wir aus den Beispielen (Datei => Beispiele => DHT Sensor Library) den Sketch „DHTtester“. In diesem Sketch ist schon soweit alles richtig eingetragen, dass es mit unserem Aufbau des Sensors an dem Arduino Nano sofort zusammenarbeitet.
Den Sketch jetzt schon schnell kompilieren und anschließend auf den Arduino übertragen und wir bekommen auf der seriellen Konsole die im Bild gezeigte Ausgabe zu sehen.
Besser…
Das Zusammenspiel - Nano, ENC28J60, DHT11
Nachdem wir nun alle Komponenten für unseren ersten Teil dieses Projektes einzeln ausprobiert haben, wird es Zeit, alle Komponenten zusammen zu bringen und den finalen Sketch zu schreiben. Eine Frage ist allerdings noch offen: wohin mit den Alarmen, wenn die eingestellten Schwellwerte überschritten werden?
Wir hatten ja anfangs gesagt, dass wir die Alarmierung per Email durchführen wollen. Jetzt könnten wir dem Arduino ja beibringen, selbst eine Email zu generieren. Wozu aber die Mühe? Wir bedienen uns hier eines Services im Internet, über den wir, abhängig von bestimmten Ereignissen, Aktionen auslösen lassen können. Und bei solchen Aktionen kann es sich z.B. um das Versenden einer Email handeln.
IFTTT - IF This Than That
Um unsere Alarmierungs-Email senden zu lassen, nutzen wir den Webdienst IFTTT. IFTTT steht für If This Than That und wird abgekürzt IFT gesprochen, wie in GIFT, bloß ohne das G. Eine Einführung in IFTTT kann ich hier an dieser Stelle nicht leisten, das würde den Rahmen sprengen. Am besten richten Sie sich unter https://ifttt.com/join ein eigenes kostenloses Konto ein. Die für unsere Zwecke notwendigen Services sind kostenlos – es fallen also keine Kosten an.
Sobald ein entsprechendes Konto angelegt ist, zeige ich hier im Schnelldurchlauf, wie wir einen sogenannten Webhook Service einrichten, den wir anschließend nutzen können, um unsere Alarmierungs-Email senden zu lassen.
Nach dem Aufrufen und Anmelden auf der Seite ifttt.com erzeugen wir einen neuen Event, indem wir im Menü oben rechts auf “Create” klicken.
Durch Klicken auf das + Symbol beginnen wir mit dem Einrichten des Events.
Event/Service wählen wir “Webhooks” aus.
Als Trigger für unseren Event, dass ein Web Request eintrifft
Wir geben dem Event einen Namen, welcher beliebig gewählt sein kann, aber doch einen sprechenden Charakter haben sollte und klicken dann auf “Create trigger”.
Die “If” Bedingung unseres Services ist damit erledigt, jetzt müssen wir nur noch festlegen, was passieren soll (Then), wenn die Bedingung erfüllt ist. Dazu klicken wir auf das + Symbol rechts vor dem That.
Wir wollen den Email Service nutzen, tragen als “Email” als Suchbegriff ein und bekommen den “einfachen” Email Service angezeigt (links), welchen wir durch Anklicken auch auswählen.
Der einfache Email Service bietet aktuell als einzige Aktion nur an, eine Email zu versenden. Wir klicken als zur Auswahl auf das blaue Kästchen “Send me an email”.
Nun füllen wir die Felder für die Betreffzeile und den Email Body nach unseren Vorstellungen aus. Im geringen Umfang stehen dabei HTML Tags zur Verfügung, ebenso wie einige vordefinierte IFTTT Variablen.
Am Ende bekommen wir eine Übersicht über unseren gerade eingerichteten Service. Hier ändern wir jetzt gar nichts mehr und klicken nur noch auf den Button “Finish”.
Jetzt benötigen wir noch den sogenannten KEY, unseren Authorisierungs-Schlüssel. Nur mit diesem Key können wir von extern IFTTT aufrufen und dazu veranlassen, unseren Webhook auszuführen.
Um den Key angezeigt zu bekommen, klicken wir oben links auf das Logo “Webhooks”.
Auf der Folgeseite dann wählen wir oben rechts den Punkt “Documentation” aus.
Hier bekommen wir jetzt unseren KEY angezeigt, ebenso wie Beispiele, die uns zeigen, wie man den Webhook z.B. mittels Browser aufruft.
Das war‘s… mehr ist zur Nutzung des IFTTT-Dienstes für unsere Zwecke gar nicht nötig zu wissen.
Wichtig für das Funktionieren des Webhooks ist hier vor allem das letzte Bild in der Screenshot Reihe. Hier bekommt man den Key angezeigt. Dieser Key ist die Authorisierung gegenüber IFTTT, wenn ein Webrequest gegen die Webhook Schnittstellen abgesetzt wird. Man kann das ganz einfach testen, in dem man die https:// Adresszeile in den Browser kopiert. Bitte vergessen Sie aber nicht, {event} durch den Namen Ihres Events zu ersetzen.
Der finale Aufbau der Schaltung
Der finale Sketch - die zweite Ernüchterung
Ursprünglich diente das webClient Beispiel aus der EtherCard Library als Basis für meinen Sketch. Das Aufrufen des Webhooks war hiermit leicht zu bewerkstelligen. Die Übergabe der aus dem DHT11 ausgelesenen Werte war ebenfalls mit geringem Aufwand möglich.
Als ich jedoch einen delay() zwischen die einzelnen Auslese Versuche des DHT11 setzte, da dieser ja nur mit einer Sampling Rate <= 1Hz zurechtkommt, musste ich feststellen, dass mein Sketch nicht mehr funktionierte.
Der Grund war, leider, nicht schnell gefunden, liegt aber darin begründet, dass der Arduino kein Multithreading macht, sondern ein Event-Loop und dass das von mir eingebrachte delay() an dieser Stelle den Arduino komplett zum Erliegen bringt. Das führte dann dazu, dass die EtherCard Library die Daten nicht mehr auf den Netzwerk Stack schieben oder von diesem lesen konnte – Mist!
Der finale finale Sketch - eine alternative Library
Der Tatsache geschuldet, dass ich ad hoc mit der EtherCard Library nicht weiter kam, habe ich mich nach einem Ersatz umgesehen, mit der ich die Limitierung durch das delay() nicht hatte – Lösung brachte schließlich die UIPEthernet Library. Im Folgenden finden Sie daher nur diesen Sketch. Wer Interesse an dem anderen Sketch hat, kann sich gerne melden – ich stelle den dann zur Verfügung.
#include <UIPEthernet.h>
#include "DHT.h"
// Ethernet Konfigparameter
EthernetClient client;
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
char server[] = "maker.ifttt.com";
static uint32_t sentTimer = 0;
// DHT11 Konfigurationsparameter
#define DHTPIN 2 // Der DHT11 Datenpin hängt an PIN2 des Arduino
#define DHTTYPE DHT11 // welcher DHT Typ: DHT11 (kann auch DHT22 oder DHT21 sein)
DHT dht(DHTPIN, DHTTYPE);
// Schwellwertzähler
static uint32_t highCount = 1;
void setup() {
Serial.begin(9600);
if(Ethernet.begin(mac) == 0){
Serial.println("Failed to configure Ethernet using DHCP");
while(1); // kein Netzwerk? Dann Ende!
}
Serial.println(F("DHT11 Init!"));
dht.begin();
}
void loop() {
// DHT11 Werte auslesen
float h = dht.readHumidity();
float t = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t)) {
Serial.println(F("DHT11 Sensor kann nicht gelesen werden"));
delay(5000);
return; // aus der weiteren Verarbeitung heraus springen!
}
if ( t > 27 || t < 18 || h > 55 || h < 35 )
highCount++;
else
highCount = 1;
// Nur, wenn der Schwellwert mehr als eine Minuten ansteht wird alarmiert - verhindert flappen
// Modulo 13, weil Variable highCount initial 1 ist - wäre highCount zu Beginn 0, wäre hC % 12 == 0 sofort TRUE
if (highCount % 13 == 0) {
if (millis() > sentTimer) { // prüft ob seit dem letzten HTTP GET Request mehr als 10 Min vergangen sind
sentTimer = millis() + 600000;
if (client.connect(server,80)) {
client.print("GET /trigger/RZTemp/with/key/wD37AgoV6v---------------------jlN?value1=");
client.print(t);
client.print("&value2=");
client.print(h);
client.println(" HTTP/1.1");
client.println("Host: maker.ifttt.com");
client.println();
}
else {
Serial.println("Connection to server failed");
delay(5000);
}
while(client.connected()) {
if(client.available()) {
char c = client.read();
Serial.print(c);
}
}
}
}
// 5 Sekunden warten zwischen den Messungen
delay(5000);
}
Was der Sketch tut...
Nach dem Initialisieren des ENC28J60 Netzwerk Moduls und des DHT11 Sensors (in der setup() Routine) durchläuft der Sketch „unendlich“ die loop() Routine. Dabei ließt er zunächst die Daten aus dem DHT11 Sensor aus. Sollte es hierbei zu einem Fehler kommen, wartet der Sketch 5 Sekunden und springt dann aus der weiteren Verarbeitung raus, um die loop() Routine von vorne zu beginnen.
Anschließend werden die gemessenen Werte mit den Schwellwerten für Temperatur und Luftfeuchte verglichen. Ich habe mich bei diesen Grenzwerten an den üblichen Grenzwerten für Rechenzentrums-Räume orientiert und nach oben und unten ein wenig Spielraum dazu gegeben, speziell bei der Luftfeuchtigkeit.
Kommt es zu einer Schwellwertüberschreitung, dann wird ein Counter um eins nach oben gezählt. Erreicht der Counter dabei einen Wert, welcher einem dauerhaft überschrittenen Schwellwert von einer Minute entspricht, dann wird ein HTTP GET Request zum Aufruf der ifttt.com Seite zusammen gebaut und abgesetzt – die Messwerte werden dabei natürlich als Parameter mit an die URL angehängt. Dabei wird ein weitere Counter gesetzt. Dieser Counter dient dazu zu prüfen, ob zwischen den HTTP GET Requests mindestens 10 Minuten Zeit liegen – damit soll verhindert werden, dass der Webhook bei IFTTT im Minutentakt aufgerufen wird.
Sollten die Schwellwerte nicht mehr überschritten sein, dann wird der entsprechende Counter wieder auf 1 zurück gesetzt. Im Screenshot unten seht ihr einen erfolgreich abgesetzten Request gegen die ifttt.com Schnittstelle. Im Screenshot darunter könnt ihr die von IFTTT generierte Email mit den übergebenen Messwerten sehen.
Das war es mit dem ersten Teil.
Ich wünsche Ihnen nun viel Spaß beim Nachbauen.
Sollten Fragen aufkommen, oder Anregungen, immer her damit – schreiben Sie einfach in die Kommentar-Funktion und ich bemühe mich, schnellstmöglich eine Antwort zu posten.
Beste Grüße
Markus Pohle
3 comments
Noah
Ich habe versucht das Ganze nachzubauen und komme aber leider nicht weiter.
Ich verbinde mich mit dem Server und schicke mit meinem Key den Event-Trigger raus, jedoch passiert nichts weiter. Ich bekomme keine Nachricht und das Event wird auch nicht ausgelöst.
der Code ist genau wie Ihrer und ich nutze ein ENC28J60 Ethernet Shield mit meinem Arduino Uno und der Library “UIPEthernet.h” (https://github.com/UIPEthernet/UIPEthernet). Würde mich über Hilfe freuen
Markus Pohle
Hallo Herr Stauffert,
die wichtigsten Unterschiede der beiden Module wie folgt:
- der W5500 implementiert den TCP/UDP Stack im Chip, der ENC28J60 per Software
- der W5500 kann bis zu 100Mbit, der ENC28J60 nicht mehr als 10Mbit
- der W5500 kann 3,3V, der ENC28J60 nicht
- auf Grund der Hardwareimplementierung des TCP/UDP Stacks ist der W5500 robuster im Betrieb, reagiert weniger “zickig” auf Network Broadcasts und der Code ist schlanker umd braucht weniget Ressourcen des Mikrocontrollers.
Allerdings ist er auch teurer und es gibt für ihn nicht so ein breites Spektrum an Bibliotheken oder Bauformen.
Ich hoffe, dies beantwortet Ihre Frage.
Beste Grüße
Stauffert
Was ist der Unterschied zwischen dem ENC28J60 und dem W5500 Ethernet Shield, den Az-Delivery ja zu einem ähnlichen Preis im Angebot hat?