OctoPrint-Raspi mit Status-LCD erweitern

Momentan wird mein Anycubic i3 Mega mittels OctoPrint auf einem nackten Raspberry Pi Zero WH angesprochen, den nur ein minimalistischer Halter ziert.

Der Raspi Zero hat den Vorteil, dass er einen sehr geringen Stromverbrauch hat. Es würde gar keinen Sinn machen, ihn hinter eine 433 Mhz- oder WLAN-Funksteckdose zu hängen, da diese auch ca. 1 Watt im Leerlauf benötigen.

Und wenn der Raspberry schon die ganze Zeit läuft, dann kann er doch auch einen Status anzeigen. Mein Anycubic steht im ungeheizten Hobbyraum. Da ist es vielleicht nicht ungünstig, die Temperatur und die Luftfeuchtigkeit im Auge zu haben. Filamente sind ja bekanntlich feuchtigkeitsempfindlich.

Als Feuchtigkeits / Temperatur-Sensor werde ich den DHT11 (hier am Arduino) verwenden.

Dies und die aktuelle Uhrzeit sowie die CPU-Auslastung des Raspi soll mir der Raspi über ein LC-Display anzeigen. 2 mal 16 Zeichen sollten dafür ausreichen. Ein 1602-Display, das ich ja schon vorgestellt habe sollte dafür ausreichen.

Damit die Hintergrundbeleuchtung nicht Tag und Nacht durchleuchtet, will ich einen PIR-Bewegungsmelder dazu verwenden, zu erkennen, ob überhaupt jemand im Raum ist, der etwas ablesen könnte. So sollte die Hintergrundbeleuchtung lange halten.

I-Tüpfelchen wird ein 433-Mhz-Sender sein, mit dem ich die Funksteckdose schalte, an dem der Anycubic-3D-Drucker hängt. In OctoPrint werden ich die Befehle, die hinter den Menüeinträgen "System herunterfahren" und "System neu starten" hängen, so abändern, dass sie nicht den Raspi hoch und runterfahren, sondern die Funksteckdose für den Anycubic ab- und anschalten. Diese verbraucht nämlich 5 bis 10 Watt im Standby, was nicht sein muss.

Zum Schluss soll das Ganze in ein selbstgedrucktes Gehäuse, dass ich neben den Anycubic stelle und so immer im Blick haben kann.

Hardware: I2C-LCD 1602


Diesmal habe ich mir ein 1602A-Display samt I2C-Platinchen huckepack gekauft, das spart doch ungemein Leitungen. Wenn man das Display ohne I2C-Modul anschließt, dann braucht man insgesamt zwölf Kabel (inkluse eines, um das Backlight zu schalten). Mit dem I2C-Modul reduziert sich das auf ganze vier Kabel: die vier vom I2C-Protokoll bekannten SDA, SCL, GND und +5V. Selbst das Backlight kann man über das I2C-Interface ohne extra Leitung schalten. Außerdem bietet das I2C-Modul den Vorteil, dass es schon ein kleines Poti für die Kontrasteinstellung mitliefert.




Das ist dann doch sehr viel bequemer und weniger fehleranfällig beim Anschluss als die gewöhnliche Methode. Ermöglicht wird das durch einen PCF8574 Chip. Dies ist ein 8-Bit-Port-Expander, der an seinen 8 Ports (P0 bis P7) jeweils 8-Bit-Werte ausgeben (bzw. einlesen) kann. Er macht sozusagen aus den zwei I2C-Datenleitungen acht.

Wer sich noch nicht mit dem I2C-Bus auskennt, sollte mal in einen Blick in die entsprechende Anleitung werfen, dort wird auch beschrieben, wie man sich die I2C-Tools auf dem Raspi installiert. Diese Tabelle könnte dabei hilfreich sein.

Das LCD-Modul wird wie folgt angeschlossen: LCD-Modul Kabelfarbe Pin am Raspi Zero GND schwarz GND VCC rot +3.3V (+5V besser nicht, wenn dann höchstens mit ausgelöteten Pullups, wie weiter unten beschrieben) SDA (Data) orange BCM 2 (SDA) SCL (Clock) braun BCM 3 (SCL) Dabei ist der Jumper links an der I2C-Platine natürlich vorher zu entfernen. Durch diesen Anschluss-Trick können wir das Backlight ein- und ausschalten, wie es uns beliebt. Denn geht man z. B. von einer Lebensdauer von 20'000 Stunden für die Backlight-LED aus und lässt diese rund um die Uhr leuchten, dann wird sie in etwas über 2 Jahren das Zeitliche segnen und in den Elektronikhimmel aufsteigen.

Wir überprüfen, ob das LCD richtig angeschlossen ist und funktioniert, indem wir danach suchen: pi@octopi:~ $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- Wie man sieht, meldet es sich auf Port 0x27. Den notieren wir uns, denn darüber müssen wir unser Display ansprechen.

I2C-LCD-Library

Zur Ansteuerung wird das I2C-Interface benutzt. Die dort ankommenden Befehle müssen dann zu Befehlen für den HD44780 Controller des LCD umgewandelt werden und über ein bestimmtes Protokoll an seine Data-Leitungen D4 bid D7 übertragen werden.

Dies leistet die I2C-LCD-Library, die hier heruntergeladen werden kann. Diese wird in das Pi-Home-Verzeichnis kopiert und stellt dann folgende Python-Befehle zur Verfügung: Befehl Bedeutung import i2c_lcd_lib Einbinden der Library lcd = i2c_lcd_lib.lcd(i2cAdresse, Erzeugen eine Instanz namens lcd. Hier wird die 0x27 von Zeilen, Spalten) oben als Adresse übergeben backlight_on() Hintergrundbeleuchtung an (Default) backlight_off() Hintergrundbeleuchtung aus clear() Displayinhalt löschen display_off() Display aus (Inhalt bleibt erhalten) display_on() Display wieder ein cursor_on() schaltet den Cursor aus cursor_blink() lässt den Cursor blinken cursor_off() schaltet den Cursor wieder aus home() nächste Ausgabe bei 0,0 (Zeile 1, Spalte 1) set_cursor(Zeile, Spalte) nächste Ausgabe bei Zeile,Spalte write_string(Text) gibt Text an aktueller Position aus display_string(Text, Zeile, Spalte) gibt Text an angegebener Position aus move_left() verschiebt Inhalt um eine Stelle nach links move_right() verschiebt Inhalt um eine Stelle nach rechts create_char(Adresse, Muster) erzeugt ein selbstdefiniertes Zeichen mit dem ang. Muster an ang. Adresse (vgl. Funktion loadCustomChars()) get_display() Rückgabe, ob Display an oder aus (on/off) get_cursor() Rückgabe, ob Cursor an, aus oder blinkend (on/off/blink) get_backlight() Rückgabe, ob Hintergrundbeleuchtung an oder aus (on/off) get_col_pos() Rückgabe des aktuellen Spalte des Cursorposition get_row_pos() Rückgabe des aktuellen Zeile des Cursorposition lcd_write_cmd(cmd) Low-Level-Kommando-String ans Display senden (vgl. Funktion lcdCmdByte(byte)) lcd_write_data(data) Low-Level-Daten-String ans Display senden (vgl. Funktion lcdByte(byte)) Beim 1. Test des LCD zeigte sich aber dieses Bild:



3.3V sind wohl doch nicht genügend für das Display, denn a) ist der Konstrast und die Helligkeit eher suboptimal und b) flackert die Hintergrundbeleuchtung bei jedem Update (alle 2 Sekunden). Das ist unschön.

Wenn ich das Display aber auf 5V betreibe, stellt sich folgendes Problem ein: Das bidirektionale Protokoll macht die SDA-Leitung auch zu einem Eingang. Wenn ich das LCD mit 5V speise, dann wird es auch Signale mit 5V zum Raspberry schicken. Die GPIO-Ports vom Raspi sollen aber nur bis maximal 3.3V belastet werden.


