Bewässerungsanlage Datenübernahme in CSV über Cronjob

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Pythagoras89
User
Beiträge: 7
Registriert: Sonntag 24. Januar 2021, 20:47

Guten Abend alle miteinander :)

ich habe gerade angefangen Python zu lernen, um meine Pflanzen besser im Blick zu haben :mrgreen:
Das Auslesen des Datum, der Daten sowie die Beschriftung in der Konsole funktioniert schonmal ganz gut.
Ich habe auch eingefügt, dass die Daten welche ich auslese in eine CSV Datei übernimmt.

Der Aufbau sieht folgender Maßen aus:
Ich habe 5 kapazitive Bodefeuchtigkeitssensoren über einen AD-Wandler an meinem Raspberry angeschlossen.
Wenn ich das Python Script laufen lasse bekomme ich für jede Pflanze mit Datum und Uhrzeit meine Messwerte angezeigt ( 0 = nass 100 = trocken)

Soweit so gut, die Datenübernahme in die CSV-Datei funktioniert wunderbar aber......... nur wenn ich das Skript über Thonny direkt ausführe :( :evil:
Ich kann in der Shell sehen dass das Skript ausgeführt worden ist und die Daten angezeigt werden, aber der Export wird nicht getriggert

in die Shell schreibe ich
python /home/pi/Desktop/BF.py

darauf hin
Efeu,Basilikum,Gummibaum,Aloe Vera, Erde
<Datum>, 36,8,29,35,70()

Wenn ich drauf hin mit tail /home/pi/Desktop/Datenaufzeichnung.csv kontrolliere bzw manuell reinschaue ist sie leer :(
Aber wie gesagt, starte ich das Skript manuell sind die Daten in der CSV-Datei

Hab den Befehl python /home/pi/Desktop/BF.py auch schon mit sudo vorne dran versucht. => Bringt nix

Im Endeffekt war die Idee mit einem Crontab 20 * * * * python /home/pi/Desktop/BF.py die Datenübernahme zu starten was aber natürlich auch nicht geht.
Vielleicht hat jemand einen Denkanstoß bezüglich der Datenübernahme, damit ich wenigstens mal ein Problem erschlagen kann.
Die CSV Datei wird außerdem auch ordentlich mit With geschlossen.



----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Der Code (BF.py)

from signal import signal, SIGTERM, SIGHUP, pause
from smbus import SMBus
from gpiozero import PWMLED
from time import sleep
import csv
import sys
import datetime

time = datetime.datetime.now()
bus = SMBus(1)
Pflanzen = ["Efeu","Basilikum", "Gummibaum", "Aloe Vera", "Erde"]
Wert = [0,0,0,0,0]

ads7830_commands = [0x84, 0xc4, 0x94, 0xd4, 0xa4, 0xe4, 0xb4, 0xf4]
def read_ads7830(input):
bus.write_byte(0x4b, ads7830_commands[input])
return bus.read_byte(0x4b)


print(Pflanzen[0] + "," + Pflanzen[1] + "," + Pflanzen[2] + "," + Pflanzen[3] + "," + Pflanzen[4])

def values(input):
for i in range(1):
sys.stdout.write(str(time) + " ,")
Wert[0] = read_ads7830(input)
sys.stdout.write(str(Wert[0]-107) +",")
Wert[1] = read_ads7830(input+1)
sys.stdout.write(str(Wert[1]-107) +",")
Wert[2] = read_ads7830(input+2)
sys.stdout.write(str(Wert[2]-107) +",")
Wert[3] = read_ads7830(input+3)
sys.stdout.write(str(Wert[3]-107) +",")
Wert[4] = read_ads7830(input+4)
sys.stdout.write(str(Wert[4]-107))
print()

with open('Datenaufzeichnung.csv', mode='a') as Datenaufzeichnung:
employee_writer = csv.writer(Datenaufzeichnung, delimiter=',', quoting=
csv.QUOTE_MINIMAL)

employee_writer.writerow([time, Wert[0]-107,Wert[1]-107,Wert[2]-107,Wert[3]-107,Wert[4]-107])

values(0)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst den Pfad zu deiner Datei absolut angeben. Nicht relativ, wie jetzt.
Benutzeravatar
Dennis89
User
Beiträge: 1153
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

auf dem Raspberry OS, das du vermutlich verwendest(?), ist Python2 und Python3 installiert. Deine verwendeten 'print' Anweisungen deuten auf Python3 hin, das bedeutet du musst auch beim Start im Terminal python3 aufrufen:
'python3 /home/pi/Desktop/BF.py'

Wenn du das Programm automatisch starten willst, informiere dich über SystemUnits, dass ist der Stand Dinge.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Importe aus `signal` werden gar nicht benutzt, ist auch besser so, denn sinnvoll kann man die selten verwenden.
`Pflanzen` und `Werte` scheinen irgendwie zusammen zu gehören.
Pflanzen ist eine Konstante, sollte also PFLANZEN geschrieben werden, `Werte` sollte gar nicht global existieren.
`ads7830_commands` scheint auch zu den Pflanzen zu gehören, hat aber ein paar Einträge mehr, die aber gar nicht verwendet werden.
`time` ist der Zeitpunkt des Programmstarts, was selten das ist, was man haben möchte.
Strings stückelt man nicht mit + zusammen. sys.stdout braucht man nicht, wenn man doch `print` hat.
Eine for-Schleife, die exakt einmal durchlaufen wird, ist unsinnig.
Beim Öffnen der CSV-Datei fehlen das encoding- und newline-Argument.
Warum hast Du einen `employee_writer`? Wo sind hier Mitarbeiter? Oder nennst Du Deine Sensoren so?

Code: Alles auswählen

import csv
import datetime
from smbus import SMBus
import os

OUTPUT_FILENAME = os.path.join(os.path.dirname(__file__), 'Datenaufzeichnung.csv')

PFLANZEN = [
    ("Efeu", 0x84),
    ("Basilikum", 0xc4),
    ("Gummibaum", 0x94),
    ("Aloe Vera", 0xd4),
    ("Erde", 0xa4), 
    # unused 0xe4, 0xb4, 0xf4
]

def read_ads7830(bus, command):
    bus.write_byte(0x4b, command)
    return bus.read_byte(0x4b)
      
def values(bus, pflanzen):
    time = datetime.datetime.now()
    werte = [
        read_ads7830(bus, command) - 107
        _, command in pflanzen
    ]
    print(time, ',', ','.join(map(str, werte)))
    with open(OUTPUT_FILENAME, mode='a', newline="", encoding="utf8") as output:
        writer = csv.writer(output, delimiter=',', quoting=csv.QUOTE_MINIMAL)
        writer.writerow([time] + werte)
      
def main():
    bus = SMBus(1)
    print(",".join(name for name, _ in PFLANZEN))
    read_values(PFLANZEN)
    
if __name__ == "__main__":
    main()
Pythagoras89
User
Beiträge: 7
Registriert: Sonntag 24. Januar 2021, 20:47

__deets__ hat geschrieben: Sonntag 24. Januar 2021, 22:08 Du musst den Pfad zu deiner Datei absolut angeben. Nicht relativ, wie jetzt.
ahh okay, das werde ich gleich mal heute ausprobieren.
Also der Absolute Pfad heißt dann z.B.

C:/home/pi/Desktop/BF.py

danke für den Hinweis
Pythagoras89
User
Beiträge: 7
Registriert: Sonntag 24. Januar 2021, 20:47

Dennis89 hat geschrieben: Sonntag 24. Januar 2021, 22:14 Hallo,

auf dem Raspberry OS, das du vermutlich verwendest(?), ist Python2 und Python3 installiert. Deine verwendeten 'print' Anweisungen deuten auf Python3 hin, das bedeutet du musst auch beim Start im Terminal python3 aufrufen:
'python3 /home/pi/Desktop/BF.py'

Wenn du das Programm automatisch starten willst, informiere dich über SystemUnits, dass ist der Stand Dinge.

Grüße
Dennis
Auf dem Raspberry Pi 4 läuft Raspbian und ich vermute dass Python 3 und Python 2 drauf ist. Wobei ich selber nicht weiß welches Python jetzt benützt wird damit der Code interpretiert wird :S
Ich werde es aufjeden Fall ausprobieren :) danke für den Hinweis.
Bezüglich dem automatischen Start habe ich in meinem Buch gelesen, dass man für die Automatisierung den Crontab verwenden kann.
Aber ich lese mich bezüglich den SystemUnits rein :geek: danke
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Pythagoras89 hat geschrieben: Montag 25. Januar 2021, 09:48
__deets__ hat geschrieben: Sonntag 24. Januar 2021, 22:08 Du musst den Pfad zu deiner Datei absolut angeben. Nicht relativ, wie jetzt.
ahh okay, das werde ich gleich mal heute ausprobieren.
Also der Absolute Pfad heißt dann z.B.

C:/home/pi/Desktop/BF.py

danke für den Hinweis
Da dein Pi kein C-Laufwerk hat, ganz sicher nicht.
Benutzeravatar
Dennis89
User
Beiträge: 1153
Registriert: Freitag 11. Dezember 2020, 15:13

@Pythagoras89 Ich kann mir nicht vorstellen, das auf deinem Raspberry der Pfad mit 'C:' anfängt. '/home/pi/Desktop/BF.py' passt schon, das ist der absolute Pfad.
Ich glaube @__deets__ meinte die Pfadangabe in der Codezeile, in der du deine Datei öffnest. Da gibst du nur 'Datenaufzeichnung.csv' an. Schau dir dazu den Code von @Sirus3 an wie er das gelöst hat.

Verwende Python3, Python2 erhält seit über einem Jahr keinen Support durch die Entwickler mehr.

Zum Thema SystemUnits und Crontab:
https://www.howtogeek.com/687970/how-to ... h-systemd/

https://www.splendid-internet.de/blog/b ... t-systemd/

https://wiki.archlinux.de/title/Systemd/Timers

https://opensource.com/article/20/7/systemd-timers

Viel Erfolg
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Pythagoras89
User
Beiträge: 7
Registriert: Sonntag 24. Januar 2021, 20:47

Dennis89 hat geschrieben: Montag 25. Januar 2021, 10:23 @Pythagoras89 Ich kann mir nicht vorstellen, das auf deinem Raspberry der Pfad mit 'C:' anfängt. '/home/pi/Desktop/BF.py' passt schon, das ist der absolute Pfad.
Ich glaube @__deets__ meinte die Pfadangabe in der Codezeile, in der du deine Datei öffnest. Da gibst du nur 'Datenaufzeichnung.csv' an. Schau dir dazu den Code von @Sirus3 an wie er das gelöst hat.

Verwende Python3, Python2 erhält seit über einem Jahr keinen Support durch die Entwickler mehr.

Zum Thema SystemUnits und Crontab:
https://www.howtogeek.com/687970/how-to ... h-systemd/

https://www.splendid-internet.de/blog/b ... t-systemd/

https://wiki.archlinux.de/title/Systemd/Timers

https://opensource.com/article/20/7/systemd-timers

Viel Erfolg
Dennis
Boahh danke, jetzt hab ichs gecheckt
Pythagoras89
User
Beiträge: 7
Registriert: Sonntag 24. Januar 2021, 20:47

Sirius3 hat geschrieben: Montag 25. Januar 2021, 08:16 Die Importe aus `signal` werden gar nicht benutzt, ist auch besser so, denn sinnvoll kann man die selten verwenden.
`Pflanzen` und `Werte` scheinen irgendwie zusammen zu gehören.
Pflanzen ist eine Konstante, sollte also PFLANZEN geschrieben werden, `Werte` sollte gar nicht global existieren.
`ads7830_commands` scheint auch zu den Pflanzen zu gehören, hat aber ein paar Einträge mehr, die aber gar nicht verwendet werden.
`time` ist der Zeitpunkt des Programmstarts, was selten das ist, was man haben möchte.
Strings stückelt man nicht mit + zusammen. sys.stdout braucht man nicht, wenn man doch `print` hat.
Eine for-Schleife, die exakt einmal durchlaufen wird, ist unsinnig.
Beim Öffnen der CSV-Datei fehlen das encoding- und newline-Argument.
Warum hast Du einen `employee_writer`? Wo sind hier Mitarbeiter? Oder nennst Du Deine Sensoren so?

Code: Alles auswählen

import csv
import datetime
from smbus import SMBus
import os

OUTPUT_FILENAME = os.path.join(os.path.dirname(__file__), 'Datenaufzeichnung.csv')

PFLANZEN = [
    ("Efeu", 0x84),
    ("Basilikum", 0xc4),
    ("Gummibaum", 0x94),
    ("Aloe Vera", 0xd4),
    ("Erde", 0xa4), 
    # unused 0xe4, 0xb4, 0xf4
]

def read_ads7830(bus, command):
    bus.write_byte(0x4b, command)
    return bus.read_byte(0x4b)
      
def values(bus, pflanzen):
    time = datetime.datetime.now()
    werte = [
        read_ads7830(bus, command) - 107
        _, command in pflanzen
    ]
    print(time, ',', ','.join(map(str, werte)))
    with open(OUTPUT_FILENAME, mode='a', newline="", encoding="utf8") as output:
        writer = csv.writer(output, delimiter=',', quoting=csv.QUOTE_MINIMAL)
        writer.writerow([time] + werte)
      
def main():
    bus = SMBus(1)
    print(",".join(name for name, _ in PFLANZEN))
    read_values(PFLANZEN)
    
if __name__ == "__main__":
    main()
Vielen Dank für deine Mühe :) ich werde versuchen den Code anzupassen

