Der digitale Öltankmesser
Es wird mal Zeit das ich euch berichte was ich in den letzten tagen so gemacht habe, und warum ich nichts geblogt habe. Der Grund ist relativ einfach – ich habe wieder mal programmiert und das ist eine etwas längere Geschichte.
Wie wir alle wissen, wird ja Energie teurer. Ich habe schon in den letzten Jahren tendenziell weniger Energie verbraucht, mein Büro, in dem ich den größten Teil des Tages bin herunter geregelt wenn ich es mehr als eine Stunde lang nicht benutze, dieses Jahr habe ich die Heizung erst am 10.11 eingeschaltet und die Temperatur in den Räumen zwischen 18 und 19 Grad geregelt, im Schlafzimmer waren es, als es nun so kalt war, sogar nur 12 Grad. Trotzdem interessiert mich natürlich der Ölverbrauch. Ich habe einen uralten Tank, der 7.000 l fasst. Da ich in den letzten sechs Jahren nur zwischen 1.450 und 1.550 l pro Jahr brauchte und immer alle zwei Jahre nachtanke bis der Füllstandsensor auslöste, war mir bisher der aktuelle Füllstand egal. Zuerst kaufte ich einen einfachen Füllstandsensor mit Schwimmer. Der zeigt aber die Füllung nur auf etwa 5 bis 10 cm an, das ist zu ungenau, das können bis zu 500 l Unterschied sein. Also kam in mir der Wunsch auf doch einen eigenen digitalen Messer zu „maken“.
Ich fing erst mal an in einem Sensorkit herumzukramen das ich mal vor Jahren gekauft habe, aber nach einigen Tests nie weiter verwendet habe. Doch da war Fehlanzeige. Es gibt eine Lichtschrankenmessung und einen „Hinderniserkennugssensor“, aber nichts womit man Abstände messen kann. Immerhin habe ich einige Teile aufgebaut und getestet um mich vertraut zu machen, darunter einen Button, schließlich will ich den Messwert auf Knopfdruck speichern. Anders als beim ersten Versuch programmierte ich direkt in Pascal (Lazarus-IDE) anstatt Programme die in C oder Python als Beispiele vorliegen, zu starten. Nach einigen Tests fand ich auch die zugehörigen Bibliotheken, die auf der C-Bibliothek WiringPi basieren. Schon da stellte ich ein Manko des Buttons fest: er prellt, selbst wenn man ihn nach einer Sekunde nochmals abfragt, signalisiert er „gedrückt“. Vielleicht ist es aber auch ein Fehler der Verkablung: ich hatte drei Sachen angeschlossen, jedes braucht eine Spannungsversorgung von 5 V und der Button war der einzige der obwohl für 5 V spezifiziert, auch bei 3,3 V funktionierte – es gibt nur zwei 5 V Pins beim Raspberry Pi.
Auf den Raspberry Pi fiel meine Wahl weil ich etliche rumliegen habe (Modell A+,B, 2, 3 und 4) und zudem ich schon von meiner Wetterstation schätzen lernte das ich alles bis auf das hardwarespezifische auch auf dem PC erstellen kann und dann auf dem Raspberry nur kompilieren muss. Gegen Arduino sprach, das ich für einige schon angedachte Funktionalitäten – Speichern der Werte in einer Textdatei auf dem Massenspeicher und Übertragung als HTML Datei auf einen FTP-Server – den Arduino beträchtlich erweitern müsste. Die Wahl fiel auf einen Pi 3, ganz einfach weil sein Gehäuse Aussparungen an den GPIO Pins hat – jedes Modell des Raspberry hat leider etwas andere Anschlüsse sodass jedes sein eigenes Gehäuse braucht.
Dann habe ich gesucht. Wie man wohl die Füllhöhe messen kann und kam bald auf Ultraschallsensoren. Gängig ist der HC-SR04. Doch der war für mich nicht brauchbar. Er hat wie man auf Angeboten sieht einen Sender und Empfänger auf einer kleinen Platine. Die Platine ist 4 cm breit. Damit passt er nicht durch die Öffnung des Entlüftungsstutzen von 1,35 Zoll (31,8 mm) Durchmesser, von der Gefahr der Schrägen Ausrichtung ganz zu schweigen. Ich fand aber heraus, das es auch eine andere Bauform gibt, der hat Empfänger und Sender in einem Bauteil und nur 1,8 cm Durchmesser, zudem hängt er an einem 2,5 m langen Kabel was auch nicht unpraktisch ist. Der Sensor JSN-SR04T war etwas teurer, aber was solls. Weil sich der Button als prellend erwies, kaufte ich noch ein Numpad um nicht eine ganze Tastatur herumzutragen. Mit 16 Tasten kann man dann auch noch mehr machen – mir schwebte eine Taste für Lesen, eine für Speichern und eine für Shutdown vor. Es gibt zwar auch Minitastaturen, die man direkt an die GPIO Leiste anschließt, aber die sind genauso teuer und angesichts der wenigen Spannungspins wollte ich da keine Experimente machen.
Dann brauche ich noch ein Display. Da hatte ich schon eines, mal gekauft für ein MP3-Player Projekt auf Basis des Raspberry. Nur 3,5 Zoll groß und mit 360 x 480 Punkten, aber es sollte ja nicht viel anzeigen. Leider zeigte das bei einem Test nichts an, ich sah auf der Website nach und dann erinnerte ich mich: es gab damals ein Image für die SD-Karte mit dem kompletten Betriebssystem und Treiben zum herunterladen. Das kam nun nicht in Frage, das war 2017 und ich wollte schon aktuelle Software einsetzen. Also kaufte ich noch ein Zweizeilen LCD-Display dazu. Dazu eine neue schnelle SD-Karte – das deren Geschwindigkeit wichtig ist, weiß ich seit ich mal wirklich eine schnelle für den Raspberry 4 gekauft habe.
Der Sensor kam als erstes an, womit ich anfangen konnte zu experimentieren. Ein Python Beispiel im Netz war schnell in Objekt-Pascal übersetzt und nachdem ich rausfand, das Python eine andere Nummerierung der Pins nutz, als die WiringPi Bibliothek lief es auch. Allerdings mit Distanz Null, während die Messungen unter Python korrekt waren. Die Ursache war mir gleich klar, weil ich vor Jahren mal für einen Kunden eine Messwerterfassung über den Parallelport schrieb und da war exaktes Timing wichtig: die „normalen“ Timer von Betriebssystemen, die auch von Lazarus als Komponente TTimer genutzt werden, sind viel zu grob. Unter Windows liegt die Genauigkeit des Standardtimers nach Microsoft bei 10 bis 16 ms, in der Zeit legt der Schall 340 bis 500 cm zurück. Die Messung funktioniert so, das man einen Triggerpegel erst auf „High“ legt und dann auf „Low“ zieht. Dann sendet der Sensor die Schallwellen aus und man muss die Zeit stoppen bis das Signal wieder auf Low geht. Ohne präzisen Timer geht da gar nichts. Besonders ärgerte mich, das Python da genauer war, offensichtlich wie ich am Quelltext sah, auch eine Routine hatte, die den Trigger 10 µs lang auf High setzte, während Lazarus minimal 1 ms lange Pausen machen kann. Dabei kenne ich Python als langsam – den einzigen Kontakt den ich vorher hatte war eine Python Unit für die Runge-Kutta-Feldberg-45 Methode für die Integration von Bahnen von Himmelskörpern die ich in Pascal umsetzte und als Test habe ich auch das Python Programm laufen lassen – es war 170-mal langsamer.
Ich suchte nach einem schnelleren Timer, fand den Epiktimer, der war besser, aber die Abstände waren immer noch zu lang und zwar bei mehreren Messungen um 20 cm, also um 5-6 ms. Ich hätte mit dem Offset leben können, aber das war mir zu unsicher, wollte ich doch zentimetergenaue Messungen haben und da dann pauschal 20 cm abziehen? Nein Danke!
Inzwischen war auch die SD-Karte angekommen und die beiden LCDs (ich brauche nur eines, aber das war das billigste Angebot). Zuerst wollte ich erst mal die alte SD-Karte auf die neue umspielen mittels auslesen am PC und schreiben des Images auf die neue. Dabei brach ein Stückchen ab und sie war kaputt. Ich hasse Micro-SD Karten. Neben dem Gefummel verliert man sie leicht und sie sind eben extrem empfindlich. Also alles komplett neu installieren und den Code nochmal schreiben.
Inzwischen habe ich mich entschlossen nun doch alles in Python zu machen, obwohl ich die Sprache nicht beherrsche, allerdings mit reduziertem Ziel, nur einer Messung, nicht abspeichern und auch kein FTP auf meinen Webserver wie unter Lazarus geplant. Das ging recht schnell, das Programm für das LCD habe ich einfach um den Python Code für die Messung ergänzt und die Ausgabe aufs LCD-Display umgeleitet. Das nächste war die Anbindung des Keypads. Erste Überraschung: es gibt im Standard Python keine Routine die signalisiert ob eine Taste gedrückt ist ohne gleich eine Eingabe zu erwarten und so das Programm zu stoppen. So was kenne ich nicht. Selbst die älteste Turbo Pascal Version mit der ich es zu tun hatte (Version 3,02, das war 1986) kannte schon eine Befehl: Read(kbd, Taste). Es gab zwar im Netz Codes mit einem „Keyboard“ Modul, doch das gab es bei meiner Standardinstallation nicht und selbst als ich es über pip und (nachdem das nicht funktionierte) mit github nachinstallierte und rebootete wurde der Befehl bemängelt. Also muss wieder der Button dazu, was den Drahtverhau vergrößert.
Immerhin das ging, wenngleich in der Regel nach Knopfdruck gleich dreimal gespeichert wurde. Mittlerweile hatte ich auch herausgefunden wie man unter Python Dateien anlegt, das ist relativ straight zu anderen Programmiersprachen. Mit etwas Gefummel bekam ich auch den gewünschten ftp Upload hin. Das es nur ein Button ist, ist nun etwas mehr störend, denn nach einigen Tests kam in mir der Wunsch auf, das man doch die Protokolldatei für den realen Einsatz doch löschen sollte, da stehen nun etliche Tests drin. Okay, das werde ich nun manuell über Remote Desktop machen. Das Problem des Prellens ist geblieben, manchmal ist eine Zeile in der Datei, manchmal sind es drei. Als weiteres Problem habe ich schon am Anfang identifiziert, dass der Sensor ab und an Ausreißer hat. So habe ich den Code so angepasst, das ich 10 Werte im 0,1 s Sekunden Abstand messe und dann alle die lösche die mehr als 1 cm vom Mittelwert abweichen. Verwendet wird dann der Mittelwert der restlichen Werte. Dabei habe ich noch was neues entdeckt: Python ist die einzige Sprache die ich seit 1986 kennengelernt habe, die keine „repeat-Schleife“ (in c do … while) hat, also eine „annehmende Schleife“ die mindestens einmal durchläuft bevor die Bedingung geprüft wird. Gut kann man durch eine while-Schleife (in c: while … do) ersetzen, ist aber umständlich. Ich sehe das als ein fundamentales Sprachfeature.
Am Schluss noch etwas an der Ausgabe gefeilt – zwei Zeilen mit je 16 Zeichen auf dem LCD Display ist etwas wenig, ich hätte wohl das 20 x 4 Display nehmen sollen. Dann suchte ich nach einer Lösung das ganze portabel zu machen. Ich kam drauf ein Block Verpackungsstryophor auszuhöhlen. Die Öffnung orientiere ich nach der Größe der Powerbank als Stromversorgung plus Kabel. Immerhin Sensor. LCD und Button konnte ich dank Löcher in den Platinen mit kleinen Bildernägeln festpinnen. Die Sensorplatine ist so schräg drin, weil sie auf der Rückseite an einer Seite einen Stecker hat und ich den in die Vertiefung platziert habe.
Dann heute die Probe – und es klappte, nun ja im großen und ganzen. Sobald sich der Raspberry Pi abrupt bewegt, aufgetreten beim Absetzen, war das Display leer (als Funktionstest läuft mit dem Programmstart die Messung in einer Endlosschleife – das Programm habe ich als Dienst bei etc/init.D mit einem Shellscript registriert). Stromversorgung abgezogen und angesteckt und es lief wieder (ich habe noch einen Resetbutton bei dem Sensorpaket, mal sehen ob ich den noch unterbringen kann), auf den Knopf gedrückt und es kam die Meldung „Speichern“. Danach aber kein „Gespeichert“, was erscheint, wenn auch die Übertragung auf den FTP Server erfolgreich war. Ich vermute im Tankraum unter sehr dicken Kellerwänden, ist der WLAN Empfang weg. Aber die Datei ist ja lokal vorhanden und kann so leicht wieder hochgespielt werden.
Es geht noch weiter. Ich will die Tabelle, die ich nur auf Papier habe, gleich als Messdaten ins Programm eingeben. Weil der Tank ein Zylinder ist ist das nicht linear. Als Hauptmanko bleibt das der Einfüllstutzen natürlich nochmals einige Zentimeter in der Höhe addiert. Ich kann das außen messen, aber nicht innen und ich weiß auch nicht wie voll der Tank bei der letzten Füllung war – der Füllstandsensor wird sicher auslösen bevor der Tank ganz voll ist, sodass so leicht einige hundert Liter Differenz auftreten können. Doch den Wert kann ich erst bei der nächsten Füllung ermitteln. Ideal wäre ein zweiter Sensor der die Flüssigkeit durchdringen kann und erst von der Metalloberfläche reflektiert wird. Vielleicht kennt unter den Lesern ja jemand so einen Sensor, passend für den Raspberry?
Was kam raus: ich habe noch 3.798 Liter, das heißt ich habe in den letzten zwei Wintern und seit Winterbeginn rund 3200 l verbraucht, was zu den 2900 l passt die ich bei der letzten Füllung vor zwei Jahren nachtankte.
Anbei einige Fotos, bevor Beschwerden kommen: handwerkliches Arbeiten gehört nicht zu meinen Stärken. Ich bin mehr der geistige Programmierertyp. Immerhin, ich habe wieder Lust bekommen. Vielleicht verwirkliche ich noch mal den Plan eines MP3 Players – das 3,5 Zoll Display habe ich ja noch und nun auch eine Tastatur, da müsste das möglich sein.
Statt Arduino oder RPi käme auch ein ESP32 in Frage, das ist ein Mikrokontroller mit WLAN (oder Ethernet) und Bluetooth, das sich leicht über Arduino IDE programmieren lässt.
Zum justieren Ihrer Software können Sie die Füllhöhe des Öltanks 2-3 mal mit einem Zollstock messen, und dann jeweils direkt hinterher mit Ihrem Raspi.
Die Summe sollte dann jeweils gleich sein.
Die Wetterdaten jetzt nicht mit dem füllstand kombinieren.