Also habe ich nur einmal GND und +5V an das LCD angelegt und SDA und SCL gemessen. Dort lagen dann dauerhaft 5.1 Volt an, was dem Raspi bestimmt nicht gut tut. Ich habe zwar eine Videoanleitung gesehen, wie jemand ein genau baugleiches Board an einen Raspi anschloss und das klaglos lief, aber ich habe kein gutes Gefühl, dauerhaft +5.1V an die GPIO-Ports des Raspis anzulegen.

Das Dauer-+5V wird durch zwei Pullup-Widerstände mit 4.7 kΩ (Bezeichnung 472) erzeugt, die auf der I2C-Platine verlötet sind (im oberen Foto gelb markiert).


Wenn man diese auslötet, dann wird SDA und SCL nicht ständig auf +5V gezogen. Das ist auch gar nicht nötig, denn der Raspberry Pi hat ja selbst schon Pullup-Widerstände an den I2C-Ports verbaut.

Nach der kleinen Löt-Amputation habe ich nur noch +0.5V an den SDA und SCL-Pins gemessen. Wer nicht gut mit dem Lötkolben umgehen kann, kann die Widerstände natürlich auch brutal mit einer Printzange zerstören, Hauptsache, die Verbindungen sind unterbrochen.

Jetzt liegen also dauerhaft lediglich 0.5V an und nur, wenn über den I2C-Bus kommuniziert wird, kurzzeitig 5V. Das traue ich dem Raspi zu, dass er das aushält, auch längerfristig.

Mit 5V betrieben ist das Display sehr viel heller, schon fast zu hell und der Kontrast sehr viel besser:



Das die Hintergrundbeleuchtung bei jeder Aktualisierung flackert, dass ist allerdings noch immer so. Das Problem habe ich nicht, wenn ich meine LCDs direkt über 9 Leitungen über meine eigenen Routinen anspreche. Aber mit diesem kleinen Manko werde ich wohl leben müssen, will ich nicht noch einmal alles selbst neu programmieren.

Es hat mir doch keine Ruhe gelassen und ich habe mir den Source-Code der Library doch noch einmal genauer angeschaut und die Ursache für das Flackern gefunden und den Fehler korrigiert. In der bei mir downloadbaren Version der I2C-LCD-Library funktioniert die Anzeige jetzt flackerfrei.

Hardware: PIR-Sensor (HC-SR501)


Über den PIR-Bewegungsmelder und wie man ihn verwendet habe ich ja schon ausführlich berichtet. Auch diesmal wollen wir einen einsetzen, um die Hintergrundbeleuchtung des LCD anzuschalten, sobald eine Bewegung erkannt wird und wieder aus, wenn eine bestimmte Zeit keine Bewegung mehr stattfand.

Das PIR-Modul wird wie folgt angeschlossen: PIR-Modul Kabelfarbe Pin am Raspi Zero VCC rot +5V GND schwarz GND OUT (auf 3.3V begrenzt) braun BCM 24 Mit den Potentiometer können wir Empfindlichkeit und Verzögerung (wie hier beschrieben) einstellen, also ab welchem Entfernung eine Bewegung als solche erkannt werden soll. Beim späteren Einbau in ein Gehäuse müssen wir daran denken, dass der Sensor richtig ausgerichtet ist, nämlich nach vorne und nicht etwa an die Decke.

