Rollladensteuerung: Alternativen zu DOIF

Begonnen von spi3845, 27 März 2017, 13:28:59

Vorheriges Thema - Nächstes Thema

Beta-User

Zitat von: spi3845 am 10 April 2017, 15:03:34
Ist es.
Habe echt schon einen Knoten im Hirn >:(....

Was "Trockenübungen" angeht, habe ich meine Zweifel, wie weit das trägt, aber einen Versuch wäre es wert. Der Soll-Ablauf an sich ist ja gar nicht sooo schwer... (Aber die Jalousifunktion gefällt mir, sollte eigentlich drin bleiben 8)).

Womit ich mich aber erst nochmal beschäftigen werde, kurz dargestellt:
- Sind die Events für die notifys OK oder kann man das noch besser begrenzen, um eventuelle Mehrfachauslösungen (oder zu frühe) zu vermeiden  (ergo: sind ggf. bereits bestimmte Zustände vorab gesetzt oder nicht)?
- Anders formuliert: Inwiefern spielt die Reihenfolge eine Rolle, in der CUL_HM die EVENTS feuert bzw. wie herum berücksichtigt man das am besten.
- Wäre es nicht insgesamt besser, die Ereignisse ($EVENT) oder Teile davon an die subs zu übergeben statt des Texts? Dann kann man auch dort noch Duplikate aussortieren und hat "Rohevents" für den Fall, dass man das detailierter auswerten muß (für FK wohl egal, aber sonst habe ich die Hoffnung, dass das helfen würde...?).

Aber das muß ich mir in Ruhe nochmal ansehen und eine Event-Übergabe dürfte einige Änderungen am (Eingangs-) code nach sich ziehen...

Ansonsten ist Github mit der Änderungsverfolgung wirklich hilfreich, auch wenn es die Formatierung zerhackt (ist wahrscheinlich eher ein Thema des internen Editors, da sieht das ok aus). Läßt sich sicher besser machen, war aber erst mal nicht prio 1 ;).

Gruß, Beta-User
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

spi3845

Zitat von: Beta-User am 10 April 2017, 15:30:24
Habe echt schon einen Knoten im Hirn >:(....
Und ich erst...

Zitat von: Beta-User am 10 April 2017, 15:30:24
Was "Trockenübungen" angeht, habe ich meine Zweifel, wie weit das trägt, aber einen Versuch wäre es wert. Der Soll-Ablauf an sich ist ja gar nicht sooo schwer... (Aber die Jalousifunktion gefällt mir, sollte eigentlich drin bleiben 8)).
Ich sehe vor lauter Ablaufplänen keinen Code mehr vor Augen, daher der Versuch alles zu minimieren...

Zitat von: Beta-User am 10 April 2017, 15:30:24
- Sind die Events für die notifys OK oder kann man das noch besser begrenzen, um eventuelle Mehrfachauslösungen (oder zu frühe) zu vermeiden  (ergo: sind ggf. bereits bestimmte Zustände vorab gesetzt oder nicht)?
- Anders formuliert: Inwiefern spielt die Reihenfolge eine Rolle, in der CUL_HM die EVENTS feuert bzw. wie herum berücksichtigt man das am besten.
Hm, das käme dann auf den Versuch darauf an. Ich glaube, wir könnten mit einer Semaphore etwas abfangen, die zu Beginn des Skripts auf "running" gesetzt und am Ende wieder gelöscht wird. Eine Abfrage ganz zu Beginn des Skripts auf =~ running beendet das Skript gleich wieder, weil es ja bereits läuft. Ggf. muss man die Semaphore aber auf den Namen des Device setzen, da eine mehrfache Ausführung für unterschiedliche Geräte nicht hinderlich ist.

Zitat von: Beta-User am 10 April 2017, 15:30:24
- Wäre es nicht insgesamt besser, die Ereignisse ($EVENT) oder Teile davon an die subs zu übergeben statt des Texts? Dann kann man auch dort noch Duplikate aussortieren und hat "Rohevents" für den Fall, dass man das detailierter auswerten muß (für FK wohl egal, aber sonst habe ich die Hoffnung, dass das helfen würde...?).
Klingt gut. Vermutlich kann man einige Events zusammenfassen und gleich behandeln, aber das kann auch im Skript erfolgen.

Zitat von: Beta-User am 10 April 2017, 15:30:24
Ansonsten ist Github mit der Änderungsverfolgung wirklich hilfreich, auch wenn es die Formatierung zerhackt (ist wahrscheinlich eher ein Thema des internen Editors, da sieht das ok aus).
Urgh, noch 'ne Baustelle. Was muss ich tun?


P.S. Noch ein Gedanke zu dem Testcode, den ich auf Basis deines Entwurfs gepostet hatte: wie wäre folgende Darstellung im Code? Sorry, Jalousien immer noch draußen, weil ich keine habe und das Wenden nicht verstehe...  ::) Mir geht's hier erst einmal um die Darstellung für zukünftige Erweiterung des Codes.


use Switch;


          #Wir speichern ein paar Infos, damit das nicht zu unübersichtlich wird
          my $event = "Window";
          my $windowcontact = "Fenster1";
          my $position = 8; # Werte 0-100
          my $winState = "tilted"; # Werte open, tilted oder closed
          my $maxPosOpen = 30; # Lüften-Position bei winstate=open
          my $maxPosTilted = 10;  # Lüften-Position bei winstate=tilted
          my $onHoldState = "none"; # "none" oder alte Position

if($windowcontact eq "none") { die "Fehler, Türkontakt nicht zugeordnet"; }             # in Subroutine dann return verwenden

