While-Schleife beenden

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
Stevio
User
Beiträge: 2
Registriert: Freitag 1. Juni 2018, 20:05

Hallo zusammen :)

Ich habe ein Python Script für ein kleines Projekt zusammengeschrieben, es soll sich um eine art Klimaanlage handeln. Das Programm läuft auch so wie ich mir das bis jetzt vorgestellt habe.

Das Problem ist jetzt nur, dass ich nach dem erstmaligen Betätigen des Touch Switch die Messungen starten kann aber dann nach der zweiten Betätigung leider nicht mehr aus der while-Schleife, in der Funktion main(), herauskomme (obwohl das der Plan ist). Habe das mit dem break offensichtlich leider noch nicht begriffen. :roll:

Diese letzte Bedingung bereitet mir seit einigen Tagen ziemlich Kopfzerbrechen und ich bekomme es einfach nicht hin, kann mir daher jemand bitte einen Tipp geben, wo der Fehler in der Funktion main() mit dem break liegt? :K

P.S.: Ich möchte nicht das mir hier irgendjemand mein Progamm für mich schreibt, ich will lediglich nur ein Tipp.

Danke schon mal im voraus!


Code: Alles auswählen

'''
Zwei unterschiedliche Temperatursensoren werden in einer Schleife ausgelesen und auf einem Display ausgegeben.
Wenn der DHT11 Sensor den ausgelesenen Grenzwert aus der Konfigurationsdatei ueberschreitet laeuft ein Motor an.
Eine RGB-LED leuchtet gruen wenn sich beide Sensoren in einem definierten Bereich befinden, sobald einer
der Sensoren oder sogar beide den Bereich verlassen wechselt die RGB-LED ihre Farbe auf rot.
Das Programm soll mit einem Touch Switch gestartet und beendet werden.
'''


import time
import Adafruit_DHT
import RPi.GPIO as GPIO
import lcddriver
import Temp2 as t


GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

DHT11 = Adafruit_DHT.DHT11
TempPin = 17



