FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: dominik am 19 Juli 2015, 17:36:24

Titel: [solved] Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 17:36:24
//Lösung unten

Hallo,
ich bin gerade dabei einen Button für alle Lichter zu machen welcher wie ein Sleeptimer funktionieren soll.

Beispiel:
- BettLampe on|off|timer
on => Lampe wird eingeschaltet
off => Lampe wird ausgeschaltet
timer => Lampe wird eingeschaltet mit einem Timer von 5min. Drückt man nochmals auf "timer" wird der Timer auf 10min erhöht, usw.

Wie lässt sich so etwas am besten abbilden? Ich dachte daran eine Funktion in Utils zu schreiben mit (Pseudocode)
timer_funktion($lampe, $aktuellerwert) {
if ($aktuellerwert = 5min) {
    set $lampe off at +0:10:0
}
...
}
und die rufe ich dann im Notify auf. Nur wo kann ich den aktuellen Wert speichern!?

Gruß
dominik
--
Hier meine Lösung
99_myUtils.pm
sub Timerfunktion ($$)
{
my ($Device) = $_[0];
    my ($Schalter) = $_[1];
    my ($TimerIntervall) = 10;
my ($currentValue) = ReadingsVal($Device, "timerValue", 0);
    my ($currentState) = ReadingsVal($Device, "state", "off");
   
    #Nur einschalten wenn zuvor "off"
    if ($currentState ne "on") {
    fhem("set $Device on");
        $currentValue = 0;
    }
   
    #Sleeptimer hochzählen. Max=180 Minuten
    $currentValue = $currentValue + 10;
    if ($currentValue > 180) {
    $currentValue = 0;
    }
    my $timerValue = sprintf("%02d:%02d:%02d", (gmtime($currentValue*60))[2,1,0]);
   
    #Schalter state ändern
    fhem("set $Schalter $currentValue");
   
    #Aktuellen Sleeptimer schreiben
    fhem("setreading $Device timerValue $currentValue");
    #Alten Timer löschen
    fhem("delete $Device.timer");
   
    #Neuen Timer setzen bzw. ausschalten wenn 0
    if ($currentValue > 0) {
    fhem("define $Device.timer at +$timerValue set $Device off;;setreading $Device timerValue 0");
    } else {
    fhem("set $Device off");
    }
   
}


fhem.conf (EingangsLampe ist das zu schaltende Element in diesem Fall)
define EingangsLampeTimer dummy
attr EingangsLampeTimer alias EingangsLampe Timer
attr EingangsLampeTimer group Beleuchtung
attr EingangsLampeTimer room Wohnzimmer
attr EingangsLampeTimer webCmd timer
define NEingangsLampeTimer notify EingangsLampeTimer:timer { Timerfunktion("EingangsLampe", "EingangsLampeTimer") }


...und damit der Timer beim Ausschalten wieder gelöscht wird noch folgendes:
99_myUtils.pm
sub deleteDeviceTimers ($) {
my ($device) = @_;
    fhem("delete $device.timer");
}

sub notifyOnOff ($$) {
my ($device, $event) = @_;
   
    if ($event eq "off") {
    deleteDeviceTimers($device);
    }
}


fhem.conf
define Neingangslampe_onoff notify EingangsLampe:* {notifyOnOff($NAME,$EVENT)}

Bugs (wer hat Lösungen? :))
- FIXED: Wird das Device in der Zwischenzeit aus und wieder eingeschalten, so bleibt der Timer dennoch erhalten
- FIXED: Limitiert auf einen maximalen Timer von 60 Minuten => ist nun auf 180 Minuten Maximum eingestellt

Titel: Antw:Sleeptimer
Beitrag von: Otto123 am 19 Juli 2015, 19:56:38
Hallo Dominik,

ich hatte so was ähnliches als Frage vor Kurzem.
Mit einem DOIF so in der Art (nur DEF):
([Test2] eq "on") (set SD3 on) DOELSEIF ([8:00 -20:00] and [+:05] and ([Test2] eq "intervall")) (set SD3 on-for-timer 5) DOELSEIF (([Test2] eq "countdown")) (set SD3 on-for-timer 10)

Nur die Timerverlängerung musst Du dir einfallen lassen.

Gruß Otto
Titel: Antw:Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 20:32:31
Danke Otto123.

