Ich habe eine Brauchwasserzisterne, die ich zum Gartengießen benutzen werde. Nun ist es natürlich praktisch zu wissen, ob und wieviel Wasser sich in der Zisterne befindet. Ich habe also ein wenig recherchiert und mich schlussendlich für die Messung mittels Ultraschall-Modul entschlossen. Diese Variante ist günstig und sehr einfach zu machen. Sie kann natürlich nicht nur für den Zisternenfüllstand verwendet werden, sondern auch für andere Tanks jeglicher Art.
Ich zeige euch wie es geht!
Die erste Frage, die sich stellte, war wie die gemessenen Daten des Arduinos an den Home-Server (FHEM) übertragen werden sollten. Zuerst hatte ich RS485 mit dem modbus-Protokoll im Sinn. Also alles zusammengebaut, eine der zahlreichen modbus libraries verwendet und in Fhem das modbus-Modul aktiviert und konfiguriert. Funktionierte alles perfekt. Dann kam mir die Idee sowohl Daten als auch Stromversorgung über das CAT7 Ethernet Kabel zu realisieren. Die Daten sollten über eine Website bereitgestellt werden und die Power sollte übers Ethernet, also Power over Ethernet, kommen. Also alles wieder auseinandergebaut, ein Ethernet Shield für den Arduino besorgt und erneut gebastelt. Was dabei herausgekommen ist und wie ihr es nachmachen könnt, versuche ich in den nächsten Absätzen zu beschreiben…
Was wird benötigt?
- Wasserdichte Aufputzdose
- Wasserdichter RJ45 Anschluss: Die Stromversorgung wird extra herausgeführt! Das ist deswegen so praktisch, weil man da den DC-Konverter direkt anschließen kann. Alternative und mehr dazu weiter unten.
- DC-Konverter von den 48 Volt (PoE) auf die benötigten 5V für den Arduino
- Arduino nano
- Ethernet Shield für den Arduino Nano
- Wasserdichter Ultraschall Sensor
Verkabelung
PoE arbeitet mit einer Spannung von 48V, die für den Arduino natürlich auf seine 5V heruntergeregelt werden muss. Der DC-DC Converter übernimmt diese Aufgabe. Das Ultraschall Modul muss einerseits mit der Betriebsspannung von 5V gespeist werden und andererseits müssen Pin 8 mit dem Echo-Pin und Pin 9 mit dem Trigger-Pin des Moduls verbunden werden.
Bezüglich der wasserdichten „RJ45-Gehäuse-Durchführung“: Leider gibt es das Teil mit den für Stromversorgung und LAN aufgesplitteten Kabeln nur bei Aliexpress (= mind. 3 Wochen Lieferzeit). Du kannst alternativ auch einfach ein Modell ohne extra Stromversorgung und einen POE-Splitter besorgen. Damit ist es möglich, gleich die 5V in das LAN-Kabel einzuspeisen, womit der DC-Konverter wegfallen würde. (Aber Achtung bei so geringen Spannungen darf der Spannungsabfall nicht außer Acht gelassen werden! Ich weiß nicht wie lange das Ethernet-Kabel sein darf, damit die Schaltung noch ordnungsgemäß funktioniert, also sollte das auf jeden Fall vorher ausprobiert werden.)
In meinem Fall speist der Switch die Spannung ein und laut Spezifikation arbeitet POE mit 48V. Somit würde es sich dann anbieten, statt dem Fulree DC-Konverter gleich einen Active PoE Splitter einzusetzen. Achtet auf genug Platz in der Dose. 😳
Arduino Code
Der Code bewirkt, dass der Arduino mit dem Ethernet Shield einen Mini-Webserver startet. Damit wird nur eine Seite übertragen und auf dieser Seite steht die gemessene Distanz in Zentimetern. Sie wird bei jedem TCP-Request (z.B. Aufruf der Seite im Browser) neu gemessen, indem mit der Funktion „sonar.ping_median(5);“ 5 Messungen durchgeführt und der um fehlerhafte Messungen bereinigte Mittelwert zurückgegeben wird.
Achtung: Damit der Code funktioniert, müssen erst die Bibliotheken in der Arduino IDE installiert werden. Die Links dazu findest du gleich im nachfolgenden Code:
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 |
/* * LIBRARY : EtherCard : https://github.com/Snootlab/EtherCard * LIBRARY : NewPing : https://github.com/PaulStoffregen/NewPing */ /* ETHERCARD SETTINGS */ #include <EtherCard.h> /* Ultrasonic Sensor library */ #include <NewPing.h> // Ethernet interface MAC address, must be unique on the LAN static byte mymac[6] = { 0x4C,0x61,0x65,0x73,0x15,0x45 }; static byte myip[4] = { 192,168,10,60 }; //newping settings: #define TRIGGER_PIN 9 #define ECHO_PIN 8 NewPing sonar(TRIGGER_PIN, ECHO_PIN); int cM; byte Ethernet::buffer[400]; BufferFiller bfill; void setup() { Serial.begin(9600); // Init Ethernet if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) { Serial.println(F("Failed to access Ethernet controller")); return; } ether.staticSetup(myip); } word homePage() { char buf [4]; sprintf(buf, "%3i", cM); Serial.print("Sending webpage with distance value of "); Serial.print(cM); Serial.println("cm"); bfill = ether.tcpOffset(); // Actually send the packet bfill.emit_p(PSTR( "HTTP/1.0 200 OK\r\n" "Content-Type: text/html\r\n" "Pragma: no-cache\r\n" "\r\n" "<html>" "<head>" "<META HTTP-EQUIV=\"refresh\" CONTENT=\"1\">" "<title>Zisternenfüllstandsmessgerät ... ;-)</title>" "</head>" "<body>" "$Scm" "</body>" "</html>"), buf); return bfill.position(); } void loop () { word len = ether.packetReceive(); word pos = ether.packetLoop(len); if (pos) // check if valid TCP data is received { //Abstandsmessung: int uS = sonar.ping_median(5); cM = uS / US_ROUNDTRIP_CM; //Serial.print("Abstand: "); //Serial.print(cM); //Serial.println("cm"); ether.httpServerReply(homePage()); // send web page data } } |
So sieht mein fertiges Messgerät aus:
Es würde mich sehr freuen, wenn ihr ein Bild von eurem Nachbau in den Kommentaren postet!
Und das ist die (spartanische) Ausgabe:
… die jedoch super einfach von FHEM ausgelesen und weiterverarbeitet werden kann.
FHEM Implementierung
Mittels nachfolgender Definition steht der Wert inkl. Einheit (cm) im state und im Reading „Zisternenfüllstand“ steht nur der Wert ohne Einheit für weiterführende Berechnungen:
1 2 3 4 5 6 7 8 |
defmod test HTTPMOD http://deine-IP/ 10 attr test userattr reading01Name reading01Regex reading02Name reading02Regex readingEncode attr test enableControlSet 1 attr test reading01Name Zisternenfuellstand attr test reading01Regex <body>(\d*).*<\/body> attr test reading02Name state attr test reading02Regex <body>(.*)<\/body> attr test readingEncode utf8 |
Vielleicht noch ganz kurz als Erklärung:
Die Readings werden mittels Regex ermittelt. Dabei suche ich einerseits nach sämtlichem Text und andererseits nur nach Ziffern (\d) zwischen den body-Tags.
Changelog:
- 07.08.2019
- Anleitung zur Einbindung in Fhem hinzugefügt
- 15.04.2019
- Update der Hardware-Liste.
- 28.08.2018
- Update der Hardware-Liste.
- 04.11.2017
- Update der Hardware-Liste, da einige Artikel nicht mehr verfügbar waren
- Alternative für RJ45 Anschluss finden
Hallo David,
erst mal danke für diesen Beitrag.
Das war genau das was ich gesucht habe 🙂 Also schnell alle Teile bestellt und wie in deinem Beitrag beschrieben zusammengebaut.
Aber ich habe leider ein Problem. Die Funktion sonar.ping_median(5) liefert bei mir immer 0 🙁
Ich weiß, das ist jetzt so eine „lapidare“ Frage, aber: Hast du eine Idee woran das liegen könnte?
Bin Programmierer, allerdings „hauptberuflich“ mit c#. Habe also nicht wirklich eine Idee, wo ich mal nach dem Fehler suchen könnte 🙁
Viele Grüße
Hi Peter,
versuch doch mal die Sonar-Pings zu hören. Mein Ultraschall-Sensor macht bei jeder Messung ein klickendes Geräusch. Somit weißt du schon mal, ob vielleicht bei deiner Verkabelung etwas verkehrt ist (oder der Sensor kaputt ist?).
Welchen Sensor verwendest du?
lg, David
Hallo David,
danke für deine Antwort. Ich habe aber zwischenzeitlich, zumindest was das Programm angeht, einen anderen Weg eingeschlagen. Ich verwende nun anstelle der NewPing-Bibliothek die Bibliothek SoftwareSerial.
Hierfür hatte ich auch ein Beispielprogramm gefunden, welches sich aber lange Zeit weigert. Nachdem ich nun für die SoftwareSerial-Funktionen den Pin 3 und 4 verwende, klappt alles hervorragend.
Gruß, Peter
Hallo Peter,
bin auch gerade dabei alles nachzubauen, habe aber das gleiche Problem wie du, der Arduino gibt mir immer nur 0 zurück. Hast du vielleicht noch einen Link zur Lösung mit Hilfe des SoftwareSerial-Sketches?
Danke und Gruß
Frank
Hallo David,
tolle Anleitung, werde ich demnächst mal ausprobieren. Ich spendiere dem Arduino noch einen Temperatursensor um die korrekte Schallgeschwindigkeit zu ermitteln.
Viele Grüße
Armin
Ja, daran hab ich auch gedacht, den Gedanken aber wieder verworfen, da für die Visualisierung durch meine Raffstores (0-100% geöffnet = Wasserstand in der Zisterne) diese höhere Genauigkeit ziemlich sinnlos ist… 😉 Mir ist es eigentlich nur darum gegangen, dass ich grob im Überblick habe, wieviel Wasser noch in der Zisterne ist.
Solltest du aber den Füllstand in Liter ausrechnen wollen, glaube ich, dass du mit dem Temp. Sensor und der angepassten Formel für die Berechnung des Abstands bestimmt genauere Werte erhalten wirst.
Hallo,
was müsste man alles ändern damit man Ethernet.h nutzen kann? Ich habe leider eine W5100 und mit der funktioniert Ethercard anscheint nicht. Finde aber auch leider keine Lösung da ich überhaupt nicht durchblicke und mit copy paste komme ich hier nicht weiter da alles irgendwie zusammen verschachtelt ist.
Dieses Beispiel habe ich für das W5100 Ethernet Shield gefunden: https://www.arduino.cc/en/Tutorial/WebServer
Macht im Prinzip das gleiche wie mein Beispiel. Du musst nur statt der Schleife nach dem Kommentar „output the value of each analog input pin“ die Abstandsmessung durchführen und mit dem HTML-Code mitausgeben.
Und nicht vergessen die NewPing library und die globale Variable cM zu initialisieren:
NewPing sonar(TRIGGER_PIN, ECHO_PIN);
int cM;
Hallo David!
Habe deinen Füllstandsmesser nachgebaut, funktioniert super, danke für diesen Beitrag.
Du schreibst in deinem Artikel auch, dass der Füllstandswert von der Website einfach von FHEM ausgelesen werden kann.
Darf ich dich da um einen Tipp ersuchen wie du das gemacht hast?
Ich experimentiere schon seit längerem mit HTTPMOD herum, hatte aber bis jetzt keinen Erfolg. Scheinbar bin ich damit am Holzweg 🙁
Würde mich freuen, wenn du mich da auf die richtige Spur führen könntest.
Danke dir, vG Fritz
Hi Fritz,
ich habe eine beispielhafte FHEM-Definition in den Beitrag eingefügt.
lg, David
Hallo David!
Danke für deine Unterstützung, das hilft mir weiter. Bei den RegEx’s bin ich nicht so fit, das hätte ich ohne dein Beispiel nicht hinbekommen. Einen kleinen Schönheitsfehler habe ich noch bei zweistelligen Füllstandswerten. Da kommt der Wert mit einem führenden Leerzeichen daher (ich seh’s so im Logfile), da zieht (\d*).* nicht. Aber das sollte ich doch hinbekommen.
Danke, vG Fritz
<code><body>\D*(\d*).*<\/body>
Erklärung:
Matche <body>
Matche alles, was keine Zahl ist
Matche die Zahl, die danach kommt und gib sie zurück (Capturing Group)
Matche alles, was nach der Zahl kommt bis zum schließenden </body> Tag
lg
Hallo David
Gibt es eine einfache Möglichkeit den Wer per UDP zu versenden?
Grüsse
CHristian
Probier mal die UIPEthernet Library. Hier ein Beispiel für das Senden eines Packets via UDP:
https://codebender.cc/example/UIPEthernet/UdpClient#UdpClient.ino
Hallo David,
sehr schöner Beitrag.
Ich bin auch in der Richtung unterwegs. Wie auf den Fotos erkannbar, hast Du das Anschlusskabel des US-Sensors gekürzt. Ist das problemlos möglich? Ich habe mal probiert, die Leitung um mehrere Meter zu verlängern, kein Erfolg.
mfG
Wolfgang
Hallo Wolfgang,
verkürzen des Kabels ist kein Problem. Aber beim Verlängern könnte ich mir vorstellen, dass das Signal durch den Spannungsabfall im längeren Kabel nicht mehr ankommt.
Das einzige was mir einfällt: Du könntest es mit einem Kabel mit größerem Querschnitt versuchen. Aber keine Ahnung, ob das funktioniert.
lg David
Hallo David,
danke für die Antwort. Wenn ich mich recht erinnere habe ich seinerzeits 0,14qmm-Leitung benutzt. Der Spannungsabfall bei diesen kleinen Strömmen dürfte m.E. nicht den großen Einfluss haben, hat sicherlich andere Gründe.
Nochmals vielen Dank für die schnelle Antwort.
mfG
Wolfgang