Um den Bewegungssensor zu testen, benutzen wir folgendes kleines Programm: # -*- encoding: utf-8 -*- # (C) 2018 by Oliver Kuhlemann # Bei Verwendung freue ich mich um Namensnennung, # Quellenangabe und Verlinkung # Quelle: http://cool-web.de/raspberry/ import RPi.GPIO as GPIO # Funktionen für die GPIO-Ansteuerung laden from time import sleep # damit müssen wir nur noch sleep() statt time.sleep schreiben import time import i2c_lcd_lib # für das I2C-Display GPIO.setmode(GPIO.BCM) # die GPIO-Pins im BCM-Modus ansprechen PinPIR=24 # IN PIR-Bewegungsmelder GPIO.setup(PinPIR, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) i2cLCD = 0x27 # I2C-Adresse des LCD lcd = i2c_lcd_lib.lcd(i2cLCD,2,16) try: seksPerMove = 20 # wieviele Sekunden bleibt das Display pro Bewegung an? lastMove = time.time() lcd.clear() lcd.backlight_on() backlight=True # backlight ist an lcd.display_on() while 1: ts=time.time() print "PIR:",GPIO.input(PinPIR) if GPIO.input(PinPIR) == GPIO.HIGH: # Es wurde eine Bewegung festgestellt lastMove = time.time() if backlight == False: lcd.backlight_on() print "on" backlight =True seksUnbewegt = int(ts - lastMove) print seksUnbewegt, backlight if seksUnbewegt > seksPerMove and backlight: lcd.backlight_off() print "off" backlight=False if backlight: # jede Ausgabe schaltet automatisch das Backlight ein lcd.display_string("letzte Bewegung", 0, 0) lcd.display_string("vor ", 1, 0) lcd.display_string(str(seksUnbewegt), 1, 4) lcd.display_string("Sekunden", 1, 7) sleep(1) except KeyboardInterrupt: pass lcd.clear() lcd.backlight_off() GPIO.cleanup() # Programm sauber verlassen und Ressourcen wieder freigeben

Funktioniert wunderbar. Und wie man sieht, ist in diesem Video auch das sekündliche Flackern der Hintergrundbeleuchtung weg.

Hardware: DHT11 (Modul KY-015)


Den DHT11-Sensor habe ich bereits hier beschrieben.. Es handelt sich dabei und einen Kombi-Sensor, der Temperatur und Luftfeuchtigkeit über ein spezielles Protokoll liefert. Wunderdinge in Sachen Genauigkeit darf man von dem Teil nicht erwarten, aber das ist für diese Projekt auch gar nicht nötig.

Der DHT11 kann auch mit 3.3V betrieben werden, ist also Raspi-kompatiblel. Wir schließen ihn wie folgt an: DHT11 Kabelfarbe Pin am Raspi Zero - (GND) blau GND OUT oder S (Signal) grau BCM 10 + (VCC) rot +3.3V (da beide +5V schon belegt) Da das properitäre Protokoll für den DHT11 doch etwas komplizierter ist, sparen wir uns die Arbeit und installieren eine fertige Library, die wird von Github beziehen. ISt Git noch nicht installiert, sollten wir dies jetzt nachholen: sudo apt-get install build-essential python-dev python-openssl git Danach holen wir die Adafruit Library für den DHT11 git clone https://github.com/adafruit/Adafruit_Python_DHT.git Sobald das erledigt ist, wechseln wir in das entsprechende Verzeichnis cd Adafruit_Python_DHT und installieren die Library mit sudo python setup.py install Nachdem der Pi ein bisschen herumgerödelt hat, checken wir anhand eines mitgelieferten Bespielprogramms, ob der Sensor funktioniert und richtig angeschlossen ist. pi@octopi:~/Adafruit_Python_DHT $ cd examples/ pi@octopi:~/Adafruit_Python_DHT/examples $ ls AdafruitDHT.py google_spreadsheet.py simpletest.py pi@octopi:~/Adafruit_Python_DHT/examples $ ./AdafruitDHT.py 11 10 Temp=24.0* Humidity=43.0% Die 11 beim Aufruf von AdafruitDHT.py steht für DHT11 (für den DHT22 wäre es 22) und die 10 gibt den BCM-Port an, an dem die Signal-Leitung des Sensors angeschlossen ist. Wie wir sehen, funktioniert der Sensor und liefert plausible Daten zurück.

Diese werden wir später auf dem LCD ausgeben, um darüber stehts mit einem Blick darauf informiert zu sein.