switch($event){
   case "Window"           {
                                       switch($winState){
                                            case "open"         {
                                                                        if($position < $maxPosOpen) {
                                                                                print "fhem(\"set $shutter $maxPosOpen\")";
                                                                                if ($onHoldState eq "none") { print "fhem(\"setreading $shutter WindowContactOnHoldState $position\")"; }
                                                                                }
                                                                         }
                                            case "tilted"         {
                                                                        if($position < $maxPosTilted) {
                                                                                print "fhem(\"set $shutter $maxPosTilted\")";
                                                                                if ($onHoldState eq "none") { print "fhem(\"setreading $shutter WindowContactOnHoldState $position\")"; }
                                                                                }
                                                                         }
                                            case "closed"         {
                                                                         if ($onHoldState ne "none") {
                                                                                print "fhem(\"set $shutter $onHoldState\")";
                                                                                print "fhem(\"setreading $shutter WindowContactOnHoldState none\")";
                                                                                }
                                                                         }
                                            else                       { print "Fehler: unbekannter winState $winState\n" }
                                       }
   case "Rollo"           {
                                   if($position != $maxPosOpen && $position != $maxPosTilted && $onHoldState ne "none") {
                                        print "fhem(\"setreading $shutter WindowContactOnHoldState none\")";
                                        }
                                    }

                                       }
   else              { print "Fehler: unbekannter event $event" }
}


Kann man leider nicht mehr unter https://www.tutorialspoint.com/execute_perl_online.php einkopieren, da Switch.pm dort nicht vorhanden ist... Ich habe Padre auf einem Linux-Rechner laufen, F5 zaubert dann die Ergebnisse abhängig der gesetzten Werte, damit muss ich nicht dauernd Rollläden fahren zum Testen.

Für fhem muss Switch.pm installiert werden, auf Debian-Systemen am einfachsten über
sudo apt-get install libswitch-perl

Gruß,
spi

Beta-User

Zitat von: spi3845 am 10 April 2017, 16:22:10
Ich glaube, wir könnten mit einer Semaphore etwas abfangen, die zu Beginn des Skripts auf "running" gesetzt und am Ende wieder gelöscht wird.
Kann ich irgendwo für Dummies nachlesen, was das ist und wie das geht?!?

Was den Ablauf angeht, klappt das an sich "in der wirklichen Welt" (tilted habe ich evtl. kurz vor Ende "verschlimmbessert"). Das Problem scheint jetzt eben zu sein, dass zu oft getriggert wird (und dabei neben dieser ungewollten "Dauer-Schleife" vor allem auch die onHoldPosition fälschlicherweise gelöscht bzw. auf "0" gesetzt wird). Es wirkt aber so, als würde das script nicht - gesehen bei einem Rolladen - mehrfach parallel laufen, sondern eben immer wieder aufgerufen. Würde hier ein Semaphore helfen?

ZitatUrgh, noch 'ne Baustelle. Was muss ich tun?
War nicht als Aufforderung gedacht, an der Stelle nutze ich grade auch nicht den "git commit"-Mechanismus auf der Konsole vom PI, sondern die Web-Schnittstelle. Bei Interesse kannst Du ja einen eigenen Account beantragen (kostet für öffentlich sichtbaren code nichts) und mein Repo "forken". Damit könntest Du mir Änderungswünsche übermitteln.
Aber auch so kannst Du auf der Web-Oberfläche code-Changes sichtbar machen, indem Du die commits (=Änderungen) nachvollziehst. Dabei werden diese farblich dargestellt und haben auch Zeilennummern, was das Suchen vereinfacht.

Das mit dem Wenden ist einfach:
- geht die Jalousie (um einen Mindestwert, den die Lamellen zu drehen brauchen) nach unten, ist die Stellung "normal" (den Mindestwert prüfe ich derzeit nicht, wenn sonst ein Ereignis die Jalousie nach unten schickt).
- geht sie nach oben, wird um den Mindestwert übersteuert und bei Stop auf der Wendeposition wieder um diesen Wert nach unten gefahren. Für die Jalousie ein weiteres Attribut, für das Script drei weitere Werte (incl. dem Attributwert).

Zu Switch und so melde ich mich ggf. später, sieht interessant aus, wobei ich mich schon an die vielen elsif's gewöhnt habe...

Gruß, Beta-User
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

spi3845

Zitat von: Beta-User am 10 April 2017, 16:57:15
Zu Switch und so melde ich mich ggf. später, sieht interessant aus, wobei ich mich schon an die vielen elsif's gewöhnt habe...
Ich habe gerade einen kleinen Run auf Switch ;)

Habe das Codebeispiel (aka Logik) erweitert um Timer. Macht das Sinn?

use Switch;


          #Wir speichern ein paar Infos, damit das nicht zu unübersichtlich wird
          my $event = "Timer_up";
          my $windowcontact = "Fenster";
          my $position = 0; # Werte 0-100
          my $winState = "closed"; # Werte open, tilted oder closed
          my $maxPosOpen = 30; # Lüften-Position bei winstate=open
          my $maxPosTilted = 10;  # Lüften-Position bei winstate=tilted
          my $posBlindClosed = 0; # Position, auf die Rollo beim Schließen gefahren werden soll
          my $posBlindOpened = 100; # Position, auf die Rollo beim Öffnen gefahren werden soll
          my $posBlindNotToOpen = 20; # Position, ab der erst ein Rollo bei offener Tür automatisch geöffnet wird, um ein Eindringen zu verhindern
          my $onHoldState = "none"; # "none" oder alte Position

if($windowcontact eq "none") { die "Fehler, Türkontakt nicht zugeordnet"; }             # in Subroutine dann return verwenden

switch($event){
   case "Window"           {
                                       switch($winState){
                                            case "open"         {
                                                                        if($position < $maxPosOpen) {
                                                                                print "fhem(\"set $shutter $maxPosOpen\")";
                                                                                if ($onHoldState eq "none") { print "fhem(\"setreading $shutter WindowContactOnHoldState $position\")"; }
                                                                                }
                                                                         }
                                            case "tilted"         {
                                                                        if($position < $maxPosTilted) {
                                                                                print "fhem(\"set $shutter $maxPosTilted\")";
                                                                                if ($onHoldState eq "none") { print "fhem(\"setreading $shutter WindowContactOnHoldState $position\")"; }
                                                                                }
                                                                         }
                                            case "closed"         {
                                                                         if ($onHoldState ne "none") {
                                                                                print "fhem(\"set $shutter $onHoldState\")";
                                                                                print "fhem(\"setreading $shutter WindowContactOnHoldState none\")";
                                                                                }
                                                                         }
                                            else                       { print "Fehler: unbekannter winState $winState\n" }
                                            }
                                        }
   case "Timer_down"           {
                                       switch($winState){
                                            case "open"         { # Aussperrschutz, nichts tun
                                                                        print "fhem(\"setreading $shutter WindowContactOnHoldState $posBlindClosed\")";
                                                                         }
                                            case "tilted"         { # auf Lüften-Position gekipptes Fenster fahren, als alte Position Schließposition des Rollos speichern
                                                                            print "fhem(\"set $shutter $maxPosTilted\")";
                                                                            print "fhem(\"setreading $shutter WindowContactOnHoldState $posBlindClosed\")";
                                                                         }
                                            case "closed"         {
                                                                           print "fhem(\"set $shutter $posBlindClosed\")";
                                                                           print "fhem(\"setreading $shutter WindowContactOnHoldState none\")";
                                                                         }
                                            else                       { print "Fehler: unbekannter winState $winState\n" }
                                        }
                                        }
   case "Timer_up"           {
                                       switch($winState){
                                            case "open"         { # Eindringen von außen verhindern
                                                                        if($position > $posBlindNotToOpen) {
                                                                                print "fhem(\"set $shutter $posBlindOpened\")";
                                                                                print "fhem(\"setreading $shutter WindowContactOnHoldState none\")";
                                                                                }
                                                                        else { print "fhem(\"setreading $shutter WindowContactOnHoldState $posBlindOpened\")"; }
                                                                         }
                                            case ["tilted","closed"]         { # Rollos eines gekipptes Fenster können geöffnet werden, ansonsten tilted wie open behandeln
                                                                        print "fhem(\"set $shutter $posBlindOpened\")";
                                                                        print "fhem(\"setreading $shutter WindowContactOnHoldState none\")";
                                                                         }
                                            else                       { print "Fehler: unbekannter winState $winState\n" }
                                            }
                                        }
   case "Rollo"           {
                                   if($position != $maxPosOpen && $position != $maxPosTilted && $onHoldState ne "none") {
                                        print "fhem(\"setreading $shutter WindowContactOnHoldState none\")";
                                        }
                                    }
   else              { print "Fehler: unbekannter event $event" }
}


Gruß,
spi

spi3845

#79
Zitat von: Beta-User am 10 April 2017, 16:57:15
Kann ich irgendwo für Dummies nachlesen, was das ist und wie das geht?!?
Ich würde so etwas vorschlagen...
sub winOpenShutterTester($$) {
    my ($dev, $event) = @_;
    #Erst mal prüfen, ob das übergebene device überhaupt existiert
    if ($defs{$dev}) {
               # Lock-Status lesen
               my $lock = ReadingsVal($shutter,'winOpenShutterTesterLock',0);
               if($lock == 1) { return "Skript für dieses Devices läuft bereits"; }
               # Lock setzen, falls es 0 war
               fhem("setreading $shutter winOpenShutterTesterLock 1");
               # "normale" Skript-Funktionen, Lock ist jetzt 1, sollte das Skript für dieses Device ein weiteres Mal gestartet werden,
               # beendet es sich wieder, bevor irgendwelche Aktionen ausgelöst werden
               ...
               # am Ende Lock wieder löschen
               fhem("setreading $shutter winOpenShutterTesterLock 0");   
}


Ach ja, noch ein Gedanke, wollte man sinnvoll unterbinden, dass nach einer Aktion die nächste Aktion am Aktor erst nach einer Karenzzeit passiert, könnte der Lock z.B. auch erst 5s nach Ende des Skript gelöscht werden (mit einem at).

Der Lock ist nur blöd bei Timern, da die dann verpasst werden könnten, aber das passiert ja nur, wenn der Timer zuschlägt während dem jemand am Rollo rumspielt - und er hat hoffentlich gute Gründe für  :D

Gruß,
spi

Beta-User

Zitat von: spi3845 am 10 April 2017, 16:59:18
Habe das Codebeispiel (aka Logik) erweitert um Timer. Macht das Sinn?
Es sieht vom Aufbau her nachvollziehbar aus, allerdings müßte ich für meine "Abfanglogik" noch einiges mehr berücksichtigen, was ich auf die Schnelle aber von den Auswirkungen her nicht überblicken kann.
"timer" als case gefällt mir irgendwie nicht, das paßt nicht mehr so richtig zu dem dynamischen Konzept, bei der jeder Fahrbefehl wieder analysiert wird unabhängig davon, wo er herkommt. Danach gilt: wer zuletzt kommt, bestimmt die Ziel- und onHold-Positionen, ganz gleich ob über timer, Schalter oder FHEMWEB ausgelöst...

Ganz neu (für meine Betrachtung) ist der Gedanke, trotz geöffnetem Fenster den Rolladen runterzumachen ???. Macht unter Sicherheitsaspekten Sinn, bisher war das gedanklich eher andersrum: ich komme ursprünglich von dem Ansatz zu verhindern, dass ich mich aussperre. Hmmm, sieht so aus, als würde dafür noch ein (einstellbares) Attribut benötigt, um den Aussperrschutz zu übersteuern. Behalte das mal im Hinterkopf, muß aber hintanstehen.
Zitat von: spi3845 am 10 April 2017, 17:21:35
Ich würde so etwas vorschlagen...
OK, Danke für die Info. Das geht in die Richtung wie ReadingsAge(), ohne dass man dafür ein eigenes Attribut bräuchte (?). ReadingsAge() sollte auch für eine sequenzielle Abarbeitung tauglich sein und ist in Zeilen 24 und 28 im Dev-tree für die "Abfangfunktion" schon genutzt, den Umbau im Tester habe ich gestern nicht mehr geschafft, was so schon spät ::).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

spi3845

Zitat von: Beta-User am 10 April 2017, 18:03:01
"timer" als case gefällt mir irgendwie nicht, das paßt nicht mehr so richtig zu dem dynamischen Konzept, bei der jeder Fahrbefehl wieder analysiert wird unabhängig davon, wo er herkommt. Danach gilt: wer zuletzt kommt, bestimmt die Ziel- und onHold-Positionen, ganz gleich ob über timer, Schalter oder FHEMWEB ausgelöst...
Interessanter Gedanke, wie würde Das Konzept aussehen? Kannst Du das skizzieren, dann überlege ich, wie man das abbilden könnte. Aktuell haben wir notifys für FK und motor, bräuchten dann noch Timer, die müssen aber irgend etwas anderes triggern, z.B. Rollopositionen. Timer könnten dann abgebildet werden als "set Rollo 0" und "set Rollo 100".

Zitat von: Beta-User am 10 April 2017, 18:03:01
Ganz neu (für meine Betrachtung) ist der Gedanke, trotz geöffnetem Fenster den Rolladen runterzumachen ???. Macht unter Sicherheitsaspekten Sinn, bisher war das gedanklich eher andersrum: ich komme ursprünglich von dem Ansatz zu verhindern, dass ich mich aussperre. Hmmm, sieht so aus, als würde dafür noch ein (einstellbares) Attribut benötigt, um den Aussperrschutz zu übersteuern.
Geht das in die Richtung "Vergessen, Tür zu schließen und jetzt will ich wenigstens noch Rollladen schließen"? Dann wäre ja ein Aussperrschutz beim Feuern des Timers ok. Danach periodische Erinnerung, dass Balkontür offen steht... Nach 30 Min ohne Reaktion Rollladen zu  :-X

Zitat von: Beta-User am 10 April 2017, 18:03:01
Das geht in die Richtung wie ReadingsAge(), ohne dass man dafür ein eigenes Attribut bräuchte (?).
Was ist denn das nun schon wieder? Muss nicht nur fhem, perl, DOIF lernen, jetzt auch noch ReadingsAge  ::)

Auf den ersten Blick sieht das aus, wie ein Wert, der anzeigt, wann ein spezielles Reading eines Devices das letzte mal geändert wurde. Der Lock-Mechanismus dagegen sorgt dafür, dass die Funktion für das gleiche Device nicht zweimal ausgeführt wird, auch wenn die erste Instanz schon eine Stunde läuft...

Zitat von: Beta-User am 10 April 2017, 18:03:01
ReadingsAge() sollte auch für eine sequenzielle Abarbeitung tauglich sein und ist in Zeilen 24 und 28 im Dev-tree für die "Abfangfunktion" schon genutzt, den Umbau im Tester habe ich gestern nicht mehr geschafft, was so schon spät ::).
Habe Dev erst jetzt gesehen, muss ich mir noch ansehen. Noch mehr Code... Ich keinen Code mehr sehen...  8)

Gruß,
spi

Beta-User

OK, den dev-tree hast Du ja gefunden wg. des Konzepts. Damit bliebe erst mal alles Event-basiert, nur dass eben durch irgendwas (timer usw.) veranlasste settings angepaßt würden.
Zitat von: spi3845 am 10 April 2017, 18:53:33
Geht das in die Richtung "Vergessen, Tür zu schließen und jetzt will ich wenigstens noch Rollladen schließen"?...
Das hatte ich so als Wunsch von Deiner Seite verstanden ;D, ich brauche sowas eher nicht.

Habe mir eben das mit den Events nochmal angesehen. Das wäre m.E. wirklich zielführend, die Events mit zu übergeben, ist aber ein gewisser Umbau. Denn sowohl der "stop" wie der "down"-Event senden die aktuelle Position mit, zu der Zeit ist aber der STATE des Geräts noch nicht geändert, das passiert erst danach. Damit holt Value() einen veralteten Wert, daher m.E. die trigger-loop. Man muß also den Value() überschreiben, (mindestens) wenn ein "stop" auslöst.

Mal sehen, wann ich dazu komme...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

spi3845

Zitat von: Beta-User am 10 April 2017, 19:54:07
OK, den dev-tree hast Du ja gefunden wg. des Konzepts. Damit bliebe erst mal alles Event-basiert, nur dass eben durch irgendwas (timer usw.) veranlasste settings angepaßt würden.Das hatte ich so als Wunsch von Deiner Seite verstanden ;D, ich brauche sowas eher nicht.
Ne, ich brauche nur Aussperrschutz. Sonst sitzt meine Familie draußen, wenn ich mal nicht da bin  :)

Zitat von: Beta-User am 10 April 2017, 19:54:07
Habe mir eben das mit den Events nochmal angesehen. Das wäre m.E. wirklich zielführend, die Events mit zu übergeben, ist aber ein gewisser Umbau.
Ich glaube mit Switch geht das einfacher, denn die case-Befehle könnten die Events direkt aufnehmen.

Zitat von: Beta-User am 10 April 2017, 19:54:07
Denn sowohl der "stop" wie der "down"-Event senden die aktuelle Position mit, zu der Zeit ist aber der STATE des Geräts noch nicht geändert, das passiert erst danach. Damit holt Value() einen veralteten Wert, daher m.E. die trigger-loop. Man muß also den Value() überschreiben, (mindestens) wenn ein "stop" auslöst.
Auf den Motor zu triggern führt zu einer Verzögerung. Denn erst gibt es irgendein Ereignis (Taste wird gedrückt oder Timer feuert), das wird verarbeitet und dann triggert der Aktor den Motor. Da die Aktoren die Position aus der Laufzeit bestimmen, dauert deren Bestimmung entsprechend. Deshalb habe ich versucht, den Timer gleich in die Funktion mit einzubauen - weiß noch nicht, wie gut das funktioniert. Der Timer ist im endlichen Automaten ein Ereignis wie "Tür auf", "Tür zu" oder "Schalter gedrückt" und führt zu einem Ergebnis wie Rolladen auf oder zu.

Zitat von: Beta-User am 10 April 2017, 19:54:07
Mal sehen, wann ich dazu komme...
Kenne ich  8)

spi3845

#84
Habe Beta-Users Code mit Switch-Anweisungen umgeschrieben und an Dummys zum Testen angepasst. Wer möchte, kann das so in fhem einkopieren. Das landet alles in einem Raum namens Test.Rollladen.sp.

Der Rolladen wird entsprechend bewegt je nachdem, ob die Tür geöffnet, geschlossen oder gekippt ist. Timer-Logik ist eingebaut und kann über die fhem Befehlszeile getestet werden. Hier gibt es unterschiedliche Reaktionen, je nachdem, ob die Tür offen (Aussperr- und Eindringschutz), gekippt (Lüften) oder geschlossen ist.

Timer_down testen mittels
{ WinShutterTester(AttrVal("t.r.sp.tuerkontakt_re",'ShutterAssociated','none'), "Timer_down") }
Timer_up:
{ WinShutterTester(AttrVal("t.r.sp.tuerkontakt_re",'ShutterAssociated','none'), "Timer_up") }

Die Funktionen für die 99_*Utils.pm (umbenannt, damit sie nicht mit Beta-Users-Funktionen kollidieren):

# am Anfang nach anderen use-Statements einfügen
use Switch;
# ...
# Enter you functions below _this_ line.

sub WinShutterTester($$) {
    #Als Parameter muss der device-Name übergeben werden
    #notify-Definitionen:
    #defmod n_Rolladen_Window notify .*(closed|open|tilted)..to.VCCU. { WinShutterTester(AttrVal($NAME,'ShutterAssociated','none'), "Window") }
    #defmod n_Rolladen_Stop notify .*:motor:.stop.* { WinShutterTester($NAME, "Rollo")}
    #Hint for window contacts: make sure to modify settings of device wrt. some delay in sending state changes to avoid unnecessary triggers
    my ($dev, $event) = @_;

    #Erst mal prüfen, ob das übergebene device überhaupt existiert
if ($defs{$dev}) {

        #Als erstes brauchen wir die Info, welcher Rolladen bzw. welcher Fenster- bzw. Türkontakt
        #betroffen sind
        my $windowcontact = AttrVal($dev,'WindowContactAssociated',"none");
        my $shutter=$dev;
     
        if (!$shutter) {}
        else {       
          #Wir speichern ein paar Infos, damit das nicht zu unübersichtlich wird
          my $position = ReadingsVal($shutter,'level',0);
          my $winState = Value($windowcontact);
          my $maxClosedIfOpen = AttrVal($shutter,'ShutterMaxClosedIfOpen',30);
          my $maxClosedIfTilted = AttrVal($shutter,'ShutterMaxClosedIfTilted',10);
  my $onHoldState = ReadingsVal($shutter,'ShutterOnHoldState',"none");
  my $maxClosed = AttrVal($shutter,'ShutterMaxClosed',0);
  my $maxOpened = AttrVal($shutter,'ShutterMaxOpened',100);
  my $notOpenIfBelow = AttrVal($shutter,'ShutterNotOpenIfBelow',20);
 
  # wenn kein $windowcontact, so tun als wäre Fenster immer zu (=closed)
  if($windowcontact eq "none") { $winState = "closed"; }

  switch($event){
  case "Window"{
switch($winState){
case "open"{
if($position < $maxClosedIfOpen) {
                        fhem("set $shutter $maxClosedIfOpen");
                            if ($onHoldState eq "none") { fhem("setreading $shutter ShutterOnHoldState $position"); }
                            }
                    }
case "tilted"{
if($position < $maxClosedIfTilted) {
fhem("set $shutter $maxClosedIfTilted");
if ($onHoldState eq "none") { fhem("setreading $shutter ShutterOnHoldState $position"); }
}
}
case "closed"{
if ($onHoldState ne "none") {
fhem("set $shutter $onHoldState");
fhem("setreading $shutter ShutterOnHoldState none");
}
}
else { return "Fehler: unbekannter winState $winState"; }
}
}
case "Timer_down"{
switch($winState){
case "open"{ # Aussperrschutz, nichts tun
fhem("setreading $shutter ShutterOnHoldState $maxClosed");
}
case "tilted"{ # gekipptes Fenster auf Lüften-Position fahren,
# als alte Position Schließposition des Rollos speichern
fhem("set $shutter $maxClosedIfTilted");
fhem("setreading $shutter ShutterOnHoldState $maxClosed");
}
case "closed"{
fhem("set $shutter $maxClosed");
fhem("setreading $shutter ShutterOnHoldState none");
}
else { return "Fehler: unbekannter winState $winState"; }
}
}
case "Timer_up"{
switch($winState){
case "open"{ # Eindringen von außen verhindern
if($position > $notOpenIfBelow) {
fhem("set $shutter $maxOpened");
fhem("setreading $shutter ShutterOnHoldState none");
}
else {
fhem("set $shutter $notOpenIfBelow");
fhem("setreading $shutter ShutterOnHoldState $maxOpened");
}
}
case ["tilted","closed"]{ # Rollos eines gekippten Fensters können geöffnet werden,
# ansonsten müsste tilted wie open behandelt werden
fhem("set $shutter $maxOpened");
fhem("setreading $shutter ShutterOnHoldState none");
}
else { return "Fehler: unbekannter winState $winState"; }
}
}
case "Rollo"{ # noch nicht fertig, testen
if($position != $maxClosedIfOpen && $position != $maxClosedIfTilted && $onHoldState ne "none") {
fhem("setreading $shutter ShutterOnHoldState none");
}
}
else { return "Fehler: unbekannter event $event"; }
}
  }
}
}


sub WinShutterLink($$$$$$$) {
    #Als Parameter müssen die Namen vom Fensterkontakt und Rolladen übergeben werden sowie der Maxlevel bei Fensteröffnung und tilted
    #Call in FHEMWEB e.g.: { WinShutterLink("Fenster_Wohnzimmer_SSW","Rolladen_WZ_SSW",30,10,0,100,20) }
    my ($windowcontact, $shutter, $maxClosedIfOpen, $maxClosedIfTilted, $maxClosed, $maxOpened, $notOpenIfBelow) = @_;
    my ($hash, @param) = @_;
    #Erst mal prüfen, ob die Parameter sinnvoll sind
    if($defs{$windowcontact} && $defs{$shutter}) {

if(AttrVal($shutter,'subType', undef) =~ "blindActuator|dummy|" && AttrVal($windowcontact,'subType',undef) =~ "threeStateSensor|dummy|") {
            my $oldAttrWin = AttrVal($windowcontact,'userattr',undef);
            my $oldAttrRollo = AttrVal($shutter,'userattr',undef);
           
            #Jetzt können wir sehen, ob und welche notwendigen userattr vorhanden sind
            #und ggf. Werte zuweisen
            if(index($oldAttrWin,"ShutterAssociated") < 0){
                fhem("attr $windowcontact userattr $oldAttrWin ShutterAssociated");
                }
            fhem("attr $windowcontact ShutterAssociated $shutter");
            if(index($oldAttrRollo,"WindowContactAssociated") < 0) {
                fhem("attr $shutter userattr $oldAttrRollo WindowContactAssociated");
                $oldAttrRollo = AttrVal($shutter,'userattr',undef);
            }
            fhem("attr $shutter WindowContactAssociated $windowcontact");
            if(index($oldAttrRollo,"ShutterOnHoldState") < 0) {
                fhem("attr $shutter userattr $oldAttrRollo ShutterOnHoldState");
                $oldAttrRollo = AttrVal($shutter,'userattr',undef);
            }
fhem("setreading $shutter ShutterOnHoldState none");
            if(index($oldAttrRollo,"ShutterMaxClosed") < 0) {
                fhem("attr $shutter userattr $oldAttrRollo ShutterMaxClosed");
                $oldAttrRollo = AttrVal($shutter,'userattr',undef);
            }
            fhem("attr $shutter ShutterMaxClosed $maxClosed");
            if(index($oldAttrRollo,"ShutterMaxOpened") < 0) {
                fhem("attr $shutter userattr $oldAttrRollo ShutterMaxOpened");
                $oldAttrRollo = AttrVal($shutter,'userattr',undef);
            }
            fhem("attr $shutter ShutterMaxOpened $maxOpened");
            if(index($oldAttrRollo,"ShutterMaxClosedIfOpen") < 0) {
                fhem("attr $shutter userattr $oldAttrRollo ShutterMaxClosedIfOpen");
                $oldAttrRollo = AttrVal($shutter,'userattr',undef);
            }
            fhem("attr $shutter ShutterMaxClosedIfOpen $maxClosedIfOpen");
            if(index($oldAttrRollo,"ShutterMaxClosedIfTilted") < 0) {
                fhem("attr $shutter userattr $oldAttrRollo ShutterMaxClosedIfTilted");
                $oldAttrRollo = AttrVal($shutter,'userattr',undef);
            }
            fhem("attr $shutter ShutterMaxClosedIfTilted $maxClosedIfTilted");
            if(index($oldAttrRollo,"ShutterNotOpenIfBelow") < 0) {
                fhem("attr $shutter userattr $oldAttrRollo ShutterNotOpenIfBelow");
            }
            fhem("attr $shutter ShutterNotOpenIfBelow $notOpenIfBelow");
        }
        else { return "One of the devices has wrong subtype"; }
    }
    else { return "One of the devices does not exist"; }
}


Und hier die Dummys zum Testen:
define t.r.sp.rollo_re dummy
attr t.r.sp.rollo_re userattr WindowContactAssociated ShutterOnHoldState ShutterNotOpenIfBelow
attr t.r.sp.rollo_re ShutterMaxClosed 0
attr t.r.sp.rollo_re ShutterMaxClosedIfOpen 30
attr t.r.sp.rollo_re ShutterMaxClosedIfTilted 10
attr t.r.sp.rollo_re ShutterMaxOpened 100
attr t.r.sp.rollo_re ShutterNotOpenIfBelow 20
attr t.r.sp.rollo_re WindowContactAssociated t.r.sp.tuerkontakt_re
attr t.r.sp.rollo_re room Test.Rollladen.sp
attr t.r.sp.rollo_re userReadings level { ReadingsVal("t.r.sp.rollo_re","state",0);;;; }
attr t.r.sp.rollo_re webCmd 0:5:10:20:30:50:70:100
define t.r.sp.tuerkontakt_re dummy
attr t.r.sp.tuerkontakt_re userattr ShutterAssociated
attr t.r.sp.tuerkontakt_re ShutterAssociated t.r.sp.rollo_re
attr t.r.sp.tuerkontakt_re room Test.Rollladen.sp
attr t.r.sp.tuerkontakt_re setList tilted open closed
attr t.r.sp.tuerkontakt_re webCmd tilted:open:closed
define t.r.sp.n_Rolladen_Window notify t.r.sp.tuerkontakt_.*(closed|open|tilted) { WinShutterTester(AttrVal($NAME,'ShutterAssociated','none'), "Window") }
attr t.r.sp.n_Rolladen_Window group Türen und Fenster
attr t.r.sp.n_Rolladen_Window icon fts_shutter_automatic
attr t.r.sp.n_Rolladen_Window room Test.Rollladen.sp


Zum Konfigurieren von Türkontakt und Rollladen initial ausführen (in fhem Befehlszeile einkopieren):
{ WinShutterLink("t.r.sp.tuerkontakt_re","t.r.sp.rollo_re",30,10,0,100,20) }
Dabei sind die Parameter:








t.r.sp.tuerkontakt_reDevice Türkontakt
t.r.sp.rollo_reDevice Rollo
30Lüften-Position des Rollos, wenn Tür offen ist
10Lüften-Position des Rollos, wenn Tür gekippt ist
0Soll-Position des Rollos nach autom. Schließen
100Soll-Position des Rollos nach autom. Öffnen
20Schwellwert des Rollos, ab der es autom. geöffnet wird, sollte die Tür offen sein (Schutz vor Eindringen)
Ist das Rollo darunter, wird es bis zu dieser Position geöffnet, wenn die Tür beim autom. Öffnen offen steht.

ToDos:

  • Testen :-\ in Reallife mit "echten" Rollläden, bisher teste ich nur mit Dummies
  • Seiteneffekte abfangen
  • Auf Motorbewegungen reagieren
  • Timer erstellen mit min/max/Sonnenstandzeiten (dazu auch ein userattr je Rollladen mit Horizon-/Light-/Weather-Wert o.ä. aus twilight hinterlegen)
  • GUI
  • Beschattung

Grüße,
spi

Nachtrag: WinShutterLink habe ich angepasst (die Reihenfolge der userattr-Einträge geändert), damit auch alle angelegt werden, die gleich beginnen. Also erst die kürzeren und dann die längeren userattr (z.B. zuerst ShutterMaxClosed, dann erst ShutterMaxClosedIfOpen).

Beta-User

