devspec added

delattr reenamed to deleteattr


git-svn-id: https://fhem.svn.sourceforge.net/svnroot/fhem/trunk/fhem@135 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig
2007-12-29 15:57:42 +00:00
parent 143604a287
commit 4849787b1b
6 changed files with 332 additions and 162 deletions

View File

@@ -369,6 +369,8 @@
- feature: Generate warning if too many commands were sent in the last hour - feature: Generate warning if too many commands were sent in the last hour
- doc: linux.html: Introduction (Peter S.) - doc: linux.html: Introduction (Peter S.)
- feature: contrib/82_M232Voltage.pm (by Boris, 24.12) - feature: contrib/82_M232Voltage.pm (by Boris, 24.12)
- feature: delattr renamed to deleteattr (Rudi, 29.12)
- feature: device spec (list/range/regexp) for most commands implemented
- TODO - TODO
emem -2.5kW / getDevData for emwz -1 emem -2.5kW / getDevData for emwz -1

View File

@@ -71,7 +71,7 @@ sr($$$$)
$sst += ($seconds/3600); $sst += ($seconds/3600);
my $diff = 0; my $diff = 0;
if($nh > $sst) { if($nh >= $sst) {
$nt += 86400; # Tommorow $nt += 86400; # Tommorow
$diff = 24; $diff = 24;
@lt = localtime($nt); @lt = localtime($nt);

22
HISTORY
View File

@@ -2,7 +2,7 @@
Created the file HISTORY and the file README.DEV Created the file HISTORY and the file README.DEV
- Pest, Thu Feb 1 20:45 MET 2007 - Pest, Thu Feb 1 20:45 MET 2007
Added description for attribute "model" in commandref.html Added description for attribute ,
- Rudi, Sun Feb 11 18:56:05 MET 2007 - Rudi, Sun Feb 11 18:56:05 MET 2007
- showtime added for pgm2 (useful for FS20 piri display) - showtime added for pgm2 (useful for FS20 piri display)
@@ -23,7 +23,7 @@
- Rudi, Sun Mar 4 11:18:10 MET 2007 - Rudi, Sun Mar 4 11:18:10 MET 2007
Reorganization. Goal: making attribute adding/deleting more uniform Reorganization. Goal: making attribute adding/deleting more uniform
("at/notify" and other device differences), and making web-configuration (,
possible (i.e. saving the configfile, list of possible devices etc). possible (i.e. saving the configfile, list of possible devices etc).
Internal changes: Internal changes:
@@ -34,24 +34,24 @@
-> User written scripts can more easily analyze device states -> User written scripts can more easily analyze device states
User visible changes: User visible changes:
- at/notify "renamed" to "define <name> at/notify", both moved to external - at/notify ,
modules. Now it is possible modules. Now it is possible
- to have a further "at" or "notify" modules - to have a further ,
(notify & filelog use the same interface) (notify & filelog use the same interface)
- to have more than one notify for the same event - to have more than one notify for the same event
- to delete at commands without strange escapes. - to delete at commands without strange escapes.
The delete syntax changed (no more def/at/ntfy needed) The delete syntax changed (no more def/at/ntfy needed)
- at/notify can have attributes - at/notify can have attributes
Drawback: each at and notify must have a name, which is strange first. Drawback: each at and notify must have a name, which is strange first.
- logfile/modpath/pidfile/port/verbose "renamed" to "attr global xxx" - logfile/modpath/pidfile/port/verbose ,
Dumping and extending these attributes is easier, no special handling Dumping and extending these attributes is easier, no special handling
required in the web-frontend. required in the web-frontend.
- savefile renamed to "attr global statefile" - savefile renamed to ,
- configfile global attribute added. - configfile global attribute added.
- save command added, it writes the statefile and then the configfile. - save command added, it writes the statefile and then the configfile.
- delattr added to delete single attributes - delattr added to delete single attributes
- list/xmllist format changed, they contain more information. - list/xmllist format changed, they contain more information.
- "define/set/get/attr name ?" returns a list of possible arguments - ,
in the same format. This data is contained in the xmllist. in the same format. This data is contained in the xmllist.
- disable attribute for at/notify/filelog - disable attribute for at/notify/filelog
- rename added - rename added
@@ -92,7 +92,7 @@
- feature: modify command added. It helps change e.g. only the time component - feature: modify command added. It helps change e.g. only the time component
for an at command, without deleting and creating it again and then for an at command, without deleting and creating it again and then
reapplying all the attributes. reapplying all the attributes.
- feature: the "-" character is disallowed in defined names. Use dot (.) or _ - feature: the ,
instead. The - is used to separate ranges in the set command. instead. The - is used to separate ranges in the set command.
- Rudi, Sun May 27 12:51:52 MEST 2007 - Rudi, Sun May 27 12:51:52 MEST 2007
@@ -164,3 +164,9 @@
- Peter Sun Dec 23 19:59:00 MEST 2007 - Peter Sun Dec 23 19:59:00 MEST 2007
- linux.html: Introduction refinement. - linux.html: Introduction refinement.
- Rudi Sat Dec 29 16:27:14 MET 2007
- delattr renamed to deleteattr
- devicespec introduced:
it may contain a list of devices, a range of devices, or multiple devices
identified by regexp. Following commands take a devicespec as argument:
attr, deleteattr, delete, get, list, set, setstate, trigger

View File

@@ -15,7 +15,7 @@
<a href="#attr">attr</a><br> <a href="#attr">attr</a><br>
<a href="#defattr">defattr</a><br> <a href="#defattr">defattr</a><br>
<a href="#define">define</a><br> <a href="#define">define</a><br>
<a href="#delattr">delattr</a><br> <a href="#deleteattr">deleteattr</a><br>
<a href="#delete">delete</a><br> <a href="#delete">delete</a><br>
<a href="#get">get</a><br> <a href="#get">get</a><br>
<a href="#include">include</a><br> <a href="#include">include</a><br>
@@ -32,6 +32,7 @@
<a href="#trigger">trigger</a><br> <a href="#trigger">trigger</a><br>
<a href="#sleep">sleep</a><br> <a href="#sleep">sleep</a><br>
<a href="#xmllist">xmllist</a><br> <a href="#xmllist">xmllist</a><br>
<a href="#devspec">Device specification</a><br>
<a href="#perl">Perl specials</a><br> <a href="#perl">Perl specials</a><br>
<a name="intro"></a> <a name="intro"></a>
@@ -115,7 +116,7 @@ split in multiple lines<br><br>
<a name="attr"></a> <a name="attr"></a>
<h3>attr</h3> <h3>attr</h3>
<ul> <ul>
<code>attr &lt;name&gt; &lt;attrname&gt; [&lt;value&gt;] </code><br> <code>attr &lt;devspec&gt; &lt;attrname&gt; [&lt;value&gt;] </code><br>
or <br> or <br>
<code>attr at &lt;at-spec-regexp&gt; &lt;attribute&gt; </code><br> <code>attr at &lt;at-spec-regexp&gt; &lt;attribute&gt; </code><br>
@@ -126,6 +127,8 @@ split in multiple lines<br><br>
below.<br> below.<br>
Use "attr &lt;name&gt; ?" to get a list of possible attributes. Use "attr &lt;name&gt; ?" to get a list of possible attributes.
See the <a href="#devspec">Device specification</a> section for details on
&lt;devspec&gt;.
<br><br> <br><br>
Following are attributes of the global device:<br> Following are attributes of the global device:<br>
@@ -470,7 +473,7 @@ split in multiple lines<br><br>
Notes:<br> Notes:<br>
<ul> <ul>
<li>See <a href="#delattr">delattr</a> to delete attributes.</li> <li>See <a href="#deleteattr">deleteattr</a> to delete attributes.</li>
</ul> </ul>
</ul> </ul>
@@ -1093,18 +1096,20 @@ split in multiple lines<br><br>
</ul> </ul>
<a name="delattr"></a> <a name="deleteattr"></a>
<h3>delattr</h3> <h3>deleteattr</h3>
<ul> <ul>
<code>delattr &lt;name&gt; [&lt;attrname&gt;]</code> <br> <code>deleteattr &lt;devspec&gt; [&lt;attrname&gt;]</code> <br>
<br> <br>
Delete either a single attribute (see the <a href="#attr">attr</a> command) Delete either a single attribute (see the <a href="#attr">attr</a> command)
or all attributes for a device (if no &lt;attrname&gt; is defined).<br> or all attributes for a device (if no &lt;attrname&gt; is defined).
See the <a href="#devspec">Device specification</a> section for details on
&lt;devspec&gt;.<br>
Examples: Examples:
<ul> <ul>
<code>delattr lamp follow-on-for-timer</code><br> <code>deleteattr lamp follow-on-for-timer</code><br>
<code>delattr lamp</code><br> <code>deleteattr lamp</code><br>
</ul> </ul>
<br> <br>
</ul> </ul>
@@ -1112,10 +1117,11 @@ split in multiple lines<br><br>
<a name="delete"></a> <a name="delete"></a>
<h3>delete</h3> <h3>delete</h3>
<ul> <ul>
<code>delete &lt;name&gt;</code> <br> <code>delete &lt;devspec&gt;</code> <br>
<br> <br>
Delete something created with the <a href="#define">define</a> command. Delete something created with the <a href="#define">define</a> command.
<br> See the <a href="#devspec">Device specification</a> section for details on
&lt;devspec&gt;.<br>
Examples: Examples:
<ul> <ul>
<code>delete lamp</code><br> <code>delete lamp</code><br>
@@ -1126,12 +1132,13 @@ split in multiple lines<br><br>
<a name="get"></a> <a name="get"></a>
<h3>get</h3> <h3>get</h3>
<ul> <ul>
<code>get &lt;name&gt; &lt;type-specific&gt;</code> <code>get &lt;devspec&gt; &lt;type-specific&gt;</code>
<br><br> <br><br>
Ask a value directly from the device, and wait for an answer. In general, you Ask a value directly from the device, and wait for an answer. In general, you
can get a list of possible commands by<br><code>get &lt;device&gt; ?</code> can get a list of possible commands by<br><code>get &lt;device&gt; ?</code>
<br> <br>
Right now only the FHZ module supports this function. See the <a href="#devspec">Device specification</a> section for details on
&lt;devspec&gt;.<br>
<h4>Type FHZ:</h4> <h4>Type FHZ:</h4>
<ul> <ul>
@@ -1231,11 +1238,13 @@ split in multiple lines<br><br>
<a name="list"></a> <a name="list"></a>
<h3>list</h3> <h3>list</h3>
<ul> <ul>
<code>list [name]</code> <code>list [devspec]</code>
<br><br> <br><br>
Output a list of all definitions, all notify settings and all at Output a list of all definitions, all notify settings and all at
entries. This is one of the few commands which return a string in a entries. This is one of the few commands which return a string in a
normal case. normal case.
See the <a href="#devspec">Device specification</a> section for details on
&lt;devspec&gt;.
<br><br> <br><br>
Example: Example:
<pre><code> FHZ> list <pre><code> FHZ> list
@@ -1404,13 +1413,13 @@ Send buffer:<br /> 2007-10-19 00:31:24 desired-temp 22.5
<a name="set"></a> <a name="set"></a>
<h3>set</h3> <h3>set</h3>
<ul> <ul>
<code>set &lt;name&gt; &lt;type-specific&gt;</code> <code>set &lt;devspec&gt; &lt;type-specific&gt;</code>
<br><br> <br><br>
Set parameters of a device / send signals to a device. You can Set parameters of a device / send signals to a device. You can
get a list of possible commands by<br><code>set &lt;name&gt; ?</code> get a list of possible commands by<br><code>set &lt;name&gt; ?</code>
<br> <br>
Instead of &lt;name&gt; you can also use an enumeration (separated by comma) See the <a href="#devspec">Device specification</a> section for details on
or ranges (separated by -), see the FS20 examples. &lt;devspec&gt;.<br>
<a name="FHZset"></a> <a name="FHZset"></a>
<h4>Type FHZ:</h4> <h4>Type FHZ:</h4>
@@ -1687,12 +1696,14 @@ must between 5.5 and 30.5 Celsius. Value 5.5 set the actuator to OFF, value 30.
<a name="setstate"></a> <a name="setstate"></a>
<h3>setstate</h3> <h3>setstate</h3>
<ul> <ul>
<code>setstate &lt;name&gt; &lt;value&gt;</code> <code>setstate &lt;devspec&gt; &lt;value&gt;</code>
<br><br> <br><br>
Set the "STATE" for <code>&lt;name&gt;</code> as shown in paranthesis in the Set the "STATE" for <code>&lt;name&gt;</code> as shown in paranthesis in the
<a href="#list">list</a> command <a href="#list">list</a> command
to <code>&lt;value&gt;</code> without sending any signals to the device to <code>&lt;value&gt;</code> without sending any signals to the device
itself. This command is also used in the <a href="#statefile">statefile</a>. itself. This command is also used in the <a href="#statefile">statefile</a>.
See the <a href="#devspec">Device specification</a> section for details on
&lt;devspec&gt;.
<br><br> <br><br>
Examples: Examples:
<ul> <ul>
@@ -1726,9 +1737,12 @@ must between 5.5 and 30.5 Celsius. Value 5.5 set the actuator to OFF, value 30.
<a name="trigger"></a> <a name="trigger"></a>
<h3>trigger</h3> <h3>trigger</h3>
<ul> <ul>
<code>trigger &lt;dev&gt; &lt;state&gt;</code> <code>trigger &lt;devspec&gt; &lt;state&gt;</code>
<br><br> <br><br>
Trigger a <a href="#notify">notify</a> definition. Trigger a <a href="#notify">notify</a> definition.
See the <a href="#devspec">Device specification</a> section for details on
&lt;devspec&gt;.
<br><br> <br><br>
Example: Example:
<ul> <ul>
@@ -1777,6 +1791,45 @@ must between 5.5 and 30.5 Celsius. Value 5.5 set the actuator to OFF, value 30.
</ul> </ul>
<a name="devspec"></a>
<h3>Device specification</h3>
<ul>
The commands
<a href="#attr">attr</a>,
<a href="#deleteattr">deleteattr</a>,
<a href="#delete">delete</a>,
<a href="#get">get</a>,
<a href="#list">list</a>,
<a href="#set">set</a>,
<a href="#setstate">setstate</a>,
<a href="#trigger">trigger</a>
can take a more complex device specification as argument,
which will be expanded to a list of devices. A devspec can be:
<ul>
<li>a list of devices, separated by comma (,)</li>
<li>a range of devices, separated by dash (-)</li>
<li>a regular expression, if the the spec contains on e of the following
characters: ^*[]$</li>
</ul>
Example:
<ul>
<code>set lamp1,lamp2,lamp3 on</code><br>
<code>set lamp[1-3] on</code><br>
<code>set lamp.* on</code><br>
<code>set lamp1-lamp3 on</code><br>
<code>set lamp1-lamp3,lamp3 on</code><br>
</ul>
Notes:
<ul>
<li>first the spec is separated by komma, then the range or the regular
expression operations are executed.</li>
<li>if there is a device which xactly corresponds to the spec, then
no special processing is done.</li>
<li>the returned list can contain the same device more than once, so
int tha last example the list will contain lamp3 twice.</li>
</ul>
</ul>
<a name="perl"></a> <a name="perl"></a>
<h3>Perl specials</h3> <h3>Perl specials</h3>
<ul> <ul>

View File

@@ -93,7 +93,7 @@ define roll_eg_wz1 FS20 fb02 0c fg f2 lm 8f
define roll_wz1_off1 at *20:00:00 { if( $value{roll_eg_wz1} ne "off" ) { \ define roll_wz1_off1 at *20:00:00 { if( $value{roll_eg_wz1} ne "off" ) { \
if( $attr{roll_eg_wz1}{freigabe} ) { \ if( $attr{roll_eg_wz1}{freigabe} ) { \
fhem("set roll_eg_wz1 off");; \ fhem("set roll_eg_wz1 off");; \
fhem("delattr roll_eg_wz1 freigabe") \ fhem("deleteattr roll_eg_wz1 freigabe") \
} else { \ } else { \
fhem("attr roll_eg_wz1 freigabe") \ fhem("attr roll_eg_wz1 freigabe") \
} \ } \
@@ -102,11 +102,11 @@ define roll_wz1_off1 at *20:00:00 { if( $value{roll_eg_wz1} ne "of
define roll_wz1_off2 at +*{sunset_rel(+3600)} { if( $value{roll_eg_wz1} ne "off" ) { \ define roll_wz1_off2 at +*{sunset_rel(+3600)} { if( $value{roll_eg_wz1} ne "off" ) { \
if( $attr{roll_eg_wz1}{freigabe} ) { \ if( $attr{roll_eg_wz1}{freigabe} ) { \
fhem("set roll_eg_wz1 off");; \ fhem("set roll_eg_wz1 off");; \
fhem("delattr roll_eg_wz1 freigabe") \ fhem("deleteattr roll_eg_wz1 freigabe") \
} else { \ } else { \
fhem("attr roll_eg_wz1 freigabe") \ fhem("attr roll_eg_wz1 freigabe") \
} \ } \
} } } }
define roll_wz1_off3 at *22:00:00 { fhem("set roll_eg_wz1 off") if($value{roll_eg_wz1} ne "off");; \ define roll_wz1_off3 at *22:00:00 { fhem("set roll_eg_wz1 off") if($value{roll_eg_wz1} ne "off");; \
fhem("delattr roll_eg_wz1 freigabe") } fhem("deleteattr roll_eg_wz1 freigabe") }

371
fhem.pl
View File

@@ -64,11 +64,12 @@ sub fhem($);
sub fhz($); sub fhz($);
sub doGlobalDef($); sub doGlobalDef($);
sub PrintHash($$); sub PrintHash($$);
sub devspec2array($);
sub CommandAttr($$); sub CommandAttr($$);
sub CommandDefAttr($$); sub CommandDefAttr($$);
sub CommandDefine($$); sub CommandDefine($$);
sub CommandDelAttr($$); sub CommandDeleteAttr($$);
sub CommandDelete($$); sub CommandDelete($$);
sub CommandGet($$); sub CommandGet($$);
sub CommandHelp($$); sub CommandHelp($$);
@@ -137,7 +138,7 @@ my %intAt; # Internal at timer hash.
my $intAtCnt=0; my $intAtCnt=0;
my $reread_active = 0; my $reread_active = 0;
my $AttrList = "room comment"; my $AttrList = "room comment";
my $cvsid = '$Id: fhem.pl,v 1.32 2007-12-13 15:26:27 rudolfkoenig Exp $'; my $cvsid = '$Id: fhem.pl,v 1.33 2007-12-29 15:57:42 rudolfkoenig Exp $';
$init_done = 0; $init_done = 0;
@@ -152,17 +153,17 @@ my %cmds = (
"?" => { Fn=>"CommandHelp", "?" => { Fn=>"CommandHelp",
Hlp=>",get this help" }, Hlp=>",get this help" },
"attr" => { Fn=>"CommandAttr", "attr" => { Fn=>"CommandAttr",
Hlp=>"<name> <attrname> [<attrvalue>],set attributes for <name>" }, Hlp=>"<devspec> <attrname> [<attrval>],set attribute for <devspec>" },
"defattr" => { Fn=>"CommandDefAttr", "defattr" => { Fn=>"CommandDefAttr",
Hlp=>"<attrname> <attrvalue>,set attr for following definitions" }, Hlp=>"<attrname> <attrvalue>,set attr for following definitions" },
"define" => { Fn=>"CommandDefine", "define" => { Fn=>"CommandDefine",
Hlp=>"<name> <type> <options>,define a device/at/notify entity" }, Hlp=>"<name> <type> <options>,define a device/at/notify entity" },
"delattr" => { Fn=>"CommandDelAttr", "deleteattr" => { Fn=>"CommandDeleteAttr",
Hlp=>"<name> [<attrname>],delete attribute <attrname> for <name>" }, Hlp=>"<devspec> [<attrname>],delete attribute for <devspec>" },
"delete" => { Fn=>"CommandDelete", "delete" => { Fn=>"CommandDelete",
Hlp=>"name,delete the corresponding definition"}, Hlp=>"<devspec>,delete the corresponding definition(s)"},
"get" => { Fn=>"CommandGet", "get" => { Fn=>"CommandGet",
Hlp=>"<name> <type dependent>,request data from <name>" }, Hlp=>"<devspec> <type dependent>,request data from <devspec>" },
"help" => { Fn=>"CommandHelp", "help" => { Fn=>"CommandHelp",
Hlp=>",get this help" }, Hlp=>",get this help" },
"include" => { Fn=>"CommandInclude", "include" => { Fn=>"CommandInclude",
@@ -170,7 +171,7 @@ my %cmds = (
"inform" => { Fn=>"CommandInform", "inform" => { Fn=>"CommandInform",
Hlp=>"{on|off},echo all commands and events to this client" }, Hlp=>"{on|off},echo all commands and events to this client" },
"list" => { Fn=>"CommandList", "list" => { Fn=>"CommandList",
Hlp=>"[device],list definitions and status info" }, Hlp=>"[devspec],list definitions and status info" },
"modify" => { Fn=>"CommandModify", "modify" => { Fn=>"CommandModify",
Hlp=>"device <options>,modify the definition (e.g. at, notify)" }, Hlp=>"device <options>,modify the definition (e.g. at, notify)" },
"quit" => { Fn=>"CommandQuit", "quit" => { Fn=>"CommandQuit",
@@ -184,15 +185,15 @@ my %cmds = (
"save" => { Fn=>"CommandSave", "save" => { Fn=>"CommandSave",
Hlp=>"[configfile],write the configfile and the statefile" }, Hlp=>"[configfile],write the configfile and the statefile" },
"set" => { Fn=>"CommandSet", "set" => { Fn=>"CommandSet",
Hlp=>"<name> <type dependent>,transmit code for <name>" }, Hlp=>"<devspec> <type dependent>,transmit code for <devspec>" },
"setstate"=> { Fn=>"CommandSetstate", "setstate"=> { Fn=>"CommandSetstate",
Hlp=>"<name> <state>,set the state shown in the command list" }, Hlp=>"<devspec> <state>,set the state shown in the command list" },
"shutdown"=> { Fn=>"CommandShutdown", "shutdown"=> { Fn=>"CommandShutdown",
Hlp=>",terminate the server" }, Hlp=>",terminate the server" },
"sleep" => { Fn=>"CommandSleep", "sleep" => { Fn=>"CommandSleep",
Hlp=>"<sec>,sleep for sec, 3 decimal places are interpreted" }, Hlp=>"<sec>,sleep for sec, 3 decimal places are interpreted" },
"trigger" => { Fn=>"CommandTrigger", "trigger" => { Fn=>"CommandTrigger",
Hlp=>"<dev> <state>,trigger notify command" }, Hlp=>"<devspec> <state>,trigger notify command" },
"xmllist" => { Fn=>"CommandXmlList", "xmllist" => { Fn=>"CommandXmlList",
Hlp=>",list definitions and status info as xml" }, Hlp=>",list definitions and status info as xml" },
); );
@@ -533,6 +534,38 @@ AnalyzeCommand($$)
} }
} }
#####################################
my $namedef =
"where <name> is either:\n" .
"- a single device name\n" .
"- a list seperated by komma (,)\n" .
"- a regexp, if contains one of the following characters: *[]^\$\n" .
"- a range seperated by dash (-)\n";
sub
devspec2array($)
{
my ($name) = @_;
return $name if(defined($defs{$name}));
my @ret;
foreach my $l (split(",", $name)) { # List
if($l =~ m/[*\[\]^\$]/) { # Regexp
push @ret, grep($_ =~ m/$l/, sort keys %defs);
next;
}
if($l =~ m/-/) { # Range
my ($lower, $upper) = split("-", $l, 2);
push @ret, grep($_ ge $lower && $_ le $upper, sort keys %defs);
next;
}
push @ret, $l;
}
return $name if(!@ret); # No match, return the input
return @ret;
}
##################################### #####################################
sub sub
CommandHelp($$) CommandHelp($$)
@@ -782,7 +815,6 @@ CommandShutdown($$)
exit(0); exit(0);
} }
##################################### #####################################
sub sub
DoSet(@) DoSet(@)
@@ -798,6 +830,7 @@ DoSet(@)
return DoTrigger($dev, join(" ", @a)); return DoTrigger($dev, join(" ", @a));
} }
##################################### #####################################
sub sub
CommandSet($$) CommandSet($$)
@@ -805,32 +838,10 @@ CommandSet($$)
my ($cl, $param) = @_; my ($cl, $param) = @_;
my @a = split("[ \t][ \t]*", $param); my @a = split("[ \t][ \t]*", $param);
return "Usage: set <name> <type-dependent-options>\n" . return "Usage: set <name> <type-dependent-options>\n" .
" <name> can be an enumeration (separated by comma)\n" . "$namedef" if(int(@a)<1);
" or a range (separated by -)" if(int(@a)<1);
my $dev = $a[0];
my @rets; my @rets;
foreach my $sdev (devspec2array($a[0])) {
foreach my $sdev (split(",", $dev)) {
if($sdev =~ m/-/) { # Range (separated by -)
if(defined($defs{$sdev})) {
$a[0] = $sdev;
my $ret = DoSet(@a);
push @rets, $ret if($ret);
next;
}
my @lim = split("-", $sdev);
foreach my $sd (sort keys %defs) {
next if($sd lt $lim[0] || $sd gt $lim[1]);
$a[0] = $sd;
my $ret = DoSet(@a);
push @rets, $ret if($ret);
}
next;
}
if(!defined($defs{$sdev})) { if(!defined($defs{$sdev})) {
push @rets, "Please define $sdev first"; push @rets, "Please define $sdev first";
@@ -853,12 +864,26 @@ CommandGet($$)
my ($cl, $param) = @_; my ($cl, $param) = @_;
my @a = split("[ \t][ \t]*", $param); my @a = split("[ \t][ \t]*", $param);
return "Usage: get <name> <type-dependent-options>" if(int(@a) < 1); return "Usage: get <name> <type-dependent-options>\n" .
my $dev = $a[0]; "$namedef" if(int(@a) < 1);
return "Please define $dev first ($param)" if(!defined($defs{$dev}));
return "No get implemented for $dev" if(!$modules{$defs{$dev}{TYPE}}{GetFn});
return CallFn($a[0], "GetFn", $defs{$dev}, @a);
my @rets;
foreach my $sdev (devspec2array($a[0])) {
if(!defined($defs{$sdev})) {
push @rets, "Please define $sdev first";
next;
}
if(!$modules{$defs{$sdev}{TYPE}}{GetFn}) {
push @rets, "No get implemented for $sdev";
next;
}
$a[0] = $sdev;
my $ret = CallFn($sdev, "GetFn", $defs{$sdev}, @a);
push @rets, $ret if($ret);
}
return join("\n", @rets);
} }
##################################### #####################################
@@ -985,38 +1010,65 @@ CommandDelete($$)
{ {
my ($cl, $def) = @_; my ($cl, $def) = @_;
return "Please define $def first" if(!defined($defs{$def})); return "Usage: delete <name>\n" .
my $ret = CallFn($def, "UndefFn", $defs{$def}, $def); "$namedef" if(!$def);
return $ret if($ret);
delete($attr{$def}); my @rets;
delete($defs{$def}); foreach my $sdev (devspec2array($def)) {
if(!defined($defs{$sdev})) {
push @rets, "Please define $sdev first";
next;
}
return undef; my $ret = CallFn($sdev, "UndefFn", $defs{$sdev}, $sdev);
if($ret) {
push @rets, $ret;
next;
}
delete($attr{$sdev});
delete($defs{$sdev});
}
return join("\n", @rets);
} }
############# #############
sub sub
CommandDelAttr($$) CommandDeleteAttr($$)
{ {
my ($cl, $def) = @_; my ($cl, $def) = @_;
my @a = split(" ", $def, 2); my @a = split(" ", $def, 2);
return "Usage: delattr <name> [<attrname>]" if(@a < 1); return "Usage: deleteattr <name> [<attrname>]\n" .
return "Cannot delete global parameters" if($a[0] eq "global"); "$namedef" if(@a < 1);
return "No definition found for $a[0]\n" if(!$defs{$a[0]});
$ret = CallFn($a[0], "AttrFn", "del", @a); my @rets;
return $ret if($ret); foreach my $sdev (devspec2array($a[0])) {
if($sdev eq "global") {
push @rets, "Cannot delete global parameters";
next;
}
if(!defined($defs{$sdev})) {
push @rets, "Please define $sdev first";
next;
}
$a[0] = $sdev;
$ret = CallFn($sdev, "AttrFn", "del", @a);
if($ret) {
push @rets, $ret;
next;
}
if(@a == 1) {
delete($attr{$sdev});
} else {
delete($attr{$sdev}{$a[1]}) if(defined($attr{$sdev}));
}
if(@a == 1) {
delete($attr{$a[0]});
return undef;
} }
return "Attribute not defined"
if(!defined($attr{$a[0]}) || !defined($attr{$a[0]}{$a[1]})); return join("\n", @rets);
delete($attr{$a[0]}{$a[1]});
return undef;
} }
sub sub
@@ -1071,11 +1123,15 @@ CommandList($$)
} else { } else {
return "No device named $param found" if(!defined($defs{$param})); foreach my $sdev (devspec2array($param)) {
my $d = $defs{$param}; if(!defined($defs{$sdev})) {
$str .= "No device named $param found";
next;
}
$str .= "Internals:\n";
$str .= PrintHash($defs{$sdev}, 2);
}
$str .= "Internals:\n";
$str .= PrintHash($d, 2);
} }
return $str; return $str;
@@ -1224,40 +1280,15 @@ getAllAttr($)
return $list; return $list;
} }
#####################################
sub sub
CommandAttr($$) GlobalAttr($$)
{ {
my ($cl, $param) = @_; my ($name, $val) = @_;
my $ret = undef;
my @a = split(" ", $param, 3);
return "Usage: attr <name> <attrname> [<attrvalue>]" if(@a < 2);
return "Please define $a[0] first: no definition found"
if(!defined($defs{$a[0]}));
my $list = getAllAttr($a[0]);
return "Unknown argument $a[1], choose one of $list" if($a[1] eq "?");
return "Unknown attribute $a[1], use attr global userattr ($list)"
if(" $list " !~ m/ ${a[1]}[ :;]/);
$ret = CallFn($a[0], "AttrFn", "set", @a);
return $ret if($ret);
if(defined($a[2])) {
$attr{$a[0]}{$a[1]} = $a[2];
} else {
$attr{$a[0]}{$a[1]} = "1";
}
return if($a[0] ne "global"); # Global specials ahead
################ ################
if($a[1] eq "logfile") { if($name eq "logfile") {
my @t = localtime; my @t = localtime;
my $ret = OpenLogfile(ResolveDateWildcards($a[2], @t)); my $ret = OpenLogfile(ResolveDateWildcards($val, @t));
if($ret) { if($ret) {
return $ret if($init_done); return $ret if($init_done);
die($ret); die($ret);
@@ -1265,10 +1296,10 @@ CommandAttr($$)
} }
################ ################
elsif($a[1] eq "port") { elsif($name eq "port") {
return undef if($reread_active); return undef if($reread_active);
my ($port, $global) = split(" ", $a[2]); my ($port, $global) = split(" ", $val);
if($global && $global ne "global") { if($global && $global ne "global") {
return "Bad syntax, usage: attr global port <portnumber> [global]"; return "Bad syntax, usage: attr global port <portnumber> [global]";
} }
@@ -1289,8 +1320,8 @@ CommandAttr($$)
} }
################ ################
elsif($a[1] eq "verbose") { elsif($name eq "verbose") {
if($a[2] =~ m/^[0-5]$/) { if($val =~ m/^[0-5]$/) {
return undef; return undef;
} else { } else {
$attr{global}{verbose} = 3; $attr{global}{verbose} = 3;
@@ -1298,10 +1329,10 @@ CommandAttr($$)
} }
} }
elsif($a[1] eq "modpath") { elsif($name eq "modpath") {
return "modpath must point to a directory where the FHEM subdir is" return "modpath must point to a directory where the FHEM subdir is"
if(! -d "$a[2]/FHEM"); if(! -d "$val/FHEM");
my $modpath = "$a[2]/FHEM"; my $modpath = "$val/FHEM";
opendir(DH, $modpath) || return "Can't read $modpath: $!"; opendir(DH, $modpath) || return "Can't read $modpath: $!";
my $counter = 0; my $counter = 0;
@@ -1327,12 +1358,67 @@ CommandAttr($$)
"point modpath to a directory where the FHEM subdir is"; "point modpath to a directory where the FHEM subdir is";
} }
$modpath_set = $a[2]; $modpath_set = $val;
} }
return undef; return undef;
} }
#####################################
sub
CommandAttr($$)
{
my ($cl, $param) = @_;
my $ret = undef;
my @a = split(" ", $param, 3);
return "Usage: attr <name> <attrname> [<attrvalue>]\n" .
"$namedef" if(@a < 2);
my @rets;
foreach my $sdev (devspec2array($a[0])) {
if(!defined($defs{$sdev})) {
push @rets, "Please define $sdev first";
next;
}
my $list = getAllAttr($sdev);
if($a[1] eq "?") {
push @rets, "Unknown argument $a[1], choose one of $list";
next;
}
if(" $list " !~ m/ ${a[1]}[ :;]/) {
push @rets, "Unknown attribute $a[1], use attr global userattr ($list)";
next;
}
$a[0] = $sdev;
$ret = CallFn($sdev, "AttrFn", "set", @a);
if($ret) {
push @rets, $ret;
next;
}
if(defined($a[2])) {
$attr{$sdev}{$a[1]} = $a[2];
} else {
$attr{$sdev}{$a[1]} = "1";
}
if($sdev eq "global") {
$ret = GlobalAttr($a[1], $a[2]);
if($ret) {
push @rets, $ret;
next;
}
}
}
return join("\n", @rets);
}
##################################### #####################################
# Default Attr # Default Attr
@@ -1357,42 +1443,52 @@ sub
CommandSetstate($$) CommandSetstate($$)
{ {
my ($cl, $param) = @_; my ($cl, $param) = @_;
my $ret = undef;
my @a = split(" ", $param, 2); my @a = split(" ", $param, 2);
return "Usage: setstate <name> <state>" if(@a != 2); return "Usage: setstate <name> <state>\n" .
return "Please define $a[0] first" if(!defined($defs{$a[0]})); "$namedef" if(@a != 2);
my $d = $defs{$a[0]};
# Detailed state with timestamp my @rets;
if($a[1] =~ m/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} /) { foreach my $sdev (devspec2array($a[0])) {
my @b = split(" ", $a[1], 4); if(!defined($defs{$sdev})) {
push @rets, "Please define $sdev first";
if($defs{$a[0]}{TYPE} eq "FS20" && $b[2] ne "state") { # Compatibility mode next;
$b[3] = $b[2] . ($b[3] ? " $b[3]" : "");
$b[2] = "state";
} }
my $tim = "$b[0] $b[1]"; my $d = $defs{$sdev};
$ret = CallFn($a[0], "StateFn", $d, $tim, $b[2], $b[3]);
return $ret if($ret);
if(!$d->{READINGS}{$b[2]} || $d->{READINGS}{$b[2]}{TIME} lt $tim) { # Detailed state with timestamp
$d->{READINGS}{$b[2]}{VAL} = $b[3]; if($a[1] =~ m/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} /) {
$d->{READINGS}{$b[2]}{TIME} = $tim; my @b = split(" ", $a[1], 4);
if($defs{$sdev}{TYPE} eq "FS20" && $b[2] ne "state") { # Compatibility
$b[3] = $b[2] . ($b[3] ? " $b[3]" : "");
$b[2] = "state";
}
my $tim = "$b[0] $b[1]";
my $ret = CallFn($sdev, "StateFn", $d, $tim, $b[2], $b[3]);
if($ret) {
push @rets, $ret;
next;
}
if(!$d->{READINGS}{$b[2]} || $d->{READINGS}{$b[2]}{TIME} lt $tim) {
$d->{READINGS}{$b[2]}{VAL} = $b[3];
$d->{READINGS}{$b[2]}{TIME} = $tim;
}
} else {
$d->{STATE} = $a[1];
$oldvalue{$sdev}{VAL} = $a[1];
# This time is not the correct one, but we do not store a timestamp for
# this reading.
$oldvalue{$sdev}{TIME} = TimeNow();
} }
} else {
$d->{STATE} = $a[1];
$oldvalue{$a[0]}{VAL} = $a[1];
# This time is not the correct one, but we do not store a timestamp for
# this reading.
$oldvalue{$a[0]}{TIME} = TimeNow();
} }
return join("\n", @rets);
return $ret;
} }
##################################### #####################################
@@ -1402,9 +1498,22 @@ CommandTrigger($$)
my ($cl, $param) = @_; my ($cl, $param) = @_;
my ($dev, $state) = split(" ", $param, 2); my ($dev, $state) = split(" ", $param, 2);
return "Usage: trigger <device> <state>" if(!$state); return "Usage: trigger <name> <state>\n" .
return "Please define $dev first" if(!defined($defs{$dev})); "$namedef" if(!$state);
return DoTrigger($dev, $state);
my @rets;
foreach my $sdev (devspec2array($dev)) {
if(!defined($defs{$sdev})) {
push @rets, "Please define $sdev first";
next;
}
my $ret = DoTrigger($sdev, $state);
if($ret) {
push @rets, $ret;
next;
}
}
return join("\n", @rets);
} }
##################################### #####################################