Folgende Zeilen werden wir dafür später im Programm brauchen: import Adafruit_DHT ... DHT11 = Adafruit_DHT.DHT11 PinDHT11 = 10 ... humidity, temperature = Adafruit_DHT.read_retry(DHT11, PinDHT11) ...

Hardware: 433 Mhz-Sender FS1000A


Wie man Funksteckdosen mit dem Raspi schaltet habe ich ja bereits ausführlich erklärt. Dafür nötig ist nur ein kleines Modul namens FS100A und die 433 Utils nötig.

In der Standardeinstellung der 433 Utils hängt der Sender an Port BCM 17 (WPI 0), an den wir ihn auch anschließen: FS1000A Kabelfarbe Pin am Raspi Zero GND schwarz GND OUT grün BCM 27 VCC rot +5V Die 433Utils installieren wir mit git clone --recursive git://github.com/ninjablocks/433Utils.git cd 433Utils/RPi_utils/ make Überprüfen wir noch schnell, ob wir alles richtig angeschlossen haben mit /home/pi/433Utils/RPi_utils/send 11111 3 1 wobei 11111 der Code der Funksteckdosengruppe ist, die 3 die dritte Dose bezeichnet (meist C genannt) und die 1 für einschalten steht (0 dementsprechend für ausschalten). Hier müssen natürlich noch die richtigen Angaben für eure eigene Dose eingetragen werden.

Wenn das Relais in der Steckdose klackt, dann ist alles richtig verkabelt und die Funkverbindung klappt. Wenn das 433-Sende-Modul über keine Antenne verfügt (wird manchmal vergessen anzulöten), dürfte das nicht weiter schlimm sein, denn der 3D-Drucker steht ja direkt neben unserem Raspi.


Das Schalten der Dose machen wir nicht über unser eigenes Python-Script, auch wenn dieses es könnte über die Funktion funksteckdose (steckdosenNr, onOff), sondern an einem viel günstigeren Platz.

In OctoPrint gibt es ein System-Menü, gekennzeichnet mit einem Ein-Ausschalt-Symbol, dass die Einträge System herunterfahren und System neustarten enthält. Diese sind eigentlich dafür da, den Raspi auszuschalten oder neu zu starten. Da ich den Raspi aber eh die ganze Zeit über laufen lassen will, was wegen des geringen Stromverbrauchs auch kein Problem ist, zweckentfremde ich diese beiden Einträge, oder, wenn man es so sehen will, führe ich sie einer zweckmäßerigeren Verwendung zu.

Über den Schraubschlüssel daneben kommt man in die Einstellungen. Hier wählen wir OctoPint/Server aus.

Normalerweise steht dort unter Befehle: OctoPrint neustarten sudo service octoprint restart System neustarten sudo shutdown -r now System herunterfahren sudo shutdown -h now was wir ändern zu: OctoPrint neustarten sudo service octoprint restart System neustarten /home/pi/433Utils/RPi_utils/send 11111 3 1 System herunterfahren /home/pi/433Utils/RPi_utils/send 11111 3 0 Und schon können wir unseren 3D-Drucker, der in der Funksteckdose steckt mit System neustarten einschalten und mit System herunterfahren ausschalten. Die Warnungen die angezeigt werden, müssen wir entsprechend interpretieren und sind eine Sicherheit, den Drucker nicht ausversehen auszuschalten, wenn noch ein Druck läuft.

Und in Octorpint werden wir sowieso gehen, wenn wir einen Druck starten wollen. Da sind wir dann gleich am richtigen Platz, um den Drucker einzuschalten.

So sieht unsere fertige Schaltung aus:



Dem LCD habe ich drei selbstdefinierte Symbole für Temperatur, Luftfeuchtigkeit und CPU-Auslastung spendiert (von links nach rechts).

So kann der Ausbau natürlich nicht bleiben. Das Ganze muss noch in ein Gehäuse. Das zu entwerfen und 3D zu drucken wird noch ein wenig Zeit in Anspruch nehmen.