Das DOIF ist in meinem Fall glaub ich nicht passend. Ich möchte nämlich per Timer Button den Sleeptimer setzen, von daher muss ich den per Notify abfragen. on-for-timer dachte ich auch schon, aber der funktioniert mit pilight nicht. Daher werde ich wohl auf at +... als Funktion zurückgreifen.

Meine Idee war gerade folgende
sub Timerfunktion ($)
{
my ($Device) = $_[0];
    my ($currentValue) = Value($Device);
    $currentValue = $currentValue + 10;
    fhem("set $Device $currentValue");
}

Zumindest um mal irgendwo die aktuell gesetzte Zeit zu speichern. Obwohl ich das nicht unbedingt im "state" machen möchte. Und dann plane ich ein Notify auf den state und verwende $EVENT als at +0:$EVENT:00.

Aktuell schlägt der Code oben aber schon fehl. Weil ich den state nicht ausgelesen bekomm...ich dachte der Sleeptimer geht einfacher :)
Titel: Antw:Sleeptimer
Beitrag von: krikan am 19 Juli 2015, 20:35:56
Zitat von: dominik am 19 Juli 2015, 20:32:31
Ich möchte nämlich per Timer Button den Sleeptimer setzen, von daher muss ich den per Notify abfragen. on-for-timer dachte ich auch schon, aber der funktioniert mit pilight nicht.
Schau Dir mal http://www.fhemwiki.de/wiki/ReadingsProxy#setExtensions_f.C3.BCr_Ger.C3.A4te_implementieren an. Mit einem ReadingsProxy-Device bekommt man "on-for-timer"
Titel: Antw:Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 20:44:55
Der ReadingProxy wird ja nur verwendet wenn standardmäßig kein on,off state gesetzt wird, oder? In meinem Fall arbeitet pilight bereits mit on,off states. Daher macht es dann keinen Unterschied.

Wo speichert man mit fhem normal Variablen zum Device wenn das nicht in state hinterlegt werden soll? Bei der Verwendung von setreading... und danach ReadingsVal() bekomm ich das Reading in Perl leider auch nicht ausgelesen. Glaub sobald ich eine Variable hab die ich hochzählen kann, sollte der Rest nicht mehr so schwer sein  :-[
Titel: Antw:Sleeptimer
Beitrag von: Puschel74 am 19 Juli 2015, 21:07:04
ZitatGlaub sobald ich eine Variable hab die ich hochzählen kann, sollte der Rest nicht mehr so schwer sein  :-[

Hier bitte.
Mach ich seit gut einem Jahr so und funktioniert einwandfrei.

Zitat
my $Wert=ReadingsVal("OG_Zimmer_Licht2","counter",0);
...
$Wert = $Wert+1;
fhem("setreading OG_Zimmer_Licht2 counter $Wert");
Titel: Antw:Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 21:17:33
Danke Puschel74!!

So...hier nun mein aktueller Code:
sub Timerfunktion ($)
{
my ($Device) = $_[0];
    my ($currentValue) = ReadingsVal($Device, "timerValue", 0);
   
    #FIXME hier wird leider immer "timer" als state eingelesen
    my ($currentState) = ReadingsVal($Device, "state", "off");
   
    #FIXME sollte nur eingeschalten werden wenn zuvor "off"
    fhem("set $Device on");
   
    #Sleeptimer hochzählen. Max=60 Minuten
    $currentValue = $currentValue + 10;
    if ($currentValue > 60) {
    $currentValue = 0;
    }
   
    #Aktuellen Sleeptimer schreiben
    fhem("setreading $Device timerValue $currentValue");
    #Alten Timer löschen
    fhem("delete $Device.timer");
   
    #Neuen Timer setzen bzw. ausschalten wenn 0
    if ($currentValue > 0) {
    fhem("define $Device.timer at +0:$currentValue:00 set $Device off");
    } else {
    fhem("set $Device off");
    }
   
}


Folgende Konfiguration ist in FHEM nötig:
attr Lampe webCmd on:off:timer
define Nbettlampesleep notify Lampe:timer { Timerfunktion("Lampe") }

Bugs:
- Lampe schaltet noch bei jedem "timer" Klick kurz aus und wieder ein, der "timer" webCmd sollte nicht als state gesetzt werden. Jemand eine Idee wie man das umgehen kann? :)
- Aktuell max. 60 Minuten Sleeptimer
Titel: Antw:Sleeptimer
Beitrag von: krikan am 19 Juli 2015, 21:30:40
Zitat von: dominik am 19 Juli 2015, 20:44:55
Der ReadingProxy wird ja nur verwendet wenn standardmäßig kein on,off state gesetzt wird, oder? In meinem Fall arbeitet pilight bereits mit on,off states. Daher macht es dann keinen Unterschied.
Nein.
Mit readingsProxy solltest Du eigentlich jedem Original-Device, das von sich aus keine setExtensions (u.a. auch on-for-timer) unterstützt, das beibringen können.
Aber Du hast ja auch so schon eine Lösung. Viele Wege...
Titel: Antw:Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 21:38:08
Ah, jetzt versteh ich es. Ich dachte on-for-timer ist eine fhem interne Funktion die nur on/off der Devices aufruft. Danke für die Klarstellung.
Titel: Antw:Sleeptimer
Beitrag von: Puschel74 am 19 Juli 2015, 21:47:40
ZitatSo...hier nun mein aktueller Code:
Der nicht funktioniert - sorry.

Das
fhem("define $Device.timer at +0:$currentValue:00 set $Device off");
von dir wurde von mir abgeändert damit ich was damit anfangen kann.
Das
Zitatfhem("define $NAME.timer at +0:$EVENT:00 set Sender off");
kommt dabei raus und liefert das im Logfile
Zitat2015.07.19 21:43:36 3: define Sendepause.timer at +0:8:00 set Sender off : Wrong timespec 0:8:00: either HH:MM:SS or {perlcode}

Eigenartig das du diese Meldung nicht im Log bekommst wenn du das notify triggerst  ???
Sollte ich wirklich so weit daneben liegen  :o
Titel: Antw:Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 22:00:48
Du dürftest statt 10 Minuten 8 verwendet haben. Probier es mal mit 10, vielleicht braucht at die Minuten wirklich 2-stellig.
Titel: Antw:Sleeptimer
Beitrag von: Puschel74 am 19 Juli 2015, 22:12:09
Ok, ich geh immer von mir aus das die "unmöglichen Sachen" auch funktionieren.
Mit 53 Minuten klappt es aber mit 4 nicht - das ist richtig.
Einfach eine 0 vor die einstelligen und dann erst erstellen hilft dabei  ;)
Nicht schön aber ich behelf mir bei sowas damit
if ($Smin < "10") {
        $Smin = "0".$Smin;
      }
Titel: Antw:Sleeptimer
Beitrag von: Damian am 19 Juli 2015, 22:34:46
Zitat von: dominik am 19 Juli 2015, 17:36:24
Hallo,
ich bin gerade dabei einen Button für alle Lichter zu machen welcher wie ein Sleeptimer funktionieren soll.

Beispiel:
- BettLampe on|off|timer
on => Lampe wird eingeschaltet
off => Lampe wird ausgeschaltet
timer => Lampe wird eingeschaltet mit einem Timer von 5min. Drückt man nochmals auf "timer" wird der Timer auf 10min erhöht, usw.

Wie lässt sich so etwas am besten abbilden? Ich dachte daran eine Funktion in Utils zu schreiben mit (Pseudocode)
timer_funktion($lampe, $aktuellerwert) {
if ($aktuellerwert = 5min) {
    set $lampe off at +0:10:0
}
...
}
und die rufe ich dann im Notify auf. Nur wo kann ich den aktuellen Wert speichern!?

Gruß
dominik

define di_on_for_timer DOIF ([BettLampe:?on])
  (set lamp on)
DOELSEIF ([BettLampe:?off])
  (set lamp off)
DOELSEIF ([BettLampe:?timer])
  (set lamp on)
  (set lamp off)

attr di_on_for_timer do resetwait
attr di_on_for_timer wait 0:0:0,300


siehe http://forum.fhem.de/index.php/topic,39070.msg312029.html#msg312029

Gruß

Damian

Titel: Antw:Sleeptimer
Beitrag von: Puschel74 am 19 Juli 2015, 22:38:48
@Damian
Und nun noch den timer in das Attribut wait übergeben  ;)
Aber so wie ich dich kenne geht das mittlerweile auch  ::)
Sorry ich benutz kein DOIF daher kenn ich die commandref dazu nicht
Titel: Antw:Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 23:17:50
@Damian
Hab ich es richtig verstanden, dass der Timer verlängert wird? Also wenn dort 300 steht (5 Minuten) und ich 2x Timer drücke, dann erhalte ich einen Timer von 10 Minuten?
Weil in deinem Post lese ich es eher so, als ob der Timer nochmals mit 0 beginnt und wieder 5 Minuten läuft.
Titel: Antw:Sleeptimer
Beitrag von: Damian am 19 Juli 2015, 23:29:49
Zitat von: dominik am 19 Juli 2015, 23:17:50
@Damian
Hab ich es richtig verstanden, dass der Timer verlängert wird? Also wenn dort 300 steht (5 Minuten) und ich 2x Timer drücke, dann erhalte ich einen Timer von 10 Minuten?
Weil in deinem Post lese ich es eher so, als ob der Timer nochmals mit 0 beginnt und wieder 5 Minuten läuft.

ja, hier wird ab dem wiederholten Tastendruck um 5 Minuten verlängert. Ein Doppelklick lässt sich mit dem Attribut waitsame realisieren, siehe Commandref zu DOIF.

Gruß

Damian
Titel: Antw:Sleeptimer
Beitrag von: Puschel74 am 19 Juli 2015, 23:43:34
Sogar noch eins drauf gesetzt und noch besser gemacht  8)
Titel: Antw:Sleeptimer
Beitrag von: dominik am 19 Juli 2015, 23:47:12
Hab mir mal die commandref dazu durchgelesen, aber so wie ich das verstehe, kann ich damit nicht wirklich verlängern, sondern nur den timer wieder auf 0 setzen.

Ich möchte nämlich, dass wenn ich 1x timer drücke nach 10 Minuten die Lampe aus geht. 2x timer drücken => 20 Minuten, 3x => 30 Minuten, usw.

Ich werde jetzt mal dein neues Modul installieren und es ausprobieren ;)
Titel: Antw:Sleeptimer
Beitrag von: Damian am 19 Juli 2015, 23:55:20
Zitat von: dominik am 19 Juli 2015, 23:47:12
Hab mir mal die commandref dazu durchgelesen, aber so wie ich das verstehe, kann ich damit nicht wirklich verlängern, sondern nur den timer wieder auf 0 setzen.

Ich möchte nämlich, dass wenn ich 1x timer drücke nach 10 Minuten die Lampe aus geht. 2x timer drücken => 20 Minuten, 3x => 30 Minuten, usw.

Ich werde jetzt mal dein neues Modul installieren und es ausprobieren ;)

Bei x-mal drücken musst du auch jeweils Zeitspannen programmieren, wann weiter gezählt wird und wann nicht. Dann sollte dein System auch performant genug sein und sich keine Zeitpausen gönnen, sonst kommst du beim Zählen durcheinander.

Gruß

Damian
Titel: Antw:Sleeptimer
Beitrag von: dominik am 20 Juli 2015, 20:59:17
Ich habe jetzt mal meinen Code belassen, denn damit funktioniert es ja :)
Mich stört nur, dass wenn ich "timer" drücke, die Lampe gleich "timer" als state übernimmt und sich damit kurz ausschaltet. Kann man ein webCmd an einem Device auch absetzen ohne dass sich das webCmd gleich als state hinterlegt?

Hab mal testweise einen dummy Schalter gebaut und dort die "timer" Funktionalität integriert. Da funktioniert es dann prima, da die Lampe nicht auf "timer" gesetzt wird sondern immer schön auf on oder off bleibt.

Wie handhabt ihr das generell im Webinterface? Erstellt ihr dummy Schalter im WebIf oder schaltet ihr direkt an den Devices? Was ist da die Empfehlung? Nachdem ich keine Hardware Schalter habe, steuer ich zur Zeit alles über das WebIf bzw. lasse die Devices zeitgesteuert agieren.
Titel: Antw:[solved] Sleeptimer
Beitrag von: dominik am 29 Juli 2015, 23:43:31
Hab meine Lösung auf der ersten Seite angepasst. Nun läuft der Sleeptimer einwandfrei und lässt sich auch sehr leicht auf weitere Geräte erweitern.

Btw, nutzt ihr eigentlich viel Perl Code oder eher mehr fhem.conf Befehle? Mache gerade die Erfahrung, dass ich viel besser zurecht komme, wenn ich die Befehle wie notify gleich auf Perl Code umleite und dort dann mit entsprechenden Funktionen arbeiten. Hat auch den Charm, dass ich dort die Funktionen wiederverwenden kann. Ist das auch Best Practice?