"Zeitschaltuhr"

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.
loba74
User
Beiträge: 5
Registriert: Freitag 24. Oktober 2014, 23:41

In der Theorie wage ich es nicht, Dir zu widersprechen. Wie gesagt, ich bin ein Noob und habe von der Theorie (noch) nicht viel Ahnung. Allerdings sieht die Praxis anders aus. Kanal 24, 25 und 27 haben Schaltzeiten von 00:00 bis 00:00, sollten also aus sein, sind aber dennoch an, wie mir NetBeans ausgibt (hier, morgens um sieben :)). Wie NetBeans meint, sind die Bedingungen für Kanal 24 bis 27 ebenfalls wahr und zieht an. Übrigens hat auch der Raspi die Relais im 'Feldtest' angezogen. Es scheint also nicht eine Sonderheit von NetBeans zu sein (die ganzen Prints habe ich nur eingefügt, damit die verschiedenen Schleifen was zu tun haben):
(17, 'reset')
06:45:29 Kanal 17 aus
(22, 'reset')
06:45:29 Kanal 22 an
(23, 'reset')
(24, 'reset')
06:45:29 Kanal 23 an
(25, 'reset')
06:45:29 Kanal 24 an
(27, 'reset')
06:45:29 Kanal 25 an
06:45:29 Kanal 27 an
17 False
22 True
23 True
24 True
25 True
27 True
17 True
06:47:00 Kanal 17 an
Gruss, Oli
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@loba74: dann ist wohl in einem anderen Teil des Programms etwas falsch.
juntiedt
User
Beiträge: 10
Registriert: Dienstag 13. Dezember 2016, 16:22

Hallo,

ich hab mir aus der Anleitung von BlackJack eine Zeitschaltuhr_class programmiert die als separater thread läuft um Regel_Loops mit z.B. einer Nachabsenkung zu steuern. Funktioniert sehr gut.

Jetzt möchte ich die Anregung von BlackJack mit erweiterten Zeitstrukturen zu arbeiten, umsetzen und stoße an meine Python Grenzen.
Wie macht man das am besten?

Code: Alles auswählen

#!/usr/bin/python

#import logging
import threading
import time
from datetime import datetime as DateTime, time as Time

# TODO Maybe configure basic logging here.
#LOG = logging.getLogger(__name__)

#:
#: Tuples of the form (name, (start, end)).
#:
# 
# TODO Maybe it is useful to extend this structure and the code by more
# than one time interval per relay.
# 

class Zeitschaltuhr(object):

    R1_Stat = None
    R2_Stat = None
    R3_Stat = None
    R4_Stat = None
    R5_Stat = None
    R6_Stat = None
    R7_Stat = None
    R8_Stat = None

    def __init__(self):
        self.RELAYS = [
        ('Relay 1', ('00:00:00', '00:00:00')),
        ('Relay 2', ('00:00:00', '00:00:00')),
        ('Relay 3', ('06:45:00', '22:00:00')),
        ('Relay 4', ('00:00:00', '00:00:00')),
        ('Relay 5', ('00:00:00', '00:00:00')),
        ('Relay 6', ('00:00:00', '00:00:00')),
        ('Relay 7', ('00:00:00', '00:00:00')),
        ('Relay 8', ('00:00:00', '00:00:00')),
        ]        
        print("init")
        self._lock = threading.Lock()
        self._zsu_thread = threading.Thread(target=self._run_uhr)
        self._zsu_thread.daemon = True  # Don't let this thread block exiting.
        self._zsu_thread.start()
        time.sleep(2)

#--------------------------------------        

    class Relay(object):

        def __init__(self, name):
            self.name = name
            self.state = None
            #print(self.name)   
    
        def switch(self, new_state):
            global R1_Stat
            global R2_Stat
            global R3_Stat
            global R4_Stat
            global R5_Stat
            global R6_Stat
            global R7_Stat
            global R8_Stat
            if self.state != new_state:
                self.state = new_state
                #print(self.name + " : " + str(self.state))
                if self.name == "Relay 1":
                    R1_Stat = self.state
                elif self.name == "Relay 2":
                    R2_Stat = self.state
                elif self.name == "Relay 3":
                    #print("R3")
                    R3_Stat = self.state
                    #print(R3_Stat)
                elif self.name == "Relay 4":
                    R4_Stat = self.state
                elif self.name == "Relay 5":
                    R5_Stat = self.state
                elif self.name == "Relay 6":
                    R6_Stat = self.state
                elif self.name == "Relay 7":
                    R7_Stat = self.state
                elif self.name == "Relay 8":
                    R8_Stat = self.state
                else:
                    print("Error: Relay unbekannt!")
    #            for name in self.name:
    #            print(self.name, ['aus', 'an'][new_state])
    #           if self.name == "Relay 1" and self.state == True:
    #               print("Relay1 do something")
                
    class TimeSpan(object):
        def __init__(self, start, end):
            if start > end:
                raise ValueError('start must not be greater than end')
            self.start = start
            self.end = end
        
        def __contains__(self, time):
            return self.start <= time < self.end