Wenden wir uns zuvor der Software für die Anzeige zu:

Sourcecode

# -*- encoding: utf-8 -*- # (C) 2018 by Oliver Kuhlemann # Bei Verwendung freue ich mich um Namensnennung, # Quellenangabe und Verlinkung # Quelle: http://cool-web.de/raspberry/ import RPi.GPIO as GPIO # Funktionen für die GPIO-Ansteuerung laden from time import sleep # damit müssen wir nur noch sleep() statt time.sleep schreiben import time import datetime from sys import exit # um das Programm ggf. vorzeitg zu beenden import os from subprocess import PIPE, Popen import signal # um SIGTERM abfangen zu können import math import i2c_lcd_lib # für das I2C-Display import Adafruit_DHT # für DHT11-Sensor GPIO.setmode(GPIO.BCM) # die GPIO-Pins im BCM-Modus ansprechen Pin433Send=17 # OUT WPI 0 Switch-Lib #Pin433Rcv=27 # IN WPI 2 Switch-Lib PinPIR=24 # IN PIR-Bewegungsmelder PinDHT11=10 # IN DHT11 Temp/Feuchte-Sensor # GPIO-Ports initialisieren GPIO.setup(Pin433Send, GPIO.OUT) GPIO.setup(PinPIR, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.setup(PinDHT11, GPIO.IN) i2cLCD = 0x27 # I2C-Adresse des LCD lcd = i2c_lcd_lib.lcd(i2cLCD,2,16) # LCD-Objekt aus Library instanziieren DHT11 = Adafruit_DHT.DHT11 # DHT11-Objekt aus Library instanziieren def loadCustomChars(): # definiert bis zu 8 eigene Zeichen (ansprechbar über chr(0) bis chr(7) muster = [ 0b00100 , # Temperatur 0b01010 , 0b01010 , 0b01010 , 0b10001 , 0b10001 , 0b01110 , 0b00000 ] lcd.create_char(0, muster) muster = [ 0b00100 , # Luftfeuchtigkeit 0b00100 , 0b01010 , 0b01010 , 0b10001 , 0b10001 , 0b01110 , 0b00000 ] lcd.create_char(1, muster) muster = [ 0b00000 , # CPU-Symbol 0b11111 , 0b01110 , 0b11111 , 0b01110 , 0b11111 , 0b00000 , 0b00000 ] lcd.create_char(2, muster) def funksteckdose (steckdosenNr, onOff): # steckdosenNr = 1 bis 5 (für A bis E) onOff = 1 | 0 proc=os.popen("/home/pi/433Utils/RPi_utils/send 11111 "+str(steckdosenNr)+ " " +str(onOff)) def sigterm_handler(signal, frame): lcd.clear() lcd.backlight_off() GPIO.cleanup() exit(0) # --- Ende Funktionen --- Beginn Hauptprogramm ------------------------------------------- signal.signal(signal.SIGTERM, sigterm_handler) # LCD aus bei SIGTERM loadCustomChars() try: weekdays=["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"] seksPerMove = 120 # wieviele Sekunden bleibt das Display pro Bewegung an? lastMove = time.time() lcd.clear() lcd.backlight_on() backlight=True # backlight ist an lcd.display_on() altDatum="" # zum Zwischenspeichern der angezeigten Daten, altZeit="" # um LCD-Aktualisierungen zu sparen altTemp="" altHumi="" altCPU="" while 1: ts=time.time() if GPIO.input(PinPIR) == GPIO.HIGH: # Es wurde eine Bewegung festgestellt lastMove = time.time() if backlight == False: lcd.backlight_on() backlight =True seksUnbewegt = int(ts - lastMove) if seksUnbewegt > seksPerMove and backlight: lcd.backlight_off() backlight=False if backlight: # jede Ausgabe schaltet automatisch das Backlight ein # Datum, Zeit (mit Wochentag) ts = datetime.datetime.now() weekday= int(ts.strftime("%w")) datum=weekdays[weekday] + ts.strftime(" %d.%m.") zeit=ts.strftime("%H:%M") if datum != altDatum: lcd.display_string (datum,0,0) if zeit != altZeit: lcd.display_string (zeit,0,11) altDatum=datum altZeit=zeit # Temperatur und Luftfeuchtigkeit humidity, temperature = Adafruit_DHT.read_retry(DHT11, PinDHT11) if temperature != altTemp: lcd.display_string (chr(0)+str(int(temperature))+chr(223)+" ",1,0) if humidity != altHumi: lcd.display_string (chr(1)+str(int(humidity))+"% ",1,5) altTemp=temperature altHumi=humidity # CPU-Auslastung proc=os.popen("ps -eo pcpu") lines=proc.readlines() proc.close() cpu=0.0 for i in range (1,len(lines)): cpu += float(lines[i]) if cpu > 100: cpu = 100 # weil mehr nicht sein kann if int(round(cpu)) != altCPU: lcd.display_string (chr(2)+ str(int(round(cpu))) + "% ",1,11) altCPU=int(round(cpu)) sleep(1) except KeyboardInterrupt: pass lcd.clear() lcd.backlight_off() GPIO.cleanup() # Programm sauber verlassen und Ressourcen wieder freigeben Ich habe das Programm unter octopi-monitor.py in /home/pi gespeichert. Fehlt zu guter Letzt nur noch, dass unser Python-Programm automatisch gestartet wird, sobald OctoPi hochgefahren wird. Das geht am einfachsten, indem wir die Datei /etc/rc.local editieren sudo nano /etc/rc.local und dort die Zeile python /home/pi/octopi-monitor.py & vor die Zeile exit 0 eintragen.

