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($$$)
Set
+
- MD15 commands. Note: The command is not sent until the MD15
wakes up and sends a mesage, usually every 10 minutes.
@@ -705,6 +710,10 @@ EnOcean_A5Cmd($$$)
attr eventMap BI:on B0:off
set switch1 on
+ Note: set extensions are supported,
+ if the corresponding eventMap specifies
+ the on and off mappings.
+
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
+ The set extensions are also supported.
+
Examples:
set lamp on
@@ -546,6 +547,7 @@ four2hex($$)
set lamp on-for-timer 12
+
Notes:
- 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($$)
Set
+
+ Note: devices with on/off functionality support the set extensions.
-
Class BASIC
+
Class BASIC
- basicValue value
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.
@@ -571,7 +585,6 @@ ZWave_Undef($$)
- associationDel groupId nodeId ...
Remove the specified list of nodeIds from the assotion group groupId.
-
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.
+
+
+ Some modules support a common list of set extensions, and point in
+ their documentation to this section. If the module itself implements one of
+ the following commands, then the module-implementation takes precedence.
+
+ - on-for-timer <seconds>
+ 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.
+ - off-for-timer <seconds>
+ see on-for-timer above.
+ - on-till <timedet>
+ 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.
+ - off-till <timedet>
+ see on-till above.
+ - blink <number> <blink-period>
+ 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.
+ - intervals <from1>-<till1> <from2>-<till2>...
+
+ set the device on for the specified intervals, which are all timespecs
+ in the form HH:MM[:SS]. The intervals are space separated.
+
+ Examples:
+
+
+ set switch on-for-timer 12.5
+ set switch on-till {sunset()}
+ set switch blink 3 1
+ set switch intervals 08:00-12:00 13:00-18:00
+
+
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.
set <devspec> <type-specific>
- 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:
- Lesen Sie bitte den Abschnitt Device specification für
- Details zu
- <devspec>. Der "set"-Befehl gibt nur bei Fehler einen Wert zurück.
-
- 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.
+ Lesen Sie bitte den Abschnitt Device specification
+ für Details zu <devspec>. Der "set"-Befehl gibt nur bei
+ Fehler einen Wert zurück.
+
+ 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.
+
+
+ Manche Module unterstützen die sog. set extensions, 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.
+
+ - on-for-timer <sekunden>
+ 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.
+ - off-for-timer <sekunden>
+ siehe on-for-timer.
+ - on-till <timedet>
+ 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.
+ - off-till <timedet>
+ siehe on-till.
+ - blink <anzahl> <blink-periode>
+ 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.
+ - intervals <from1>-<till1> <from2>-<till2>...
+
+ 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.
+
+
+ Beispiele:
+
+
+ set switch on-for-timer 12.5
+ set switch on-till {sunset()}
+ set switch blink 3 1
+ set switch intervals 08:00-12:00 13:00-18:00
+
+
+