From 0340785260186cdc172eb5b759cb74d3b88b1cfb Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Sun, 27 Jan 2013 21:30:41 +0000 Subject: [PATCH] set extensions (on-for-timer, etc) git-svn-id: https://svn.fhem.de/fhem/trunk@2582 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 5 +- fhem/FHEM/10_EnOcean.pm | 23 +++-- fhem/FHEM/10_FS20.pm | 18 ++-- fhem/FHEM/10_ZWave.pm | 19 +++- fhem/FHEM/SetExtensions.pm | 152 +++++++++++++++++++++++++++++ fhem/docs/commandref_frame.html | 38 ++++++++ fhem/docs/commandref_frame_DE.html | 63 ++++++++++-- 7 files changed, 290 insertions(+), 28 deletions(-) create mode 100644 fhem/FHEM/SetExtensions.pm diff --git a/fhem/CHANGED b/fhem/CHANGED index 384009f58..79a16856a 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -51,10 +51,11 @@ - feature: telnet client mode - bugfix: FHEMWEB longpoll misses initial state change (HM: set_on vs. on) - change: 20_OWFS.pm, 21_OWTEMP modules flagged as "deprecated". These - modules will be removed in a future release. Use OWServer / OWDevice - instead. (M. Fischer) + modules will be removed in a future release. Use OWServer / + OWDevice instead. (M. Fischer) - feature: a lot of new features and known 1-wire slaves to OWServer / OWDevice added (M. Fischer) + - feature: set-extensions (additional set commands) for FS20, EnOcean, ZWave - 2012-10-28 (5.3) - feature: added functions trim, ltrim, rtrim, UntoggleDirect, diff --git a/fhem/FHEM/10_EnOcean.pm b/fhem/FHEM/10_EnOcean.pm index e2cb7acdc..20f162c4f 100755 --- a/fhem/FHEM/10_EnOcean.pm +++ b/fhem/FHEM/10_EnOcean.pm @@ -4,6 +4,7 @@ package main; use strict; use warnings; +use SetExtensions; sub EnOcean_Define($$); sub EnOcean_Initialize($); @@ -221,8 +222,10 @@ EnOcean_Set($@) $dimVal=0; } else { - return "Unknown argument $cmd, choose one of dim:slider,0,1,100 ". - "dimup:slider,0,1,100 dimdown:slider,0,1,100 on off teach" + my $list = "dim:slider,0,1,100 dimup:slider,0,1,100 ". + "dimdown:slider,0,1,100 on off teach"; + return SetExtensions($hash, $list, $name, @a); + } if($sendDimCmd) { @@ -288,11 +291,12 @@ EnOcean_Set($@) ########################### } else { # Simulate a PTM my ($c1,$c2) = split(",", $cmd, 2); - return "Unknown argument $cmd, choose one of " . - join(" ", sort keys %EnO_ptm200btn) - if(!defined($EnO_ptm200btn{$c1}) || - ($c2 && !defined($EnO_ptm200btn{$c2}))); - Log $ll2, "EnOcean: set $name $cmd"; + + if(!defined($EnO_ptm200btn{$c1}) || + ($c2 && !defined($EnO_ptm200btn{$c2}))) { + my $list = join(" ", sort keys %EnO_ptm200btn); + return SetExtensions($hash, $list, $name, @a); + } my ($db_3, $status) = split(":", $EnO_ptm200btn{$c1}, 2); $db_3 <<= 5; @@ -636,6 +640,7 @@ EnOcean_A5Cmd($$$) <a name="EnOceanset"></a> <b>Set</b> <ul> + <br> <li>MD15 commands. Note: The command is not sent until the MD15 wakes up and sends a mesage, usually every 10 minutes. <ul> @@ -705,6 +710,10 @@ EnOcean_A5Cmd($$$) attr eventMap BI:on B0:off<br> set switch1 on<br> </code></ul> + <b>Note</b>: <a href="#setExtensions">set extensions</a> are supported, + if the corresponding <a href="#eventMap">eventMap</a> specifies + the on and off mappings. + <br> </li> </ul> diff --git a/fhem/FHEM/10_FS20.pm b/fhem/FHEM/10_FS20.pm index 76ada4b38..0770515b6 100755 --- a/fhem/FHEM/10_FS20.pm +++ b/fhem/FHEM/10_FS20.pm @@ -4,6 +4,7 @@ package main; use strict; use warnings; +use SetExtensions; my %codes = ( "00" => "off", @@ -167,7 +168,7 @@ FS20_Set($@) my $ret = undef; my $na = int(@a); - return "no set value specified" if($na < 2 || $na > 3); + return "no set value specified" if($na < 2); return "Readonly value $a[1]" if(defined($readonly{$a[1]})); if($na > 2 && $a[1] eq "dim") { @@ -181,16 +182,14 @@ FS20_Set($@) if(!defined($c)) { # Model specific set arguments + my $list; if(defined($attr{$name}) && defined($attr{$name}{"model"})) { my $mt = $models{$attr{$name}{"model"}}; - return "Unknown argument $a[1], choose one of " - if($mt && $mt eq "sender"); - return "Unknown argument $a[1], choose one of $fs20_simple" - if($mt && $mt eq "simple"); + $list = "" if($mt && $mt eq "sender"); + $list = $fs20_simple if($mt && $mt eq "simple"); } - return "Unknown argument $a[1], choose one of " . - join(" ", sort keys %fs20_c2b) . - " dim:slider,0,6.25,100"; + $list = join(" ", sort keys %fs20_c2b) if(!defined($list)); + return SetExtensions($hash, $list, @a); } @@ -538,6 +537,8 @@ four2hex($$) toggle # between off and previous dim val on-till # Special, see the note </pre> + The <a href="#setExtensions"> set extensions</a> are also supported.<br> + <br> Examples: <ul> <code>set lamp on</code><br> @@ -546,6 +547,7 @@ four2hex($$) <code>set lamp on-for-timer 12</code><br> </ul> <br> + Notes: <ul> <li>Use reset with care: the device forgets even the housecode. diff --git a/fhem/FHEM/10_ZWave.pm b/fhem/FHEM/10_ZWave.pm index 3d64e8092..bc05c687c 100755 --- a/fhem/FHEM/10_ZWave.pm +++ b/fhem/FHEM/10_ZWave.pm @@ -14,6 +14,7 @@ package main; use strict; use warnings; +use SetExtensions; sub ZWave_Parse($$@); sub ZWave_Set($@); @@ -236,6 +237,7 @@ ZWave_Cmd($$@) my $name = shift(@a); my $cmd = shift(@a); + # Collect the commands from the distinct classes my %cmdList; my $classes = AttrVal($name, "classes", ""); @@ -249,14 +251,23 @@ ZWave_Cmd($$@) } } } + if(!$cmdList{$cmd}) { my $list = join(" ",sort keys %cmdList); foreach my $cmd (keys %zwave_cmdArgs) { # add slider & co $list =~ s/\b$cmd\b/$cmd:$zwave_cmdArgs{$cmd}/; } - return "Unknown $type argument $cmd, choose one of $list"; + + if($type eq "set") { + unshift @a, $name, $cmd; + return SetExtensions($hash, $list, @a); + } else { + return "Unknown argument $cmd, choose one of $list"; + } + } + Log GetLogLevel($name,2), "ZWave $type $name $cmd"; ################################ # ZW_SEND_DATA,nodeId,CMD,ACK|AUTO_ROUTE @@ -525,8 +536,11 @@ ZWave_Undef($$) <a name="ZWaveset"></a> <b>Set</b> <ul> + <br> + <b>Note</b>: devices with on/off functionality support the <a + href="#setExtensions"> set extensions</a>. - <br><b>Class BASIC</b> + <br><br><b>Class BASIC</b> <li>basicValue value<br> Send value (0-255) to this device. The interpretation is device dependent, e.g. for a SWITCH_BINARY device 0 is off and anything else is on.</li> @@ -571,7 +585,6 @@ ZWave_Undef($$) <li>associationDel groupId nodeId ...<br> Remove the specified list of nodeIds from the assotion group groupId.</li> - </ul> <br> diff --git a/fhem/FHEM/SetExtensions.pm b/fhem/FHEM/SetExtensions.pm new file mode 100644 index 000000000..789139dfb --- /dev/null +++ b/fhem/FHEM/SetExtensions.pm @@ -0,0 +1,152 @@ +############################################## +# $Id: $ + +package main; +use strict; +use warnings; + +sub SetExtensions($$@); +sub SetExtensionsFn($); + +sub +SetExtensions($$@) +{ + my ($hash, $list, $name, $cmd, @a) = @_; + + my %se_list = ( + "on-for-timer" => 1, + "off-for-timer" => 1, + "on-till" => 1, + "off-till" => 1, + "blink" => 2, + "intervals" => 0, + ); + + my $hasOn = ($list =~ m/\bon\b/); + my $hasOff = ($list =~ m/\bon\b/); + if(!$hasOn || !$hasOff) { + my $em = AttrVal($name, "eventMap", undef); + if($em) { + $hasOn = ($em =~ m/:on\b/) if(!$hasOn); + $hasOff = ($em =~ m/:off\b/) if(!$hasOff); + } + $cmd = ReplaceEventMap($name, $cmd, 1) if($cmd ne "?"); # Fix B0-for-timer + } + if(!$hasOn || !$hasOff) { # No extension + return "Unknown argument $cmd, choose one of $list"; + } + + if(!defined($se_list{$cmd})) { + # Add only "new" commands + my @mylist = grep { $list !~ m/\b$_\b/ } keys %se_list; + return "Unknown argument $cmd, choose one of $list " . + join(" ", @mylist); + } + if($se_list{$cmd} && $se_list{$cmd} != int(@a)) { + return "$cmd requires $se_list{$cmd} parameter"; + } + + my $cmd1 = ($cmd =~ m/on.*/ ? "on" : "off"); + my $cmd2 = ($cmd =~ m/on.*/ ? "off" : "on"); + my $param = $a[0]; + + if($cmd eq "on-for-timer" || $cmd eq "off-for-timer") { + RemoveInternalTimer("SE $name $cmd"); + return "$cmd requires a number as argument" if($param !~ m/^\d*\.?\d*$/); + + if($param) { + DoSet($name, $cmd1); + InternalTimer(gettimeofday()+$param,"SetExtensionsFn","SE $name $cmd",0); + } + + } elsif($cmd eq "on-till" || $cmd eq "off-till") { + my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($param); + return "$cmd: $err" if($err); + + my $at = $name . "_till"; + CommandDelete(undef, $at) if($defs{$at}); + + my @lt = localtime; + my $hms_till = sprintf("%02d:%02d:%02d", $hr, $min, $sec); + my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]); + if($hms_now ge $hms_till) { + Log 4, "$cmd: won't switch as now ($hms_now) is later than $hms_till"; + return ""; + } + DoSet($name, $cmd1); + CommandDefine(undef, "$at at $hms_till set $name $cmd2"); + + } elsif($cmd eq "blink") { + my $p2 = $a[1]; + delete($hash->{SE_BLINKPARAM}); + return "$cmd requires 2 numbers as argument" + if($param !~ m/^\d+$/ || $p2 !~ m/^\d*\d?\d*$/); + + if($param) { + DoSet($name, "on-for-timer", $p2); + $param--; + if($param) { + $hash->{SE_BLINKPARAM} = "$param $p2"; + InternalTimer(gettimeofday()+2*$p2,"SetExtensionsFn","SE $name $cmd",0); + } + } + + } elsif($cmd eq "intervals") { + my $at0 = "${name}_till"; + my $at1 = "${name}_intervalFrom", + my $at2 = "${name}_intervalNext"; + CommandDelete(undef, $at0) if($defs{$at0}); + CommandDelete(undef, $at1) if($defs{$at1}); + CommandDelete(undef, $at2) if($defs{$at2}); + + my $intSpec = shift(@a); + if($intSpec) { + my ($from, $till) = split("-", $intSpec); + + my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($from); + return "$cmd: $err" if($err); + my @lt = localtime; + my $hms_from = sprintf("%02d:%02d:%02d", $hr, $min, $sec); + my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]); + + if($hms_from le $hms_now) { # By slight delays at will schedule tomorrow. + SetExtensions($hash, $list, $name, "on-till", $till); + + } else { + CommandDefine(undef, "$at1 at $from set $name on-till $till"); + + } + + if(@a) { + my $rest = join(" ", @a); + my ($from, $till) = split("-", shift @a); + CommandDefine(undef, "$at2 at $from set $name intervals $rest"); + } + } + + } + + return undef; +} + +sub +SetExtensionsFn($) +{ + my (undef, $name, $cmd) = split(" ", shift, 3); + return if(!defined($defs{$name})); + + + if($cmd eq "on-for-timer") { + DoSet($name, "off"); + + } elsif($cmd eq "off-for-timer") { + DoSet($name, "on"); + + } elsif($cmd eq "blink") { + DoSet($name, "blink", split(" ", $defs{$name}{SE_BLINKPARAM}, 2)); + + } + +} + +1; diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html index 81bac499a..47b91c5b0 100644 --- a/fhem/docs/commandref_frame.html +++ b/fhem/docs/commandref_frame.html @@ -782,7 +782,45 @@ A line ending with \ will be concatenated with the next one, so long lines Each device has different set parameters, see the corresponding device section for details.<br> <br> + <br> + <a name="setExtensions"></a> + Some modules support a common list of <b>set extensions</b>, and point in + their documentation to this section. If the module itself implements one of + the following commands, then the module-implementation takes precedence. + <ul> + <li>on-for-timer <seconds><br> + Issue the on command for the device, and after <seconds> the off + command. For issuing the off command an internal timer will be + scheduled, which is deleted upon a restart. To delete this internal + timer without restart specify 0 as argument.</li> + <li>off-for-timer <seconds><br> + see on-for-timer above.</li> + <li>on-till <timedet><br> + Issue the on command for the device, and create an at definition with + <timedet> (in the form HH:MM[:SS]) to set it off. This definition + is visible, and its name is deviceName+"_till". To cancel the scheduled + off, delete the at definition.</li> + <li>off-till <timedet><br> + see on-till above.</li> + <li>blink <number> <blink-period><br> + set the device on for <blink-period> then off for + <blink-period> and repeat this <number> times. + To stop blinking specify "0 0" as argument.</li> + <li>intervals <from1>-<till1> <from2>-<till2>... + </br> + set the device on for the specified intervals, which are all timespecs + in the form HH:MM[:SS]. The intervals are space separated.</li> + </ul> + Examples: + <ul> + <code> + set switch on-for-timer 12.5<br> + set switch on-till {sunset()}<br> + set switch blink 3 1<br> + set switch intervals 08:00-12:00 13:00-18:00<br> + </code> + </ul> </ul> diff --git a/fhem/docs/commandref_frame_DE.html b/fhem/docs/commandref_frame_DE.html index 3031e4f62..b5fc4d5ad 100644 --- a/fhem/docs/commandref_frame_DE.html +++ b/fhem/docs/commandref_frame_DE.html @@ -800,19 +800,66 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.</p> <ul> <code>set <devspec> <type-specific></code> <br><br> - Der Befehl setzt Geräteparameter/sendet Signale an ein Gerät. Sie erhalten - eine Liste verfügbarer Parameter wenn Sie folgendes eingeben: + Der Befehl setzt Geräteparameter/sendet Signale an ein Gerät. Sie + erhalten eine Liste verfügbarer Parameter wenn Sie folgendes eingeben: <ul> <code>set <name> ?</code> </ul> - Lesen Sie bitte den Abschnitt <a href="#devspec">Device specification</a> für - Details zu - <devspec>. Der "set"-Befehl gibt nur bei Fehler einen Wert zurück.<br> - <br> - Jedes Gerät hat verschiedene Parameter die mit "set" gesetzt werden können. - Lesen Sie bitte den entsprechenden Abschnitt für das Gerät für Details durch.<br> + Lesen Sie bitte den Abschnitt <a href="#devspec">Device specification</a> + für Details zu <devspec>. Der "set"-Befehl gibt nur bei + Fehler einen Wert zurück. + <br><br> + Jedes Gerät hat verschiedene Parameter die mit "set" gesetzt + werden können. Lesen Sie bitte den entsprechenden Abschnitt für + das Gerät für Details durch. <br> + <br> + <a name="setExtensions"></a> + Manche Module unterstützen die sog. <b>set extensions</b>, und in der + entsprechenden Dokumentation ist ein Link auf diesem Text zu finden. Falls im + Modul selber einer der unten aufgeführten Befehle implementiert ist, dann + wird die Modul-Implementation verwendet. + <ul> + <li>on-for-timer <sekunden><br> + Das Gerät wird per "on" eingeschaltet, und ein interner Zeitgeber + wird erstellt, um nach <sekunden> ein "off" Kommando + auszuführen. Um diesen Zeitgeber zu entfernen sollte man das + Kommando mit dem Argument 0 erneut aufrufen. Achtung: dieser Zeitgeber + wird bei einem restart nicht gespeichert.</li> + <li>off-for-timer <sekunden><br> + siehe on-for-timer.</li> + <li>on-till <timedet><br> + Das Gerät wird per "on" eingeschaltet, und ein at Instanz wird + definiert, um es um <timedet> (Format: HH:MM[:SS]) per off + auszuschalten. Diese at Instanz ist sichtbar unter dem Namen + geräteName+"_till". Um das Ausschalten zu deaktivieren + löscht man diese at Definition. </li> + <li>off-till <timedet><br> + siehe on-till.</li> + <li>blink <anzahl> <blink-periode><br> + Das Gerät wird mit "on" für die <blink-periode> + eingeschaltet, und das wird nach <blink-periode> wiederholt. Um + das Blinken vorzeitig zu stoppen spezifiziert man "0 0" als + Argument.</li> + <li>intervals <from1>-<till1> <from2>-<till2>... + </br> + Das Gerät wird für die spezifizierten Intervalle + eingeschaltet. Die einzelnen Intervalle sind Leerzeichen getrennt, und + ein Intervall besteht aus zwei Zeitspezifikationen, die mit einem "-" + getrennt sind. + </li> + </ul> + Beispiele: + <ul> + <code> + set switch on-for-timer 12.5<br> + set switch on-till {sunset()}<br> + set switch blink 3 1<br> + set switch intervals 08:00-12:00 13:00-18:00<br> + </code> + </ul> + </ul> </ul>