ENC28J60 – Ethernet Modul – Temperatur Messung mit Alarm – Teil 1

Einführung - worum es geht...

Liebe Maker Freunde,
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 Luftfeuchtemessung in meinem Rechenzentrum, inklusive Alarmierung per Email, sollten die Schwellwerte überschritten werden.

Im zweiten Teil 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.

Die Bauteile

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 Netzwerkmoduls einbinden. 

Dies können wir direkt aus der Arduino IDE heraus machen, indem wir im Menüpunkt „Sketch => Bibliothek einbinden“ => „Bibliothek verwalten“ auswählen und nach der Bibliothek suchen.

Das Programm

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 nebenstehenden Video kann man sehen, wie der Netzwerk Adapter initialisiert wird, sich seine IP Adresse und die weiteren Netzwerkinformationen 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 Luftfeuchtesensor. Der Sensor hat die folgenden Specs:

– Temperatur Bereich: 0° bis 50° C mit einem Delta von +- 2°C
– Luftfeuchte Bereich: 20 – 90 % rel. mit einem Delta von +- 5%
– Versorgungsspannung: 3.3 bis 5 V
– Sampling Rate: 1Hz
– Auflösung: 8Bit

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 5V Microcontrollern 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.5mA – also kein Problem für die Anschlüsse des Arduino. 

DHT 11                            Arduino Nano
VCC                                  VCC
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äzisionsmessung 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 mit installieren.

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 zusammen arbeitet.

Den Sketch jetzt schon schnell kompilieren und anschließend auf den Arduino übertragen und wir bekommen auf der seriellen Konsole die nebenstehende 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, dass würde den Rahmen sprengen. Am Besten ihr richtet euch jetzt unter https://ifttt.com/join ein eigenes Konto ein. Die für unsere Zwecke notwendigen Services sind kostenlos. 

Sobald ihr euch ein entsprechendes Konto angelegt habt, 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.

Wichtig für das Funktionieren des Webhooks ist hier vor allem das letzte Bild in der Screenshot Reihe. Hier bekommt ihr euren Key angezeigt. Dieser Key ist eure Authorisierung gegenüber IFTTT, wenn ihr einen Webrequest gegen die Webhook Schnittstellen absetzen wollt. Ihr könnt das ganz einfach testen, in dem ihr die https:// Adresszeile in eueren Browser kopiert. Vergesst aber nicht {event} durch den Namen eures 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 setze, da dieser ja nur mit einer Sampling Rate <= 1Hz zurecht kommt, 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 adhoc 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 findet ihr daher nur dieses 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 liest 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 eins 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 euch nun viel Spaß beim Nachbauen. Sollten Fragen aufkommen, oder Anregungen, immer her damit – schreibt sie einfach in die Kommentar-Funktion und ich bemühe mich, euch schnellstmöglich eine Antwort zukommen zu lassen.

Beste Grüße
Markus

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert