Ankündigung

Einklappen
Keine Ankündigung bisher.

Automatische Beschattung

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • arnix
    antwortet
    Hi Jan,

    hatte ich schon versucht, ich versuche es aber nochmal. Welchen Typ bekommt das Item? Oder bleibt es ohne Typ?

    Grüße

    Einen Kommentar schreiben:


  • JanT
    antwortet
    Hallo Arne,

    Versuch mal bitte folgendes: Ich gehe davon aus, dass die Taster separate KNX Gruppenadressen haben. Binde die in SmartHome als Items mit enforce_updates und knx_listen (NICHT knx_cache). Diese Items werden dann bei ein Tastendruck – und nur bei Tastendruck, auch nicht bei eine SmartHome Neustart – „getriggert“.

    Viele Grüße,

    Jan

    Einen Kommentar schreiben:


  • arnix
    antwortet
    Hallo zusammen,

    ich habe mir die Logik von offline auch eingebaut und es ist jetzt bei dem Sonnenschein schon eine schöne Sache. Ich habe rund um die Uhr immer irgendeinen Zustand, der von der Logik hergenommen werden kann.

    Mein einziges Problem ist, wenn man morgens die Rollladen früher oben haben möchte, sie natürlich innerhalb kurzer Zeit wieder runterfahren, denn die Logik checkt alle 10 Minuten, was gemacht werden soll. Ich bräuchte also dringend so was...

    Zitat von Onkelandy Beitrag anzeigen
    Ich hab die Manuell-Situation so bei mir gelöst, dass die Logik zuerst mal checkt, von wem die Jalousie als Letztes aktualisiert worden ist. Wenn das nicht durch die Logik geschehen ist, dann wohl durch die Visu oder KNX Taster. Dann soll bis zur Dunkelheit (theoretisch auch nach Ablauf von einer gewissen Zeit) die Jalousie unangetastet bleiben. Das spart letztlich, für jede einzelne Jalousie ein Aktiv-Item anzulegen und abzufragen.
    Ich scheitere aber daran, in der getriggerten Logik zu unterscheiden, von woher de Impuls für den Rollladen kam. Überwacht wird zuzeit die Rollladenposition, das Fahren und das Stoppen. Ich habe schon Versuche mit trigger['by'], trigger['source'] und changed_by() gemacht. Am erfolgversprechendsten finde ich noch changed_by().
    Allerdings bekomme ich schon beim Start von smarthome.py durch das Setzen der Werte Probleme. Changed_by sagt dann mal "Cache" und mal "Init". Es kommt beim Start aber auch manchmal "knx", was ja eigentlich sonst nur bei Tasterdruck kommt. Es liegt wohl daran, dass sich nach dem Initiieren der Werte die Position mit irgendwelchen Statuswerten meldet.
    Beim Tasterdruck kommt mehrheitlich "knx", aber bei manchen Ereignissen auch "Init".
    Beim Triggern durch die Logic kommt mehrheitlich "Logic", dass würde ja helfen, aber in der Folge kommen dann auch wieder "knx"-Meldungen.
    Lediglich ein Ereignis von der Visu kann ich klar indentifizieren.Bei dem Ansatz von JanT schein ja nur die Visu eine Rolle zu spielen, aber die nutzen wir fast nie.

    Ich weiss, dass ich für eine detaillierte Analyse die Logs etc mitschicken müsste. Ich wollte aber vorab mal fragen, ob es vielleicht einen ganz anderen Ansatz gibt, um herauszufinden, woher der initiale Befehl kommt. Ideal wäre auch, wenn die Logik durch eine Rollladenbewegung mehrfach getriggert würde (Fahren, Stopp, Position)

    Vielen Dank

    Arne

    Einen Kommentar schreiben:


  • JanT
    antwortet
    Hallo offline,

    ich möchte meinen momentanen Stand basierend auf der Logik-Variante hier beschreiben. Es ist ein totes Pferd und dürfte spätestens wenn Du die Plugin-Version veröffentlichst keine Anwendung mehr finden. Ich spare mir deshalb das weitere Finetunen und Robustmachen der Logik gegenüber „Fehlkonfiguration“ . Ich würde mich freuen, wenn wir es schafften, dem Plugin die gleichen Fähigkeiten zu geben und würde die Zeit lieber in das Finetunen der Plugin-Variante investieren.

    Meine Ansätze für die Beschattungssteuerung, die mit der Raffstoreautomatik zusammen mit weiteren Logiken umgesetzt sind, sind die folgenden:

    1. Tagesablauf und Raum-Trigger
    Die Raffstore (bzw. Lamellen) werden in Abhängigkeit von Raumparametern gefahren: Anwesenheit, Kunstlicht an, Heizungsbedarf und Raummodus (Nacht/ Aufstehzeit/ Tag/Zubettgehen). Wenn niemand im Raum ist, wird je nach Heiz- oder Kühlbedarf und aktueller Solarstrahlung beschattet oder die Sonne eingelassen. Anwesenheit hat immer Priorität und ich habe unter Verwendung weiterer Items eine - für mich zufriedenstellende- Ansteuerung implementiert, siehe Beispiele in der beigefügten beschattungsautomatik.conf. Der grobe Tagesablauf bei Anwesenheit ist wie folgt: Ab dem Weckerklingeln bis zu einer halben Stunde Schonzeit später (Raum: Betriebsmodus = 1) werden die Lamellen nur eingeschränkt geöffnet (Beschattung). Danach wird, wenn möglich, die Sicht nach außen ermöglicht (Lamellenstellung 0 = gerade). Sollte die Sonne zu stark hineinscheinen, wird beschattet. Wenn es draußen ausreichend hell ist, kann man nicht in die Fenster gucken und ein Sichtschutz wird nur bei Einbruch der Dunkelheit oder, wenn das Licht im Raum angeschaltet wird (Kunstlicht = True) aktiviert. In Betriebsmodus = 3 (Zubettgehen), falls jemand halbnackt durch die Räume läuft, wird Sichtschutz auch aktiviert.

    Ein Sonderfall ist der globale Modus „Putzen“. Wenn aktiviert, werden - wenn der Raum betreten wird - die Lamellen in Richtung der Sonne gestellt, um möglichst viel Licht einzulassen (Lamellenwinkel = hell). Der Modus wird erst verlassen, wenn der globale Modus „Putzen“ wieder deaktiviert wird.

    Das Hoch- und Runterfahren der Raffstore versuche ich zu vermeiden und habe mich für folgende Variante entschieden: Im Winter bzw. in der Heizperiode darf die Automatik die Raffstore in den Wohnräumen hochfahren, wenn der Raum Heizbedarf hat und die Sonnenstrahlung hoch ist. Wieder herunterfahren wird die Automatik die Raffstore nicht. Im Sommer darf die Automatik die Raffstore entsprechend bei Bedarf herunterfahren.

    Um die Antwortzeiten klein zu halten, habe ich ein raumweises Abarbeiten der Steuerung implementiert.

    Eine allgemeine Implementation der Bedingungen über item_*, min_, max_* usw. wäre sicherlich sinnvoll, um die Flexibilität der Logik zu erhöhen.

    2. Mit einer Logik Raffstore und Markisen steuern
    Wir haben ein Satteldach und Dachfenster. Entsprechend gibt es nicht nur Raffstore sondern auch Markisen, die ich mit derselben Logik ansteuere. Deshalb auch mein Vorschlag zur Namensänderung von Raffstoreautomatik zu Beschattungsautomatik

    Um Markisen und Rollläden ansteuern zu können, habe ich den Konfigurationspunkt „Position“ der item.conf in Behanghöhe und Lamellenwinkel aufgeteilt.

    3. Optimale Lamellenwinkel für Blendschutz
    Durch die Angabe von Lamellenwinkel = beschatten in der item.conf werden die Lamellen so angesteuert, dass eine Linie von der Lamellenhinterkante durch die Vorderkante der darüberliegenden Lamelle in Richtung Sonne zeigt. Dadurch wird das Sonnenlicht gerade so abgeblockt und der Raum trotzdem nicht abgedunkelt, da Streulicht durchkommen kann.

    Die Berechnung der Lamellenwinkel für Blendschutz wird global einmal pro Logik-Aufruf unter die Annahme durchgeführt, dass die Sonne direkt vor dem Fenster steht (Azimut). Das ist eine konservative Annahme und man könnte bei seitlicher Sonne die Lamellen noch weiter öffnen. Die Lamellengeometrie, Blatttiefe und Abstand zwischen zwei Lamellen werden in der Logik angegeben.

    Die Berechnung für jedes Fenster zu wiederholen, wäre übertrieben. Es würde reichen, einmal je Fensterausrichtung die Berechnung durchzuführen.

    4. Freigaben zurücknehmen bei manueller Bedienung
    Wenn ein Raffstore manuell über die Visu bedient wird, hat das ja meist einen Grund und man möchte nicht, dass die Automatik es wenige Minuten später rückgängig macht. Ich habe dafür eine separate Logik implementiert, die auf Änderungen der Behanghöhe oder Lamellenwinkel über die Visu lauscht und dann die Freigabe für die betroffenen Raffstore aufhebt. Siehe beigelegter Quellcode „beschattungsautomatik_freigaben.py“. Dabei werden noch Freigaben raumübergreifend und global (alle Raffstore und Markisen) verwaltet. Die Raumfreigabe bleibt per Definition aktiv bis keine der Raffstore oder Markisen mehr eine Freigabe hat oder die Raumfreigabe selbst getriggert wird. Die globale Freigabe ist nur zum Setzen oder Aufheben der Freigabe. Dessen Status ist nicht definiert.

    Ich habe den Namen des Items von Aktiv auf Freigabe geändert, bestehe aber nicht drauf.

    5. Heizen/ Kühlen
    Wir Heizen mit Erdwärme und nutzen die Möglickeit der passive Kühlung im Sommer (nur Zirkulation, der Kompressor läuft nicht). Entsprechend ist die „Heizungsanlage“ immer aktiv. Im Winter wird Energie aufgewandt für das Heizen und im Sommer für das Kühlen. Die Raffstore unterstützen, indem raumweise bedarfsgerecht beschattet oder offen gelassen wird. Die Entscheidung ob beschattet oder die Lamellen die Sonne durchlassen sollen, wird über zwei kleine Logiken ausgeführt, siehe Anhang „heizung_tagesvoraussage.py“ und „beschattung_momentanbedarf.py“. Morgens um 06:00 wird nachgeschaut, ob in den letzten 24 Stunden der thermoelektrische Stellantrieb für den Raum offen war. Wenn ja, wurde Energie für die Klimatisierung aufgewandt. Ist die Anlage im Heizbetrieb war es fürs Heizen, sonst fürs Kühlen und die Beschattungsstrategie für den Tagesanfang steht fest. War der thermoelektrische Stellantrieb nicht offen, wird weiter geschaut: Zusätzlich zu einer Solltemperatur, stellen wir einen Temperaturbereich ein. In Räumen wo das Einhalten der Temperatur wichtig ist , wird ein kleiner Temperaturbereich eingestellt, sonst halt größer. Ist die durchschnittliche Temperatur der letzten 24h höher als die obere Grenze des Temperaturbereichs, wird für heute erstmal gekühlt werden. Wenn der Temperaturbereich unterschritten ist, entsprechend geheizt. Liegt die Durchschnittstemperatur innerhalb des definierten Temperaturbereichs wird anhand des Tagesmaximum und -minmum entschieden.

    Danach wird im Tagesverlauf zweimal pro Stunde die Temperatur überprüft und das Heizen oder Kühlen über die Raffstore ggf. neu gesetzt.

    6. Kalibrierung der Lamellenwinkel
    Wir nutzen zwar SMI-Antriebe für die Raffstore, wodurch die Wiederholgenauigkeit des Ansteuerns ziemlich gut ist; allerdings hat der Fensterbauer oder Raffstorehersteller im Werk „gepfuscht“, so dass die Unterschiede zwischen den Raffstoren bis zu 15 Grad beträgt. Um das auszugleichen, habe ich in einer separaten Logik eine individuelle Kalibrierung der Lamellenwinkel ermöglicht.

    Die Ausgabe der Lamellenwinkel wie auch die Angaben in „item.conf „habe ich auf Grad (statt Aktorwert) umgestellt. Den Ausgabentyp habe ich auf „str“ gesetzt, die das Anfahren der Extremposition wie ’unten’, ’kuehlen’ oder auch ’-90’ erlaubt.

    An dieser Logik bastele ich noch. Ich möchte eine transparente Umrechnung zwischen Aktorwert (Byte) und Winkel (Fließzahl). Wenn der eine geändert wird, soll der zweite sich auch ändern. Das Problem ist der „Triggerhagel“ schon beim Hochfahren wie auch beim Ausführen der Logik. Als einfache Logik habe ich die Funktion nicht reentrant hingekriegt und es kommt zur Vertauschung der Werte. Ich werde versuchen, die Funktionalität als Plugin zu implementieren.

    7. Beschattungssteuerung bei Alarm
    Das Auffahren und Sperren der Raffstore und Markisen bei Alarm oder beim Fensteröffnen ist am besten auf der unteren Ebene, sprich KNX aufgehoben.

    Viele Grüße,

    Jan

    logic.conf:
    Code:
    # logic.conf
    
    [heizung_tagesvoraussage]
        filename = heizung_tagesvoraussage.py
        crontab = 0 6 * *
     
    [beschattung_momentanbedarf]
        filename = beschattung_momentanbedarf.py
        crontab = 30 * * *
    
    [beschattungsautomatik_freigaben]
        filename = beschattungsautomatik_freigaben.py
        watch_item = globals.beschattung.automatik.freigabe | *.*.beschattung.automatik.freigabe | *.*.raffstore.*.automatik.freigabe | *.*.markise.*.automatik.freigabe | *.*.raffstore.*.lamellenwinkel_aktor | *.*.raffstore.*.behangposition_aktor | *.*.markise.*.behangposition_aktor
        crontab = init = init
    
    [beschattungsautomatik]
        filename = beschattungsautomatik.py
        watch_item =  *.*.beschattung.automatik.freigabe | *.*.markise.automatik.freigabe | og.*.betriebsmodus | *.*.anwesendheit | *.*.beleuchtung.aktiv | Wetter.helligkeit.sw | globals.putzen
        cycle = 300
    heizung_tagesvoraussage.py:
    Code:
    #!/usr/bin/env python3
    
    kuehlen = 0
    heizen = 1
    
    # Berechnung für alle Items durchführen, die ein Subitem "heizung.bedarf_kuehlen_heizen" haben
    items =  sh.match_items('*.heizung.bedarf_kuehlen_heizen')
    for item in items:              
        heizungsitem = item.return_parent()
        logger.debug("item:{}".format(heizungsitem))
        T_soll = heizungsitem.soll()
        T_range = heizungsitem.temperaturbereich()
        max_ventilstellung = heizungsitem.stellwert.db('max', '24h')
        if max_ventilstellung > 0.0:
            heizungsitem.bedarf_kuehlen_heizen(sh.globals.heizung.kuehlen_heizen())
        else:
            T_avg = heizungsitem.ist.db('avg', '24h')
            if T_avg > (T_soll + T_range):
                heizungsitem.bedarf_kuehlen_heizen(kuehlen)
            elif (T_avg) < (T_soll - T_range):
                heizungsitem.bedarf_kuehlen_heizen(heizen)
            else:
                T_min = heizungsitem.ist.db('min', '24h')
                T_max = heizungsitem.ist.db('max', '24h')
                if T_min < (T_soll - T_range) and T_max < (T_soll + T_range):
                    heizungsitem.bedarf_kuehlen_heizen(heizen)
                elif T_max > (T_soll + T_range) and T_min > (T_soll - T_range):
                    heizungsitem.bedarf_kuehlen_heizen(kuehlen)
                else:
                    pass #unverändert
    beschattung_momentanbedarf.py:
    Code:
    #!/usr/bin/env python3
    
    # Tagesvoraussagen aus_ heizung_tagesvoraussage.py
    
    kuehlen = 0
    heizen = 1
    
    # Berechnung für alle Items durchführen, die ein Subitem "heizung.bedarf_kuehlen_heizen" haben
    items =  sh.match_items('*.heizung.bedarf_kuehlen_heizen')
    for item in items:              
        heizungsitem = item.return_parent()
        T_soll = heizungsitem.soll()
        T_range = heizungsitem.temperaturbereich()
        if heizungsitem.bedarf_kuehlen_heizen() == heizen:
            if heizungsitem.ist() > (T_soll + T_range):
                heizungsitem.bedarf_kuehlen_heizen(kuehlen)
        else:
            if heizungsitem.ist() < (T_soll - T_range):
                heizungsitem.bedarf_kuehlen_heizen(heizen)
    beschattungsautomatik_freigaben.py:
    Code:
    #!/usr/bin/env python3
    
    # trigger from: globals.beschattung.automatik.freigabe | *.[room].beschattung.automatik.freigabe | *.[room].raffstore/markise.*.automatik.freigabe | *.[room].raffstore.*.lamellenwinkel_aktor | *.[room].raffstore/markise.*.behangposition_aktor
    
    def test_room_enable(sh, room):
        items =  sh.match_items("*.{0}.raffstore.*.automatik.freigabe".format(room))
        freigabe_item = sh.match_items("*.{0}.beschattung.automatik.freigabe".format(room))[0]
        one_enabled = False
        all_enabled = True
        for item in items:      
            one_enabled = one_enabled or item()
            all_enabled = all_enabled and item()
    
        items =  sh.match_items("*.{0}.markise.*.automatik.freigabe".format(room))
        for item in items:      
            one_enabled = one_enabled or item()
            all_enabled = all_enabled and item()
        if not one_enabled:
            freigabe_item = sh.match_items("*.{0}.beschattung.automatik.freigabe".format(room))[0]
            if freigabe_item() != False:
                freigabe_item(False)
        if all_enabled:
            freigabe_item = sh.match_items("*.{0}.beschattung.automatik.freigabe".format(room))[0]
            if freigabe_item() != True:
                freigabe_item(True)
    
    # Globale Freigabe
    if trigger['source'] == 'globals.beschattung.automatik.freigabe':
        # Feigabe für alle Raffstore Items setzen
        #all_items_set =  set(sh.match_items('*raffstore.*.automatik.freigabe'))
        #items = all_items_set.difference(sh.match_items('*raffstore.alle.automatik.freigabe'))
        items = sh.match_items('*.*.beschattung.automatik.freigabe')
        for item in items:      
            item(trigger['value'])
        exit()
    
    # Init
    if ('Scheduler' in trigger['by']) or ('None' in trigger['by']):
        for item in sh.match_items("*.*.beschattung.automatik.freigabe"):
            room = str(item).split('.')[1]    
            test_room_enable(sh, room)
        exit()
    
    # Test von CLI
    if 'CLI' in trigger['by']:
        room = 'schlafen'
    else:
        room = str(trigger['source']).split('.')[1]    
    
    
    # Raumweise Freigabe
    if (trigger['source'] in str(sh.match_items('*.*.beschattung.automatik.freigabe'))):
        # Feigabe für alle Raffstore und Markisen in 'room' setzen  
        items =  sh.match_items("*.{0}.raffstore.*.automatik.freigabe".format(room))
        for item in items:      
            item(trigger['value'])
        items =  sh.match_items("*.{0}.markise.*.automatik.freigabe".format(room))
        for item in items:      
            item(trigger['value'])
    
    elif (trigger['source'] in str(sh.match_items('*.*.raffstore.alle.*'))) and ('Visu' in sh.match_items(trigger['source'])[0].changed_by()):
        # Eine oder alle (im Raum) Raffstore wurde über die Visu bewegt: Automatik Freigabe zurücknehmen
        freigabe_item = sh.match_items("*.{0}.beschattung.automatik.freigabe".format(room))[0]
        if freigabe_item() != False:
            freigabe_item(False)
    
    elif (trigger['source'] in str(sh.match_items('*.*.markise.alle.*'))) and ('Visu' in sh.match_items(trigger['source'])[0].changed_by()):
        # Eine oder alle (im Raum) Raffstore wurde über die Visu bewegt: Automatik Freigabe zurücknehmen
        freigabe_item = sh.match_items("*.{0}.beschattung.automatik.freigabe".format(room))[0]
        if freigabe_item() != False:
            freigabe_item(False)
        
    elif (trigger['source'] in str(sh.match_items('*.*.raffstore.*.behangposition_aktor')) or (trigger['source'] in str(sh.match_items('*.*.raffstore.*.lamellenwinkel_aktor')))) and ('Visu' in sh.match_items(trigger['source'])[0].changed_by()):
        raffstore = str(trigger['source']).split('.')[3]
        logger.debug("Hebe Freigabe auf, aufgrund: {0}, trigger by:{1}".format(trigger['source'],sh.match_items(trigger['source'])[0].changed_by()  ))
        sh.match_items("*.{0}.raffstore.{1}.automatik.freigabe".format(room, raffstore))[0](False)
    
    elif (trigger['source'] in str(sh.match_items('*.*.markise.*.behangposition_aktor'))) and ('Visu' in sh.match_items(trigger['source'])[0].changed_by()):
        markise = str(trigger['source']).split('.')[3]
        logger.debug("Hebe Freigabe auf, aufgrund: {0}, trigger by:{1}".format(trigger['source'],sh.match_items(trigger['source'])[0].changed_by() ))
        sh.match_items("*.{0}.markise.{1}.automatik.freigabe".format(room, markise))[0](False)
    
    elif (trigger['source'] in str(sh.match_items('*.*.raffstore.*.freigabe')) or (trigger['source'] in str(sh.match_items('*.*.markise.*.freigabe')))):
        # wenn für den Raum keine Freigaben mehr aktiv sind, dann setzte Freigabe für den Raum zurück
        test_room_enable(sh, room)
    beschattungsautomatik.conf:
    Code:
    [globals]
            [[beschattung]]
                    [[[automatik]]]
                            [[[[freigabe]]]]
                            type = bool
                            enforce_updates = true
    
    [og]
            [[bad]]  
                    [[[beschattung]]]
                            [[[[automatik]]]]
                                    [[[[[freigabe]]]]]
                                    type = bool
                                    enforce_updates = true
                    [[[raffstore]]]
                            [[[[so_links]]]]
                                    [[[[[automatik]]]]]
                                    item_helligkeit = Wetter.helligkeit.so
                                    item_anwesendheit = og.bad.anwesendheit
                                    item_heizungsbedarf = og.bad.heizung.bedarf_kuehlen_heizen
                                    item_kunstlicht = og.bad.beleuchtung.aktiv
                                    item_raummodus = og.bad.betriebsmodus
    
                                            [[[[[[putzen]]]]]]
                                            name = Putzen
                                            anwesendheit = True
                                            putzen = True
                                            leave_putzen = False
                                            lamellenwinkel = hell
    
                                            ## Tageszyklus mit Anwesendheit
                                            [[[[[[morgen_daemmerung_anwesend]]]]]]
                                            name = Dämmerung am Morgen Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 5
                                            raummodus = 1
                                            lamellenwinkel = beschatten
                                            [[[[[[tag_anwesend]]]]]]
                                            name = Tag Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 20000
                                            kunstlicht = False
                                            raummodus = 2
                                            max_sun_altitude = 41
                                            min_sun_azimut = 45
                                            max_sun_azimut = 225
                                            lamellenwinkel = beschatten
                                            [[[[[[tag_anwesend_aussen_hell]]]]]]
                                            name = Tag Anwesend Hell ohne Sichtshutz
                                            anwesendheit = True
                                            min_helligheit = 500
                                            kunstlicht = False
                                            raummodus = 2
                                            lamellenwinkel = 0
                                            [[[[[[tag_anwesend_mit_sichtshutz]]]]]]
                                            name = Tag Anwesend Hell mit Sichtschutz  
                                            anwesendheit = True
                                            min_helligheit = 500
                                            kunstlicht = True
                                            raummodus = 2
                                            lamellenwinkel = 90
                                            [[[[[[abend_daemmerung_anwesend]]]]]]
                                            name = Dämmerung Abend Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 300
                                            raummodus = 2
                                            lamellenwinkel = 90
                                            [[[[[[abend_dunkel_dunkel_anwesend]]]]]]
                                            name = Abend Dunkel Anwesend
                                            anwesendheit = True
                                            max_helligkeit = 300
                                            raummodus = 2
                                            kunstlicht = False
                                            lamellenwinkel = 0                                      
                                            [[[[[[abend_dunkel_hell]]]]]]
                                            name = Abend Dunkel Anwesend
                                            max_helligkeit = 300
                                            raummodus = 2
                                            kunstlicht = True
                                            lamellenwinkel = 90                                     
                                            [[[[[[nacht_anwesend]]]]]]
                                            name = Nacht Anwesend
                                            anwesendheit = True  
                                            raummodus = 0
                                            hoehe = 100
                                            lamellenwinkel = 90
                                            [[[[[[default_anwesend]]]]]]
                                            name = Default Anwesend
                                            anwesendheit = True
                                            lamellenwinkel = 90
     
                                            ## Tageszyklus ohne Anwesendheit
                                            [[[[[[nacht_abwesend]]]]]]
                                            name = Nacht Abwesend
                                            anwesendheit = False  
                                            max_helligkeit = 5
                                            #max_solarstrahlung = 5 #kuehlen/heizen nicht mehr relevant
                                            raummodus = 0
                                            lamellenwinkel = 90
                                            [[[[[[heizen_winter]]]]]]
                                            name = heizen im Winter
                                            anwesendheit = False
                                            raummodus = 2
                                            heizperiode = True
                                            heizungsbedarf = True
                                            min_solarstrahlung = 100
                                            min_sun_azimut = 45
                                            max_sun_azimut = 225
                                            #hoehe = 0
                                            lamellenwinkel = heizen
                                            [[[[[[heizen]]]]]]
                                            name = heizen
                                            anwesendheit = False
                                            heizungsbedarf = True
                                            min_solarstrahlung = 50
                                            min_sun_azimut = 45
                                            max_sun_azimut = 225
                                            #hoehe = auto #hoehe nie verstellen?
                                            lamellenwinkel = heizen
                                            [[[[[[kuehlen_sommer]]]]]]
                                            name = Kühlen im Sommer
                                            anwesendheit = False
                                            heizperiode = False
                                            heizungsbedarf = False
                                            min_solarstrahlung = 600
                                            min_sun_azimut = 45
                                            max_sun_azimut = 225
                                            hoehe = 100
                                            lamellenwinkel = kuehlen
                                            [[[[[[kuehlen]]]]]]
                                            name = Kühlen
                                            anwesendheit = False
                                            heizungsbedarf = False
                                            min_solarstrahlung = 50
                                            min_sun_azimut = 45
                                            max_sun_azimut = 225
                                            #hoehe = auto #hoehe nie verstellen?
                                            lamellenwinkel = kuehlen
                                            [[[[[[default_abwesend]]]]]]
                                            name = Default Abwesend
                                            anwesendheit = False
                                            lamellenwinkel = 0
    
    
                                            [[[[[[freigabe]]]]]]
                                            type = bool
                                            value = 1
                                            cache = on
                                            [[[[[[letzte_position_id]]]]]]
                                            type = str
                                            cache = on
                                            [[[[[[letzte_position_name]]]]]]
                                            type = str
                                            cache = on
    
            [[schlafen]]  
                    [[[beschattung]]]
                            [[[[automatik]]]]
                                    [[[[[freigabe]]]]]
                                    type = bool
                                    enforce_updates = true
                    [[[raffstore]]]
                            [[[[sw]]]]
                                    [[[[[automatik]]]]]
                                    item_helligkeit = Wetter.helligkeit.sw
                                    item_anwesendheit = og.schlafen.anwesendheit
                                    item_heizungsbedarf = og.schlafen.heizung.bedarf_kuehlen_heizen
                                    item_kunstlicht = og.schlafen.beleuchtung.aktiv
                                    item_raummodus = og.schlafen.betriebsmodus
    
                                            [[[[[[putzen]]]]]]
                                            name = Putzen
                                            anwesendheit = True
                                            putzen = True
                                            leave_putzen = False
                                            lamellenwinkel = hell
    
                                            ## Tageszyklus mit Anwesendheit
                                            [[[[[[morgen_daemmerung_anwesend]]]]]]
                                            name = Dämmerung am Morgen Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 5
                                            raummodus = 1
                                            lamellenwinkel = beschatten
                                            [[[[[[tag_anwesend]]]]]]
                                            name = Tag Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 20000
                                            kunstlicht = False
                                            raummodus = 2
                                            max_sun_altitude = 41
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            lamellenwinkel = beschatten
                                            [[[[[[tag_anwesend_aussen_hell]]]]]]
                                            name = Tag Anwesend Hell ohne Sichtshutz
                                            anwesendheit = True
                                            min_helligheit = 500
                                            kunstlicht = False
                                            raummodus = 2
                                            lamellenwinkel = 0
                                            [[[[[[tag_anwesend_mit_sichtshutz]]]]]]
                                            name = Tag Anwesend Hell mit Sichtschutz  
                                            anwesendheit = True
                                            min_helligheit = 500
                                            kunstlicht = True
                                            raummodus = 2
                                            lamellenwinkel = 90
                                            [[[[[[abend_daemmerung_anwesend]]]]]]
                                            name = Dämmerung Abend Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 300
                                            raummodus = 2
                                            lamellenwinkel = 90
                                            [[[[[[abend_dunkel_dunkel_anwesend]]]]]]
                                            name = Abend Dunkel Anwesend
                                            anwesendheit = True
                                            max_helligkeit = 300
                                            raummodus = 2
                                            kunstlicht = False
                                            lamellenwinkel = 0                                      
                                            [[[[[[abend_dunkel_hell]]]]]]
                                            name = Abend Dunkel Anwesend
                                            max_helligkeit = 300
                                            raummodus = 2
                                            kunstlicht = True
                                            lamellenwinkel = 90                                     
                                            [[[[[[abens_anwesend_kunstlicht]]]]]]
                                            name = Zubettgehen (Abend) mit Kunstlicht
                                            anwesendheit = True
                                            kunstlicht = True
                                            raummodus = 3
                                            lamellenwinkel = -90
                                            [[[[[[abens_anwesend]]]]]]
                                            name = Zubettgehen (Abend) ohne Kunstlicht
                                            anwesendheit = True
                                            kunstlicht = False
                                            raummodus = 3
                                            lamellenwinkel = 0
                                            [[[[[[nacht_anwesend]]]]]]
                                            name = Nacht Anwesend
                                            anwesendheit = True  
                                            raummodus = 0
                                            hoehe = 100
                                            lamellenwinkel = -90
                                            [[[[[[default_anwesend]]]]]]
                                            name = Default Anwesend
                                            anwesendheit = True
                                            lamellenwinkel = 90
     
                                            ## Tageszyklus ohne Anwesendheit
                                            [[[[[[nacht_abwesend]]]]]]
                                            name = Nacht Abwesend
                                            anwesendheit = False  
                                            max_helligkeit = 5
                                            raummodus = 0
                                            lamellenwinkel = -90
                                            [[[[[[heizen_winter]]]]]]
                                            name = heizen im Winter
                                            anwesendheit = False
                                            raummodus = 2
                                            heizperiode = True
                                            heizungsbedarf = True
                                            min_solarstrahlung = 100
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            hoehe = 0
                                            lamellenwinkel = heizen
                                            [[[[[[heizen]]]]]]
                                            name = heizen
                                            anwesendheit = False
                                            heizungsbedarf = True
                                            min_solarstrahlung = 50
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            #hoehe = auto #hoehe nie verstellen?
                                            lamellenwinkel = heizen
                                            [[[[[[kuehlen_sommer]]]]]]
                                            name = Kühlen im Sommer
                                            anwesendheit = False
                                            heizperiode = False
                                            heizungsbedarf = False
                                            min_solarstrahlung = 600
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            hoehe = 100
                                            lamellenwinkel = kuehlen
                                            [[[[[[kuehlen]]]]]]
                                            name = Kühlen
                                            anwesendheit = False
                                            heizungsbedarf = False
                                            min_solarstrahlung = 50
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            #hoehe = auto #hoehe nie verstellen?
                                            lamellenwinkel = kuehlen
                                            [[[[[[default_abwesend]]]]]]
                                            name = Default Abwesend
                                            anwesendheit = False
                                            lamellenwinkel = 0
     
    
                                            [[[[[[freigabe]]]]]]
                                            type = bool
                                            value = 1
                                            cache = on
                                            [[[[[[letzte_position_id]]]]]]
                                            type = str
                                            cache = on
                                            [[[[[[letzte_position_name]]]]]]
                                            type = str
                                            cache = on
    
                    [[[markise]]]
                            [[[[so_unten]]]]
                                    [[[[[automatik]]]]]
                                    item_helligkeit = Wetter.helligkeit.so
                                    item_anwesendheit = og.schlafen.anwesendheit
                                    item_heizungsbedarf = og.schlafen.heizung.bedarf_kuehlen_heizen
                                    item_raummodus = og.schlafen.betriebsmodus
                                    item_kunstlicht = og.schlafen.beleuchtung.aktiv
    
                                            [[[[[[putzen]]]]]]
                                            name = Putzen
                                            putzen = True
                                            hoehe = 0
    
                                            ## Tageszyklus mit/ohne Anwesendheit
                                            [[[[[[blendenschutz]]]]]]
                                            name = Blendenschutz
                                            raummodus = 2
                                            min_helligkeit = 20000
                                            hoehe = 100
                                            [[[[[[nacht]]]]]]
                                            name = Nacht
                                            raummodus = 0
                                            hoehe = 100
                                            [[[[[[heizen]]]]]]
                                            name = Heizen
                                            raummodus = 2
                                            min_solarstrahlung = 200
                                            heizungsbedarf = True
                                            min_sun_azimut = 45
                                            max_sun_azimut = 225
                                            hoehe = 0
                                            [[[[[[kuehlen]]]]]]
                                            name = Kühlen
                                            raummodus = 2
                                            min_solarstrahlung = 200
                                            heizungsbedarf = False
                                            min_sun_azimut = 45
                                            max_sun_azimut = 225
                                            hoehe = 100
    
    
                                            [[[[[[freigabe]]]]]]
                                            type = bool
                                            value = 1
                                            cache = on
                                            [[[[[[letzte_position_id]]]]]]
                                            type = str
                                            cache = on
                                            [[[[[[letzte_position_name]]]]]]
                                            type = str
                                            cache = on
    
    
            [[wohnen]]
                    [[[beschattung]]]
                            [[[[automatik]]]]
                                    [[[[[freigabe]]]]]
                                    type = bool
                                    enforce_updates = true
                    [[[raffstore]]]   
                            [[[[sw_links]]]]
                                    [[[[[automatik]]]]]
                                    item_helligkeit = Wetter.helligkeit.sw
                                    item_anwesendheit = eg.wohnen.anwesendheit
                                    item_heizungsbedarf = eg.wohnen.heizung.bedarf_kuehlen_heizen
                                    item_kunstlicht = eg.wohnen.beleuchtung.aktiv
                                    item_raummodus = eg.wohnen.betriebsmodus
    
                                            [[[[[[putzen]]]]]]
                                            name = Putzen
                                            anwesendheit = True
                                            putzen = True
                                            leave_putzen = False
                                            lamellenwinkel = hell
    
                                            ## Tageszyklus mit Anwesendheit
                                            [[[[[[morgen_daemmerung_anwesend]]]]]]
                                            name = Dämmerung am Morgen Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 5
                                            raummodus = 1
                                            lamellenwinkel = beschatten
                                            [[[[[[tag_anwesend]]]]]]
                                            name = Tag Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 20000
                                            kunstlicht = False
                                            raummodus = 2
                                            max_sun_altitude = 41
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            lamellenwinkel = beschatten
                                            [[[[[[tag_anwesend_aussen_hell]]]]]]
                                            name = Tag Anwesend Hell ohne Sichtshutz
                                            anwesendheit = True
                                            min_helligheit = 500
                                            kunstlicht = False
                                            raummodus = 2
                                            lamellenwinkel = 0
                                            [[[[[[tag_anwesend_mit_sichtshutz]]]]]]
                                            name = Tag Anwesend Hell mit Sichtschutz  
                                            anwesendheit = True
                                            min_helligheit = 500
                                            kunstlicht = True
                                            raummodus = 2
                                            lamellenwinkel = 90
                                            [[[[[[abend_daemmerung_anwesend]]]]]]
                                            name = Dämmerung Abend Anwesend  
                                            anwesendheit = True
                                            min_helligkeit = 300
                                            raummodus = 2
                                            lamellenwinkel = 90
                                            [[[[[[abend_dunkel_dunkel_anwesend]]]]]]
                                            name = Abend Dunkel Anwesend
                                            anwesendheit = True
                                            max_helligkeit = 300
                                            raummodus = 2
                                            kunstlicht = False
                                            lamellenwinkel = 0                                      
                                            [[[[[[abend_dunkel_hell]]]]]]
                                            name = Abend Dunkel Anwesend
                                            max_helligkeit = 300
                                            raummodus = 2
                                            kunstlicht = True
                                            lamellenwinkel = 90                                     
                                            [[[[[[nacht_anwesend]]]]]]
                                            name = Nacht Anwesend
                                            anwesendheit = True  
                                            raummodus = 0
                                            lamellenwinkel = -90
                                            [[[[[[default_anwesend]]]]]]
                                            name = Default Anwesend
                                            anwesendheit = True
                                            lamellenwinkel = 90
     
                                            ## Tageszyklus ohne Anwesendheit
                                            [[[[[[nacht_abwesend]]]]]]
                                            name = Nacht Abwesend
                                            anwesendheit = False  
                                            max_helligkeit = 5
                                            raummodus = 0
                                            lamellenwinkel = -90
                                            [[[[[[heizen_winter]]]]]]
                                            name = heizen im Winter
                                            anwesendheit = False
                                            raummodus = 2
                                            heizperiode = True
                                            heizungsbedarf = True
                                            min_solarstrahlung = 100
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            hoehe = 0
                                            lamellenwinkel = heizen
                                            [[[[[[heizen]]]]]]
                                            name = heizen
                                            anwesendheit = False
                                            heizungsbedarf = True
                                            min_solarstrahlung = 50
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            #hoehe = auto #hoehe nie verstellen?
                                            lamellenwinkel = heizen
                                            [[[[[[kuehlen_sommer]]]]]]
                                            name = Kühlen im Sommer
                                            anwesendheit = False
                                            heizperiode = False
                                            heizungsbedarf = False
                                            min_solarstrahlung = 600
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            hoehe = 100
                                            lamellenwinkel = kuehlen
                                            [[[[[[kuehlen]]]]]]
                                            name = Kühlen
                                            anwesendheit = False
                                            heizungsbedarf = False
                                            min_solarstrahlung = 50
                                            min_sun_azimut = 135
                                            max_sun_azimut = 315
                                            #hoehe = auto #hoehe nie verstellen?
                                            lamellenwinkel = kuehlen
                                            [[[[[[default_abwesend]]]]]]
                                            name = Default Abwesend
                                            anwesendheit = False
                                            lamellenwinkel = 0
    
     
                                            [[[[[[freigabe]]]]]]
                                            type = bool
                                            value = 1
                                            cache = on
                                            [[[[[[letzte_position_id]]]]]]
                                            type = str
                                            cache = on
                                            [[[[[[letzte_position_name]]]]]]
                                            type = str
                                            cache = on
    beschattungsautomatik.py:
    Code:
    # Raffstore Automatik V2
    #
    # ThEr081014    Initiale fertigstellung
    # ThEr141014    Aktivierung über Subitem "Aktiv" anstatt über Attribut "aktiv"
    # ThEr141014    Item für letzte Position auch unterhalb von "RaffstoreAutomatik"
    # ThEr141014    Zusätzliches Item für den Namen der letzten Position
    # JT  240415    Bugfix in Bediengunsauswertung Azimut und Uhrzeit
    #               Verarbeitung von weitere Items für die Bediengungsauswertung - globale und raumbezogene
    #               Raumweise Trigger und Verarbeitung möglich
    #               Berechnung der optimale Lamellenstellung für Beschattung: kein direkter Sonneneinlass, dabei
    #                  Lamellen möglichst weit offen (Eine gedachte Linie von der Hinterkante eine Lamelle zum Vorderkante
    #                  der überliegende Lamelle zeigt in richtung Sonne)
    #               Trennung von behanghöhe und Lamellenwinkel um auch Markisen steuern zu können
    #               Umstellung Einheiten: Lamellenwinkel in Grad, Behanghoehe in %
    #               Ausgabeitems als String, ermöglicht angabe der Extremstellungen
    #               Behhangposition: auto => bei Beschattung und Kühlen Behang nach unten fahren sonnst unverändert NICHT GETSETET!                   
    #
    # Einheiten:
    #   item.conf: hoehe: [%], 0% oben, 100% unten
    #   item.conf: lamellemwinkel [°], 90° nach oben, -90° nach unten
    #                   
    #
    # ToDo: Lösche alte Werte wenn Freigabe zurückgenommen wird
    #
    
    
    class RaffstoreAutomatik:
        # Konstruktor
        def __init__(self, sh):
    
            import math     
            logger.info("Initialisiere Raffstore-Automatik")
    
            # Daten übernehmen
            self.sh = sh
            self.item = None
    
            # Zeit ermitteln
            now = time.localtime()        
            self.akt_zeit = [now.tm_hour,now.tm_min]
    
            # Position der Sonne ermitteln und in Dezimalgrad umrechnen
            azimut, altitude = self.sh.sun.pos()
            self.sun_azimut = math.degrees(float(azimut))
            self.sun_altitude = math.degrees(float(altitude))
    
            # Solarstrahlung ermitteln
            self.solar_radiation = sh.Wetter.davis.solarstrahlung()
    
            # Heizperiode aktiv setzen
            self.heizperiode = sh.globals.heizung.kuehlen_heizen()
    
            # Putzmodus ermitteln
            self.putzen = sh.globals.putzen()
    
            # Lamellen geometrie
            L = 8.4
            H = 7.2
     
            # Grenzwert Sonnenhoehe für Beschattung
            sun_altitude_lim = math.degrees(math.atan((2*H*L+math.sqrt((2*H*L)**2-4*L**2*H**2))/(2*L**2)))
    
            c = H**2-L**2
            a = (math.tan(math.radians(self.sun_altitude)))**2+1.0
            b = -2*math.tan(math.radians(self.sun_altitude))*H
            x = ((-b+math.sqrt(b**2-4*a*c))/(2*a))/L
            if(self.sun_altitude < sun_altitude_lim):
                self.shadow_angle = math.degrees(-math.acos(x))
            else:
                self.shadow_angle = math.degrees(math.acos(x))            
    
            logger.info("Sonnenhöe: {0}, optimale Lamellenwinkel für Beschattung: {1} ".format(self.sun_altitude,self.shadow_angle))
    
            if sh.trigger_source != None and (sh.trigger_source in str(sh.match_items("*.*.anwesendheit")) or sh.trigger_source in str(sh.match_items("*.*.beleuchtung.aktiv"))):
                # Automatik für alle Raffstore im Raum des Triggeritems durchführen, die ein Subitem "automatik" mit Subitem "freigabe = 1" haben
                room = sh.trigger_source.split('.')[1]
                logger.info("Raffstore-Automatik trigger für Raum:{0}".format(room))
                items =  sh.match_items("*.{0}.raffstore.*.automatik.freigabe".format(room))
                for item in items:              
                    if (item() == 1):
                        self.__run(item.return_parent())
                # Automatik für alle Markisen im Raum des Triggeritems durchführen, die ein Subitem "automatik" mit Subitem "freigabe = 1" haben
                room = sh.trigger_source.split('.')[1]
                logger.info("Markisen-Automatik trigger für Raum:{0}".format(room))
                items =  sh.match_items("*.{0}.markise.*.automatik.freigabe".format(room))
                for item in items:              
                    if (item() == 1):
                        self.__run(item.return_parent())
    
            else:
                # Automatik für alle Raffstore Items durchführen, die ein Subitem "automatik" mit Subitem "freigabe = 1" haben
                items =  sh.match_items("*.*.raffstore.*.automatik.freigabe")
                logger.info("Raffstore-Automatik trigger für alle Räume")
                for item in items:              
                    if (item() == 1):
                        self.__run(item.return_parent())
                # Automatik für alle markisen Items durchführen, die ein Subitem "automatik" mit Subitem "freigabe = 1" haben
                items =  sh.match_items("*.*.markise.*.automatik.freigabe")
                logger.info("Markisen-Automatik trigger für alle Räume")
                for item in items:              
                    if (item() == 1):
                        self.__run(item.return_parent())
    
    
        # Führt die Automatik für ein Raffstore-Item durch
        def __run(self, item):
            logger.info("Starte Raffstore-Automatik mit Item {0}".format(item.id()))
    
            # Daten übernehmen
            self.item = item.return_parent()
            self.config = item.conf
    
            # Items holen
            self.item_letzte_position_id = self.__get_child_item(item,"letzte_position_id")
            self.item_letzte_position_name = self.__get_child_item(item,"letzte_position_name")
    
            try:
                self.item_helligkeit = self.sh.return_item(self.config["item_helligkeit"])
                if self.item_helligkeit == None:
                    raise AttributeError("Das für 'item_helligkeit' angegebene Item '%s' ist unbekannt." %(self.config['item_helligkeit']))
            except KeyError:
                self.item_helligkeit = None
    
    
            self.item_anwesendheit = self.sh.return_item(self.config["item_anwesendheit"])
            if self.item_anwesendheit == None:
                raise AttributeError("Das für 'item_anwesendheit' angegebene Item '%s' ist unbekannt." %(self.config['item_anwesendheit']))
    
            self.item_heizungsbedarf = self.sh.return_item(self.config["item_heizungsbedarf"])
            if self.item_heizungsbedarf == None:
                raise AttributeError("Das für 'item_heizungsbedarf' angegebene Item '%s' ist unbekannt." %(self.config['item_heizungsbedarf']))
    
            self.item_kunstlicht = self.sh.return_item(self.config["item_kunstlicht"])
            if self.item_kunstlicht == None:
                raise AttributeError("Das für 'item_kunstlicht' angegebene Item '%s' ist unbekannt." %(self.config['item_kunstlicht']))
    
            self.item_raummodus = self.sh.return_item(self.config["item_raummodus"])
            if self.item_raummodus == None:
                raise AttributeError("Das für 'item_raummodus' angegebene Item '%s' ist unbekannt." %(self.config['item_raummodus']))
    
            self.items_position = self.sh.find_children(self.item, "hoehe")
            self.items_position += self.sh.find_children(self.item, "lamellenwinkel")
                
            logger.info("items_position: {0}".format(self.items_position))
    
            # Anwesendheit ermitteln        
            try:
                self.anwesendheit = self.item_anwesendheit()            
            except:
                self.anwesendheit = None
    
            # Relevante Helligkeit ermitteln        
            try:
                self.helligkeit = self.item_helligkeit()            
            except:
                self.helligkeit = None
    
            # Heizungsbedarf ermitteln        
            try:
                self.heizungsbedarf = self.item_heizungsbedarf()            
            except:
                self.heizungsbedarf = None
    
            # Status Kunstlicht ermitteln        
            try:
                self.kunstlicht = self.item_kunstlicht()            
            except:
                self.kunstlicht = None
    
            # Status Raum Betriebsmodus ermitteln        
            try:
                self.raummodus = self.item_raummodus()            
            except:
                self.raummodus = None
    
            # Bisherige Position ermitteln
            old_pos_item_id = self.item_letzte_position_id()
            old_pos_item = self.sh.return_item(old_pos_item_id)
            if old_pos_item != None and not self.__check_leave_pos_item(old_pos_item):
                logger.info("Position kann nicht verlassen werden")
                new_pos_item = old_pos_item
            else:       
                # Passende Position heraussuchen
                new_pos_item = self.__find_pos_item()
                if new_pos_item == None:
                    logger.info("Keine passende Position gefunden!")
                    return
    
                # Position im Item "Modus" speichern
                new_pos_item_id = new_pos_item.id()     
                new_pos_item_name = new_pos_item._name      
                self.item_letzte_position_id(new_pos_item_id)
                self.item_letzte_position_name(new_pos_item_name)
                logger.info("Neue Position: '{0}' ({1})".format(new_pos_item_name,new_pos_item_id))
    
    
            # Raffstoreposition aus dem Positions-Item ermitteln
            #position = self.__get_position_from_pos_item(new_pos_item)
            ret = self.__get_angle_from_pos_item(new_pos_item)
            angle = ret[0]
            anglecontrol = ret[1]
            height = self.__get_height_from_pos_item(new_pos_item, anglecontrol)
    
            # Raffstoreposition anfahren
            if height == None: return
            try:
                logger.info("Fahre auf Höhe {0:.0f}%, Lamelle {1:.1f}°".format(height, angle))
            except ValueError:
                logger.info("Fahre auf Höhe {0}, Lamelle {1}".format(height, angle))
    
            #Items für Raffstoresteuerung holen
            item_hoehe = self.__get_child_item(self.item,"behangposition_prozent")
            try:
                item_lamelle = self.__get_child_item(self.item,"lamellenwinkel_grad")
                logger.info("item_lamelle: {0}".format(item_lamelle))
            except AttributeError: # ToDo: nur wenn Markise erlauben
                item_lamelle = None
                
    
            # Fahrbefehl für Höhe nur senden, wenn wir um mindestens 10% verändern //Attribut "hoehe" existiert und
            try:
                hoehe_delta = self.__byte2rel(item_hoehe()) - height            
                if (abs(hoehe_delta) > 10):
                    #item_hoehe(position[0])
                    item_hoehe(int(self.__rel2byte(height) + 0.5))
            except:
                pass
    
            # Fahrbefehl für Lamelle nur, wenn "lamellenwinkel" exisitiert, der Raffstore um mindestens 10% herabgelassen ist
            # und die Winkeländerung > 2° ist        
            try:
                if item_lamelle != None:
                    if len(item_lamelle()) == 0: # Lamellenitem leer?
                        logger.debug("item_lamelle: {0}".format(item_lamelle))
                        logger.debug("angle: {0}".format(angle))
                        try:
                            winkel_delta = float(item_lamelle()) - angle
                            if (abs(winkel_delta) >= 2 and height > 10):
                                item_lamelle(str(int(angle + 0.5)))
                        except (ValueError, TypeError):
                            if angle != item_lamelle():
                                item_lamelle(str(angle))
                    else:
                        try:
                            winkel_delta = float(item_lamelle()) - angle
                            if (abs(winkel_delta) >= 2 and height > 10):
                                item_lamelle(str(int(angle + 0.5)))
                        except (ValueError, TypeError):
                            if angle != item_lamelle():
                                item_lamelle(str(angle))
            except ValueError:
                logger.info("Fehler in Lamellentem: {0}='{1}'".format(item_lamelle, item_lamelle()))
     
        # Liest die Positionsinformationen aus einem Item und gibt Sie im Format "Liste [%Höhe,%Lamelle]" zurück
        def __get_position_from_pos_item(self, item):
            if not 'position' in item.conf:
                id = item.id()
                logger.error("Das Item '{0}' enthält kein Attribut 'position'".format(id))
                return None
    
            value = item.conf['position']
            if value == 'auto':
                return self.__get_position_from_sun()
    
            value_parts = value.split(",")
            if len(value_parts) != 2:
                id = item.id()
                logger.error("Das Konfigurations-Attribut '{0}' im Item '{1}' muss im Format '###, ###' angegeben werden.".format(attribute, id))
                return None
            else:
                try:
                    hoehe = int(value_parts[0])
                    lamelle = int(value_parts[1])
                    return [hoehe,lamelle]
                except ValueError:
                    id = item.id()
                    logger.error("Das Konfigurations-Attribut '{0}' im Item '{1}' muss im Format '###, ###' angegeben werden.".format(attribute, id))
                    return None
    
        # Liest die Positionsinformationen aus einem Item und gibt die Lamellenwinkel zurück
        def __get_angle_from_pos_item(self, item):
            if not 'lamellenwinkel' in item.conf: # lamellenwinkel nicht ändern
                return [None, 'None']
            value = item.conf['lamellenwinkel']
            if value in ['down', 'min', 'unten', 'max_down', 'max_unten', 'cooling', 'kuehlen', '-90']:
                return ['max_unten', 'kuehlen']
            elif value == 'heizen':
                return [self.__get_angle_from_sun_heating(), 'heizen']
            elif value == 'hell':
                return [self.__get_angle_from_sun_heating(), 'hell']
            elif value == 'beschatten':
                return [self.__get_angle_from_sun_shadow(), 'beschatten']
            else:
                try:
                    angle = int(value)
                    return [angle, 'None']
                except ValueError:
                    id = item.id()
                    logger.error("Das Konfigurations-Attribut '{0}' im Item '{1}' ist Fehlerhaft.".format(attribute, id))
                    return None
    
    
                
        # Liest die Positionsinformationen aus einem Item und gibt die Höhe zurück
        def __get_height_from_pos_item(self, item, anglecontrol):
            if not 'hoehe' in item.conf: # hohe nicht ändern verwende jetztige Wert
                item_hoehe = self.__get_child_item(self.item,"behangposition_prozent")
                return item_hoehe()
    
                
            value = item.conf['hoehe']
            if value == 'auto':
                if value in ['kuehlen', 'beschatten']:
                    return 100
            else:
                try:
                    hoehe = int(value)
                    return hoehe
                except ValueError:
                    id = item.id()
                    logger.error("Das Konfigurations-Attribut '{0}' im Item '{1}' ist Fehlerhaft.".format(attribute, id))
                    return None
    
    
        # Liefert eine Positionsangabe für den Raffstore basierend auf dem Sonnenstand
        # Zur Nachführung wird der Raffstore ganz heruntergefahren und versucht,
        # den Lamellenwinkel senkrecht zur Sonne zu stellen.
        def __get_position_from_sun(self):
            #TODO % => byte
            logger.info("Sonnenposition: Azimut {0} Altitude {1}".format(self.sun_azimut,self.sun_altitude))
    
            # Raffstore senkrecht zur Sonne stellen
            winkel = 90-self.sun_altitude
            logger.info("Winkel auf {0}°".format(winkel))
    
            # Umrechnen auf Wert (90° = 0%, 0° = 50%, -90° = 100%)
            prozent = 50-winkel/90*50
            logger.info("Lamelle auf {0}%".format(prozent))
    
            return [100,prozent]
    
        # Liefert ein Lamellenwinkel in % für Heizbetrieb basierend auf dem Sonnenstand
        def __get_angle_from_sun_heating(self):
            logger.info("Sonnenposition: Azimut {0} Altitude {1}".format(self.sun_azimut,self.sun_altitude))
    
            # Lamellen richtung Sonne stellen
            winkel = self.sun_altitude
            logger.info("Winkel auf {0}°".format(winkel))
    
            # Umrechnen auf Wert (90° = 0%, 0° = 50%, -90° = 100%)
            # prozent = 50-winkel/90*50
            #byte = self.__deg2byte(winkel)
            #logger.info("Lamelle auf {0}/255".format(byte))
    
            return winkel
    
        # Liefert ein Lamellenwinkel in % für eine optimierte Beschattung basierend auf dem Sonnenstand
        def __get_angle_from_sun_shadow(self):
            logger.info("Sonnenposition: Azimut {0} Altitude {1}".format(self.sun_azimut,self.sun_altitude))
    
            # Lamellen einstellen so, dass gearde alles abgeschattet ist
            winkel = self.shadow_angle
            logger.info("Winkel auf {0}°".format(winkel))
            
            return winkel
    
    
        # Sucht ein bestimmtes Item unterhalb eines gegebenen Items
        # Wenn das Item gefunden wird, wird es zurückgegeben
        # Wird das Item nicht gefunden, wird ein AttributeError geworfen
        def __get_child_item(self, item, child_id):
            search_id = item.id()+"."+child_id
            for child in item.return_children():
                if child.id() == search_id:
                    return child
            itemId = self.item.id()
            raise AttributeError("Unterhalb des Items '%s' fehlt ein Item '%s'" %(itemId, child_id))
    
        # Loopt durch alle Positionen und liefert die erste Position zurück, bei der alle Bedingungen erfüllt sind
        def __find_pos_item(self):
            logger.info("Suche Item für Zeit = {0}, Helligkeit = {1}, Sonnenhöhe = {2:.1f}°, Sonne Azimut: {3:.1f}°, Heizperiode: {4}, Putzmodus: {5}, Anwesendheit = {6}, Heizungsbedarf = {7}, Solarstrahlung = {8}, Kunstlicht aktiv = {9}, Raummodus = {10}".format(self.akt_zeit, self.helligkeit, self.sun_altitude, self.sun_azimut, self.heizperiode, self.putzen, self.anwesendheit, self.heizungsbedarf, self.solar_radiation, self.kunstlicht, self.raummodus))    
            for item in self.items_position:
                if self.__check_enter_pos_item(item):
                    return item
            return None
    
        # Prüft, ob die in einem Positions-Item erfassten Leave-Bedingungen erfüllt sind, so dass die Position wieder verlassen werden darf
        # position: Positions-Item mit den Bedingungen als Attribute
        # Rückgabe: TRUE: Position darf verlassen werden, FALSE: Position darf nicht verlassen werden
        def __check_leave_pos_item(self, position):
            id = position.id()
            logger.info("Prüfe ob Position '{0}' verlassen werden darf".format(id))
    
            # Helligkeitsbedingung      
            if 'leave_min_helligkeit' in position.conf and self.helligkeit < int(position.conf['leave_min_helligkeit']):
                logger.info(" -> zu dunkel")
                return False;
            if 'leave_max_helligkeit' in position.conf and self.helligkeit > int(position.conf['leave_max_helligkeit']):
                logger.info(" -> zu hell")
                return False;
    
            # Solarstrahlung
            if 'leave_min_solarstrahlung' in position.conf and self.solar_radiation < int(position.conf['leave_min_solarstrahlung']):
                logger.info(" -> Solarstrahlung zu gering")
                return False;
            if 'leave_max_solarstrahlung' in position.conf and self.solar_radiation > int(position.conf['leave_max_solarstrahlung']):
                logger.info(" -> Solarstrahlung zu hoch")
                return False;
    
    
            # Zeitbedingung
            if 'leave_min_zeit' in position.conf or 'leave_max_zeit' in position.conf:
                min_zeit = self.__get_time_attribute(position,"leave_min_zeit",[0,0])
                max_zeit = self.__get_time_attribute(position, "leave_max_zeit", [24,00])   
                if self.__compare_time(min_zeit, max_zeit) != 1:
                    # min </= max: Normaler Vergleich
                    if self.__compare_time(self.akt_zeit, min_zeit) == -1 or self.__compare_time(self.akt_zeit, max_zeit) == 1:
                        logger.info(" -> außerhalb der Zeit (1)")
                        return False
                else:
                    # min > max: Invertieren
                    #if self.__compare_time(self.akt_zeit, min_zeit) == 1 and self.__compare_time(self.akt_zeit, min_zeit) == -1:
                    if self.__compare_time(self.akt_zeit, min_zeit) == -1 and self.__compare_time(self.akt_zeit, max_zeit) == 1:
                        logger.info(" -> außerhalb der Zeit (2)")
                        return False
    
            # Putzbedingung
            if 'leave_putzen' in position.conf and self.putzen != self.__cast_bool(position.conf['leave_putzen']):
                logger.info(" -> Putzmodus nicht {0}".format(str(self.__cast_bool(position.conf['putzen']))))
                return False;
    
            # Sonnenhöhe
            if 'leave_min_sun_altitude' in position.conf and self.sun_altitude < int(position.conf['leave_min_sun_altitude']):
                logger.info(" -> Sonne zu niedrig")
                return False
            if 'leave_max_sun_altitude' in position.conf and self.sun_altitude > int(position.conf['leave_max_sun_altitude']):
                logger.info(" -> Sonne zu hoch")
                return False
    
            # Sonnenrichtung
            if 'leave_min_sun_azimut' in position.conf or 'leave_max_sun_azimut' in position.conf:
                min_azimut = 0
                max_azimut = 90
                if 'leave_min_sun_azimut' in position.conf:
                    min_azimut = int(position.conf['leave_min_sun_azimut'])         
                if 'leave_max_sun_azimut' in position.conf:
                    max_azimut = int(position.conf['leave_max_sun_azimut'])
    
                if min_azimut < max_azimut:
                    if self.sun_azimut < min_azimut or self.sun_azimut > max_azimut:
                        logger.info(" -> außerhalb der Sonnenrichtung (1)")
                        return False;               
                else:
                    #if self.sun_azimut > min_azimut and self.sun_azimut < max_azimut:
                    if self.sun_azimut < min_azimut and self.sun_azimut > max_azimut:
                        logger.info(" -> außerhalb der Sonnenrichtung (2)")
                        return False;
    
            # Alle Bedingungen erfüllt
            logger.info(" -> passt".format(position.id()));
            return True
    
        # Prüft, ob die in einem Positions-Item erfassten Bedingungen erfüllt sind, so dass die Position geeignet ist
        # position: Positions-Item mit den Bedingungen als Attribute
        # Rückgabe: TRUE: Position ist geeignet, FALSE: Position ist nicht geeignet
        def __check_enter_pos_item(self, position):
            id = position.id()
            logger.info("Prüfe ob Position '{0}' geeignet ist ".format(id))
    
            # Anwesendheitsbedingung
            if 'anwesendheit' in position.conf and self.anwesendheit != self.__cast_bool(position.conf['anwesendheit']):
                logger.info(" -> Anwesendheit nicht {0}".format(str(self.__cast_bool(position.conf['anwesendheit']))))
                return False;
    
            # Heizungsbedingung
            if 'heizungsbedarf' in position.conf and self.heizungsbedarf != self.__cast_bool(position.conf['heizungsbedarf']):
                logger.info(" -> Heizungsbedarf nicht {0}".format(str(self.__cast_bool(position.conf['heizungsbedarf']))))
                return False;
    
            # Kunstlichtbedingung
            if 'kunstlicht' in position.conf and self.kunstlicht != self.__cast_bool(position.conf['kunstlicht']):
                logger.info(" ->Kunstlicht aktiv nicht {0}".format(str(self.__cast_bool(position.conf['kunstlicht']))))
                return False;
    
            # Raummodusbedingung
            if 'raummodus' in position.conf and self.raummodus != int(position.conf['raummodus']):
                logger.info(" ->Raummodus nicht {0}".format(str(int(position.conf['raummodus']))))
                return False;
    
            # Heizperiode aktiv
            if 'heizperiode' in position.conf and self.heizperiode != self.__cast_bool(position.conf['heizperiode']):
                logger.info(" ->Heizperiode nicht {0}".format(str(self.__cast_bool(position.conf['heizperiode']))))
                return False;
    
            # Putzenbedingung
            if 'putzen' in position.conf and self.putzen != self.__cast_bool(position.conf['putzen']):
                logger.info(" ->Putzmodus nicht {0}".format(str(self.__cast_bool(position.conf['putzen']))))
                return False;
    
    
            # Helligkeitsbedingung
            if 'min_helligkeit' in position.conf and self.helligkeit < int(position.conf['min_helligkeit']):
                logger.info(" -> zu dunkel")
                return False;
            if 'max_helligkeit' in position.conf and self.helligkeit > int(position.conf['max_helligkeit']):
                logger.info(" -> zu hell")
                return False;
    
            # Solarstrahlung
            if 'min_solarstrahlung' in position.conf and self.solar_radiation < int(position.conf['min_solarstrahlung']):
                logger.info(" -> Solarstrahlung zu gering")
                return False;
            if 'max_solarstrahlung' in position.conf and self.solar_radiation > int(position.conf['max_solarstrahlung']):
                logger.info(" -> Solarstrahlung zu hoch")
                return False;
    
    
            # Zeitbedingung
            if 'min_zeit' in position.conf or 'max_zeit' in position.conf:
                min_zeit = self.__get_time_attribute(position,"min_zeit",[0,0])
                max_zeit = self.__get_time_attribute(position, "max_zeit", [24,00])
                if self.__compare_time(min_zeit, max_zeit) != 1:
                    # min </= max: Normaler Vergleich
                    if self.__compare_time(self.akt_zeit, min_zeit) == -1 or self.__compare_time(self.akt_zeit, max_zeit) == 1:
                        logger.info(" -> außerhalb der Zeit (1)")
                        return False
                else:
                    # min > max: Invertieren
                    #if self.__compare_time(self.akt_zeit, min_zeit) == 1 and self.__compare_time(self.akt_zeit, min_zeit) == -1:
                    if self.__compare_time(self.akt_zeit, min_zeit) == -1 and self.__compare_time(self.akt_zeit, max_zeit) == 1:
                        logger.info(" -> außerhalb der Zeit (2)")
                        return False
    
            # Sonnenhöhe
            if 'min_sun_altitude' in position.conf and self.sun_altitude < int(position.conf['min_sun_altitude']):
                logger.info(" -> Sonne zu niedrig")
                return False
            if 'max_sun_altitude' in position.conf and self.sun_altitude > int(position.conf['max_sun_altitude']):
                logger.info(" -> Sonne zu hoch")
                return False
    
            # Sonnenrichtung
            if 'min_sun_azimut' in position.conf or 'max_sun_azimut' in position.conf:
                min_azimut = 0
                max_azimut = 90
                if 'min_sun_azimut' in position.conf:
                    min_azimut = int(position.conf['min_sun_azimut'])           
                if 'max_sun_azimut' in position.conf:
                    max_azimut = int(position.conf['max_sun_azimut'])
    
                if min_azimut < max_azimut:
                    if self.sun_azimut < min_azimut or self.sun_azimut > max_azimut:
                        logger.info(" -> außerhalb der Sonnenrichtung (1)")
                        return False;               
                else:
                    #if self.sun_azimut > min_azimut and self.sun_azimut < max_azimut:
                    if self.sun_azimut < min_azimut and self.sun_azimut > max_azimut:
                        logger.info(" -> außerhalb der Sonnenrichtung (2)")
                        return False;               
    
            # Alle Bedingungen erfüllt
            logger.info(" -> passt".format(position.id()));
            return True
    
        # Ermittelt und prüft ein Zeit-Attribut und liefert es im Format "Liste [Stunde, Minute]" zurück
        def __get_time_attribute(self, item, attribute, default):
            if not attribute in item.conf: return default
    
            value = item.conf[attribute]
            value_parts = value.split(",")
            if len(value_parts) != 2:
                id = item.id()
                logger.error("Das Konfigurations-Attribut '{0}' im Item '{1}' muss im Format '###, ###' angegeben werden.".format(attribute, id))
            else:
                try:
                    stunde = int(value_parts[0])
                    minute = int(value_parts[1])
                    return [stunde,minute]
                except ValueError:
                    id = item.id()
                    logger.error("Das Konfigurations-Attribut '{0}' im Item '{1}' muss im Format '###, ###' angegeben werden.".format(attribute, id))
                    return default
    
        # Vergleicht zwei Zeitwerte (als Liste [Stunde, Minute])
        # -1: Zeit1 < Zeit2
        # 0: Zeit1 = Zeit2
        # 1: Zeit 1 > Zeit 2
        def __compare_time(self, zeit1, zeit2):
            if zeit1[0] < zeit2[0]:
                return -1
            elif zeit1[0] > zeit2[0]:
                return 1
            else:
                if zeit1[1] < zeit2[1]:
                    return -1
                elif zeit1[1] > zeit2[1]:
                    return 1
                else:
                    return 0
    
        def __cast_bool(self, value):
            if type(value) in [bool, int, float]:
                if value in [False, 0]:
                    return False
                elif value in [True, 1]:
                    return True
                else:
                    raise ValueError
            elif type(value) in [str, str]:
                if value.lower() in ['0', 'false', 'no', 'off']:
                    return False
                elif value.lower() in ['1', 'true', 'yes', 'on']:
                    return True
                else:
                    raise ValueError
            else:
                raise TypeError
        
    # Raffstore-Automatik aufrufen (Klasse instanziieren, den Rest macht der Konstruktor ...)
    sh.trigger_source = trigger['source']
    logger.info("trigger_source: {0}".format(str(sh.trigger_source)))
    RaffstoreAutomatik(sh)

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Ich hab die Manuell-Situation so bei mir gelöst, dass die Logik zuerst mal checkt, von wem die Jalousie als Letztes aktualisiert worden ist. Wenn das nicht durch die Logik geschehen ist, dann wohl durch die Visu oder KNX Taster. Dann soll bis zur Dunkelheit (theoretisch auch nach Ablauf von einer gewissen Zeit) die Jalousie unangetastet bleiben. Das spart letztlich, für jede einzelne Jalousie ein Aktiv-Item anzulegen und abzufragen.

    Bei Einbruch der Dunkelheit werden alle Jalousie durch die Logik um 1% nach oben gefahren, somit also von der Logik getriggert und wieder im Automatikbetrieb. Letzteres ist vielleicht nicht ganz so nobel, da hat sicher wer ne feinere Lösung

    Einen Kommentar schreiben:


  • JanT
    antwortet
    Hallo,

    Zitat von hhhc Beitrag anzeigen
    Was zusätzlich noch auf der Wunschliste steht ist, das bei manueller Schaltung eines Items dieses für 2-3h von der Automatik ausgenommen wird und danach wieder in den Automatik-Modus zurück fällt.
    Use case:
    * Übergangszeit, Raffstoren eigentlich oben, manuelles Fahren wg Fernsehen / Mittagsschlaf auf der Couch
    * Hochsommer, Kinder gehen um 19-19:30h ins Bett, es ist noch richtig hell, Raffstoren werden manuell gefahren
    ich habe das gelöst in dem ich in eine separate Logik auf manuelles fahren der Behanghöhen/Lamellenwinkel lausche und das Aktiv-Item dann lösche. In der Nacht wird global alle Aktiv-Item wieder gesetzt. Neuer Tag, neue Möglichkeiten...

    Viele Grüße,

    Jan

    Einen Kommentar schreiben:


  • offline
    antwortet
    Hallo hhhc,

    Zitat von hhhc Beitrag anzeigen
    1) Steuerung der automatischen Beschattung nur, wenn die Aussentemperatur eine gewisse Höhe hat. Im Sommer soll das natürlich beschatten, aber im Winter / in der Übergangszeit soll der Sonneneinfall das Haus mit heizen.
    Sowas habe ich im Plugin auch bereits eingebaut.

    Zitat von hhhc Beitrag anzeigen
    2) Abschaltung der gesamten Logik mittels eines neuen Items, so dass ich nicht alle 18 Items deaktivieren muss (bei Besuch oder so)
    Das habe ich bei mir so gelöst, dass ich eine GA habe, auf die alle "Aktiv"-Items zusätzlich hören.

    Zitat von hhhc Beitrag anzeigen
    Was zusätzlich noch auf der Wunschliste steht ist, das bei manueller Schaltung eines Items dieses für 2-3h von der Automatik ausgenommen wird und danach wieder in den Automatik-Modus zurück fällt.
    Use case:
    * Übergangszeit, Raffstoren eigentlich oben, manuelles Fahren wg Fernsehen / Mittagsschlaf auf der Couch
    * Hochsommer, Kinder gehen um 19-19:30h ins Bett, es ist noch richtig hell, Raffstoren werden manuell gefahren
    Das ist eine gute Idee. Das lässt sich sicherlich einbauen

    Grüße
    offline

    Einen Kommentar schreiben:


  • Dragonos2000
    antwortet
    Zitat von JanT Beitrag anzeigen
    und keine war im Raum anwesend, da der Präsenzmelder die Dusche nicht erfasst!
    Deswegen hab' ich mir inzwischen nen zusätzlichen HF-Melder im Bad gegönnt. Hatte nämlich zusätzlich noch viel Spass, weil unter der Dusche immer das Licht aus ging (Winter)

    Gruss
    Jochen

    Einen Kommentar schreiben:


  • hhhc
    antwortet
    Hallo offline,

    ich nutze Deine Automatik seit gut einem halben Jahr und habe jetzt im Frühling auch noch die automatische Beschattung konfiguriert. Funktioniert tadellos und bin echt happy.
    Ich habe kleinere Adaptionen eingebaut, die Du ggf für das Plugin berücksichtigen könntest?

    1) Steuerung der automatischen Beschattung nur, wenn die Aussentemperatur eine gewisse Höhe hat. Im Sommer soll das natürlich beschatten, aber im Winter / in der Übergangszeit soll der Sonneneinfall das Haus mit heizen.
    Das habe ich analog der Helligkeit implementiert.

    item.conf
    Code:
                    [[[[[RaffstoreAutomatik]]]]]
                            item_helligkeit = Aussen.wetterstation.helligkeit_sued               # Item, über das die Helligkeit ermittelt wird
                            [B]item_temperatur = Waermepumpe.Temperatur_TA[/B]                          # Item, über das die Temperatur ermittelt wird
    ...
                            [[[[[TagNachfuehren]]]]]
                                name = Tag (nachführen)
                                min_helligkeit = 45000
                                leave_max_helligkeit = 30000
                                min_sun_altitude = 25
                                min_sun_azimut = 120
                                max_sun_azimut = 270
                                [B]min_temperatur = 16[/B]
                                position = auto

    In der logik.py habe ich an allen Stellen, wo du mit der Helligkeit arbeitest, das auf das neue Attribut erweitert.
    Code:
    ...
            self.item_helligkeit = self.sh.return_item(self.config["item_helligkeit"])
            self.item_temperatur = self.sh.return_item(self.config["item_temperatur"])
    ...
            if self.item_helligkeit == None:
                raise AttributeError("Das für 'item_helligkeit' angegebene Item '%s' ist unbekannt." %(self.config['item_helligkeit']))
            if self.item_temperatur == None:
                raise AttributeError("Das für 'item_temperatur' angegebene Item '%s' ist unbekannt." %(self.config['item_temperatur']))
    ...
    usw
    2) Abschaltung der gesamten Logik mittels eines neuen Items, so dass ich nicht alle 18 Items deaktivieren muss (bei Besuch oder so)
    item.conf
    Code:
    [Raffstore]
        [[Automatik]]
            type = bool
            cache = on
            visu_acl = rw
    logik.py (im Constructor)
    Code:
            # Check if global Raffstore automatik an oder aus
            if not self.sh.Raffstore.Automatik():
                logger.info("Raffstore Automatik ist aus. Item: Raffstore.Automatik")
                exit()
    Was zusätzlich noch auf der Wunschliste steht ist, das bei manueller Schaltung eines Items dieses für 2-3h von der Automatik ausgenommen wird und danach wieder in den Automatik-Modus zurück fällt.
    Use case:
    * Übergangszeit, Raffstoren eigentlich oben, manuelles Fahren wg Fernsehen / Mittagsschlaf auf der Couch
    * Hochsommer, Kinder gehen um 19-19:30h ins Bett, es ist noch richtig hell, Raffstoren werden manuell gefahren

    Freu mich schon auf das Plugin. Gute Arbeit!
    hhhc

    Einen Kommentar schreiben:


  • offline
    antwortet
    Hallo zusammen,

    Zitat von JanT Beitrag anzeigen
    Hallo Sprocky,

    offline hat einen schönen Ansatz implementiert, siehe Forumsthread Logik für Raffstore-Steuerung oder auch SmartHome Wiki. [...]
    Jan
    ich habe die Logik mittlerweile zu einem Plugin umgebaut, das macht programmiertechnisch ein paar Sachen einfacher. Ich bin da immer noch am Feintuning. Im Moment baue ich zusätzliche "Sperrbedingungen" ein, über die gesteuert werden kann, dass ein Zustand bis auf weiteres nicht verlassen werden kann. Wenn alles fertig ist werde ich den Wiki-Eintrag entsprechend ergänzen bzw. das Plugin anderweitig zur Verfügung stellen.

    Grüße
    offline

    Einen Kommentar schreiben:


  • JanT
    antwortet
    Hallo,

    nach dem ich gestern zu den Lamellensteuerungen das hoch und herunterfahren der Raffstore aktiviert habe, wurden sie im Bad hochgefahren als ich unter der Dusche stand

    Alle Bediengungen waren erfüllt: Es war nach dem Aufstehen, die Heizperiode ist noch aktiv, der Raum wurde gestern beheizt, die Solareinstrahlung war > 100 W/m^2, die Sonne kam von vorne und keine war im Raum anwesend, da der Präsenzmelder die Dusche nicht erfasst!

    Ich debugge noch ein bisschen vor ich den Quellcode hier reinsetze...

    Viele Grüße,

    Jan

    Einen Kommentar schreiben:


  • Shai
    antwortet
    Nein, Sonntags um 7.30 sind wir noch nicht in der Küche unterwegs ;-) - Aber wenn das wohlverdiente Ausschlafen schlagartig durch viel Sonne beendet wird hat sich der WAF ganz schnell erledigt

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Du meinst, sie stand nackt in der Küche und wurde enttarnt ?

    Einen Kommentar schreiben:


  • Shai
    antwortet
    Moin,

    bei mir läuft die automatische Beschattung zwar fast komplett über die Wetterstation und wurde angangs nur durch Parameter wie Temperatur (< 18°) bzw. Handeingabe gesperrt, aber ein Hinweis zum WAF:

    umbedingt eine Zeit-Sperre berücksichtigen (z.B am Wochenende erst ab 9.30 aktiv) - Mein Küchenfeldwebel war an den ersten wärmeren Sommertagen "not amused" als Sonntags um 7.30 der Sonnenschutz die Rollläden auf 75% hochgefahren hat :-D (am Abend vorher händisch ausschalten und morgens wieder an, hat den WAF stark reduziert)

    Grüße Lars

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Hallo Jan!
    Fände ich super, wenn du deine Arbeit hier posten könntest, zumindest auszugsweise. Damit bekommt man bestimmt gute Ideen

    Ich habe seit neuem eine Wetterstation und stehe dann auch vor dem Problem der vernünftigen Lamellensteuerung..

    Vielen Dank!

    Einen Kommentar schreiben:

Lädt...
X