Lüftersteuerung mit einstellbarem Timer + Prüfung, ob das Signal angekommen ist

Begonnen von Khazmadoz, 30 Juni 2021, 13:20:42

Vorheriges Thema - Nächstes Thema

Khazmadoz

Hallo liebes Forum,

ich möchte gerne für eine Lüftersteuerung mit (bis zu) drei Variablen einstellen, wann und wie oft der Lüfter ein- und ausgeschaltet werden soll. Zusätzlich soll das Signal so lange gesendet werden, bis die Lüfter wirklich die Geschwindigkeit ändern (dafür nutze ich das Tacho-Signal der Lüfter).

Bisher sieht das so aus:
subs {

sub fan_off{
set_Exec("timer",15,'fhem"set MYSENSOR_1 percentage1 0"','ReadingsVal("MYSENSOR_1","level2","300") > "350"')
}

sub fan_begin{
fhem"set MYSENSOR_1 percentage1 25"
}

sub fan_half{
fhem"set MYSENSOR_1 percentage1 50"
}

sub fan_tq{
fhem"set MYSENSOR_1 percentage1 75"
}

sub fan_full {
fhem"set MYSENSOR_1 percentage1 100"
}

}

{if (([([+[{(sprintf("%02d",ReadingsVal("TerraFanTimer", "P_every", "3")))}]:00])]) and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){fan_begin()}}
{if (([([+[{(sprintf("%02d",ReadingsVal("TerraFanTimer", "P_every", "3")))}]:00] + ((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*60))]) and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){fan_half()}}
{if (([([+[{(sprintf("%02d",ReadingsVal("TerraFanTimer", "P_every", "3")))}]:00] + ((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*120))]) and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){fan_tq()}}
{if (([([+[{(sprintf("%02d",ReadingsVal("TerraFanTimer", "P_every", "3")))}]:00] + ((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*180))]) and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){fan_full()}}
{if (([([+[{(sprintf("%02d",ReadingsVal("TerraFanTimer", "P_every", "3")))}]:00] + ((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*240))]) and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){fan_off()}}


Wie man sieht, habe ich die Prüfung nur für das Ausschalten implementiert bisher, weiß aber auch nicht, ob das so klappt, denn ich bekomme für die Zeit folgendes gemeldet:
error: the function "(sprintf("%02d",ReadingsVal("TerraFanTimer","P_every","3")))" must return a timespec and not 01.

Ich muss gestehen, dass mich als jemand, der normalerweise Cpp/C# u.ä. programmiert, Perl unfassbas irritiert und der Mix mit der FHEM und DOIF Syntax machts mir nicht einfacher, vielleicht kann mir jemand helfen, wie der Cast als timespec funktionieren kann und was an der Syntax noch fehlerhaft ist. Was im obigen Code noch komplett fehlt, ist, dass mit einer dritten Variable eingestellt werden soll, wieviel nach der vollen Stunde der Timer anfangen soll. Da bin ich mir nicht sicher, was passiert, wenn die Timer sich den DAU angenommen überlappen sollten.

Viele Fragen ich weiß, aber ich habs jetzt drei Abende alleine versucht und drehe mich nur im Kreis...

Vielen Dank schonmal!

Damian

Du musst schon die ganze Timer-Definition in Perl formulieren und nicht nur Teile davon.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Khazmadoz

Das ist jetzt mein Workaround:
subs {

sub fan_off{
set_Exec("timer",15,'fhem"set MYSENSOR_1 percentage1 0"','ReadingsVal("MYSENSOR_1","level2","300") > "350"')
}

sub fan_begin{
set_Exec("timer",15,'fhem"set MYSENSOR_1 percentage1 25"','ReadingsVal("MYSENSOR_1","level2","550") < "500"')
}

sub fan_half{
set_Exec("timer",15,'fhem"set MYSENSOR_1 percentage1 50"','ReadingsVal("MYSENSOR_1","level2","950") < "900"')
}

sub fan_tq{
set_Exec("timer",15,'fhem"set MYSENSOR_1 percentage1 75"','ReadingsVal("MYSENSOR_1","level2","1250") < "1200"')
}

sub fan_full {
set_Exec("timer",15,'fhem"set MYSENSOR_1 percentage1 100"','ReadingsVal("MYSENSOR_1","level2","1550") < "1500"')
}

}

{if ([{sprintf("%02d:%02d:00",ReadingsVal("TerraFanTimer", "P_every", "3")+ReadingsVal("TerraFanTimer", "P_lasttimerhour", "3"),ReadingsVal("TerraFanTimer", "P_mybegin", "0"))}]
and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){
fan_begin();
my $nexttimerhour = ReadingsVal("TerraFanTimer", "P_every", "0") + ReadingsVal("TerraFanTimer", "P_lasttimerhour", "0");
if ($nexttimerhour > 23){
$nexttimerhour = $nexttimerhour - 24;
}
fhem"set TerraFanTimer P_lasttimerhour $nexttimerhour";
}
}

{if ([([{sprintf("%02d:%02d:00",ReadingsVal("TerraFanTimer", "P_every", "3")+ReadingsVal("TerraFanTimer", "P_lasttimerhour", "3"),ReadingsVal("TerraFanTimer", "P_mybegin", "0"))}])+((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*60)]
and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){
fan_half()
}
}
{if ([([{sprintf("%02d:%02d:00",ReadingsVal("TerraFanTimer", "P_every", "3")+ReadingsVal("TerraFanTimer", "P_lasttimerhour", "3"),ReadingsVal("TerraFanTimer", "P_mybegin", "0"))}])+((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*120)]
and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){
fan_tq()
}
}
{if ([([{sprintf("%02d:%02d:00",ReadingsVal("TerraFanTimer", "P_every", "3")+ReadingsVal("TerraFanTimer", "P_lasttimerhour", "3"),ReadingsVal("TerraFanTimer", "P_mybegin", "0"))}])+((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*180)]
and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){
fan_full()
}
}
{if ([([{sprintf("%02d:%02d:00",ReadingsVal("TerraFanTimer", "P_every", "3")+ReadingsVal("TerraFanTimer", "P_lasttimerhour", "3"),ReadingsVal("TerraFanTimer", "P_mybegin", "0"))}])+((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*240)]
and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){
fan_off()
}
}


Tut das, was es soll, habe aber das Gefühl, es ist etwas umständlich...

Meintest du das mit der Timerfunktion komplett in Perl?

Gibts da noch Tipps?

Vielen Dank!


Khazmadoz

Okay es gibt immer noch ein Problem, heute Nacht ist der Timer nach Ausführung von 3 Uhr heute auf 6 Uhr morgen gesprungen...

Habe ich was übersehen?

Damian

Es sieht mir unnötig kompliziert aus. Du brauchst doch nur einen Start- und einen End-Timer. Die Steigerung der Drehzahl würde ich in eine Routine packen und per set_Exec aufrufen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Khazmadoz

Habe es ein bisschen mit meinem Wissen angepasst:
subs {

sub fan_progression{
if ($_[0] == 0){set_Exec("timerBegin",15,'fhem"set MYSENSOR_1 percentage1 25"','ReadingsVal("MYSENSOR_1","level2","550") < "500"')}
if ($_[0] == 1){set_Exec("timerHalf",15,'fhem"set MYSENSOR_1 percentage1 50"','ReadingsVal("MYSENSOR_1","level2","950") < "900"')}
if ($_[0] == 2){set_Exec("timerTQ",15,'fhem"set MYSENSOR_1 percentage1 75"','ReadingsVal("MYSENSOR_1","level2","550") < "500"')}
if ($_[0] == 3){set_Exec("timerFull",15,'fhem"set MYSENSOR_1 percentage1 100"','ReadingsVal("MYSENSOR_1","level2","950") < "900"')}
if ($_[0] == 4){set_Exec("timerOff",15,'fhem"set MYSENSOR_1 percentage1 0"','ReadingsVal("MYSENSOR_1","level2","300") > "350"')}
}

}

{if ([{sprintf("%02d:%02d:00",ReadingsVal("TerraFanTimer", "P_lasttimerhour", "3"),ReadingsVal("TerraFanTimer", "P_mybegin", "0"))}]
and (ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto")){
$_count = 0;
fan_progression($_count);
$_count+=1;
set_Exec("timerProgression",'((ReadingsVal("TerraFanTimer", "P_myend", "15")/3)*60)','fan_progression($_count); $_count+=1','$_count < 5');
my $nexttimerhour = ReadingsVal("TerraFanTimer", "P_every", "0") + ReadingsVal("TerraFanTimer", "P_lasttimerhour", "0");
if ($nexttimerhour > 23){
$nexttimerhour -= 24;
}
fhem"set TerraFanTimer P_lasttimerhour $nexttimerhour";
}
}


Was mich jetzt noch stört ist der Teil über dem set_exec mit dem $_count. Gibt es eine Möglichkeit, den ersten Aufruf von set_exec vor dem ersten Timer zu machen?

Der Timer springt außerdem nach der Ausführung immer auf den nächsten Tag + P_every statt auf Ausführungszeit + P_every...

Khazmadoz

Sorry fürs Doppelposten, aber jetzt ist es doch sehr anders geworden. Die Abstände sind jetzt fix. Trotzdem ist es noch unschön, dass ich vor dem set_Exec die Routine einmal aufrufen muss.



subs {

sub fan_progression{
if ($_[0] == 0){set_Exec("timerBegin",15,'fhem_set("MYSENSOR_1 percentage1 25")','ReadingsVal("MYSENSOR_1","level2","550") < "500"')}
if ($_[0] == 1){set_Exec("timerHalf",15,'fhem_set("MYSENSOR_1 percentage1 50")','ReadingsVal("MYSENSOR_1","level2","950") < "900"')}
if ($_[0] == 2){set_Exec("timerTQ",15,'fhem_set("MYSENSOR_1 percentage1 75")','ReadingsVal("MYSENSOR_1","level2","550") < "500"')}
if ($_[0] == 3){set_Exec("timerFull",15,'fhem_set("MYSENSOR_1 percentage1 100")','ReadingsVal("MYSENSOR_1","level2","1250") < "1200"')}
if ($_[0] == 4){set_Exec("timerOff",15,'fhem_set("MYSENSOR_1 percentage1 0")','ReadingsVal("MYSENSOR_1","level2","300") > "350"')}
}

}

{ [+[3]:00];
if(ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto"){
$_count=0;
fan_progression($_count);
$_count=1;
set_Exec("timerProgression",'((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*60)','fan_progression($_count); $_count+=1','$_count < 5');
}
}


Jemand ne Idee?

Damian

Die Variable $count musst du nicht hochzählen, das macht bereits set_Exec.

In der Commandref sind diverse Beispiele, auch wie man die Verzögerung beim ersten mal auf Null setzt:

defmod di_lamp_on DOIF {["button:on"];;set_Exec("timer",'$count == 0 ? 0 : 1','fhem_set("lamp on")','$count < 2')}

Die Drehzahl würde ich abhängig von $count berechnen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Khazmadoz

Was hältst du davon?

{
[+[3]:00];
if(ReadingsVal("TerraFanTimer", "P_mybutton", "manual") eq "auto"){
set_Exec("timerProgression",'$count == 0 ? 0 : ((ReadingsVal("TerraFanTimer", "P_myend", "15")/4)*60)','$count < 4 ? fhem_set("MYSENSOR_1 percentage1 @{[($count + 1)*25]}") : fhem_set("MYSENSOR_1 percentage1 0")','$count < 5');
}
}

Damian

Wenn´s funktioniert, dann dürfte das die kürzeste Version zu sein. Man kann im DOIF-Perl-Modus ReadingsVal ebenfalls abkürzen, dann aber ohne Trigger:

{if ([?TerraFanTimer:P_mybutton,manual] eq "auto") {...

Man kann natürlich auch konsequent in Perl bleiben und nur die notwendigen Triggerangaben (hier die Zeit) in DOIF-Syntax schreiben, wie in deinem Beispiel.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF