mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-13 05:06:35 +00:00
AttrTemplate.pm: first version
git-svn-id: https://svn.fhem.de/fhem/trunk@17769 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
e9c7b8fd08
commit
183c62c302
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- feature: attrTemplate set command added
|
||||||
- bugfix: 73_AutoShuttersControl: fix logical bugs,
|
- bugfix: 73_AutoShuttersControl: fix logical bugs,
|
||||||
change Antifreeze values
|
change Antifreeze values
|
||||||
- change: DOIFtools: forced change to li-tags in direct help (Forum #93243)
|
- change: DOIFtools: forced change to li-tags in direct help (Forum #93243)
|
||||||
|
158
fhem/FHEM/AttrTemplate.pm
Normal file
158
fhem/FHEM/AttrTemplate.pm
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
##############################################
|
||||||
|
# $Id$
|
||||||
|
package main;
|
||||||
|
|
||||||
|
my %templates;
|
||||||
|
my $initialized;
|
||||||
|
my %cachedUsage;
|
||||||
|
|
||||||
|
sub
|
||||||
|
AttrTemplate_Initialize()
|
||||||
|
{
|
||||||
|
my $me = "AttrTemplate_Initialize";
|
||||||
|
my $dir = $attr{global}{modpath}."/FHEM/lib/AttrTemplate";
|
||||||
|
if(!opendir(dh, $dir)) {
|
||||||
|
Log 1, "$me: cant open $dir: $!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @files = grep /\.template$/, sort readdir dh;
|
||||||
|
closedir(dh);
|
||||||
|
|
||||||
|
%templates = ();
|
||||||
|
%cachedUsage = ();
|
||||||
|
for my $file (@files) {
|
||||||
|
if(!open(fh,"$dir/$file")) {
|
||||||
|
Log 1, "$me: cant open $dir/$file: $!";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
my ($name, %h);
|
||||||
|
while(my $line = <fh>) {
|
||||||
|
chomp($line);
|
||||||
|
next if($line =~ m/^$/ || $line =~ m/^#/);
|
||||||
|
|
||||||
|
if($line =~ m/^name:(.*)/) {
|
||||||
|
$name = $1;
|
||||||
|
my (@p,@c);
|
||||||
|
$templates{$name}{pars} = \@p;
|
||||||
|
$templates{$name}{cmds} = \@c;
|
||||||
|
|
||||||
|
} elsif($line =~ m/^filter:(.*)=(.*)/) {
|
||||||
|
$templates{$name}{filterName} = $1;
|
||||||
|
$templates{$name}{filterVal} = $2;
|
||||||
|
|
||||||
|
} elsif($line =~ m/^par:(.*)/) {
|
||||||
|
push(@{$templates{$name}{pars}}, $1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
push(@{$templates{$name}{cmds}}, $line);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fh);
|
||||||
|
}
|
||||||
|
my $nr = (int keys %templates);
|
||||||
|
$initialized = 1;
|
||||||
|
Log 2, "AttrTemplates: got $nr entries" if($nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
AttrTemplate_Set($$@)
|
||||||
|
{
|
||||||
|
my ($hash, $list, $name, $cmd, @a) = @_;
|
||||||
|
|
||||||
|
AttrTemplate_Initialize() if(!$initialized);
|
||||||
|
|
||||||
|
if($cmd ne "attrTemplate") {
|
||||||
|
if(!$cachedUsage{$name}) {
|
||||||
|
my @list;
|
||||||
|
for my $k (sort keys %templates) {
|
||||||
|
my $h = $templates{$k};
|
||||||
|
if(!$h->{filterName} || $hash->{$h->{filterName}} eq $h->{filterVal}) {
|
||||||
|
push @list, $k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$cachedUsage{$name} = (@list ? "attrTemplate:".join(",",@list) : "");
|
||||||
|
}
|
||||||
|
$list .= " " if($list ne "");
|
||||||
|
return "Unknown argument $cmd, choose one of $list$cachedUsage{$name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Missing template_entry_name parameter for attrTemplate" if(@a < 1);
|
||||||
|
my $entry = shift(@a);
|
||||||
|
my $h = $templates{$entry};
|
||||||
|
return "Unknown template_entry_name $entry" if(!$h);
|
||||||
|
|
||||||
|
my (%repl, @mComm, @mList, $missing);
|
||||||
|
for my $k (@{$h->{pars}}) {
|
||||||
|
my ($parname, $comment, $perl_code) = split(";",$k,3);
|
||||||
|
|
||||||
|
if(@a) {
|
||||||
|
$repl{$parname} = $a[0];
|
||||||
|
push(@mList, $parname);
|
||||||
|
push(@mComm, "$parname: with the $comment");
|
||||||
|
shift(@a);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($perl_code) {
|
||||||
|
$perl_code =~ s/DEVICE/$name/g;
|
||||||
|
my $ret = eval $perl_code;
|
||||||
|
return "Error checking template regexp: $@" if($@);
|
||||||
|
if($ret) {
|
||||||
|
$repl{$parname} = $ret;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push(@mList, $parname);
|
||||||
|
push(@mComm, "$parname: with the $comment");
|
||||||
|
$missing = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($missing) {
|
||||||
|
if($hash->{CL} && $hash->{CL}{TYPE} eq "FHEMWEB") {
|
||||||
|
return
|
||||||
|
"<html>".
|
||||||
|
"<input size='60' type='text' spellcheck='false' ".
|
||||||
|
"value='set $name attrTemplate $entry @mList'>".
|
||||||
|
"<br><br>Replace<br>".join("<br>",@mComm).
|
||||||
|
'<script>
|
||||||
|
setTimeout(function(){
|
||||||
|
// TODO: fix multiple dialog calls
|
||||||
|
$("#FW_okDialog").parent().find("button").css("display","block");
|
||||||
|
$("#FW_okDialog").parent().find(".ui-dialog-buttonpane button")
|
||||||
|
.unbind("click").click(function(){
|
||||||
|
var val = encodeURIComponent($("#FW_okDialog input").val());
|
||||||
|
FW_cmd(FW_root+"?cmd="+val+"&XHR=1",
|
||||||
|
function(){ location.reload() } );
|
||||||
|
$("#FW_okDialog").remove();
|
||||||
|
})}, 100);
|
||||||
|
</script>
|
||||||
|
</html>';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return "Usage: set $name attrTemplate $entry @mList\nReplace\n".
|
||||||
|
join("\n", @mComm);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $cmdlist = join("\n",@{$h->{cmds}});
|
||||||
|
$repl{DEVICE} = $name;
|
||||||
|
map { $cmdlist =~ s/$_/$repl{$_}/g; } keys %repl;
|
||||||
|
my $cmd = "";
|
||||||
|
my @ret;
|
||||||
|
map {
|
||||||
|
if($_ =~ m/^(.*)\\$/) {
|
||||||
|
$cmd .= "$1\n";
|
||||||
|
} else {
|
||||||
|
my $r = AnalyzeCommand($hash->{CL}, $cmd.$_);
|
||||||
|
push(@ret, $r) if($r);
|
||||||
|
$cmd = "";
|
||||||
|
}
|
||||||
|
} split("\n", $cmdlist);
|
||||||
|
return @ret ? join("\n", @ret) : undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -4,6 +4,7 @@
|
|||||||
package main;
|
package main;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use AttrTemplate;
|
||||||
|
|
||||||
sub SetExtensions($$@);
|
sub SetExtensions($$@);
|
||||||
sub SetExtensionsFn($);
|
sub SetExtensionsFn($);
|
||||||
@ -44,7 +45,7 @@ SetExtensions($$@)
|
|||||||
{
|
{
|
||||||
my ($hash, $list, $name, $cmd, @a) = @_;
|
my ($hash, $list, $name, $cmd, @a) = @_;
|
||||||
|
|
||||||
return "Unknown argument $cmd, choose one of " if(!$list);
|
return AttrTemplate_Set($hash, $list, $name, $cmd, @a) if(!$list);
|
||||||
|
|
||||||
my %se_list = (
|
my %se_list = (
|
||||||
"on-for-timer" => 1,
|
"on-for-timer" => 1,
|
||||||
@ -74,14 +75,13 @@ SetExtensions($$@)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!$hasOn || !$hasOff) { # No extension
|
if(!$hasOn || !$hasOff) { # No extension
|
||||||
return "Unknown argument $cmd, choose one of $list";
|
return AttrTemplate_Set($hash, $list, $name, $cmd, @a);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!defined($se_list{$cmd})) {
|
if(!defined($se_list{$cmd})) {
|
||||||
# Add only "new" commands
|
# Add only "new" commands
|
||||||
my @mylist = grep { $list !~ m/\b$_\b/ } keys %se_list;
|
my @mylist = grep { $list !~ m/\b$_\b/ } keys %se_list;
|
||||||
return "Unknown argument $cmd, choose one of $list " .
|
return AttrTemplate_Set($hash, join(" ", @mylist), $name, $cmd, @a);
|
||||||
join(" ", @mylist);
|
|
||||||
}
|
}
|
||||||
if($se_list{$cmd} && $se_list{$cmd} != int(@a)) {
|
if($se_list{$cmd} && $se_list{$cmd} != int(@a)) {
|
||||||
return "$cmd requires $se_list{$cmd} parameter";
|
return "$cmd requires $se_list{$cmd} parameter";
|
||||||
|
40
fhem/FHEM/lib/AttrTemplate/mqtt2.template
Normal file
40
fhem/FHEM/lib/AttrTemplate/mqtt2.template
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Comments start with #. Empty lines are ignored.
|
||||||
|
# Syntax of one entry: name: line, one optional filter: line, zero or more par: lines, FHEM-Commands
|
||||||
|
# filter:INTERNAL=VALUE (optional)
|
||||||
|
# par: name of the parameter; comment; perl_code (optional)
|
||||||
|
# perl_code returns a value for the parameter, or undef.
|
||||||
|
# If undef, the user has to specify them (the comment is shown to the user)
|
||||||
|
|
||||||
|
name:zigbee2mqtt_bridge
|
||||||
|
filter:TYPE=MQTT2_DEVICE
|
||||||
|
par:BRIDGENAME;name of the zigbee2mqtt bridge in the topics
|
||||||
|
attr DEVICE setList\
|
||||||
|
permit_join:true,false zigbee2mqtt/BRIDGENAME/config/permit_join $EVTPART1\
|
||||||
|
remove:textField zigbee2mqtt/BRIDGENAME/config/remove $EVTPART1\
|
||||||
|
log_level:debug,info,warn,error zigbee2mqtt/BRIDGENAME/config/log_level $EVTPART1\
|
||||||
|
rename:textField zigbee2mqtt/BRIDGENAME/config/rename {"old":"$EVTPART1","new":"$EVTPART2"}\
|
||||||
|
network_map:raw,graphviz zigbee2mqtt/BRIDGENAME/networkmap $EVTPART1\
|
||||||
|
devicelist:noArg zigbee2mqtt/BRIDGENAME/config/devices
|
||||||
|
|
||||||
|
|
||||||
|
name:zigbee2mqtt_bulb
|
||||||
|
filter:TYPE=MQTT2_DEVICE
|
||||||
|
par:NAMEINTHEBRIDGE;name of this device in the bridge;{ AttrVal("DEVICE","readingList","") =~ m,zigbee2mqtt/(.*):, ? $1 : undef }
|
||||||
|
attr DEVICE icon light_control
|
||||||
|
attr DEVICE webCmd brightness
|
||||||
|
attr DEVICE setList \
|
||||||
|
on:noArg zigbee2mqtt/NAMEINTHEBRIDGE/set {"state":"ON"}\
|
||||||
|
off:noArg zigbee2mqtt/NAMEINTHEBRIDGE/set {"state":"OFF"}\
|
||||||
|
brightness:colorpicker,BRI,0,15,255 zigbee2mqtt/NAMEINTHEBRIDGE/set {"state":"on","$EVTPART0":"$EVTPART1"}
|
||||||
|
|
||||||
|
|
||||||
|
name:zigbee2mqtt_colorbulb
|
||||||
|
filter:TYPE=MQTT2_DEVICE
|
||||||
|
par:NAMEINTHEBRIDGE;name of this device in the bridge;{ AttrVal("DEVICE","readingList","") =~ m,zigbee2mqtt/(.*):, ? $1 : undef }
|
||||||
|
attr DEVICE icon light_control
|
||||||
|
attr DEVICE webCmd brightness:color_temp
|
||||||
|
attr DEVICE setList \
|
||||||
|
on:noArg zigbee2mqtt/NAMEINTHEBRIDGE/set {"state":"ON"}\
|
||||||
|
off:noArg zigbee2mqtt/NAMEINTHEBRIDGE/set {"state":"OFF"}\
|
||||||
|
brightness:colorpicker,BRI,0,15,255 zigbee2mqtt/NAMEINTHEBRIDGE/set {"state":"on","$EVTPART0":"$EVTPART1"}\
|
||||||
|
color_temp:colorpicker,CT,250,1,454 zigbee2mqtt/NAMEINTHEBRIDGE/set {"$EVTPART0":"$EVTPART1"}
|
@ -510,6 +510,7 @@ FHEM/98_SmarterCoffee CoolTux Sonstige Systeme
|
|||||||
FHEM/99_SUNRISE_EL.pm rudolfkoenig Automatisierung
|
FHEM/99_SUNRISE_EL.pm rudolfkoenig Automatisierung
|
||||||
FHEM/99_Utils.pm rudolfkoenig Automatisierung
|
FHEM/99_Utils.pm rudolfkoenig Automatisierung
|
||||||
FHEM/99_Venetian.pm Christian.Kühnel Automatisierung
|
FHEM/99_Venetian.pm Christian.Kühnel Automatisierung
|
||||||
|
FHEM/AttrTemplate.pm rudolfkoenig Automatisierung
|
||||||
FHEM/Blocking.pm rudolfkoenig Automatisierung
|
FHEM/Blocking.pm rudolfkoenig Automatisierung
|
||||||
FHEM/DevIo.pm rudolfkoenig Sonstiges
|
FHEM/DevIo.pm rudolfkoenig Sonstiges
|
||||||
FHEM/Color.pm justme1968 Sonstiges
|
FHEM/Color.pm justme1968 Sonstiges
|
||||||
|
@ -52,6 +52,7 @@ my @filelist2 = (
|
|||||||
"FHEM/lib/MP3/.*.pm",
|
"FHEM/lib/MP3/.*.pm",
|
||||||
"FHEM/lib/MP3/Tag/.*",
|
"FHEM/lib/MP3/Tag/.*",
|
||||||
"FHEM/lib/UPnP/.*",
|
"FHEM/lib/UPnP/.*",
|
||||||
|
"FHEM/lib/AttrTemplate/.*.template",
|
||||||
"FHEM/holiday/.*.holiday",
|
"FHEM/holiday/.*.holiday",
|
||||||
"contrib/commandref_join.pl.txt",
|
"contrib/commandref_join.pl.txt",
|
||||||
"contrib/commandref_modular.pl.txt",
|
"contrib/commandref_modular.pl.txt",
|
||||||
|
@ -1217,6 +1217,15 @@ The following local attributes are used by a wider range of devices:
|
|||||||
set switch intervals 08:00-12:00 13:00-18:00<br>
|
set switch intervals 08:00-12:00 13:00-18:00<br>
|
||||||
</code>
|
</code>
|
||||||
</ul>
|
</ul>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<a name="attrTemplate"></a>
|
||||||
|
attrTemplate<br>
|
||||||
|
with this command a set of predefined attributes may be set at once. The
|
||||||
|
template files containing the entries are in FHEM/lib/AttrTemplate
|
||||||
|
directory. Template entries can be module specific, and may require further
|
||||||
|
parameters to be specified.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<!-- set end -->
|
<!-- set end -->
|
||||||
|
|
||||||
|
@ -1293,7 +1293,15 @@ Die folgenden lokalen Attribute werden von mehreren Geräten verwendet:
|
|||||||
set switch intervals 08:00-12:00 13:00-18:00<br>
|
set switch intervals 08:00-12:00 13:00-18:00<br>
|
||||||
</code>
|
</code>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
<br><br>
|
||||||
|
|
||||||
|
<a name="attrTemplate"></a>
|
||||||
|
attrTemplate<br>
|
||||||
|
mit diesem Befehl kann man eine Menge an vordefinierten Attributen setzen.
|
||||||
|
Die Einträge befinden sich in Dateien im FHEM/lib/AttrTemplate
|
||||||
|
Verzeichnis. Einträge können modul-spezifisch sein, und
|
||||||
|
möglicherweise erfordern weitere Parameter.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<!-- set end -->
|
<!-- set end -->
|
||||||
|
|
||||||
|
@ -2870,7 +2870,9 @@ CommandAttr($$)
|
|||||||
$attrVal = "-" if($attrName eq "logfile");
|
$attrVal = "-" if($attrName eq "logfile");
|
||||||
$attrVal = 5 if($attrName eq "verbose");
|
$attrVal = 5 if($attrName eq "verbose");
|
||||||
}
|
}
|
||||||
|
$defs{$sdev}->{CL} = $cl;
|
||||||
$ret = CallFn($sdev, "AttrFn", "set", $sdev, $attrName, $attrVal);
|
$ret = CallFn($sdev, "AttrFn", "set", $sdev, $attrName, $attrVal);
|
||||||
|
delete($defs{$sdev}->{CL});
|
||||||
if($ret) {
|
if($ret) {
|
||||||
push @rets, $ret;
|
push @rets, $ret;
|
||||||
next;
|
next;
|
||||||
|
@ -750,7 +750,7 @@ FW_inlineModify() // Do not generate a new HTML page upon pressing modify
|
|||||||
var ifid = (devName+"-"+arg).replace(/([^_a-z0-9])/gi,
|
var ifid = (devName+"-"+arg).replace(/([^_a-z0-9])/gi,
|
||||||
function(m){ return "\\"+m });
|
function(m){ return "\\"+m });
|
||||||
if($(".dval[informid="+ifid+"]").length == 0) {
|
if($(".dval[informid="+ifid+"]").length == 0) {
|
||||||
if(cmd == "attr") {
|
if(cmd == "attr" || (cmd == "set" && arg == "attrTemplate")) {
|
||||||
reloadIfOk = true;
|
reloadIfOk = true;
|
||||||
} else {
|
} else {
|
||||||
$(this).unbind('click').click();// No element found to replace, reload
|
$(this).unbind('click').click();// No element found to replace, reload
|
||||||
@ -762,14 +762,15 @@ FW_inlineModify() // Do not generate a new HTML page upon pressing modify
|
|||||||
newDef = $(this).closest("form").find("[name^=val]").val();
|
newDef = $(this).closest("form").find("[name^=val]").val();
|
||||||
cmd = $(this).attr("name")+"="+cmd+" "+devName+" "+arg+" "+newDef;
|
cmd = $(this).attr("name")+"="+cmd+" "+devName+" "+arg+" "+newDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
FW_cmd(FW_root+"?"+encodeURIComponent(cmd)+"&XHR=1", function(resp){
|
FW_cmd(FW_root+"?"+encodeURIComponent(cmd)+"&XHR=1", function(resp){
|
||||||
if(!resp && reloadIfOk)
|
if(!resp && reloadIfOk)
|
||||||
location.reload();
|
location.reload();
|
||||||
if(resp) {
|
if(resp) {
|
||||||
resp = FW_htmlQuote(resp);
|
if(!resp.match(/^<html>[\s\S]*<\/html>/ ) ) {
|
||||||
if(resp.indexOf("\n") >= 0)
|
resp = FW_htmlQuote(resp);
|
||||||
resp = '<pre>'+resp+'</pre>';
|
if(resp.indexOf("\n") >= 0)
|
||||||
|
resp = '<pre>'+resp+'</pre>';
|
||||||
|
}
|
||||||
return FW_okDialog(resp);
|
return FW_okDialog(resp);
|
||||||
}
|
}
|
||||||
if(isDef) {
|
if(isDef) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user