#------------------------------------------------
    def parse_time(self, string):
        return Time(*map(int, string.split(':')))
    
    def _run_uhr(self): 
        relays = [
            (self.Relay(name), self.TimeSpan(self.parse_time(start), self.parse_time(end)))
            for name, (start, end) in self.RELAYS
        ]
        #time.sleep(1)
        while True:
            now = DateTime.now().time()
            for relay, time_span in relays:
                relay.switch(now in time_span)
            time.sleep(1)

    def read_r1(self):
        with self._lock:
            return R1_Stat
    def read_r2(self):
        with self._lock:
            return R2_Stat        
    def read_r3(self):
        with self._lock:
            return R3_Stat
    def read_r4(self):
        with self._lock:
            return R4_Stat
    def read_r3(self):
        with self._lock:
            return R3_Stat
    def read_r5(self):
        with self._lock:
            return R5_Stat
    def read_r6(self):
        with self._lock:
            return R6_Stat
    def read_r7(self):
        with self._lock:
            return R7_Stat
    def read_r8(self):
        with self._lock:
            return R8_Stat        
#------------------------------------------------

ZSU = Zeitschaltuhr()

while True:
    if ZSU.read_r1() == True:
        print("Relay 1 An")
    elif ZSU.read_r1() == False:
        print("Relay 1 aus")
    if ZSU.read_r2() == True:
        print("Relay 2 An")
    elif ZSU.read_r2() == False:
        print("Relay 2 aus")    
    if ZSU.read_r3() == True:
        print("Relay 3 An")
    elif ZSU.read_r3() == False:
        print("Relay 3 aus")
    if ZSU.read_r4() == True:
        print("Relay 4 An")
    elif ZSU.read_r4() == False:
        print("Relay 4 aus")
    if ZSU.read_r5() == True:
        print("Relay 5 An")
    elif ZSU.read_r5() == False:
        print("Relay 5 aus")
    if ZSU.read_r6() == True:
        print("Relay 6 An")
    elif ZSU.read_r6() == False:
        print("Relay 6 aus")
    if ZSU.read_r7() == True:
        print("Relay 7 An")
    elif ZSU.read_r7() == False:
        print("Relay 7 aus")
    if ZSU.read_r8() == True:
        print("Relay 8 An")
    elif ZSU.read_r8() == False:
        print("Relay 8 aus")    
    else:
        print ("Relay unbekannt")
    time.sleep(10)


Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@juntiedt: globale Variablen und Klassenvariablen sind zwei verschiedene Dinge, die Du hier vermischst. Beides sollte man aber sowieso nicht verwenden. Wenn Du anfängst, Variablen durchzunummerieren, willst Du eigentlich eine passende Datenstruktur (hier ein Wörterbuch) verwenden. Auch großgeschriebene Attribute bedeuten in Python Konstanten, die dann aber nicht in __init__ definiert werden. Ein sleep in __init__ ist unerwartet, gehört also da nicht hin. Um Referenzen zurückzugeben, braucht man kein Lock. Entweder die Variable zeigt auf das eine Objekt oder ein anderes, einen Mischzustand kann es da nicht geben. Klassen innerhalb von Klassen zu definieren macht selten Sinn. Welchen Sinn macht die Relay-Klasse überhaupt? Die gehören auf Modulebene. Zum Parsen von Zeiten benutzt man auch Datetime.strptime: Datetime.strptime("13:02:44", "%H:%M:%S").time(). Funktionen durchzunummerieren ist genauso fragwürdige wie Variablennamen.

Edit:

Code: Alles auswählen

#!/usr/bin/python
import threading
import time
from datetime import datetime as DateTime
 