Strings stückelt man nicht mit + zusammen. sys.stdout braucht man nicht, wenn man doch `print` hat. <- den habe ich verwendet damit ich keinen Zeilenumbruch mehr habe, weil ich alle Zahlen in einer Reihe wollte
Aber wenn das mit + auch funktioniert :D okay

Uff mein Code ist echt n Murks xd danke auf jedenfall
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

print hat das end-Argument, um Zeilenumbruch zu verhindern.
Pythagoras89
User
Beiträge: 7
Registriert: Sonntag 24. Januar 2021, 20:47

Wollte mich nochmals bei allen bedanken.
Die Lösung war einerseits den absoluten Pfad mit in mein Pythoncode mit einzubetten sowie im SSH "python3 /home/pi/Desktop/BF.py" anstatt "python /home/pi/Desktop/BF.py" zu schreiben
Die Datenübernahme in die CSV-Datei funktioniert jetzt über Crontab einwandfrei.

Einfach die Shell öffnen "crontab -l" kann überprüft werden ob schon ein job vorliegt.
Mit "crontab -e" wird eine erklärung angezeigt, einfach runterscrollen "* * * * * python3 /home/pi/Desktop/BF.py" eingeben.
Mit Str+O (O der Buchstabe) speichern dann nochmal mit Enter bestätigen.
Danach sollte man wieder mit crontab -l den job anzeigen lassen können.

Wichtig: Nicht die Leerzeichen beim anlegen des Cronjobs vergessen "* * * * * python3 /home/pi/Desktop/BF.py"
* leerzeichen * usw
Das erste Sternchen regelt in welcher Minute der Job getriggert wird
z.B.
* * * * * => jede Minute
1 * * * * => heißt zur jeden vollen Stunde in der ersten Minute
1 1 * * * => immer um 1 uhr in der ersten Minute
1 1 20 * * => immer um 1 uhr in der ersten Minute am zwanzigsten Tag des Monats
1 1 20 2 * => immer um 1 uhr in der ersten Minute am zwanzigsten Tag des Monats im Feb.
1 1 20 2 3 => immer um 1 uhr in der ersten Minute am zwanzigsten Tag des Monats im Feb an einem Mittwoch (Wochentag 0-6; 0=Sonntag, 6= Samstag, 1=Monatag ....)
Pythagoras89
User
Beiträge: 7
Registriert: Sonntag 24. Januar 2021, 20:47

Sirius3 hat geschrieben: Montag 25. Januar 2021, 12:27 print hat das end-Argument, um Zeilenumbruch zu verhindern.
hat funktioniert thx :)
Antworten