Jetzt wird unser Python-Script beim Hochfahren mitgestartet. Sobald sich das LCD einschaltet, wissen wir zudem, dass das System hochgefahren ist und OctoPrint bald zur Verfügung steht. Das wird der Fall sein, wenn die CPU-Auslastung weit unter 100% gefallen ist.

3D gedrucktes Gehäuse


Fehlt nur noch ein Gehäuse, um alle Komponenten unterzubringen. Wer einen 3D-Drucker hat, findet hier die entsprechenden Dateien, um sich die notwendigen Teile dafür auszudrucken.

Diese sind: Dabei kommt die Frontplatte auf die schrägen Stützen in der Basis, was eine angeschrängte Frontplatte ergibt, bei der sich das Display besser ablesen lässt.

Das Frontplattenabschluss-Prisma wird dann einfach in die noch freie, dreieckige Aussparung gesteckt.





Zuerst sollte man die Frontplatte drucken (das ist das untere Teil im Bild oben).

Von der Rückseite aus sollte man genau den Metall-Rahmen des LC-Display auf die linke Seite stecken können. Rechts daneben sollte genau der Dom des PIR passen. Der Jumper sollte dabei zum LCD zeigen, sonst wird er auf der Stützschräge aufliegen und die Frontplatte geht links nicht ganz rein. Bitte nur sanfte Gewalt anwenden. Die Teile sollten nicht zu schwer in die Aussparungen gehen, aber ihnen trotzdem Halt geben.

Eventuell ist die PIR-Platine ein breiteres Modell. Dann muss man gegebenfalls die Trennleiste zwischen LCD und PIR mit einer Printzange rauszwacken, was nicht schlimm ist, weil man das von vorne ja nicht sieht. Sind die Teile zu locker - es gibt ja immer Fertigkeitstoleranzen, dann hilft Klebeknete in den Ecken für die Fixierung.


Der PIR-Dom sollte dann auf der Vorderseite wie auf dem Bild herausschauen. Das LCD sollte möglichst plan mit der Frontplattenoberfläche abschließen. Ich habe schwarzes Filament für den Druck genommen, das es zum Einen zum Anycubic i3 Mega und zum Anderen zum schwarzen LCD-Rahmen farblich passt. Weiß oder eine andere Farbe sieht aber bestimmt auch nicht schlecht aus.

