Wenn man so wie wir viele Netzwerkschränke in ganz Deutschland verteilt hat und diese alle per VPN mit der Hauptniederlassung verbunden sind, dann möchten wir schon wissen, wenn sich einer am Schrank zu schaffen macht. Wir haben nämlich Kollegen die gerne mal selber schauen möchten ob alles noch „in Ordnung“ ist. Oft passiert es das diese freundlichen und hilfsbereiten Kollegen eher das Gegenteil tun. Nach dem Motto „Das Internet ging nicht. Da hab ich mal beim Server den Stecker gezogen. Seid dem geht irgendwie nichts mehr“.
Auch haben wir Probleme mit Temperaturen. Gerade in den „älteren“ Niederlassungen befinden sich einfach zu kleine Netzwerkschränke ohne aktive Kühlung und mit viel zu vielen aktiven Bauteilen, wie Modem, Firewall, Server und Switchen. Letzteres hat gerade mit der Temperatur ein Problem und droht gerne mal auszufallen. Nun da wir nicht für jede Niederlassung ein SNMP fähiges Switch verbaut haben, kommt jetzt eine „Bastel“-Lösung via Arduino.
Folgende Aufgaben sollte meine Lösung können.
1. Temperatur und Verschluss überwachen. Und bei überschreiten der Temperatur oder beim öffnen des Netzwerkschrankes eine EMail an die EDV Abteilung senden.
2. Die Daten der Temperatur und des Magnetkontaktes via Modus an unsere Firmenübergreifende Gebäudeautomation senden.
3. Einen eigenen Webserver zu Verfügung stellen, um direkt die Daten einzusehen.
Nun drei Tage bastel-, Löt- und Programmierarbeit später kann ich einen Erfolg melden. Dat Ding geht!
Hier das Ergebnis. Eine kleine Box mit großem Inhalt
In dieser Blackbox befindet sich ein Arduino Uno, ein Netzwerkshield und eine kleine Platine zur Verteilung der Anschlüsse. An der Platine befinden sich zwei One-Wire Temperatursensoren, sowie ein Magnetkontakt.
Vorteil der One-Wire Temperatursensoren. Diese belegen nur einen einzigen Digitalen Pin. Somit benötige ich lediglich zwei Digitale Pins für meine Aufgaben.
/* ******************************************************************************* ******************************************************************************* *** Temperatur- und Verschlussüberwachung Bereich IT *** *** *** *** *** *** Messung von 2 Temperaturzonen über das One-Wire Protokoll *** *** sowie die Verschlussüberwachung durch einen Magnetkontakt. *** *** *** *** Bereitstellung der Daten über einen Internen Webserver *** *** wie auch über das Modbusprotokoll für die interne Gebäudeautomation. *** *** *** *** Meldung von Temperaturüberschreitungen via Mail an definierte Empfänger *** *** *** *** Verbaute Schield's: *** *** Etherntkarte *** *** *** *** Belegte Pin's *** *** Digital PIN 2 = Temperatur Sensoren via One-Wire *** *** Digital PIN 3 = Magnetkontakt *** ******************************************************************************* ******************************************************************************* */ /* -------------------------------------- | Festlegung der benötigten Libaries | -------------------------------------- */ //Libary für die Ethernetkarte #include <Ethernet.h> #include <EthernetClient.h> #include <EthernetServer.h> #include <EthernetUdp.h> #include <util.h> #include <SPI.h> // Libary für Modbus #include <Mudbus.h> //Libary für das One-Wire Protokoll #include <OneWire.h> //Libary für den Temperatursensor #include <DallasTemperature.h> /* -------------------------------------- | Definition der Variablen | -------------------------------------- */ // ****** Hier die Ethernetconfig anpassen ****** // MAC Adresse für das Ethernetshield definieren. // Achtung diese Adresse darf nicht doppelt im Netzwerk vorkommen byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 }; // Definition der IP-Adresse IPAddress ip( 192, 168, 178, 100 ); IPAddress gateway( 192, 168, 178, 1 ); //DNS und GATEWAY IPAddress subnet( 255, 255, 255, 0 ); //IP des EMailservers //byte mailserver[] = { xxxxxxxx}; // IP Mailserver ohne DNS char mailserver[] = "xxxxxxxx; //Addresse bei DNS EthernetClient client; // Definition des Ethernetport des Webservers EthernetServer server(80); // Modbus aufrufen Mudbus Mb; // ****** Hier die Konfig des One-Wire-Bus // Pin für One-Wire-Bus festelgen. Standart = 2 #define ONE_WIRE_BUS 2 OneWire oneWire(ONE_WIRE_BUS); // One-Wire-Bus mit dem Temperatursensor verbinden DallasTemperature sensors(&oneWire); // ****** Hier die Digital Eingänge anpassen ****** // Pin für Magnetkontat festlegen. Standart = 3 int Magnetkontakt = 3; // ***** Definition von Textvariablen ***** char Title [] = "Webserver DV11"; char Object [] = "DV11"; // **** Wichtige Daten Hier stehen eigentlich die EMail Zugänge drin. Aus Sicherheit habe ich diese aber entfernt. Möchte ja schließlich nicht das einer diese hackt! char hello [] = "EHLO xxxxxx"; char user [] = "xxxxxxxx"; char pwd [] = "xxxxxxxx"; char MailFrom [] = "MAIL From: xxxxxxxx"; char MailTo [] = "RCPT To: xxxxxxxx"; char SendTo [] = "To: BASTIAN xxxxxxxx"; char SendFrom[] = "From: xxxxxxxx"; // *********** int flag = 0; int flag1 = 0; /* -------------------------------------- | SETUP BEIM STARTEN DES ARDUINO'S | -------------------------------------- */ void setup(void) { // PinMode für Magnetkontakt definieren pinMode(Magnetkontakt, INPUT); //Serial initalisieren für das debugging Serial.begin(9600); //Ethernetschnittstelle initalisieren Ethernet.begin(mac, ip, gateway, gateway, subnet); //Temperaturabfrage initalisieren sensors.begin(); delay(1000); //Webserver initalisieren server.begin(); //Warten bis alle Einstelungen übernommen wurden delay(5000); Serial.print("Server startet at "); Serial.println(Ethernet.localIP()); } /* ---------- | LOOP | ---------- */ void loop(void) { // Temperaturwerte und Magnetkontakt auslesen sensors.requestTemperatures(); float TemperatureId0 = sensors.getTempCByIndex(0); delay (500); float TemperatureId1 = sensors.getTempCByIndex(1); delay(500); int MagnetStatus = digitalRead(Magnetkontakt); //Webserver aufrufen und Werte übergeben EthernetClient client = server.available(); if (client.available()) { Webservice(TemperatureId0, TemperatureId1, MagnetStatus); } Modbus(TemperatureId0, TemperatureId1, MagnetStatus); delay(250); if (MagnetStatus == 0 && flag == 0) { sendEmail (TemperatureId0, TemperatureId1, "magnet"); flag = 1; Serial.println("Kontakt geoeffnet!"); } if (MagnetStatus == 1 && flag == 1) { flag = 0; Serial.println("Kontakt geschlossen"); } if (TemperatureId0 > 29.99 or TemperatureId1 > 29.99) { if (flag1 == 0) { Serial.println("Temperatur ueberschritten"); Serial.println(flag1); sendEmail (TemperatureId0, TemperatureId1, "temperatur"); flag1 = 1; } else { Serial.println(TemperatureId0); Serial.println(TemperatureId1); } } if (TemperatureId0 < 30.00 and TemperatureId1 < 30.00) { Serial.println(TemperatureId0); Serial.println(TemperatureId1); flag1 = 0; } //Debuggin //Serial.println(TemperatureId0); //Serial.println(TemperatureId1); //Serial.println(MagnetStatus); delay(1000); } /* ---------------- | Funktionen | ---------------- */ /* ---------------- | Webserver | ---------------- */ void Webservice(float Temp1, float Temp2, int Magnet) { EthernetClient client = server.available(); //Debugging Serial.println(Temp1); Serial.println(Temp2); Serial.println(Magnet); //Webserver starten if (client) { Serial.println("new client"); boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); if (c == '\n' && currentLineIsBlank) { client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println("Refresh: 5"); // refresh the page automatically every 5 sec client.println(); client.println("<!DOCTYPE HTML>"); client.println("<html>"); client.println("<head>"); client.print("<title>"); client.print(Title); client.print("</title>"); client.println("</head><body>"); client.print("Temperatur für Messpunkt 1: "); client.println(Temp1); client.println("<br />"); client.print("Temperatur für Messpunkt 2: "); client.println(Temp2); client.println("<br />"); if (Magnet == 0 ) { client.println("Kontakt geöffnet!"); } else { client.println("Kontakt geschlossen!"); } client.println("</body></html>"); if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } // give the web browser time to receive the data delay(1000); // close the connection: client.stop(); Serial.println("client disconnected"); } } } } } /* ---------------- | Modbus | ---------------- */ void Modbus(float Temp1, float Temp2, int Magnet) { //Modbus starten Mb.Run(); //Analog inputs 0-1023 Mb.R[0] = Temp1; Mb.R[1] = Temp2; Mb.C[2] = Magnet; } /* ---------------- | Mailing | ---------------- */ byte sendEmail(float Temp1, float Temp2, char action[]) { byte thisByte = 0; byte respCode; if(client.connect(mailserver,25)) { Serial.println(F("connected")); } else { Serial.println(F("connection failed")); return 0; } if(!eRcv()) return 0; Serial.println(F("Sending helo")); // change to your public ip client.println(hello); if(!eRcv()) return 0; Serial.println(F("Auth")); client.println(F("AUTH LOGIN")); Serial.println(F("user")); delay(500); client.println(user); Serial.println(F("pwd")); delay(500); client.println(pwd); if(!eRcv()) return 0; Serial.println(F("Sending From")); // change to your email address (sender) client.println(MailFrom); if(!eRcv()) return 0; // change to recipient address Serial.println(F("Sending To")); client.println(MailTo); if(!eRcv()) return 0; Serial.println(F("Sending DATA")); client.println(F("DATA")); if(!eRcv()) return 0; Serial.println(F("Sending email")); // change to recipient address client.println(SendTo); // change to your address client.println(SendFrom); if (action == "temperatur") { client.println(F("Subject: Temperaturüberschreitung\r\n")); client.print(F("Die Temperatur im ")); client.print(Object); client.println(F(" wurde überschritten.")); client.print(Temp1); client.print(F("°C und ")); client.print(Temp2); client.println(F("°C.")); } else if (action == "magnet") { client.println(F("Subject: Zugriff auf Netzwerkschrank\r\n")); client.print(F("Der Netzwerkschrank ")); client.print(Object); client.println(F(" wurde geöffnet!")); } client.println(F(".")); if(!eRcv()) return 0; Serial.println(F("Sending QUIT")); client.println(F("QUIT")); if(!eRcv()) return 0; client.stop(); Serial.println(F("disconnected")); return 1; } byte eRcv() { byte respCode; byte thisByte; int loopCount = 0; while(!client.available()) { delay(1); loopCount++; // if nothing received for 10 seconds, timeout if(loopCount > 10000) { client.stop(); Serial.println(F("\r\nTimeout")); return 0; } } respCode = client.peek(); while(client.available()) { thisByte = client.read(); Serial.write(thisByte); } if(respCode >= '4') { efail(); return 0; } return 1; } void efail() { byte thisByte = 0; int loopCount = 0; client.println(F("QUIT")); while(!client.available()) { delay(1); loopCount++; // if nothing received for 10 seconds, timeout if(loopCount > 10000) { client.stop(); Serial.println(F("\r\nTimeout")); return; } } while(client.available()) { thisByte = client.read(); Serial.write(thisByte); } client.stop(); Serial.println(F("disconnected")); }
Hier das vollständige Script des Arduino.
Eigentlich ist es ganz einfach. Im oberen Bereich werden alle Variablen definiert und initialisiert. z.B. IP-Adressen, Passwörter oder Textvariablen.
In der Funktion Setup wird alles für den Arduino geladen. Im Loop werden die Temperatursensoren und der Magnetkontakt abgefragt und jedes mal in der Funktion Modus gespeichert. Hier stehen sie dann in den Registervariablen für die Gebäudeautomation zu Verfügung. Sobald sich ein Client auf dem Webserver anmeldet wird zusätzlich die Funktion Webserver ausgeführt. Dort werden ebenfalls die Variablen dargestellt und alle 5 sec aktualisiert.
Wird der Magketkonakt geöffnet oder übersteigt die Temperatur 30°C so wird die Funktion sendMail ausgeführt. Mit der Variable Action übergebe ich der Funktion zusätzlich was sie denn nun für eine EMail schreiben soll. Also Netzwerkschrank geöffnet oder Temperatur im Netzwerkschrank überschritten. Damit diese EMail nicht jedes mal im Loop ausgeführt wird (Das wäre ja eine EMailbome!) setze ich einen Flag für den Magnetkonatkt und einen Flag für die Temperatur. Wird als die Bedingung true und ist der Flag false (also 0) dann wird die EMail Funktion aufgerufen. Gleichzeitig wird der Flag aber auf true (also 1) gesetzt. Somit wird im nächsten durchlauf keine EMail gesendet. Der Flag wird erst auf false gesetzt bis die Bedingung auf false steht. Also Tempertur unter 30°C oder Magnetkontakt geschlossen.
Eigentlich ganz simpel. Aber man (also ich) musste sich doch ganz schön durch die Programmierung graben und alles aus tausend Beispielen ableiten! PUH. Aber Spass macht es 😀
Hallo,
danke für diese super Beschreibung!
Kannst du mir sagen, welche Modbus Library du genutzt hast?
Dank dir & Gruß
Christian
Hi Christian,
schau doch einfach bei mir im Sketch ->
Und dann einfach bei google mudbus.h suchen. Ich glaube der zweite eintrag ist es schon!
Gruß Bastian
Hallo,
ich wäre ebenfalls an der modbus library interessiert. Leider ist deine Angabe nicht so genau…
Würde mich über einen Downloadlink freuen
Gruß
wowa
Benutze diese Googlesuche hier klicken
Hallo,
ich wollte mal danke für dieses ausführliche Tut danke sagen – habe aber gleich mal eine anregung an dich.
Überwache den Schrank nicht nur über einen magnetkontakt – schalte IN REIHE noch einen Türkontaktschalter (weißt schon die mit denen normal die schaltschrankbeleuchtung geschaltet wird)
WIr haben oft das Problem gehabt dass die oben erwähnten freundlichen kollegen ihren Pinwand Magneten Mitnehmen und so die Tür-Offen-Meldung überbrücken. Auf die Idee den Türkontaktschalter mit Klebeband zusätzlich zu brücken ist noch keiner gekommen ^^ evtl weil die leute meinen „das ist doch für´s licht da“
sind nur meine erfahrungen aus der zutrittskontrolle
Hi Peter,
Danke für Deinen Tipp. So schlimm sind unsere freundlichen Mitarbeiter dann doch nicht, dass Sie den Magneten nutzen 😀
Für alle die direkt den Downloadlink suchen für die Library Mudbus
https://code.google.com/p/mudbus/
BITTE SCHÖN 😀
Hallo,
ich bin über die IP-Symcon Seite auf Dein Script gestoßen. Sehr gut und durchdacht. Einen Verbesserungsvorschlag habe ich auf die Schnelle. Und Zwar wenn der Temperaturwert auf der Schwelle 29,99 und 30,00 ist, würde Dein Flag eventuell rasch wechseln. Als Idee kann man den TempGrenzwert in eine Variable setzten und das Flag erst:
****************
if (TemperatureId0 < TempGrenzwert-1 and TemperatureId1 < TempGrenzwert-1) {
Serial.println(TemperatureId0);
Serial.println(TemperatureId1);
flag1 = 0;
}
****************
LG
//Sven