Zitat von: spi3845 am 10 April 2017, 22:03:44
Auf den Motor zu triggern führt zu einer Verzögerung. Denn erst gibt es irgendein Ereignis (Taste wird gedrückt oder Timer feuert), das wird verarbeitet und dann triggert der Aktor den Motor.
Im realen Leben stimmen diese Annahmen m.E. leider nicht immer. Auf "motor: down" und "motor: stop" habe ich nur deswegen ein notify gelegt, weil bei einem Tastendruck am Aktor selbst (also am eingebauten Schalter) eben nur diese beiden (bzw. noch "up") kommen. "stop" braucht man auch, weil die Alternative wäre, Änderungen im Device-STATE auszuwerten. Diese kommen während des Fahrens uU aber zum einen sehr schnell, können andererseits jedoch erst sinnvoll ausgewertet werden, wenn eine gewisse Zeit keine Änderung mehr kommt. Sonst wäre manches einfacher ;), weil man dann nicht nochmal prüfen müßte, ob alle Parameter bereits geprüft und richtig gesetzt sind.

Zitat von: spi3845 am 10 April 2017, 22:03:44...Der Timer ist im endlichen Automaten ein Ereignis wie "Tür auf"...
Achtung: Die Begrifflichkeit ist etwas anders als das, was ich bisher gedacht habe. Ich verstehe das so und habe das bisher auch in den Beiträgen entsprechend verwendet:
- Ein Ereignis ist irgendetwas, was mit einem "notify" ausgewertet werden kann. Dieses kann dann der perl-Funktion Informationen übergeben, die erst durch das Ereignis näher konkretisiert werden, insbesondere $NAME und $EVENT (oder Teile davon). Wenn ich von "Event" spreche, meine ich also, ein notify wird getriggert werden (oder könnte es werden, wenn es eines gäbe) und der Übergabewert (verkürzt zu das "Event") sollte dann zukünftig auch $EVENT (oder uU. Teile davon) sein.
- Ein Timer ist etwas, was rein zeitbasiert geschieht, klassischerweise ein "at". Dieses kann natürlich auch Ereignisse auslösen.

Meine Idee zur Aussperrschutz- und Lüftungsfunktion (nicht aber Eindringschutz) bisher war, in diesem Sinne rein Event-basiert vorzugehen, damit jeder diese Funktion nutzen kann, unabhängig davon, ob er die anderen Teile, die noch zu entwickeln wären (1. Morgens auf/abends zu bzw. 2. Beschattung) ebenfalls nutzen will.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

spi3845

Zitat von: Beta-User am 11 April 2017, 09:11:01
Achtung: Die Begrifflichkeit ist etwas anders als das, was ich bisher gedacht habe. Ich verstehe das so und habe das bisher auch in den Beiträgen entsprechend verwendet:
- Ein Ereignis ist irgendetwas, was mit einem "notify" ausgewertet werden kann. Dieses kann dann der perl-Funktion Informationen übergeben, die erst durch das Ereignis näher konkretisiert werden, insbesondere $NAME und $EVENT (oder Teile davon). Wenn ich von "Event" spreche, meine ich also, ein notify wird getriggert werden (oder könnte es werden, wenn es eines gäbe) und der Übergabewert (verkürzt zu das "Event") sollte dann zukünftig auch $EVENT (oder uU. Teile davon) sein.
- Ein Timer ist etwas, was rein zeitbasiert geschieht, klassischerweise ein "at". Dieses kann natürlich auch Ereignisse auslösen.

Meine Idee zur Aussperrschutz- und Lüftungsfunktion (nicht aber Eindringschutz) bisher war, in diesem Sinne rein Event-basiert vorzugehen, damit jeder diese Funktion nutzen kann, unabhängig davon, ob er die anderen Teile, die noch zu entwickeln wären (1. Morgens auf/abends zu bzw. 2. Beschattung) ebenfalls nutzen will.
Ich meine zu verstehen, vielleicht aber auch nicht  ???
Ereignisse beziehst Du rein auf durch notify auswertbar, z.B. "Tür auf" oder "Tür zu", aber auch "motor:down" weil jemand zuvor eine (physische) Taste gedrückt hat.

Ein Fahrkommando aus der fhem GUI wäre auch ein Ereignis - könnte ja z.B. ein Dummy aka virtuelle Taste sein, der durch ein notify registriert wird.

Die ursprüngliche Version deiner Funktion reagierte auf die Events "Tür auf/zu/gekippt" und "motor:.*".

Das Fahren des Rollladen über die GUI (oder auch Timer oder sonst irgendeiner Aktionen in fhem) könnte jetzt auf zweierlei Weise erfolgen:

  • zu den ursprünglichen Events in deiner Funktion kämen noch Events "auf" und "zu" hinzu und das Fahren des Rollladens wäre ein Aufruf der Funktion mit den Parametern Rollladen-Device und "auf" oder "zu"
  • der Rollladen wird direkt getriggert (z.B. "set Rollladen 0" und das Fahren wird dann über den Event "motor:.*" (in diesem Fall "motor:down") erkannt

Ich habe Weg 1 abgebildet (auch wenn ich die Events "Timer_down" und "Timer_up" genannt habe, sind sie generelle Events für "zu" und "auf"). Wenn ich dich richtig verstehe, bildest Du die Steuerung über Weg 2 ab? Oder stehe ich immer noch auf dem Schlauch? Was auch gut möglich (und wahrscheinlich) ist  :D

Wenn das Szenario tatsächlich so wie beschrieben ist, was sind aus deiner Erfahrung Vor-/Nachteile der einen gegenüber der anderen Lösung? Ich lerne immer noch fhem und die Lernkurve der letzten Tage war so etwas von steil - echt danke dafür!

Grüße,
spi

Beta-User

Zitat von: spi3845 am 11 April 2017, 21:33:36
Ich meine zu verstehen, vielleicht aber auch nicht  ???
Das haut in etwa so hin, wie Du das jetzt beschreibst.

ZitatEin Fahrkommando aus der fhem GUI wäre auch ein Ereignis - könnte ja z.B. ein Dummy aka virtuelle Taste sein, der durch ein notify registriert wird.
Es braucht nicht mal einen Dummy, die Gerätedarstellung eines Rolladenaktors in FHEMWEB tut es auch (oder ein Set-Kommando, das von einem at, weekdaytimer usw., aus aufgerufen wird...)
ZitatDie ursprüngliche Version deiner Funktion reagierte auf die Events "Tür auf/zu/gekippt" und "motor:.*".
Korrekterweise neben den Fenster-Kontakt-Events nur auf "motor:.stop", wenn also der Rolladen - warum auch immer - angehalten hat.
In der dev-Version ist im Moment noch ein weiteres notify vorgesehen, dass auch auf "level:.set.*" und "motor:.down.*" reagiert. Ersteres ist unglücklich, weil es eigentlich besser wäre, direkt das Geräte-"set" abzufangen, so konnte ich zwar doppelte Events vermeiden, es wäre aber m.E. besser, die level-sets schlicht in der Auswertefunktion zu verwerfen. Dann wird mit der zweiten Funktion geprüft, ob ein neuer "onHold"-Wert gesetzt werden muß und der Rolladen zwischendurch anhalten soll (neuer set-Befehl).
Das Problem dabei ist "nur", dass es zwei Events gibt, die kurz nacheinander kommen und man aber den 2. (motor:.down) ignorieren kann/muß, wenn man bereits kurz vorher ein "set" hatte. Daher der Versuch mit  ReadingsAge().

So richtig kann ich nicht erkennen, was mit den unterschiedlichen Wegen gemeint ist. Im Kern geht es ja nur darum, abhängig vom Fensterzustand bzw. dessen Änderung zu erkennen, was jetzt mit dem Rolladen geschehen soll bzw. optimalerweise schon zu verhindern, dass der Aktor "falsche" Befehle überhaupt erhält. Das geht jedenfalls dann nicht, wenn jemand direkt eine Taste drückt, für den Rest könnte es sein, dass man durch ein noch früheres Abfangen des Set-Kommandos aus FHEM sogar verhindern könnte, dass "level:.set.*" überhaupt geschieht. Keine Ahnung, muß erst mal coden. 

ZitatWenn das Szenario tatsächlich so wie beschrieben ist, was sind aus deiner Erfahrung Vor-/Nachteile der einen gegenüber der anderen Lösung? Ich lerne immer noch fhem und die Lernkurve der letzten Tage war so etwas von steil - echt danke dafür!
Danke zurück!
Meine "Programmier-Erfahrung" ist kaum größer als Deine, zu Vor- und Nachteilen kann ich daher wenig sagen (zumal ich keine signifikanten Unterscheiden feststellen kann. Bislang habe ich nur etwas mit C (Arduinos) rumgespielt, das war's aber. Diese textorientierte Denkweise von perl ist auch für mich ganz neu, habe die vergangenen Tage auch recht viel dazugelernt (mußte aber auch viel experimentieren, insbesondere der erste Ansatz, nur vereinfachte Infos vom notify an perl zu übergeben war vermutlich nicht hilfreich). Die "neue" Funktion zum Neusetzen von Zielwerten ist da deutlich besser. Sogar an den "Modulgedanken" habe ich mich gewöhnt, allerdings keinen Plan, was das für Vorteile hätte ("softpeering" erleichtern, andere Initialisierungsfunktionen für die Attr aufrufen? Notifys als interne Funktion nutzen? Vielleicht kann mir da ja jemand mal auf die Sprünge helfen?

Gruß, Beta-User   
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

hugomckinley

#88
Hier nun die ordentlich kommentierte Version meines Scripts in der 99_myUtils.pm https://forum.fhem.de/index.php/topic,61844.msg532545.html#msg532545
Bei weiteren Fragen einfach melden.

Und die gewünschten Überlegungen:


  • Was ist das Ziel der Lösung?
    Rolladenautomatisierung für eine große Anzahl von Rollos (Verdunkelung und Beschattung). Einfache Parametrisierung über eine GUI. Möglichst wenige Komponenten (dummys, doifs, at, usw.), leichte Erweiterbarkeit (Rollos, Funktionen), vollautomatischer Betrieb (möglichst keine Benutzereingriffe nötig), Mehrbenutzerfähigkeit (3 Wohneinheiten), "objektorientiertes Design" (keine dummys für Parameter/Readings der Rollos, sondern alles beim "Objekt"). Mittelfristig sollen Parameter von Nicht-Experten per Floorplan auf einem  Touchdisplay einstellbar sein. Anwesenheitssimulation in Kombination mit dieser Automatik. 
  • Was ist bereits umgesetzt?
    Verdunkelung, Beschattung, GUI, automatisches Parametrieren von neuen Rollos, vollautomatischer Betrieb (Sommer/Winter, kühle/heiße Tage), unabhängige Wohneinheiten
  • Was fehlt noch?
    Bedienung über Floorplan (z.B. setzen der gewünschten Beschattungsposition per Touchscreen --> Zitat: "genau wo das Rollo jetzt steht soll es immer sein beim Beschatten"). Einbinden der Anwesenheitssimulation in die Rollosteuerung.
  • Was sind die Voraussetzungen (HW/SW) für diese Lösung?
    Rollladen-Aktoren, welche die Position melden, Helligkeitssensoren für jede (gewünschte) Hausseite, Temperatursensor(Außentemperatur), Fensterkontakte für Terrassentüren. (Bei mir alles Homematic)
  • Warum wurde die Lösung so implementiert?
    Übersichtlichkeit. Ich möchte, dass meine Lösungen auch von anderen (möglichst) einfach übernommen werden kann. (z.B. Konfiguration der Rollos)
  • Was würde ich heute anders machen?
    Kann ich so nicht sagen. Optimierungspotential ist genug vorhanden. Trotz der guten Vorsätze ist es trotzdem viel "Zeug" geworden (doifs, weekdaytimers, dummy, notify usw.) --> weitere "Monolithisierung" und wenn das nicht möglich ist, ein "Installationsscript"(vgl. mit dem Parametrisieren der Rollos)


Hugo
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

spi3845

Zitat von: hugomckinley am 12 April 2017, 20:14:30
Hier nun die ordentlich kommentierte Version meines Scripts in der 99_myUtils.pm https://forum.fhem.de/index.php/topic,61844.msg532545.html#msg532545
Bei weiteren Fragen einfach melden.

Hugo
Danke! Die nächsten freien Tage sind versaut mit dem Lesen von Code 8)