TouchPin = 13
GPIO.setup(TouchPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
tmp = 0


Gruen = 12
Rot = 15


GPIO.setup(Rot, GPIO.OUT)
GPIO.setup(Gruen, GPIO.OUT)

Motor1L = 16
Motor1E = 22

GPIO.setup(Motor1L, GPIO.OUT)
GPIO.setup(Motor1E, GPIO.OUT)

lcd = lcddriver.lcd()

t.setup()
Grenzwert = 25.0


def ReadConfigFile(Cfg):
	print "Read: " ,  Cfg
	global Grenzwert

	fStatus = False

	try:

		f = open(Cfg)
		lines = f.readlines()
		f.close()
		for l in lines:

			if "#" in l:
					continue

			cfgValue = l.split('=', 1 )


			if "LowerThresholdTemp" == cfgValue[0]:
				Grenzwert = cfgValue[1]
				print("Grenzwert=" + Grenzwert)

	except IOError:
	print "No File", Cfg



def test():


	Temperatur, Luftfeuchtigkeit = Adafruit_DHT.read_retry(DHT11, TempPin)


	if 15.0 < Temperatur < 75.0  and 15.0 < t.read() < 75.0:
		print("LED gruen")
		GPIO.output(Gruen, GPIO.HIGH)
		GPIO.output(Rot, GPIO.LOW)

	else:
		print("LED rot")
		GPIO.output(Rot, GPIO.HIGH)
		GPIO.output(Gruen, GPIO.LOW)


def main(x):


		if x == 0:

			print("Programm aus")
			lcd.lcd_clear()


		if x == 1:

			print("Programm an")

			while x == 1:

				if x == 0:
					break


				Temperatur, Luftfeuchtigkeit = Adafruit_DHT.read_retry(DHT11, TempPin)


				if Temperatur < int(Grenzwert):
					print("Kuehlung aus")
					GPIO.output(Motor1E, GPIO.LOW)
					GPIO.output(Motor1L, GPIO.HIGH)

				else:
					print("Kuehlung an")
					GPIO.output(Motor1E, GPIO.HIGH)
					GPIO.output(Motor1L, GPIO.HIGH)

				if Temperatur is None:
					print('Fehler bei der Messung')

				else:
					lcd.lcd_display_string("Temp in: " + str(int(Temperatur)) + " C  ", 1)
				lcd.lcd_display_string("Temp out: " + str(int(t.read())) + " C  ", 2)
				
				test()
				continue


def loop():

	while True:

		main(GPIO.input(TouchPin))
		time.sleep(1)



def destroy():
	GPIO.cleanup()


if __name__ == '__main__':

	try:
		ReadConfigFile("Cfg")
		loop()

	except KeyboardInterrupt:
		destroy()
		lcd.lcd_clear()
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

Du solltest den Code mehr Strukturieren, du wirst vermutlich einfach den Überblick verloren haben, weil einige Funktionen so überflüssig sind. Aber der Reihe nach:

Dein Programm startet mit dem Block if __name__ == '__main__': und ruft von dort aus als erstes die Funktion zum Einlesen der Konfig auf, und springt anschließend in die Funktion loop(), in der eine Endlosschleife läuft. Zwar hast du Abbruchbedingungen in der main()-Methode definiert (welche die main auch unterbrechen, jedoch ruft deine loop()-Funktion die main dann immer wieder auf), diese gelten jedoch im lokalen Scope der Funktion, nicht aber außerhalb respektive für die loop()-Funktion. Da eine main()-Funktion der Einstiegspunkt einer jeden guten Applikation ist, verzichte doch einfach auf deine loop()-Funktion, viel Sinnvolles macht die ja eh nicht.

Die Prüfung in der main()-Funktion ob x == 1 wäre ist auch sinnlos, weil du in der while-Schleife die gleiche Prüfung vornimmst:

Code: Alles auswählen

while x == 1:
    print("Programm an")
Die weitere Prüfung in der while-Schleife ob x == 0 ist, ist auch überflüssig. Die Bedingung der while-Schleife erledigt doch genau das für dich:

Gemeint ist das hier:

Code: Alles auswählen

if x == 0:
    break
Die Bedingung while x == 1: kann man auch so verstehen: "Solange der Inhalt der Variablen x gleich 1 ist, läuft diese Schleife" - d.h. ändert sich der Wert der Variablen x im Schleifenkörper, wird läuft die Schleife nicht mehr weiter. Demnach wird die Prüfung ob x == 1 ist, mit jedem Schleifendurchlauf durchgeführt.

Generelles zum Code: orientiere dich bitte an PEP-8, dem offiziellen Styleguide zum schreiben von pythonischen Code. Variablennamen werden klein_mit_unterstrich geschrieben, gleiches gilft für Funktionen, bspw.: read_config_file(). Variablennamen und Namen von Klassen wie `t` oder `x` sind Müll, da sie nicht aussagen wer sie sind, was sie machen. Stell' dir vor dein Code hat noch ein paar mehr Zeilen, es ist hart zu debuggen wenn man nicht weiß was `x` jetzt eigentlich macht. Konstanten werden GROSSGESCHRIEBEN und gehören ziemlich weit oben in den Code, also unterhalb der Importe und noch überhalb der Logic:

Code: Alles auswählen

GRUEN = 12
ROT = 15
usw.

Vergiss' dass es global gibt, das zu verwenden ist in 99,9 % der Fälle nicht richtig, außerdem macht es den Zustand deines Programmes enorm unübersichtlich und komplex und kann zu ganz hässlichen Fehlern führen.

Config-Files kann man mit yaml oder json o.ä. Einlesen, Python stellt dafür Bibliotheken bereit, so muss man nix händisch parsen. f = open(Cfg) solltest du durch das with statement ersetzen, dann musst du dich auch nicht mehr um das Schließen des filedescriptors kümmern.

Schau dir für diese Zeile:

Code: Alles auswählen

 lcd.lcd_display_string("Temp in: " + str(int(Temperatur)) + " C  ", 1)
mal die format()-Methode an. Ansonsten noch ein paar Zeilenumbrüche hier und da zu viel.
When we say computer, we mean the electronic computer.
Sirius3
User
Beiträge: 18267
Registriert: Sonntag 21. Oktober 2012, 17:20

Zusätzlich zu dem was sls schon geschrieben hat:

GPIO-Warnungen sind dafür da, dass man sie behebt, und nicht, dass man sie ignoriert.
Eingerückt wird immer mit 4 Leerzeichen, so wie jetzt ist das Programm nicht lesbar.
Für Config-Dateien Deiner Art, gibt es den ConfigParser. fStatus wird gesetzt, aber niemals benutzt.

Du liest pro Schleifendurchgang zwei mal Temperatur und Luftfeuchtigkeit, wobei Du immer nur einen Rückgabewert davon benutzt.
Besser ist eine klare Trennung zwischen
1. lesen der Messwerte
2. Bestimmung des Status anhand der Messwerte
3. Ändern der Ausgabe bei Statusänderungen.

Das except in der letzten Zeile ist falsch. Du unter allen Umständen aufräumen, nicht nur, wenn das Programm durch Tastendruck beendet wird:

Code: Alles auswählen

try:
    ReadConfigFile("Cfg")
    loop()
except KeyboardInterrupt:
    pass
finally:
    GPIO.cleanup()
    lcd.lcd_clear()
Stevio
User
Beiträge: 2
Registriert: Freitag 1. Juni 2018, 20:05

@sls & @Sirius3

Vielen Dank für eure sehr ausführlichen Antworten! Ich werde mein Script jetzt noch mal überarbeiten und besser strukturieren. :D

Gruß

Stevio
Antworten