Hier geht es zum --> Teil 2.
Hier ist Teil 1:
Vorwort:
Das alte Tutorial wandert bald ins Archiv, da ich hier ein neues mit einigen Verbesserungen schreibe.
Verwendung findet weiterhin ein Zero2W, ein BME280, ein MCP3208 und ein 8-Kanal-Relaisboard. Als OS habe ich hier Bullseye mit PHP 8.
Ich verwende hier nur die ersten 3 Kanäle des MCP3208 und nur die ersten beiden Relais. Die weiteren Kanäle und Relais kann man nach dieser Anleitung hoffentlich selbst belegen.
Diese Anleitung ist für eine 12 Voltbatterie an Kanal 0, die 5-Voltspannung des Raspberrys an Kanal 1 und eines 7s-Li-Ion-Akkus an Kanal 2, mit max. 15 Volt Eingangsspannung für die 12 Voltbatterie an Kanal 0, maximal 5,4 Volt für die Spannung des Raspberrys an Kanal 1 und maximal 30 Volt für den 7s-Li-Ion-Akku an Kanal 2. Die Werte hängen letzen Endes aber von der Auswahl der Spannungsteiler an den Eingängen des MCP3208 ab.
Habt ihr nur ein 2er-Relaisboard, könnt ihr euch die Einträge Relais 3 bis 8 sparen.
Der MCP3208 könnte zwar auch mit 5 Volt arbeiten, da die GPIOs jedoch nur 3,3 Volt vertragen, betreiben wir ihn auch nur mit 3,3 Volt.
Achtung:
Niemals dürfen mehr als 3,3 Volt am MCP3208 ankommen, bei höheren Spannungen immer mit Spannungsteilern arbeiten.
Zum Betrieb des MCP3208 benötigen wir zusätzlich zu den 3,3 Volt und GND auch noch die BCM GPIOs 8, 9 ,10 und 11 für SPI.
Der MCP3208 hat eine 12-Bit-Auflösung, wenn wir also an einen Kanal 3,3 Volt anlegen, bekommen wir den Wert 4095 geliefert. (0 bis 4095).
Ich setze mal voraus, dass der Pi mit PiOS läuft, up to date ist und läuft, SPI und I2C mit raspi-config aktiviert wurde, deutsche Tastatur eingestellt ist, wir uns in /home/pi befinden und im Terminal als User pi angemeldet sind.
Hauptteil:
Ich benutze hier den GPIO BCM 18, um das Relais1 zu schalten und GPIO BCM 23 für Relais 2, wie z.B. hier zu sehen ist.
Relais 3-8 sind an BCM GPIO 24,25,12,16,20 und 21.
Leider gibt es unter Bullseye den Befehl gpio readall nicht mehr. ¯\_(ツ)_/¯
Aber hier gibt es ein Script, das mit pigiod läuft.
Zuerst öffne ich mit sudo crontab -e den crontab von root und erzeuge damit schon beim boot die nötigen Dateien im RAM, damit sie vorhanden sind und ändere die Rechte der Dateien, damit sie dem User pi gehören und die SD-Karte nicht kaputtgeschrieben wird.
@reboot touch /dev/shm/relais1_status.txt && chown pi:pi /dev/shm/relais1_status.txt
@reboot touch /dev/shm/relais2_status.txt && chown pi:pi /dev/shm/relais2_status.txt
@reboot touch /dev/shm/relais3_status.txt && chown pi:pi /dev/shm/relais3_status.txt
@reboot touch /dev/shm/relais4_status.txt && chown pi:pi /dev/shm/relais4_status.txt
@reboot touch /dev/shm/relais5_status.txt && chown pi:pi /dev/shm/relais5_status.txt
@reboot touch /dev/shm/relais6_status.txt && chown pi:pi /dev/shm/relais6_status.txt
@reboot touch /dev/shm/relais7_status.txt && chown pi:pi /dev/shm/relais7_status.txt
@reboot touch /dev/shm/relais8_status.txt && chown pi:pi /dev/shm/relais8_status.txt
@reboot touch /dev/shm/temperatur.txt && chown pi:pi /dev/shm/temperatur.txt
@reboot touch /dev/shm/luftdruck.txt && chown pi:pi /dev/shm/luftdruck.txt
@reboot touch /dev/shm/luftfeuchtigkeit.txt && chown pi:pi /dev/shm/luftfeuchtigkeit.txt
@reboot touch /dev/shm/mcp3208_ch0.txt && chown pi:pi /dev/shm/mcp3208_ch0.txt
@reboot touch /dev/shm/mcp3208_ch1.txt && chown pi:pi /dev/shm/mcp3208_ch1.txt
@reboot touch /dev/shm/mcp3208_ch2.txt && chown pi:pi /dev/shm/mcp3208_ch2.txt
@reboot touch /dev/shm/mcp3208_ch3.txt && chown pi:pi /dev/shm/mcp3208_ch3.txt
@reboot touch /dev/shm/mcp3208_ch4.txt && chown pi:pi /dev/shm/mcp3208_ch4.txt
@reboot touch /dev/shm/mcp3208_ch5.txt && chown pi:pi /dev/shm/mcp3208_ch5.txt
@reboot touch /dev/shm/mcp3208_ch6.txt && chown pi:pi /dev/shm/mcp3208_ch6.txt
@reboot touch /dev/shm/mcp3208_ch7.txt && chown pi:pi /dev/shm/mcp3208_ch7.txt
@reboot touch /dev/shm/intervall_bme280.txt && chown pi:pi /dev/shm/intervall_bme280.txt
@reboot touch /dev/shm/intervall_mcp3208_ch0.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch0.txt
@reboot touch /dev/shm/intervall_mcp3208_ch1.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch1.txt
@reboot touch /dev/shm/intervall_mcp3208_ch2.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch2.txt
@reboot touch /dev/shm/intervall_mcp3208_ch3.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch3.txt
@reboot touch /dev/shm/intervall_mcp3208_ch4.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch4.txt
@reboot touch /dev/shm/intervall_mcp3208_ch5.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch5.txt
@reboot touch /dev/shm/intervall_mcp3208_ch6.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch6.txt
@reboot touch /dev/shm/intervall_mcp3208_ch7.txt && chown pi:pi /dev/shm/intervall_mcp3208_ch7.txt
@reboot touch /dev/shm/cputemp.txt && chown pi:pi /dev/shm/cputemp.txt
############################################################
Display More
Mit Strg+x speichern, mit j bestätigen und Enter drücken.
Hinweis:
Die vielen Dateien sind nötig, da wir später auch auf der Webseite sehen können, wie der aktuelle Zustand der Relais ist, wann diese zuletzt geschaltet wurden.
Zudem wird dort die Temperatur, der Luftdruck und die Luftfeuchtigkeit angezeigt und wann diese Werte zum letzten Mal gemessen wurden.
Desweiteren werden wir eine weitere Webseite erstellen, auf der wir die Einstellungen einsehen können, z.B. in welchen Intervallen die Spannungen an den einzelnen Kanälen des MCP3208 gemessen werden und in welchem Intervall der BME280 ausgelesen wird.
Nachdem die crontab von root bearbeitet wurde, nehmen wir uns nun die crontab des Users pi vor, indem wir sie mit crontab -e aufrufen.
Dort sorgen wir dafür, dass alle Relais beim Start des Systems erst einmal ausgeschaltet werden und die Python-Scripte für den BME280 und den MCP3208 gestartet werden:
@reboot /usr/bin/python3 /home/pi/relais1_aus.py
@reboot /usr/bin/python3 /home/pi/relais2_aus.py
@reboot /usr/bin/python3 /home/pi/relais3_aus.py
@reboot /usr/bin/python3 /home/pi/relais4_aus.py
@reboot /usr/bin/python3 /home/pi/relais5_aus.py
@reboot /usr/bin/python3 /home/pi/relais6_aus.py
@reboot /usr/bin/python3 /home/pi/relais7_aus.py
@reboot /usr/bin/python3 /home/pi/relais8_aus.py
@reboot /bin/sleep 30 && /usr/bin/python3 /home/pi/bme280.py
@reboot /bin/sleep 30 && /usr/bin/python3 /home/pi/ch0.py
@reboot /bin/sleep 30 && /usr/bin/python3 /home/pi/ch2.py
@reboot /bin/sleep 30 && /usr/bin/python3 /home/pi/ch1.py
* * * * * /home/pi/cputemp.sh
####################################
Display More
Nun müssen wir die Dateien erzeugen, welche beim nächsten Systemstart aufgerufen werden.
Beginnen wir mit Relais 1, indem wir mit nano /home/pi/relais1_aus.py eine Datei erzeugen:
#!/usr/bin/env python3
from RPi import GPIO as gpio
gpio.setwarnings(False)
gpio.setmode(gpio.BCM)
gpio.setup(18, gpio.OUT)
gpio.output(18, gpio.HIGH)
with open('/dev/shm/relais1_status.txt', 'w') as relais1:
relais1.write('1')
Dieses Script wird gleich nach dem Start aufgerufen und sorgt dafür, dass Relais 1 an BCM GPIO 18 ausgeschaltet ist, denn auch wenn das Relaisboard erst schaltet, wenn der entsprechende GPIO auf LOW gezogen wird, ist der GPIO-Status vorher nicht definiert, man erkennt das am leichten glimmen der LEDs auf dem Relaisboard.
Nach Aufruf der Datei erlischt die LED auf dem Board, somit ist der Status definiert und das Relais 1 ist definitiv aus.
Zusätzlich wird der Status in der sich im RAM befindlichen Statusdatei eingetragen, hier eine "1" für "aus".
Die Datei muss jetzt nur noch mit chmod +x /home/pi/relais1_aus.py ausführbar gemacht werden.
Das gleiche machen wir mit nano /home/pi/relais1_an.py zum anschalten des ersten Relais:
#!/usr/bin/env python3
from RPi import GPIO as gpio
gpio.setwarnings(False)
gpio.setmode(gpio.BCM)
gpio.setup(18, gpio.OUT)
gpio.output(18, gpio.LOW)
with open('/dev/shm/relais1_status.txt', 'w') as relais1:
relais1.write('2')
Hier wird der GPIO 18 auf LOW gezogen, damit schaltet das Relais 1 an, außerdem wird eine "2" für "an" in die Statusdatei eingetragen.
Auch hier wieder speichern mit Strg + x und anschliessend ausführbar machen mit chmod +x /home/pi/relais1_an.py, dieses Spielchen wiederholen wir jetzt für alle weiteren Relais, je nachdem, wieviele Relais euer Relaisboard hat, bei mir sind es 8 Relais.
Kommen wir zum MCP3208, zum auslesen des SPI benötigen wir diese Datei, welche wir mit nano MCP3208.py anlegen:
#!/usr/bin/env python3
from spidev import SpiDev
class MCP3208:
def __init__(self, bus = 0, device = 0):
self.bus, self.device = bus, device
self.spi = SpiDev()
self.open()
self.spi.max_speed_hz = 1000000 # 1MHz
def open(self):
self.spi.open(self.bus, self.device)
self.spi.max_speed_hz = 1000000 # 1MHz
def read(self, channel = 0):
adc = self.spi.xfer2([ 6 | (channel&4) >> 2, (channel&3)<<6, 0])
data = ((adc[1]&15) << 8) + adc[2]
return data
def close(self):
self.spi.close()
Display More
Strg+x zum speichern, mit j und Enter bestätigen.
Ausführbar machen mit chmod +x /home/pi/MCP3208.py
Diese Datei wird dann von unseren Kanalauslesescripten benutzt, um das SPI auszulesen.
Jetzt legen wir das Script an, das liest uns Kanal 0 des MCP3208 aus und schaltet Relais 1 an oder aus, je nachdem, wieviel Spannung anliegt.
nano /home/pi/ch0.py
#!/usr/bin/env python3
from MCP3208 import MCP3208
from datetime import datetime as DateTime
from RPi import GPIO as gpio
import time
import datetime
import subprocess
adc = MCP3208()
EINSCHALTSPANNUNG = "/home/pi/einschaltspannung_ch0.txt"
AUSSCHALTSPANNUNG = "/home/pi/ausschaltspannung_ch0.txt"
POWER_PIN = 18
INTERVALL_DATEI = "/home/pi/intervall_mcp3208_ch0.txt"
SPANNUNG = "/dev/shm/mcp3208_ch0.txt"
RELAIS_AUS = "/home/pi/relais1_aus.py"
RELAIS_AN = "/home/pi/relais1_an.py"
gpio.setmode(gpio.BCM)
gpio.setup(POWER_PIN, gpio.OUT, initial=gpio.HIGH)
def main():
while True:
with open(INTERVALL_DATEI, "r") as intervalldatei:
intervall = int(intervalldatei.read())
print("Ausleseintervall beträgt {0} Sekunden\n" .format(intervall))
with open(AUSSCHALTSPANNUNG, "r") as minvoltagedatei:
minvoltage = float(minvoltagedatei.read())
print("Mindestspannung beträgt {0} Volt\n" .format(minvoltage))
with open(EINSCHALTSPANNUNG, "r") as maxvoltagedatei:
maxvoltage = float(maxvoltagedatei.read())
print("Maximalspannung beträgt {0} Volt\n" .format(maxvoltage))
with open("/dev/shm/zeit_mcp3208_ch2.txt", "w") as z:
z.write(str((datetime.datetime.now().strftime('%d-%m-%Y %H:%M:%S'))))
gpio.setmode(gpio.BCM)
gpio.setup(POWER_PIN, gpio.OUT)
print("\n{:%A %d %B %Y %H:%M}\n{}".format(DateTime.now(), "-" * 30))
value = adc.read( channel = 0 )
print("Ausgelesener Wert an Kanal 0: \n", value)
print("Anliegende Spannung an Kanal 0: %.2f Volt\n" % (value / 272.1649) )
with open(SPANNUNG, "w") as v:
v.write(str("{0:.2f}".format(value / 272.1649)))
voltage = float((value / 272.1649))
with open(INTERVALL_DATEI, "r") as intervalldatei:
intervall = int(intervalldatei.read())
print("Ausleseintervall beträgt {0} Sekunden\n" .format(intervall))
with open(AUSSCHALTSPANNUNG, "r") as minvoltagedatei:
minvoltage = float(minvoltagedatei.read())
print("Mindestspannung beträgt {0} Volt\n" .format(minvoltage))
with open(EINSCHALTSPANNUNG, "r") as maxvoltagedatei:
maxvoltage = float(maxvoltagedatei.read())
print("Maximalspannung beträgt {0} Volt\n" .format(maxvoltage))
if voltage > minvoltage and gpio.input(POWER_PIN) == gpio.LOW:
print("Spannung über {0} Volt Ausschaltspannung, GPIO {1} ist noch an, bleibt so.\n".format(minvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage > maxvoltage and gpio.input(POWER_PIN) == gpio.HIGH:
print("Spannung über {0} Volt Einschaltspannung, GPIO {1} ist aus, schalte jetzt an.\n".format(maxvoltage, POWER_PIN))
subprocess.run([RELAIS_AN], check=True)
if gpio.input(POWER_PIN) == gpio.LOW:
print("GPIO {0} wurde angeschaltet.\n".format(POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif gpio.input(POWER_PIN) == gpio.HIGH:
print("Fehler ,GPIO {0} wurde nicht angeschaltet.\n".format(POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
else:
print("Sonstiger Fehler.")
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage > maxvoltage and gpio.input(POWER_PIN) == gpio.LOW:
print("Spannung über {0} Volt Einschaltspannung, GPIO {1} ist schon an, bleibt auch an.\n".format(maxvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage < minvoltage and gpio.input(POWER_PIN) == gpio.LOW:
print("Spannung unter {0} Volt Ausschaltspannung, GPIO {1} ist an, schalte jetzt aus.\n".format(minvoltage, POWER_PIN))
subprocess.run([RELAIS_AUS], check=True)
if gpio.input(POWER_PIN) == gpio.HIGH:
print("GPIO {0} wurde ausgeschaltet.\n".format(POWER_PIN))
print("Prüfe in {0} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif gpio.input(POWER_PIN) == gpio.LOW:
print("Fehler ,GPIO {0} wurde nicht ausgeschaltet.\n".format(POWER_PIN))
print("Prüfe in {0} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
else:
print("Sonstiger Fehler.")
print("Prüfe in {0} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage > minvoltage < maxvoltage and gpio.input(POWER_PIN) == gpio.HIGH:
print("Spannung über {0} Volt Ausschaltspannung, aber unter {1} Einschaltspannung, GPIO {2} ist aus und bleibt aus.\n".format(minvoltage, maxvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage < minvoltage and gpio.input(POWER_PIN) == gpio.HIGH:
print("Spannung unter {0} Volt Ausschaltspannung, GPIO {1} ist aus und bleibt aus.\n".format(minvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
else:
print("Fehler: {0} Ausschaltspannung {1} Einschaltspannung {2}\n".format(minvoltage, maxvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("Abbruch durch Benutzer. \n Schalte GPIO {0} aus.".format(POWER_PIN))
finally:
gpio.cleanup()
Display More
Die ganzen print() kann man alle mit einem # auskommentieren, sobald man sich überzeugt hat, dass das Script seine Arbeit verrichtet, es ist aber auch kein Beinbruch sie drin zu lassen.
Wichtig ist aber das ausführbar machen mitchmod +x /home/pi/ch0.py.
Das gleiche machen wir jetzt noch für Kanal 2, an dem der 7s-Li-Ion gemessen wird:
#!/usr/bin/env python3
from MCP3208 import MCP3208
from datetime import datetime as DateTime
from RPi import GPIO as gpio
import time
import datetime
import subprocess
adc = MCP3208()
EINSCHALTSPANNUNG = "/home/pi/einschaltspannung_ch2.txt"
AUSSCHALTSPANNUNG = "/home/pi/ausschaltspannung_ch2.txt"
POWER_PIN = 23
INTERVALL_DATEI = "/home/pi/intervall_mcp3208_ch2.txt"
SPANNUNG = "/dev/shm/mcp3208_ch2.txt"
RELAIS_AUS = "/home/pi/relais2_aus.py"
RELAIS_AN = "/home/pi/relais2_an.py"
gpio.setmode(gpio.BCM)
gpio.setup(POWER_PIN, gpio.OUT, initial=gpio.HIGH)
def main():
while True:
with open(INTERVALL_DATEI, "r") as intervalldatei:
intervall = int(intervalldatei.read())
print("Ausleseintervall beträgt {0} Sekunden\n" .format(intervall))
with open(AUSSCHALTSPANNUNG, "r") as minvoltagedatei:
minvoltage = float(minvoltagedatei.read())
print("Mindestspannung beträgt {0} Volt\n" .format(minvoltage))
with open(EINSCHALTSPANNUNG, "r") as maxvoltagedatei:
maxvoltage = float(maxvoltagedatei.read())
print("Maximalspannung beträgt {0} Volt\n" .format(maxvoltage))
with open("/dev/shm/zeit_mcp3208_ch2.txt", "w") as z:
z.write(str((datetime.datetime.now().strftime('%d-%m-%Y %H:%M:%S'))))
gpio.setmode(gpio.BCM)
gpio.setup(POWER_PIN, gpio.OUT)
print("\n{:%A %d %B %Y %H:%M}\n{}".format(DateTime.now(), "-" * 30))
value = adc.read( channel = 2 )
print("Ausgelesener Wert an Kanal 2: \n", value)
print("Anliegende Spannung an Kanal 2: %.2f Volt\n" % (value / 135) )
with open(SPANNUNG, "w") as v:
v.write(str("{0:.2f}".format(value / 135)))
voltage = float((value / 135))
with open(INTERVALL_DATEI, "r") as intervalldatei:
intervall = int(intervalldatei.read())
print("Ausleseintervall beträgt {0} Sekunden\n" .format(intervall))
with open(AUSSCHALTSPANNUNG, "r") as minvoltagedatei:
minvoltage = float(minvoltagedatei.read())
print("Mindestspannung beträgt {0} Volt\n" .format(minvoltage))
with open(EINSCHALTSPANNUNG, "r") as maxvoltagedatei:
maxvoltage = float(maxvoltagedatei.read())
print("Maximalspannung beträgt {0} Volt\n" .format(maxvoltage))
if voltage > minvoltage and gpio.input(POWER_PIN) == gpio.LOW:
print("Spannung über {0} Volt Ausschaltspannung, GPIO {1} ist noch an, bleibt so.\n".format(minvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage > maxvoltage and gpio.input(POWER_PIN) == gpio.HIGH:
print("Spannung über {0} Volt Einschaltspannung, GPIO {1} ist aus, schalte jetzt an.\n".format(maxvoltage, POWER_PIN))
subprocess.run([RELAIS_AN], check=True)
if gpio.input(POWER_PIN) == gpio.LOW:
print("GPIO {0} wurde angeschaltet.\n".format(POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif gpio.input(POWER_PIN) == gpio.HIGH:
print("Fehler ,GPIO {0} wurde nicht angeschaltet.\n".format(POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
else:
print("Sonstiger Fehler.")
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage > maxvoltage and gpio.input(POWER_PIN) == gpio.LOW:
print("Spannung über {0} Volt Einschaltspannung, GPIO {1} ist schon an, bleibt auch an.\n".format(maxvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage < minvoltage and gpio.input(POWER_PIN) == gpio.LOW:
print("Spannung unter {0} Volt Ausschaltspannung, GPIO {1} ist an, schalte jetzt aus.\n".format(minvoltage, POWER_PIN))
subprocess.run([RELAIS_AUS], check=True)
if gpio.input(POWER_PIN) == gpio.HIGH:
print("GPIO {0} wurde ausgeschaltet.\n".format(POWER_PIN))
print("Prüfe in {0} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif gpio.input(POWER_PIN) == gpio.LOW:
print("Fehler ,GPIO {0} wurde nicht ausgeschaltet.\n".format(POWER_PIN))
print("Prüfe in {0} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
else:
print("Sonstiger Fehler.")
print("Prüfe in {0} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage > minvoltage < maxvoltage and gpio.input(POWER_PIN) == gpio.HIGH:
print("Spannung zwar über {0} Volt Ausschaltspannung, aber unter {1} Einschaltspannung, GPIO {2} ist aus und bleibt aus.\n".format(minvoltage, maxvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
elif voltage < minvoltage and gpio.input(POWER_PIN) == gpio.HIGH:
print("Spannung unter {0} Volt Ausschaltspannung, GPIO {1} ist aus und bleibt aus.\n".format(minvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
else:
print("Fehler: {0} Ausschaltspannung {1} Einschaltspannung {2}\n".format(minvoltage, maxvoltage, POWER_PIN))
print("Prüfe in {} Sekunden nochmal.\n".format(intervall))
time.sleep(intervall)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("Abbruch durch Benutzer. \n Schalte GPIO {0} aus.".format(POWER_PIN))
finally:
gpio.cleanup()
Display More
Wie man sieht, ist das Script weitgehend identisch, bis auf die geänderten Kanäle und dem Umrechnungsfaktor für den MCP3208.
Speichern mit Strg+x, ausführbar machen mitchmod +x /home/pi/ch2.py.
Nun benötigen wir noch die Dateien mit den Ein- und Ausschaltspannungen.
nano ausschaltspannung_ch0.txt
Hier tragen wir einen realistischen Wert ein, bei dem das Relais 1 die Last ausschalten soll, je nachdem wie leer die Batterie werden darf, z.B. zwischen 13.40 und 11.80 Volt, ich nehme mal 12.80 Volt als Beispiel, speichern mit Strg+x.
Das gleiche mit Kanal 2 und Relais 2:
nano ausschaltspannung_ch2.txt
Da es bei mir ein 7s-Li-Ion-Akku ist, nehme ich als Beispiel 25.00 Volt als Abschaltspannung, um den Akku nicht zu sehr zu entladen.
Jetzt legen wir fest, ab wann die Relais einschalten sollen.
nano einschaltspannung_ch0.txt
Ich nehme mal 14.00 Volt, speichern mit Strg+x.
nano einschaltspannung_ch2.txt
Sagen wir mal 29 Volt, da bei 7x4,2 = 29,4 Volt Ladeschlusspannung ist, speichern mit Strg+x.
Für die Betriebsspannung des Pi an Kanal 1:
nano /home/pi/ch1_.py
#!/usr/bin/env python3
from MCP3208 import MCP3208
from datetime import datetime as DateTime
from RPi import GPIO as gpio
import time
import datetime
import subprocess
import os
adc = MCP3208()
while True:
with open("/home/pi/intervall_mcp3208_ch1.txt", "r") as intervalldatei:
intervall = int(intervalldatei.read())
print("Ausleseintervall beträgt {0} Sekunden" .format(intervall))
value = adc.read( channel = 1 )
print(value)
print("\n{:%A %d %B %Y %H:%M:%S}\n{}".format(DateTime.now(), "-" * 30))
print("Anliegende Spannung an Kanal 1 (von 0-7):\n %.2f Volt" % (value / 756.8627) )
with open("/dev/shm/mcp3208_ch1.txt", "w") as v:
v.write(str("{0:.2f}".format(value / 756.8627)))
time.sleep(intervall)
os.system("/usr/bin/clear")
Display More
Speichern und ausführbar machen.
Auf hier können wir die print() auskommentieren, wenn alles läuft.
Auch das /usr/bin/clear benötigen wir dann nicht mehr.
Jetzt lesen wir noch die CPU-Temperatur aus und speicher sie in die RAM-Datei:
nano /home/pi/cputemp.sh
Speichern und ausführbar machen.
Kommen wir zum BME280.
sudo apt install python3-smbus um die Software für den BME280 bzw. smbus zu installieren.
Das Script für den BME280:
nano bme280.py
#!/usr/bin/env python3
import smbus
import time
import datetime
import subprocess
from ctypes import c_short
from ctypes import c_byte
from ctypes import c_ubyte
DEVICE = 0x76 # Standard-Geräteaddresse am I2C
BUS = smbus.SMBus(1)
def get_short(data, index):
return c_short((data[index+1] << 8) + data[index]).value
def get_ushort(data, index):
return (data[index+1] << 8) + data[index]
def get_char(data, index):
result = data[index]
if result > 127:
result -= 256
return result
def get_uchar(data, index):
result = data[index] & 0xFF
return result
def read_bme280id(addr=DEVICE):
reg_id = 0xD0
(chip_id, chip_version) = BUS.read_i2c_block_data(addr, reg_id, 2)
return chip_id, chip_version
def read_bme280_all(addr=DEVICE):
reg_data = 0xF7
reg_control = 0xF4
reg_config = 0xF5
reg_control_hum = 0xF2
reg_hum_msb = 0xFD
reg_hum_lsb = 0xFE
oversample_temp = 2
oversample_pres = 2
mode = 1
oversample_hum = 2
BUS.write_byte_data(addr, reg_control_hum, oversample_hum)
control = oversample_temp << 5 | oversample_pres << 2 | mode
BUS.write_byte_data(addr, reg_control, control)
cal1 = BUS.read_i2c_block_data(addr, 0x88, 24)
cal2 = BUS.read_i2c_block_data(addr, 0xA1, 1)
cal3 = BUS.read_i2c_block_data(addr, 0xE1, 7)
dig_t1 = get_ushort(cal1, 0)
dig_t2 = get_short(cal1, 2)
dig_t3 = get_short(cal1, 4)
dig_p1 = get_ushort(cal1, 6)
dig_p2 = get_short(cal1, 8)
dig_p3 = get_short(cal1, 10)
dig_p4 = get_short(cal1, 12)
dig_p5 = get_short(cal1, 14)
dig_p6 = get_short(cal1, 16)
dig_p7 = get_short(cal1, 18)
dig_p8 = get_short(cal1, 20)
dig_p9 = get_short(cal1, 22)
dig_h1 = get_uchar(cal2, 0)
dig_h2 = get_short(cal3, 0)
dig_h3 = get_uchar(cal3, 2)
dig_h4 = get_char(cal3, 3)
dig_h4 = (dig_h4 << 24) >> 20
dig_h4 = dig_h4 | (get_char(cal3, 4) & 0x0F)
dig_h5 = get_char(cal3, 5)
dig_h5 = (dig_h5 << 24) >> 20
dig_h5 = dig_h5 | (get_uchar(cal3, 4) >> 4 & 0x0F)
dig_h6 = get_char(cal3, 6)
wait_time = 1.25 + (2.3 * oversample_temp) + ((2.3 * oversample_pres) + 0.575) + ((2.3 * oversample_hum)+0.575)
time.sleep(wait_time/1000)
data = BUS.read_i2c_block_data(addr, reg_data, 8)
pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
hum_raw = (data[6] << 8) | data[7]
var1 = ((((temp_raw>>3)-(dig_t1<<1)))*(dig_t2)) >> 11
var2 = (((((temp_raw >> 4) - dig_t1) * ((temp_raw >> 4) - dig_t1)) >> 12) * dig_t3) >> 14
t_fine = var1+var2
temperature = float(((t_fine * 5) + 128) >> 8)
var1 = t_fine / 2.0 - 64000.0
var2 = var1 * var1 * dig_p6 / 32768.0
var2 = var2 + var1 * dig_p5 * 2.0
var2 = var2 / 4.0 + dig_p4 * 65536.0
var1 = (dig_p3 * var1 * var1 / 524288.0 + dig_p2 * var1) / 524288.0
var1 = (1.0 + var1 / 32768.0) * dig_p1
if var1 == 0:
pressure = 0
else:
pressure = 1048576.0 - pres_raw
pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1
var1 = dig_p9 * pressure * pressure / 2147483648.0
var2 = pressure * dig_p8 / 32768.0
pressure = pressure + (var1 + var2 + dig_p7) / 16.0
humidity = t_fine - 76800.0
humidity = (hum_raw - (dig_h4 * 64.0 + dig_h5 / 16384.0 * humidity)) * \
(dig_h2 / 65536.0 * (1.0 + dig_h6 / 67108864.0 * humidity * (1.0 + dig_h3 / 67108864.0 * humidity)))
humidity = humidity * (1.0 - dig_h1 * humidity / 524288.0)
if humidity > 100:
humidity = 100
elif humidity < 0:
humidity = 0
return temperature/100.0, pressure/100.0, humidity
temperature,pressure,humidity = read_bme280_all()
print(datetime.datetime.now().strftime('%d-%m-%Y %H:%M:%S'))
print("Temperatur : ", temperature, "°C")
print("Luftdruck : {:.2f}".format(pressure), "hPa")
print("Luftfeuchtigkeit : {:.2f}".format(humidity), "%")
with open("/dev/shm/temperatur.txt", "w") as t:
t.write(str("{0:.2f}".format(temperature)))
with open("/dev/shm/luftdruck.txt", "w") as p:
p.write(str("{0:.2f}".format(pressure)))
with open("/dev/shm/luftfeuchtigkeit.txt", "w") as f:
f.write(str("{0:.2f}".format(humidity)))
Display More
Irgendwo hier im Forum gibt es eine schönere Version des Scripts, mit korrekten Einrückungen, ich finde es auf die schnelle nicht, Hauptsache es läuft.
Speichern mit Strg+x, mit j bestätigen und Enter drücken.
Ausführbar machen mit chmod +x /home/pi/bme280.py
Zeichenlimit erreicht, Ende Teil 1...