2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-16 04:36:02 +00:00

HMCCU: Improved attributes and bugfix

git-svn-id: https://svn.fhem.de/fhem/trunk@15429 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2017-11-13 15:36:46 +00:00
parent 263e14f63d
commit 27fc994ed2
6 changed files with 249 additions and 90 deletions

View File

@ -1,5 +1,6 @@
# 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.
- changed: 88_HMCCU: Improved attributes ccureadingfilter, stripnumber
- feature: 89_FULLY: New commands for motion detection and brightness
- update: 98_Siro.pm: add Disable attribute
- bugfix: 50_TelegramBot: fix minusdesc warning / cleanup

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.1.003
# Version 4.1.004
#
# Module for communication between FHEM and Homematic CCU2.
#
@ -65,10 +65,10 @@
# attr <name> rpcserverport <base_port>
# attr <name> rpctimeout <read>[,<write>]
# attr <name> stripchar <character>
# attr <name> stripnumber { -<digits> | 0 | 1 | 2 }
# attr <name> stripnumber [<datapoint-expr!]{-<digits>|0|1|2}[;...]
# attr <name> substitute <subst_rule>
#
# filter_rule := [channel-regexp!]datapoint-regexp[,...]
# filter_rule := channel-regexp!datapoint-regexp[;...]
# subst_rule := [[channel.]datapoint[,...]!]<regexp>:<subtext>[,...][;...]
##############################################################################
# Verbose levels:
@ -105,7 +105,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
my $HMCCU_VERSION = '4.1.003';
my $HMCCU_VERSION = '4.1.004';
# Default RPC port (BidCos-RF)
my $HMCCU_RPC_PORT_DEFAULT = 2001;
@ -216,7 +216,7 @@ sub HMCCU_AggregateReadings ($$);
sub HMCCU_ParseObject ($$$);
sub HMCCU_FilterReading ($$$);
sub HMCCU_GetReadingName ($$$$$$$);
sub HMCCU_FormatReadingValue ($$);
sub HMCCU_FormatReadingValue ($$$);
sub HMCCU_Trace ($$$$);
sub HMCCU_Log ($$$$);
sub HMCCU_SetError ($@);
@ -512,7 +512,7 @@ sub HMCCU_Attr ($@)
# Parse aggregation rules for readings.
# Syntax of aggregation rule is:
# FilterSpec[;...]
# FilterSpec := {Name|Filt|Read|Cond|Else|Pref|Coll}[,...]
# FilterSpec := {Name|Filt|Read|Cond|Else|Pref|Coll|Html}[,...]
# Name := name:Name
# Filt := filter:{name|type|group|room|alias}=Regexp[!Regexp]
# Read := read:Regexp
@ -520,6 +520,7 @@ sub HMCCU_Attr ($@)
# Else := else:Value
# Pref := prefix:{RULE|Prefix}
# Coll := coll:{NAME|Attribute}
# Html := html:Template
######################################################################
sub HMCCU_AggregationRules ($$)
@ -547,12 +548,12 @@ sub HMCCU_AggregationRules ($$)
# Parse aggregation rule
my @specs = split (',', $r);
foreach my $spec (@specs) {
if ($spec =~ /^(name|filter|read|if|else|prefix|coll):(.+)$/) {
if ($spec =~ /^(name|filter|read|if|else|prefix|coll|html):(.+)$/) {
$opt{$1} = $2;
}
}
# Check if rule syntax is correct
# Check if mandatory parameters are specified
foreach my $p (@pars) {
return HMCCU_Log ($hash, 1, "Parameter $p is missing in aggregation rule $cnt.", 0)
if (!exists ($opt{$p}));
@ -566,6 +567,46 @@ sub HMCCU_AggregationRules ($$)
return 0 if (!defined ($fval));
my ($fcoll, $fdflt) = split ('!', $opt{coll});
$fdflt = 'no match' if (!defined ($fdflt));
my $fhtml = exists ($opt{'html'}) ? $opt{'html'} : '';
# Read HTML template (optional)
if ($fhtml ne '') {
my %tdef;
my @html;
# Read template file
if (open (TEMPLATE, "<$fhtml")) {
@html = <TEMPLATE>;
close (TEMPLATE);
}
else {
return HMCCU_Log ($hash, 1, "Can't open file $fhtml.", 0);
}
# Parse template
foreach my $line (@html) {
chomp $line;
my ($key, $h) = split /:/, $line, 2;
next if (!defined ($h) || $key =~ /^#/);
$tdef{$key} = $h;
}
# Some syntax checks
return HMCCU_Log ($hash, 1, "Missing definition row-odd in template file.", 0)
if (!exists ($tdef{'row-odd'}));
# Set default values
$tdef{'begin-html'} = '' if (!exists ($tdef{'begin-html'}));
$tdef{'end-html'} = '' if (!exists ($tdef{'end-html'}));
$tdef{'begin-table'} = "<table>" if (!exists ($tdef{'begin-table'}));
$tdef{'end-table'} = "</table>" if (!exists ($tdef{'end-table'}));
$tdef{'default'} = 'no data' if (!exists ($tdef{'default'}));;
$tdef{'row-even'} = $tdef{'row-odd'} if (!exists ($tdef{'row-even'}));
foreach my $t (keys %tdef) {
$hash->{hmccu}{agg}{$fname}{fhtml}{$t} = $tdef{$t};
}
}
$hash->{hmccu}{agg}{$fname}{ftype} = $ftype;
$hash->{hmccu}{agg}{$fname}{fexpr} = $fexpr;
@ -861,7 +902,7 @@ sub HMCCU_Notify ($$)
}
######################################################################
# Calculate reading aggregation.
# Calculate reading aggregations.
# Called by Notify or via command get aggregation.
######################################################################
@ -873,17 +914,18 @@ sub HMCCU_AggregateReadings ($$)
my $mc = 0;
my $result = '';
my $rl = '';
my $table = '';
# Get rule parameters
my $ftype = $hash->{hmccu}{agg}{$rule}{ftype};
my $fexpr = $hash->{hmccu}{agg}{$rule}{fexpr};
my $fexcl = $hash->{hmccu}{agg}{$rule}{fexcl};
my $fread = $hash->{hmccu}{agg}{$rule}{fread};
# my $fcoll = $hash->{hmccu}{agg}{$rule}{fcoll};
my $fcond = $hash->{hmccu}{agg}{$rule}{fcond};
my $ftrue = $hash->{hmccu}{agg}{$rule}{ftrue};
my $felse = $hash->{hmccu}{agg}{$rule}{felse};
my $fpref = $hash->{hmccu}{agg}{$rule}{fpref};
my $fhtml = exists ($hash->{hmccu}{agg}{$rule}{fhtml}) ? 1 : 0;
my $resval;
$resval = $ftrue if ($fcond =~ /^(max|min|sum|avg)$/);
@ -906,38 +948,38 @@ sub HMCCU_AggregateReadings ($$)
$cn : AttrVal ($cn, $hash->{hmccu}{agg}{$rule}{fcoll}, $cn);
# Compare readings
my $f = 0;
foreach my $r (keys %{$ch->{READINGS}}) {
next if ($r !~ /$fread/);
my $rv = $ch->{READINGS}{$r}{VAL};
my $f = 0;
if (($fcond eq 'any' || $fcond eq 'all') && $rv =~ /$ftrue/) {
$mc++;
$rl .= ($mc > 1 ? ",$fcoll" : $fcoll);
last;
$f = 1;
}
if ($fcond eq 'max' && $rv > $resval) {
$resval = $rv;
$mc = 1;
$rl = $fcoll;
last;
$f = 1;
}
if ($fcond eq 'min' && $rv < $resval) {
$resval = $rv;
$mc = 1;
$rl = $fcoll;
last;
$f = 1;
}
if ($fcond eq 'sum' || $fcond eq 'avg') {
$resval += $rv;
$mc++;
$f = 1;
last;
}
if (($fcond eq 'gt' && $rv > $ftrue) ||
($fcond eq 'lt' && $rv < $ftrue) ||
($fcond eq 'ge' && $rv >= $ftrue) ||
($fcond eq 'le' && $rv <= $ftrue)) {
$mc++;
$f = 1;
}
if ($f) {
$rl .= ($mc > 1 ? ",$fcoll" : $fcoll);
last;
}
@ -946,6 +988,34 @@ sub HMCCU_AggregateReadings ($$)
}
$rl = $hash->{hmccu}{agg}{$rule}{fdflt} if ($rl eq '');
# HTML code generation
if ($fhtml) {
if ($rl ne '') {
$table = $hash->{hmccu}{agg}{$rule}{fhtml}{'begin-html'}.
$hash->{hmccu}{agg}{$rule}{fhtml}{'begin-table'};
$table .= $hash->{hmccu}{agg}{$rule}{fhtml}{'header'}
if (exists ($hash->{hmccu}{agg}{$rule}{fhtml}{'header'}));
my $row = 1;
foreach my $v (split (",", $rl)) {
my $t_row = ($row % 2) ? $hash->{hmccu}{agg}{$rule}{fhtml}{'row-odd'} :
$hash->{hmccu}{agg}{$rule}{fhtml}{'row-even'};
$t_row =~ s/\<reading\/\>/$v/;
$table .= $t_row;
$row++;
}
$table .= $hash->{hmccu}{agg}{$rule}{fhtml}{'end-table'}.
$hash->{hmccu}{agg}{$rule}{fhtml}{'end-html'};
}
else {
$table = $hash->{hmccu}{agg}{$rule}{fhtml}{'begin-html'}.
$hash->{hmccu}{agg}{$rule}{fhtml}{'default'}.
$hash->{hmccu}{agg}{$rule}{fhtml}{'end-html'};
}
}
if ($fcond eq 'any') {
$result = $mc > 0 ? $ftrue : $felse;
}
@ -968,6 +1038,7 @@ sub HMCCU_AggregateReadings ($$)
readingsBulkUpdate ($hash, $fpref.'match', $mc);
readingsBulkUpdate ($hash, $fpref.'count', $dc);
readingsBulkUpdate ($hash, $fpref.'list', $rl);
readingsBulkUpdate ($hash, $fpref.'table', $table) if ($fhtml);
readingsEndUpdate ($hash, 1);
return $result;
@ -1584,7 +1655,7 @@ sub HMCCU_Get ($@)
else {
if (exists ($hash->{hmccu}{agg})) {
my @rules = keys %{$hash->{hmccu}{agg}};
$options .= " aggregation:all,".join (',', @rules) if (scalar (@rules) > 0);
$usage .= " aggregation:all,".join (',', @rules) if (scalar (@rules) > 0);
}
return $usage;
}
@ -1714,9 +1785,15 @@ sub HMCCU_ParseObject ($$$)
######################################################################
# Filter reading by datapoint and optionally by channel name or
# channel address.
# Parameters: hash, channel, datapoint
# Parameter channel can be a channel name or a channel address without
# interface specification.
# Filter rule syntax is either:
# [N:]{Channel-Number|Channel-Name-Expr}!Datapoint-Expr
# or
# [N:][Channel-Number.]Datapoint-Expr
# Multiple filter rules must be separated by ;
######################################################################
sub HMCCU_FilterReading ($$$)
{
my ($hash, $chn, $dpt) = @_;
@ -1725,42 +1802,79 @@ sub HMCCU_FilterReading ($$$)
my $hmccu_hash = HMCCU_GetHash ($hash);
return 1 if (!defined ($hmccu_hash));
my $grf = AttrVal ($hmccu_hash->{NAME}, 'ccudef-readingfilter', '');
$grf = '.*' if ($grf eq '');
my $rf = AttrVal ($name, 'ccureadingfilter', $grf);
$rf = $grf.";".$rf if ($rf ne $grf && $grf ne '.*' && $grf ne '');
my $chnnam = HMCCU_IsChnAddr ($chn, 0) ? HMCCU_GetChannelName ($hmccu_hash, $chn, '') : $chn;
my $chnnam = '';
my $chnnum = '';
my $devadd = '';
HMCCU_Trace ($hash, 2, $fnc, "chn=$chn, dpt=$dpt, rules=$rf");
my $rm = 1;
my @rules = split (';', $rf);
foreach my $r (@rules) {
$rm = 1;
# Get channel name and channel number
if (HMCCU_IsChnAddr ($chn, 0)) {
$chnnam = HMCCU_GetChannelName ($hmccu_hash, $chn, '');
($devadd, $chnnum) = HMCCU_SplitChnAddr ($chn);
}
else {
($devadd, $chnnum) = HMCCU_GetAddress ($hash, $chn, '', '');
$chnnam = $chn;
}
HMCCU_Trace ($hash, 2, $fnc, "chn=$chn, chnnam=$chnnam chnnum=$chnnum dpt=$dpt, rules=$rf");
foreach my $r (split (';', $rf)) {
my $rm = 1;
my $cn = '';
# Negative filter
if ($r =~ /^N:/) {
$rm = 0;
$r =~ s/^N://;
}
# Get filter criteria
my ($c, $f) = split ("!", $r);
HMCCU_Trace ($hash, 2, undef, " rm=$rm, r=$r, dpt=$dpt chnflt=$c chnnam=$chnnam");
if (defined ($f) && $chnnam ne '') {
if ($chnnam =~ /$c/) {
HMCCU_Trace ($hash, 2, undef, " $chnnam = $c");
return $rm if (($rm && $dpt =~ /$f/) || (!$rm && $dpt =~ /$f/));
return $rm ? 0 : 1;
}
if (defined ($f)) {
next if ($c eq '' || $chnnam eq '' || $chnnum eq '');
$cn = $c if ($c =~ /^([0-9]{1,2})$/);
}
else {
HMCCU_Trace ($hash, 2, undef, " check $rm=1 AND $dpt=$r OR $rm=0 AND $dpt=$r");
return $rm if (($rm && $dpt =~ /$r/) || (!$rm && $dpt =~ /$r/));
HMCCU_Trace ($hash, 2, undef, " check negative");
$c = '';
if ($r =~ /^([0-9]{1,2})\.(.+)$/) {
$cn = $1;
$f = $2;
}
else {
$cn = '';
$f = $r;
}
}
HMCCU_Trace ($hash, 2, undef, " check rm=$rm f=$f cn=$cn c=$c");
# Positive filter
return 1 if (
$rm && (
(
($cn ne '' && "$chnnum" eq "$cn") ||
($c ne '' && $chnnam =~ /$c/) ||
($cn eq '' && $c eq '')
) && $dpt =~ /$f/
)
);
# Negative filter
return 1 if (
!$rm && (
($cn ne '' && "$chnnum" ne "$cn") ||
($c ne '' && $chnnam !~ /$c/) ||
$dpt !~ /$f/
)
);
HMCCU_Trace ($hash, 2, undef, " check result false");
}
HMCCU_Trace ($hash, 2, $fnc, "return rm = $rm ? 0 : 1");
return $rm ? 0 : 1;
return 0;
}
######################################################################
@ -1869,28 +1983,41 @@ sub HMCCU_GetReadingName ($$$$$$$)
######################################################################
# Format reading value depending on attribute stripnumber. Integer
# values are ignored.
# 0 = Preserve all digits
# 1 = Preserve 1 digit
# 2 = Remove trailing zeroes
# -n = Round value to specified number of digits (-0 is valid)
# Syntax of attribute stripnumber:
# [datapoint-expr!]format[;...]
# Valid formats:
# 0 = Preserve all digits (default)
# 1 = Preserve 1 digit
# 2 = Remove trailing zeroes
# -n = Round value to specified number of digits (-0 is allowed)
######################################################################
sub HMCCU_FormatReadingValue ($$)
sub HMCCU_FormatReadingValue ($$$)
{
my ($hash, $value) = @_;
my ($hash, $value, $dpt) = @_;
my $stripnumber = AttrVal ($hash->{NAME}, 'stripnumber', '0');
return $value if ($stripnumber eq '0' || $value !~ /\.[0-9]+$/);
if ($stripnumber eq '1') {
return sprintf ("%.1f", $value);
}
elsif ($stripnumber eq '2') {
return sprintf ("%g", $value);
}
elsif ($stripnumber =~ /^-([0-9])$/) {
my $fmt = '%.'.$1.'f';
return sprintf ($fmt, $value);
foreach my $sr (split (';', $stripnumber)) {
my ($d, $s) = split ('!', $sr);
if (defined ($s)) {
next if ($d eq '' || $dpt !~ /$d/);
}
else {
$s = $sr;
}
if ($s eq '1') {
return sprintf ("%.1f", $value);
}
elsif ($s eq '2') {
return sprintf ("%g", $value);
}
elsif ($s =~ /^-([0-9])$/) {
my $fmt = '%.'.$1.'f';
return sprintf ($fmt, $value);
}
}
return $value;
@ -2479,10 +2606,10 @@ sub HMCCU_UpdateSingleDevice ($$$)
if (HMCCU_FilterReading ($ch, $chnadd, $dpt)) {
my @readings = HMCCU_GetReadingName ($ch, '', $da, $chnnum, $dpt, '', $crf);
my $svalue = HMCCU_ScaleValue ($ch, $dpt, $value, 0);
my $fvalue = HMCCU_FormatReadingValue ($ch, $svalue);
my $fvalue = HMCCU_FormatReadingValue ($ch, $svalue, $dpt);
my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chnnum, $dpt);
my %calcs = HMCCU_CalculateReading ($ch, $chnnum, $dpt);
# Store the resulting value after scaling, formatting and substitution
if (exists ($clthash->{hmccu}{dp}{"$chnnum.$dpt"}{OSVAL})) {
$clthash->{hmccu}{dp}{"$chnnum.$dpt"}{OSVAL} = $clthash->{hmccu}{dp}{"$chnnum.$dpt"}{SVAL};
@ -2492,7 +2619,7 @@ sub HMCCU_UpdateSingleDevice ($$$)
}
$clthash->{hmccu}{dp}{"$chnnum.$dpt"}{SVAL} = $cvalue;
$results{$da}{$chnnum}{$dpt} = $cvalue;
HMCCU_Trace ($ch, 2, $fnc,
"device=$cltname, readings=".join(',', @readings).
", orgvalue=$value value=$cvalue peer=$peer");
@ -4772,7 +4899,7 @@ sub HMCCU_GetVariables ($$)
next if (@vardata != 3);
next if ($vardata[0] !~ /$pattern/);
my $rn = HMCCU_CorrectName ($vardata[0]);
my $value = HMCCU_FormatReadingValue ($hash, $vardata[2]);
my $value = HMCCU_FormatReadingValue ($hash, $vardata[2], $vardata[0]);
readingsBulkUpdate ($hash, $rn, $value) if ($ccureadings);
$result .= $vardata[0].'='.$vardata[2]."\n";
$count++;
@ -5076,7 +5203,7 @@ sub HMCCU_RPCGetConfig ($$$$)
$result .= "$key=$value\n";
next if (!$ccureadings);
$value = HMCCU_FormatReadingValue ($hash, $value);
$value = HMCCU_FormatReadingValue ($hash, $value, $key);
$value = HMCCU_Substitute ($value, $substitute, 0, $chn, $key);
my @readings = HMCCU_GetReadingName ($hash, $int, $add, $chn, $key, $nam, $readingformat);
foreach my $rn (@readings) {
@ -5345,7 +5472,7 @@ sub HMCCU_GetHMState ($$$)
}
next if ($dp eq '');
my ($chn, $dpt) = split (/\./, $dp);
my $value = HMCCU_FormatReadingValue ($clhash, $clhash->{hmccu}{dp}{$dp}{VAL});
my $value = HMCCU_FormatReadingValue ($clhash, $clhash->{hmccu}{dp}{$dp}{VAL}, $hmstate[0]);
my ($rc, $newvalue) = HMCCU_SubstRule ($value, $subst, 0);
return ($hmstate[0], $chn, $dpt, $newvalue) if ($rc);
}
@ -6165,7 +6292,7 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
<b>Get</b><br/><br/>
<ul>
<li><b>get &lt;name&gt; aggregation {&lt;rule&gt;|all}</b><br/>
Process aggregation rule defined with attribute ccuaggregation.
Process aggregation rule defined with attribute ccuaggregate.
</li><br/>
<li><b>get &lt;name&gt; configdesc {&lt;device&gt;|&lt;channel&gt;}</b><br/>
Get configuration parameter description of CCU device or channel (similar
@ -6284,13 +6411,26 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
<li><b>coll:{&lt;attribute&gt;|NAME}[!&lt;default-text&gt;]</b><br/>
Attribute of matching devices stored in aggregation results. Default text in case
of no matching devices found is optional.</li>
<li><b>html:&lt;template-file&gt;</b><br/>
Create HTML code with matching devices.</li>
</ul><br/>
Aggregation results will be stored in readings <i>prefix</i>count, <i>prefix</i>list,
<i>prefix</i>match, <i>prefix</i>state and <i>prefix</i>table.<br/><br/>
Format of a line in <i>template-file</i> is &lt;keyword&gt;:&lt;html-code&gt;. See
FHEM Wiki for an example. Valid keywords are:<br/><br/>
<ul>
<li><b>begin-html</b>: Start of html code.</li>
<li><b>begin-table</b>: Start of table (i.e. the table header)</li>
<li><b>row-odd</b>: HTML code for odd lines. A tag &lt;reading/&gt is replaced by a matching device.</li>
<li><b>row-even</b>: HTML code for event lines.</li>
<li><b>end-table</b>: End of table.</li>
<li><b>default</b>: HTML code for no matches.</li>
<li><b>end-html</b>: End of html code.</li>
</ul><br/>
Aggregation results will be stored in readings <i>prefix</i>count, <i>prefix</i>
list, <i>prefix</i>match and <i>prefix</i>state<br/><br/>
Example: Find open windows<br/>
name=lock,filter:type=^HM-Sec-SC.*,read:STATE,if:any=open,else:closed,prefix:lock_,coll:NAME!All windows closed<br/><br/>
Example: Find devices with low batteries<br/>
name=battery,filter:name=.*,read:(LOWBAT|LOW_BAT),if:any=yes,else:no,prefix:batt_,coll:NAME<br/>
Example: Find devices with low batteries. Generate reading in HTML format.<br/>
name=battery,filter:name=.*,read:(LOWBAT|LOW_BAT),if:any=yes,else:no,prefix:batt_,coll:NAME!All batteries OK,html:/home/battery.cfg<br/>
</li><br/>
<li><b>ccudef-hmstatevals &lt;subst-rule[;...]&gt;</b><br/>
Set global rules for calculation of reading hmstate.

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.1.001
# Version 4.1.003
#
# (c) 2017 zap (zap01 <at> t-online <dot> de)
#
@ -38,7 +38,7 @@
# attr <name> ccuflags { altread, nochn0, trace }
# attr <name> ccuget { State | Value }
# attr <name> ccureadings { 0 | 1 }
# attr <name> ccureadingfilter <datapoint-expr>
# attr <name> ccureadingfilter <filter-rule>[;...]
# attr <name> ccureadingformat { name[lc] | address[lc] | datapoint[lc] }
# attr <name> ccureadingname <oldname>:<newname>[;...]
# attr <name> ccuverify { 0 | 1 | 2 }
@ -84,7 +84,8 @@ sub HMCCUCHN_Initialize ($)
$hash->{AttrList} = "IODev ccuackstate:0,1 ccucalculate ".
"ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ".
"ccureadingname:textField-long ".
"ccureadings:0,1 ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint ".
"disable:0,1 hmstatevals:textField-long statedatapoint statevals substitute:textField-long ".
"substexcl stripnumber peer:textField-long ". $readingFnAttributes;
@ -778,15 +779,19 @@ sub HMCCUCHN_Get ($@)
</li><br/>
<li><b>ccureadingfilter &lt;filter-rule[;...]&gt;</b><br/>
Only datapoints matching specified expression are stored as readings.<br/>
Syntax for <i>filter-rule</i> is: [N:][&lt;channel-name&gt;!]&lt;RegExp&gt;<br/>
If <i>channel-name</i> is specified the following rule applies only to this channel.
Syntax for <i>filter-rule</i> is either:<br/>
[N:]{&lt;channel-name&gt;|&lt;channel-number&gt;}!&lt;RegExp&gt; or:<br/>
[N:][&lt;channel-number&gt;.]&lt;RegExp&gt;<br/>
If <i>channel-name</i> or <i>channel-number</i> is specified the following rule
applies only to this channel.
By default all datapoints will be stored as readings. Attribute ccudef-readingfilter
of I/O device will be checked before this attribute.<br/>
If a rule starts with 'N:' the filter is negated which means that a reading is
stored if rule doesn't match.
</li><br/>
<li><b>ccureadingformat {address[lc] | name[lc] | datapoint[lc]}</b><br/>
Set format of reading names. Default is 'name'. If set to 'address' format of reading names
Set format of reading names. Default for virtual device groups is 'name'. The default for all
other device types is 'datapoint'. If set to 'address' format of reading names
is channel-address.datapoint. If set to 'name' format of reading names is
channel-name.datapoint. If set to 'datapoint' format is channel-number.datapoint. With
suffix 'lc' reading names are converted to lowercase.
@ -910,14 +915,16 @@ sub HMCCUCHN_Get ($@)
set my_switch on
</code>
</li><br/>
<li><b>stripnumber {<u>0</u> | 1 | 2 | -n}</b><br/>
<li><b>stripnumber [&lt;datapoint-expr&gt;!]{<u>0</u>|1|2|-n}[;...]</b><br/>
Remove trailing digits or zeroes from floating point numbers and/or round floating
point numbers. If attribute is negative (-0 is valid) floating point values are rounded
to the specified number of digits before they are stored in readings. The meaning of
values 0-2 is:<br/>
0 = Floating point numbers are stored as read from CCU (i.e. with trailing zeros)<br/>
1 = Trailing zeros are stripped from floating point numbers except one digit.<br/>
2 = All trailing zeros are stripped from floating point numbers.
2 = All trailing zeros are stripped from floating point numbers.<br/>
If <i>datapoint-expr</i> is specified the formatting applies only to datapoints
matching the regular expression.
</li><br/>
<li><b>substexcl &lt;reading-expr&gt;</b><br/>
Exclude values of readings matching <i>reading-expr</i> from substitution. This is helpful
@ -926,7 +933,7 @@ sub HMCCUCHN_Get ($@)
</li><br/>
<li><b>substitute &lt;subst-rule&gt;[;...]</b><br/>
Define substitutions for datapoint/reading values. Syntax of <i>subst-rule</i> is<br/><br/>
[[&lt;channelno.&gt;]&lt;datapoint&gt;[,...]!]&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
[[&lt;channelno&gt;.]&lt;datapoint&gt;[,...]!]&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
<br/><br/>
Parameter <i>text</i> can contain variables in format ${<i>varname</i>}. The variable
${value} is
@ -937,11 +944,11 @@ sub HMCCUCHN_Get ($@)
'T=<i>val</i> deg' and append current value of datapoint 1.HUMIDITY<br/>
<code>
attr my_weather substitute TEMPERATURE!.+:T=${value} deg H=${1.HUMIDITY}%
</code>
</code><br/><br/>
If rule expression starts with a hash sign a numeric datapoint value is substituted if
it fits in the number range n &lt;= value &lt;= m.
<br/><br/>
Example: Interpret LEVEL values of dimmer as "on" and "off"<br/>
Example: Interpret LEVEL values 100 and 0 of dimmer as "on" and "off"<br/>
<code>
attr my_dim substitute LEVEL!#0-0:off,#1-100:on
</code>

View File

@ -87,7 +87,8 @@ sub HMCCUDEV_Initialize ($)
$hash->{AttrList} = "IODev ccuackstate:0,1 ccucalculate:textField-long ".
"ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter:textField-long ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ".
"ccureadingname:textField-long ".
"ccureadings:0,1 ccuget:State,Value ccuscaleval ccuverify:0,1,2 disable:0,1 ".
"hmstatevals:textField-long statevals substexcl substitute:textField-long statechannel ".
"statedatapoint controldatapoint stripnumber peer:textField-long ".$readingFnAttributes;

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 0.97 beta
# Version 0.98 beta
#
# Thread based RPC Server module for HMCCU.
#
@ -40,7 +40,7 @@ use SetExtensions;
######################################################################
# HMCCURPC version
my $HMCCURPC_VERSION = '0.97 beta';
my $HMCCURPC_VERSION = '0.98 beta';
# Maximum number of events processed per call of Read()
my $HMCCURPC_MAX_EVENTS = 50;
@ -237,7 +237,7 @@ sub HMCCURPC_Initialize ($)
$hash->{parseParams} = 1;
$hash->{AttrList} = "rpcInterfaces:multiple-strict,".join(',',sort keys %HMCCURPC_RPC_PORT).
" ccuflags:multiple-strict,expert,keepThreads,reconnect".
" ccuflags:multiple-strict,expert,keepThreads,logEvents,reconnect".
" rpcMaxEvents rpcQueueSize rpcTriggerTime".
" rpcServer:on,off rpcServerAddr rpcServerPort rpcWriteTimeout rpcAcceptTimeout".
" rpcConnTimeout rpcWaitTime rpcStatistics rpcEventTimeout ".
@ -652,7 +652,7 @@ sub HMCCURPC_Read ($)
}
elsif ($et eq 'TO') {
$hmccu_hash->{ccustate} = 'timeout';
if ($hash->{RPCState} eq 'running' && $hash->{$ccuflags} =~ /reconnect/) {
if ($hash->{RPCState} eq 'running' && $ccuflags =~ /reconnect/) {
if (HMCCU_TCPConnect ($hash->{host}, $par[0])) {
$hmccu_hash->{ccustate} = 'active';
Log3 $name, 2, "HMCCURPC: Reconnecting to CCU interface ".
@ -833,6 +833,8 @@ sub HMCCURPC_ProcessEvent ($$)
"ST", 11
);
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
# Parse event
return undef if (!defined ($event) || $event eq '');
my @t = split (/\|/, $event);
@ -865,6 +867,9 @@ sub HMCCURPC_ProcessEvent ($$)
$rpceventargs{$et};
return undef;
}
# Log event
Log3 $name, 2, "HMCCURPC: CCUEvent = $event" if ($ccuflags =~ /logEvents/);
# Update statistic counters
$rh->{$clkey}{rec}{$et}++;

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.1.001
# Version 4.1.002
#
# Configuration parameters for HomeMatic devices.
#
@ -154,8 +154,8 @@ use vars qw(%HMCCU_SCRIPTS);
statevals => "press:true",
substitute => "PRESS_SHORT,PRESS_LONG,PRESS_CONT!(1|true):pressed,(0|false):released;PRESS_LONG_RELEASE!(0|false):no,(1|true):yes"
},
"HM-RC-Key4-2|HM-RC-Key4-3" => {
_description => "Funk-Handsender Key",
"HM-RC-Key4-2|HM-RC-Key4-3|HM-RC-Sec4-2|HM-RC-Sec4-3" => {
_description => "Funk-Handsender",
_channels => "1,2,3,4",
ccureadingfilter => "PRESS",
"event-on-update-reading" => ".*",
@ -490,8 +490,8 @@ use vars qw(%HMCCU_SCRIPTS);
ccureadingfilter => "PRESS",
substitute => "PRESS_SHORT,PRESS_LONG,PRESS_CONT!(1|true):pressed,(0|false):released;PRESS_LONG_RELEASE!(0|false):no,(1|true):yes"
},
"HM-RC-Key4-2|HM-RC-Key4-3" => {
_description => "Funk-Handsender Key",
"HM-RC-Key4-2|HM-RC-Key4-3|HM-RC-Sec4-2|HM-RC-Sec4-3" => {
_description => "Funk-Handsender",
ccureadingfilter => "PRESS",
"event-on-update-reading" => ".*",
substitute => "PRESS_SHORT,PRESS_LONG!(1|true):pressed"
@ -538,6 +538,7 @@ use vars qw(%HMCCU_SCRIPTS);
cmdIcon => "Auto:sani_heating_automatic Manu:sani_heating_manual Boost:sani_heating_boost on:general_an off:general_aus",
controldatapoint => "2.SET_TEMPERATURE",
eventMap => "/datapoint 2.MANU_MODE 20.0:Manu/datapoint 2.AUTO_MODE 1:Auto/datapoint 2.BOOST_MODE 1:Boost/datapoint 2.MANU_MODE 4.5:off/datapoint 2.MANU_MODE 30.5:on/",
genericDeviceType => "thermostat",
statedatapoint => "2.SET_TEMPERATURE",
stripnumber => 1,
substexcl => "control",
@ -551,6 +552,7 @@ use vars qw(%HMCCU_SCRIPTS);
cmdIcon => "Auto:sani_heating_automatic Manu:sani_heating_manual Boost:sani_heating_boost on:general_an off:general_aus",
controldatapoint => "4.SET_TEMPERATURE",
eventMap => "/datapoint 4.MANU_MODE 20.0:Manu/datapoint 4.AUTO_MODE 1:Auto/datapoint 4.BOOST_MODE 1:Boost/datapoint 4.MANU_MODE 4.5:off/datapoint 4.MANU_MODE 30.5:on/",
genericDeviceType => "thermostat",
hmstatevals => "FAULT_REPORTING!1:valve_tight,2:range_too_large,3:range_too_small,4:communication_error,5:other_error,6:battery_low,7:valve_error_pos",
statedatapoint => "4.SET_TEMPERATURE",
stripnumber => 1,
@ -559,12 +561,14 @@ use vars qw(%HMCCU_SCRIPTS);
webCmd => "control:Auto:Manu:Boost:on:off",
widgetOverride => "control:slider,4.5,0.5,30.5,1"
},
"HMIP-eTRV" => {
"HmIP-eTRV|HmIP-eTRV-2" => {
_description => "Heizkoerperthermostat HM-IP",
ccureadingfilter => "^ACTUAL_TEMPERATURE|^BOOST_MODE|^SET_POINT_MODE|^SET_POINT_TEMPERATURE|^LEVEL|^WINDOW_STATE",
ccureadingname => "1.LEVEL:valve_position",
ccuscaleval => "LEVEL:0:1:0:100",
controldatapoint => "1.SET_POINT_TEMPERATURE",
eventMap => "/datapoint 1.BOOST_MODE true:Boost/datapoint 1.CONTROL_MODE 0:Auto/datapoint 1.CONTROL_MODE 1:Manual/datapoint 1.CONTROL_MODE 2:Holiday/datapoint 1.SET_POINT_TEMPERATURE 4.5:off/datapoint 1.SET_POINT_TEMPERATURE 30.5:on/",
genericDeviceType => "thermostat",
statedatapoint => "1.SET_POINT_TEMPERATURE",
stripnumber => 1,
substexcl => "control",
@ -576,6 +580,7 @@ use vars qw(%HMCCU_SCRIPTS);
_description => "Wandthermostat HM-IP",
controldatapoint => "1.SET_POINT_TEMPERATURE",
eventMap => "/datapoint 1.BOOST_MODE true:Boost/datapoint 1.CONTROL_MODE 0:Auto/datapoint 1.CONTROL_MODE 1:Manual/datapoint 1.CONTROL_MODE 2:Holiday/datapoint 1.SET_POINT_TEMPERATURE 4.5:off/datapoint 1.SET_POINT_TEMPERATURE 30.5:on/",
genericDeviceType => "thermostat",
statedatapoint => "1.SET_POINT_TEMPERATURE",
stripnumber => 1,
substexcl => "control",