RELAYS = [
    ('Relay 1', ('00:00:00', '00:00:00')),
    ('Relay 2', ('00:00:00', '00:00:00')),
    ('Relay 3', ('06:45:00', '22:00:00')),
    ('Relay 4', ('00:00:00', '00:00:00')),
    ('Relay 5', ('00:00:00', '00:00:00')),
    ('Relay 6', ('00:00:00', '00:00:00')),
    ('Relay 7', ('00:00:00', '00:00:00')),
    ('Relay 8', ('00:00:00', '00:00:00')),
]

def parse_time(time):
    return DateTime.strptime(time, "%H:%M:%S").time()
        
class Zeitschaltuhr(object):
    def __init__(self, relays):
        self.relays = [
            (relay, parse_time(start), parse_time(end))
            for relay, (start, end) in relays
        ]
        self.relay_states = {}
        self.update()
        self._zsu_thread = threading.Thread(target=self._run_uhr)
        self._zsu_thread.daemon = True  # Don't let this thread block exiting.
        self._zsu_thread.start()
   
    def update(self):
        states = {}
        now = DateTime.now().time()
        for relay, start, end in self.relays:
            states[relay] = start <= now < end
        self.relay_states = states

    def _run_uhr(self):
        while True:
            self.update()
            time.sleep(1)
 
 
zeitschaltuhr = Zeitschaltuhr(RELAYS)
while True:
    for relay, state in sorted(zeitschaltuhr.relay_states.items()):
        print("{} {}".format(relay, "an" if state else "aus"))
    time.sleep(10)
juntiedt
User
Beiträge: 10
Registriert: Dienstag 13. Dezember 2016, 16:22

Danke!
das nenne ich genial verkürzt! Bin halt doch noch ein Anfänger in Python.

Wenn ich jetzt in einer Regelfuntion (endlos Schleife) z.B. Relay 3 zeitsteuern möchte :
while True:
if Relay 3 on .....
wie würde man das in Python richtig schreiben?

und noch eine Frage:
wenn man mehrere Schaltperioden pro Tag (z.B. 6) für ein Relay haben möchte, wie würde dann der Python code aussehen?
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@juntiedt: zu 1) schau Dir doch mal das Attribut relay_states an, zu 2) die willst etwas erweitern, dann schau erst einmal, woher die Beschränkung auf einen Zeitabschnitt kommt und was man an der Datenstruktur ändern müßte, damit man mehrere davon haben kann. Dann überlegst Du Dir, wie man den Code ändern müßte, damit die geänderte Datenstruktur auch richtig verarbeitet wird.
juntiedt
User
Beiträge: 10
Registriert: Dienstag 13. Dezember 2016, 16:22

Hallo Sirius3,

ich hab Deinen Vorschlag in mein Programm eingebaut und es funktioniert super. Eigentlich schalte ich nicht direkt ein Relais sondern Funktionen in denen irgendetwas zeitgesteuert gemacht wird - u.a. auch auf dem Raspi geschaltet.