Die bestückte Frontplatte können wir jetzt erstmal zur Seite legen. Bestücken wir jetzt die Basis.


Auf der Rückseite unten fällt das Licht durch die Löcher für die beiden USB-Anschlüsse des Raspberry Pi Zero WH. Gegenüber davon sieht man zwei Zapfen und eine Stützleiste.

Der komplett verkabelten Raspi - es empfiehlt sich, die Dupont-Kabel irgendwie gegen herausrutschen zu sichern, etwa durch ein bisschen Klebestreifen - mit ein bisschen Klebeknete an der Unterseite wird jetzt mit den USB-Port zuerst in die beiden USB-Löcher bugsiert. Dabei schräg von oben vorgehen.

Danach den schrägen Teil langsam herunterlassen, so dass die Zapfen in die Löcher des Raspi an der Seite mit der GPIO-Pfostensteckerleiste kommen. Andrücke, damit die Klebeknete haftet - Raspi steht. Die Stützleiste hinten ist übrigens dafür da, dass man auch ein klein wenig Kraft beim Einstecken der USB-Anschlüsse benutzen kann und die zarten Zapfen nicht gleich abbrechen.


Rechts im Gehäuse ist ein Ausschnitt für den DHT11-Sensor. Da passt genau das blaue Teil vom Sensor-Modul hindurch. Fixiert wird das Teil wieder mit Klebeknete - wem eine irreversible nichts ausmacht, darf auch Sekundenkleber verwenden.

Je mehr von blauen Teil außen hängt, desto besser; schließlich wollen wir nicht die Gehäuseinnentemperatur messen.

Links in der Ecke neben dem Raspi ist noch Platz für den 433 Mhz-Sender. Auch hier sorgt ein bisschen Klebeknete für den nötigen Halt.


Nun werden Basis und Frontplatte verheiratet...

Dazu die beiden noch übrigen Headerkabel für PIR und LCD in die Teile in der Frontplatte einstecken ...







... und dann die Frontplatte mit dem PIR links oben auf der eingebauten Schräge einsetzen. Ich habe übrigens alles 10 cm lange Dupont-Kabel verwendet. Länger müssen sie gar nicht sein.

Oben bleibt dann eine Aussparung über die gesamte Breite, die sich nach unten hin verjüngt. Ganz unten sollte ungefähr eine ca. 1 mm breite Spalte sein. Wer Angst vor einem Wärmestau hat und dass sich der Prozessor überhitzt (ich sehe da keine wirkliche Gefahr), kann das jetzt so lassen.

Oder aber man setzt das Frontplattenabschluss-Prisma ein, dass genau in die Lücke hineinpassen sollte, wenn die Frontplatte plan und vorne in der Basis abschließt. Das sieht dann noch besser aus und fixiert die Frontplatte, so dass nichts mehr wackelt. Komplett sieht die Gehäusefront dann so aus:



Wer sich jetzt fragt, wer er das Teil je wieder auseinanderbekommen soll, wo jetzt doch alles so schön plan ist und man nirgend reinkommt, um was herauszuhebeln... Öffnen ist so simpel wie genial: einfach ein bisschen auf die Gehäuserückseite oben drücken und einem kommt das Prima schon entgegengeflogen. Dann kann man die Frontplatte wieder ganz einfach heruasnehmen und kommt an alles heran.



Neben dem Anycubic macht der OctoPrint-Server jetzt doch gleich einen viel besseres Eindruck und hat zudem einen praktischen Mehrwert.

Die Verkabelung ist einfach. Der linke USB-Port (von der Vorderseite aus gesehen) ist Power - hier wird der Raspi über Mikro-USB-Kabel von einem USB-Ladegerät gespeist. Und in den rechten USB-Port kommt ein OTG-Adapter und daran ein USB-B-Kabel, dass in den Drucker kommt. Fertig!