"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.
Sirius3
User
Beiträge: 17737
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: 17737
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: 17737
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: 17737
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