Bei der Erweiterung der Schaltprogramme tue ich mir noch etwas schwer. Ich habe RELAYS auf 6 Zeitpaare erweitert. Ist das so richtig? Wie erweitere ich jetzt am besten die init- und die update-Funktion, damit ich durch die 6 Zeitpaare parse? Sitze irgenwie auf dem Schlauch :-(

Code: Alles auswählen

#!/usr/bin/python
import threading
import time
from datetime import datetime as DateTime
 
RELAYS = [
    ('Relay 1', ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
    ('Relay 2', ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
    ('Relay 3', ('06:45:00', '22:30:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
    ('Relay 4', ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
    ('Relay 5', ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
    ('Relay 6', ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
    ('Relay 7', ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
    ('Relay 8', ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00'), ('00:00:00', '00:00:00')),
]
 
def parse_time(time):
    return DateTime.strptime(time, "%H:%M:%S").time()
       
class Zeitschaltuhr(object):
    def __init__(self, relays):
        self.relays = [
            (relay, parse_time(start), parse_time(end))
            for relay, (start, end) in relays
        ]
        self.relay_states = {}
        self.update()
        self._zsu_thread = threading.Thread(target=self._run_uhr)
        self._zsu_thread.daemon = True  # Don't let this thread block exiting.
        self._zsu_thread.start()
   
    def update(self):
        states = {}
        now = DateTime.now().time()
        for relay, start, end in self.relays:
            states[relay] = start <= now < end
        self.relay_states = states
 
    def _run_uhr(self):
        while True:
            self.update()
            time.sleep(1)
 
 
zeitschaltuhr = Zeitschaltuhr(RELAYS)
while True:
    for relay, state in sorted(zeitschaltuhr.relay_states.items()):
        print("{} {}".format(relay, "an" if state else "aus"))
    if zeitschaltuhr.relay_states["Relay 3"] == True:
        print("Relay 3 an")
    time.sleep(10)
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@juntiedt: am besten gibst Du gar keine feste Anzahl an Zeitabschnitten an, sondern benutzt eine Liste

Code: Alles auswählen

RELAYS = [
    ('Relay 1', [],
    ('Relay 2', [(06:30:00', '12:00:00'), ('18:00:00', '20:00:00')],
]
wobei Du dann in __init__ eine doppelte Schleife für self.relays brauchst (also am besten die Listcomprehension in zwei normale Schleifen umwandeln).
juntiedt
User
Beiträge: 10
Registriert: Dienstag 13. Dezember 2016, 16:22

Hallo,

ich habe meine Zeitschaltuhr in eine Wochenschaltuhr umgemodelt. Jetzt habe ich folgendes Problem:

bei dem Wochen Programm gebe ich die Liste als Wort (WOCHE) an. (1. Pfeil)
Bei dem Tagesprogramm ermittle ich den Tag (z.B. SONNTAG) um ihn an self.programm zu übergeben.(2. Pfeil). Wie kann ich aus dem String ein Format generieren, das Python wie WOCHE versteht, also quasi Programmtext und kein String?

Code: Alles auswählen


SONNTAG = [
    ('Prog 1', ('00:00:00', '00:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('00:00:00', '00:00:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
]
WOCHE = [
    ('Prog 1', ('06:45:00', '09:59:00')),
    ('Prog 2', ('10:00:00', '12:29:00')),
    ('Prog 3', ('12:30:00', '14:29:00')),
    ('Prog 4', ('14:30:00', '17:59:00')),
    ('Prog 5', ('18:00:00', '19:59:00')),
    ('Prog 6', ('20:00:00', '23:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
]
#
#--------------------------------------------------------------------------------
# 
def parse_time(time):
    return DateTime.strptime(time, "%H:%M:%S").time()

def get_dow_n():
    return Date.today().weekday()

def get_dow_a():
    return ("MONTAG", "DIENSTAG", "MITTWOCH", "DONNERSTAG", "FREITAG", "SAMSTAG", "SONNTAG")[get_dow_n()]
#
#--------------------------------------------------------------------------------
#       
class Zeitschaltuhr(object):
    def __init__(self, ProgType):
        self.dow = get_dow_n()
        self.programm = []
        self.progs = []
        self.progs_states = {}        
        if ProgType == "Woche":
            self.programm = WOCHE     <--------------------------------------------------------------
            self._initialize()
            self._update()
            self._zsu_thread = threading.Thread(target=self._run_uhr_woche)
        if ProgType == "Tag":
            self.programm = get_dow_a()   <---------------------------------------------------------------------------------
            self._initialize()
            self._update()
            self._zsu_thread = threading.Thread(target=self._run_uhr_tag)
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@juntiedt: was ist denn der Unterschied zwischen »_run_uhr_woche« und »_run_uhr_tag«? Und was passiert, wenn sich der Tag ändert? Zum Problem: man benutzt die passende Datenstruktur, also entweder eine Liste mit 7 Einträge, für jeden Wochentag einen, oder ein Wörterbuch mit den Wochentagen als Schlüssel.
juntiedt
User
Beiträge: 10
Registriert: Dienstag 13. Dezember 2016, 16:22

Code: Alles auswählen


#!/usr/bin/python
import threading
import time
from datetime import datetime as DateTime
from datetime import date as Date
 
MONTAG = [
    ('Prog 1', ('00:00:00', '00:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('00:00:00', '00:00:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
    ('Prog 9', ('00:00:00', '00:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00')) 
]
DIENSTAG = [
    ('Prog 1', ('00:00:00', '00:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('14:00:00', '17:48:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
    ('Prog 9', ('00:00:00', '00:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00')) 
]
MITTWOCH = [
    ('Prog 1', ('10:00:00', '11:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('00:00:00', '00:00:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
    ('Prog 9', ('00:00:00', '00:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00')) 
]
DONNERSTAG = [
    ('Prog 1', ('00:00:00', '00:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('00:00:00', '00:00:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
    ('Prog 9', ('00:00:00', '00:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00')) 
]
FREITAG = [
    ('Prog 1', ('00:00:00', '00:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('00:00:00', '00:00:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
    ('Prog 9', ('00:00:00', '00:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00')) 
]
SAMSTAG = [
    ('Prog 1', ('00:00:00', '00:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('00:00:00', '00:00:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
    ('Prog 9', ('00:00:00', '00:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00')) 
]
SONNTAG = [
    ('Prog 1', ('00:00:00', '00:00:00')),
    ('Prog 2', ('00:00:00', '00:00:00')),
    ('Prog 3', ('00:00:00', '00:00:00')),
    ('Prog 4', ('00:00:00', '00:00:00')),
    ('Prog 5', ('00:00:00', '00:00:00')),
    ('Prog 6', ('00:00:00', '00:00:00')),
    ('Prog 7', ('00:00:00', '00:00:00')),
    ('Prog 8', ('00:00:00', '00:00:00')),
    ('Prog 9', ('00:00:00', '00:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00'))    
]
WOCHE = [
    ('Prog 1', ('07:00:00', '09:00:00')),
    ('Prog 2', ('10:00:00', '10:15:00')),
    ('Prog 3', ('11:00:00', '11:15:00')),
    ('Prog 4', ('12:30:00', '14:00:00')),
    ('Prog 5', ('15:00:00', '15:15:00')),
    ('Prog 6', ('16:00:00', '16:15:00')),
    ('Prog 7', ('17:00:00', '17:15:00')),
    ('Prog 8', ('18:00:00', '20:00:00')),
    ('Prog 9', ('21:30:00', '23:00:00')),
    ('Prog 10', ('00:00:00', '00:00:00'))     
]
#
#--------------------------------------------------------------------------------
# 
def parse_time(time):
    return DateTime.strptime(time, "%H:%M:%S").time()

def get_dow_n():
    return Date.today().weekday()

def get_dow_a():
    return ("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")[get_dow_n()]
#
#--------------------------------------------------------------------------------
#       
class Zeitschaltuhr(object):
    def __init__(self, ProgType):
        self.dow = get_dow_n()
        self.programm = []
        self.progs = []
        self.progs_states = {}
        
        if ProgType == "Woche":
            self.programm = WOCHE
            self._initialize()
            self._update()
            self._zsu_thread = threading.Thread(target=self._run_uhr_woche)
        if ProgType == "Tag":
            self._get_tages_programm()
            self._initialize()
            self._update()
            self._zsu_thread = threading.Thread(target=self._run_uhr_tag)

        self._zsu_thread.daemon = True  # Don't let this thread block exiting.
        self._zsu_thread.start()

    def _initialize(self):
        self.progs = [
            (prog, parse_time(start), parse_time(end))
            for prog, (start, end) in self.programm
        ]

    def _get_tages_programm(self):
        if self.dow == 0:
            self.programm = MONTAG
        elif self.dow == 1:
            self.programm = DIENSTAG
        elif self.dow == 2:
            self.programm = MITTWOCH
        elif self.dow == 3:
            self.programm = DONNERSTAG
        elif self.dow == 4:
            self.programm = FREITAG
        elif self.dow == 5:
            self.programm = SAMSTAG
        elif self.dow == 6:
            self.programm = SONNTAG
        else:
            print("falscher Wochentag")
            
    def _update(self):
        states = {}
        now = DateTime.now().time()
        for prog, start, end in self.progs:
            #print(prog)
            states[prog] = start <= now < end
            #print(states[prog])
        self.progs_states = states
        #print(self.progs_states)
 
    def get_zsu_dow_n(self):
        return self.dow
    
    def get_zsu_dow_a(self):
        return ("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")[self.dow]

    def _run_uhr_tag(self):
        while True:
            while self.dow == get_dow_n():
                self._update()
                time.sleep(1)
            self.dow = get_dow_n()
            self._get_tages_programm()
            self._initialize()
            self._update()            
            
    def _run_uhr_woche(self):
        while True:
            self._update()
            time.sleep(1)
#
#--------------------------------------------------------------------------------
#
Die Wochen- bzw Tages-zeitschaltuhr läuft jetzt. Wird Sie mit Woche intitialisiert läuft jeden Tag das Wochenprogramm. Wir sie mit Tag initialisiert läuft jeden Wochentag das entsprechende Tageszeitprogramm.
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@juntiedt: Klassen sollten nicht von irgendwoher Daten beziehen. Wie willst Du Deine Zeitschaltuhr mit verschiedenen Programmen laufen lassen? Du hast jetzt einen Parameter ProgType, obwohl die Klasse eigentlich die Zeiten bräuchte. Ich würde intuitiv den ProgType sowieso anders verstehen, "Woche" als ich gebe für jeden Wochentag andere Zeiten an und "Tag" ich gebe für jeden Tag die selben Zeiten vor.

Wie ich schon im letzten Beitrag angemerkt hatte, brauchst Du eine bessere Datenstruktur. Eine Woche ist eine Liste mit 7 Einträgen (Tage). So wie Du die Klasse jetzt geschrieben hast, hast Du eigentlich zwei Klassen ineinandergeschachtelt, die bis auf _update so gut wie keinen gemeinsamen Code haben, eine TagZeitschaltUhr und eine WochenZeitschaltUhr.

Code: Alles auswählen

def parse_time(time):
    return DateTime.strptime(time, "%H:%M:%S").time()

def parse_program(program):
    return [
        (prog, parse_time(start), parse_time(end))
        for prog, (start, end) in program
    ]

class TagZeitschaltuhr(object):
    def __init__(self):
        self.dow = get_dow_n()
        self.progs = parse_program(WOCHE)
        self.progs_states = {}
        self._update()
        self._zsu_thread = threading.Thread(target=self._run_uhr_woche)
        self._zsu_thread.daemon = True  # Don't let this thread block exiting.
        self._zsu_thread.start()

    def _update(self):
        states = {}
        now = DateTime.now().time()
        for prog, start, end in self.progs:
            states[prog] = start <= now < end
        self.progs_states = states
 
    def _run_uhr_woche(self):
        while True:
            self._update()
            time.sleep(1)

class WochenZeitschaltuhr(object):
    def __init__(self):
        self.dow = get_dow_n()
        self.progs = []
        self.progs_states = {}
        self._get_tages_programm()
        self._update()
        self._zsu_thread = threading.Thread(target=self._run_uhr_tag)
        self._zsu_thread.daemon = True  # Don't let this thread block exiting.
        self._zsu_thread.start()
 
    def _get_tages_programm(self):
        program = [MONTAG, DIENSTAG, MITTWOCH, DONNERSTAG,
            FREITAG, SAMSTAG, SONNTAG][self.dow]
        self.progs = parse_program(program)
           
    def _update(self):
        states = {}
        now = DateTime.now().time()
        for prog, start, end in self.progs:
            states[prog] = start <= now < end
        self.progs_states = states
 
    def _run_uhr_tag(self):
        while True:
            while self.dow == get_dow_n():
                self._update()
                time.sleep(1)
            self.dow = get_dow_n()
            self._get_tages_programm()
            self._initialize()
            self._update()            
Dort könnte man sich jetzt die Frage stellen, ob ein Tagesprogramm nicht einfach ein Wochenprogramm ist, das an jedem Wochentag das selbe tut und so sich eine der Klassen sparen kann.

Code: Alles auswählen

class WochenZeitschaltuhr(object):
    def __init__(self, weekly_program):
        self.progs_states = {}
        self.progs = [parse_program(program)
            for program in weekly_program]
        self._update()
        self._zsu_thread = threading.Thread(target=self._run_uhr)
        self._zsu_thread.daemon = True  # Don't let this thread block exiting.
        self._zsu_thread.start()
           
    def _update(self):
        now = DateTime.now()
        weekday = now.weekday()
        now = now.time()
        states = {}
        for prog, start, end in self.progs[weekday]:
            states[prog] = start <= now < end
        self.progs_states = states
 
    def _run_uhr(self):
        while True:
            self._update()
            time.sleep(1)

class TagZeitschaltuhr(WochenZeitschaltuhr):
    def __init__(self, daily_program):
        weekly_program = [daily_program] * 7
        WochenZeitschaltuhr.__init__(self, weekly_program)
juntiedt
User
Beiträge: 10
Registriert: Dienstag 13. Dezember 2016, 16:22

Hallo Sirius 3,

meine Zeitschaltuhr läuft jetzt fast ein Jahr problemlos.
Jetzt möchte ich aber einen Weg finden, die Schaltzeiten im laufenden Betrieb zu ändern. Ich stelle mir vor, die Schaltlisten aus einer Datei einzulesen, falls sich das Datum der Parameterdatei geändert hat. Diese würde ich z.B. alle 60 min prüfen.

Wie macht man so was am effektivsten?

Gruß Hannes
Antworten