HMCCU: Version 3.9

git-svn-id: https://svn.fhem.de/fhem/trunk@13241 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2017-01-26 17:02:17 +00:00
parent e4c9a88dc6
commit 3fdc8187f8
5 changed files with 306 additions and 110 deletions

View File

@ -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.
- update: 88_HMCCU.pm: version 3.9
- update: 98_DOIFtools.pm: marking an eventline in DOIFs event monitor - update: 98_DOIFtools.pm: marking an eventline in DOIFs event monitor
shows different representations of the event as operand shows different representations of the event as operand
for DOIF definitions for DOIF definitions

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 3.8 # Version 3.9
# #
# Module for communication between FHEM and Homematic CCU2. # Module for communication between FHEM and Homematic CCU2.
# Supports BidCos-RF, BidCos-Wired, HmIP-RF, virtual CCU channels, # Supports BidCos-RF, BidCos-Wired, HmIP-RF, virtual CCU channels,
@ -43,6 +43,7 @@
# #
# attr <name> ccuackstate { 0 | 1 } # attr <name> ccuackstate { 0 | 1 }
# attr <name> ccuaggregate <rules> # attr <name> ccuaggregate <rules>
# attr <name> ccudef-hmstatevals <subst_rules>
# attr <name> ccudef-readingfilter <filter_rule> # attr <name> ccudef-readingfilter <filter_rule>
# attr <name> ccudef-readingname <rules> # attr <name> ccudef-readingname <rules>
# attr <name> ccudef-substitute <subst_rule> # attr <name> ccudef-substitute <subst_rule>
@ -102,7 +103,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version # HMCCU version
my $HMCCU_VERSION = '3.8'; my $HMCCU_VERSION = '3.9';
# RPC Ports and URL extensions # RPC Ports and URL extensions
my %HMCCU_RPC_PORT = ( my %HMCCU_RPC_PORT = (
@ -193,6 +194,7 @@ sub HMCCU_SetError ($$);
sub HMCCU_SetState ($$); sub HMCCU_SetState ($$);
sub HMCCU_Substitute ($$$$$); sub HMCCU_Substitute ($$$$$);
sub HMCCU_SubstRule ($$$); sub HMCCU_SubstRule ($$$);
sub HMCCU_SubstVariables ($$);
sub HMCCU_UpdateClients ($$$$); sub HMCCU_UpdateClients ($$$$);
sub HMCCU_UpdateClientReading ($@); sub HMCCU_UpdateClientReading ($@);
sub HMCCU_AddDevices ($$); sub HMCCU_AddDevices ($$);
@ -223,7 +225,9 @@ sub HMCCU_GetDatapointCount ($$$);
sub HMCCU_GetSpecialDatapoints ($$$$$); sub HMCCU_GetSpecialDatapoints ($$$$$);
sub HMCCU_GetAttrReadingFormat ($$); sub HMCCU_GetAttrReadingFormat ($$);
sub HMCCU_GetAttrSubstitute ($$); sub HMCCU_GetAttrSubstitute ($$);
sub HMCCU_IsValidDeviceOrChannel ($$);
sub HMCCU_IsValidDevice ($$); sub HMCCU_IsValidDevice ($$);
sub HMCCU_IsValidChannel ($$);
sub HMCCU_GetCCUDeviceParam ($$); sub HMCCU_GetCCUDeviceParam ($$);
sub HMCCU_GetValidDatapoints ($$$$$); sub HMCCU_GetValidDatapoints ($$$$$);
sub HMCCU_GetSwitchDatapoint ($$$); sub HMCCU_GetSwitchDatapoint ($$$);
@ -259,10 +263,11 @@ sub HMCCU_QueueEnq ($$);
sub HMCCU_QueueDeq ($); sub HMCCU_QueueDeq ($);
# Helper functions # Helper functions
sub HMCCU_GetHMState ($$); sub HMCCU_GetHMState ($$$);
sub HMCCU_AggReadings ($$$$$); sub HMCCU_AggReadings ($$$$$);
sub HMCCU_GetTimeSpec ($); sub HMCCU_GetTimeSpec ($);
sub HMCCU_Dewpoint ($$$$); sub HMCCU_Dewpoint ($$$$);
sub HMCCU_CalculateReading ($$$);
sub HMCCU_EncodeEPDisplay ($); sub HMCCU_EncodeEPDisplay ($);
# Subprocess functions # Subprocess functions
@ -297,7 +302,7 @@ sub HMCCU_Initialize ($)
$hash->{ShutdownFn} = "HMCCU_Shutdown"; $hash->{ShutdownFn} = "HMCCU_Shutdown";
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
$hash->{AttrList} = "stripchar stripnumber ccuackstate:0,1 ccuaggregate:textField-long ccudefaults ccudef-substitute:textField-long ccudef-readingname:textField-long ccudef-readingfilter:textField-long ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc ccuflags:multiple-strict,intrpc,dptnocheck,noagg,nohmstate ccureadings:0,1 ccureadingfilter ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc rpcinterval:2,3,5,7,10 rpcqueue rpcport:multiple-strict,2000,2001,2003,2010,9292 rpcserver:on,off rpcserveraddr rpcserverport rpctimeout rpcevtimeout parfile substitute ccutrace ccuget:Value,State ". $readingFnAttributes; $hash->{AttrList} = "stripchar stripnumber ccuackstate:0,1 ccuaggregate:textField-long ccudefaults ccudef-hmstatevals:textField-long ccudef-substitute:textField-long ccudef-readingname:textField-long ccudef-readingfilter:textField-long ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc ccuflags:multiple-strict,intrpc,dptnocheck,noagg,nohmstate ccureadings:0,1 ccureadingfilter ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc rpcinterval:2,3,5,7,10 rpcqueue rpcport:multiple-strict,2000,2001,2003,2010,9292 rpcserver:on,off rpcserveraddr rpcserverport rpctimeout rpcevtimeout parfile substitute ccutrace ccuget:Value,State ". $readingFnAttributes;
} }
################################################## ##################################################
@ -572,13 +577,13 @@ sub HMCCU_FindDefaults ($$)
foreach my $deftype (keys %HMCCU_CUST_CHN_DEFAULTS) { foreach my $deftype (keys %HMCCU_CUST_CHN_DEFAULTS) {
my @chnlst = split (',', $HMCCU_CUST_CHN_DEFAULTS{$deftype}{_channels}); my @chnlst = split (',', $HMCCU_CUST_CHN_DEFAULTS{$deftype}{_channels});
return \%{$HMCCU_CUST_CHN_DEFAULTS{$deftype}} return \%{$HMCCU_CUST_CHN_DEFAULTS{$deftype}}
if ($ccutype =~ /^($deftype)$/ && grep { $_ eq $chn} @chnlst); if ($ccutype =~ /^($deftype)$/i && grep { $_ eq $chn} @chnlst);
} }
foreach my $deftype (keys %{$HMCCU_CHN_DEFAULTS}) { foreach my $deftype (keys %{$HMCCU_CHN_DEFAULTS}) {
my @chnlst = split (',', $HMCCU_CHN_DEFAULTS->{$deftype}{_channels}); my @chnlst = split (',', $HMCCU_CHN_DEFAULTS->{$deftype}{_channels});
return \%{$HMCCU_CHN_DEFAULTS->{$deftype}} return \%{$HMCCU_CHN_DEFAULTS->{$deftype}}
if ($ccutype =~ /^($deftype)$/ && grep { $_ eq $chn} @chnlst); if ($ccutype =~ /^($deftype)$/i && grep { $_ eq $chn} @chnlst);
} }
} }
elsif ($type eq 'HMCCUDEV' || $type eq 'HMCCU') { elsif ($type eq 'HMCCUDEV' || $type eq 'HMCCU') {
@ -588,11 +593,11 @@ sub HMCCU_FindDefaults ($$)
} }
foreach my $deftype (keys %HMCCU_CUST_DEV_DEFAULTS) { foreach my $deftype (keys %HMCCU_CUST_DEV_DEFAULTS) {
return \%{$HMCCU_CUST_DEV_DEFAULTS{$deftype}} if ($ccutype =~ /^($deftype)$/); return \%{$HMCCU_CUST_DEV_DEFAULTS{$deftype}} if ($ccutype =~ /^($deftype)$/i);
} }
foreach my $deftype (keys %{$HMCCU_DEV_DEFAULTS}) { foreach my $deftype (keys %{$HMCCU_DEV_DEFAULTS}) {
return \%{$HMCCU_DEV_DEFAULTS->{$deftype}} if ($ccutype =~ /^($deftype)$/); return \%{$HMCCU_DEV_DEFAULTS->{$deftype}} if ($ccutype =~ /^($deftype)$/i);
} }
} }
@ -1221,7 +1226,7 @@ sub HMCCU_Get ($@)
return HMCCU_SetError ($hash, "Usage: get $name deviceinfo {device} [{'State'|'Value'}]") return HMCCU_SetError ($hash, "Usage: get $name deviceinfo {device} [{'State'|'Value'}]")
if ($ccuget !~ /^(Attr|State|Value)$/); if ($ccuget !~ /^(Attr|State|Value)$/);
return HMCCU_SetError ($hash, -1) if (!HMCCU_IsValidDevice ($hash, $device)); return HMCCU_SetError ($hash, -1) if (!HMCCU_IsValidDeviceOrChannel ($hash, $device));
$result = HMCCU_GetDeviceInfo ($hash, $device, $ccuget); $result = HMCCU_GetDeviceInfo ($hash, $device, $ccuget);
return HMCCU_SetError ($hash, -2) if ($result eq ''); return HMCCU_SetError ($hash, -2) if ($result eq '');
return HMCCU_FormatDeviceInfo ($result); return HMCCU_FormatDeviceInfo ($result);
@ -1792,8 +1797,14 @@ sub HMCCU_Substitute ($$$$$)
################################################################## ##################################################################
# Execute substitution list. # Execute substitution list.
# Syntax for single substitution: {#n-n|regexp|text}:text # Syntax for single substitution: {#n-n|regexp|text}:newtext
# mode: 0=Substitute regular expression, 1=Substitute text # mode=0: Substitute regular expression
# mode=1: Substitute text (for setting statevals)
# newtext can contain ':'. Parameter ${value} in newtext is
# substituted by original value.
# Return (status, value)
# status=1: value = substituted value
# status=0: value = original value
################################################################## ##################################################################
sub HMCCU_SubstRule ($$$) sub HMCCU_SubstRule ($$$)
@ -1801,24 +1812,30 @@ sub HMCCU_SubstRule ($$$)
my ($value, $substitutes, $mode ) = @_; my ($value, $substitutes, $mode ) = @_;
my $rc = 0; my $rc = 0;
$substitutes =~ s/\$\{value\}/$value/g;
my @sub_list = split /,/,$substitutes; my @sub_list = split /,/,$substitutes;
foreach my $s (@sub_list) { foreach my $s (@sub_list) {
my ($regexp, $text) = split /:/,$s; # my ($regexp, $text) = split /:/,$s;
my ($regexp, $text) = split /:/,$s,2;
next if (!defined ($regexp) || !defined($text)); next if (!defined ($regexp) || !defined($text));
if ($regexp =~ /^#([+-]?\d*\.?\d+?)\-([+-]?\d*\.?\d+?)$/) { if ($regexp =~ /^#([+-]?\d*\.?\d+?)\-([+-]?\d*\.?\d+?)$/) {
my ($mi, $ma) = ($1, $2); my ($mi, $ma) = ($1, $2);
if ($value =~ /^\d*\.?\d+?/ && $value >= $mi && $value <= $ma) { if ($value =~ /^\d*\.?\d+?/ && $value >= $mi && $value <= $ma) {
$value = $text; # $value = $text;
$rc = 1; # $rc = 1;
last; my $x = eval { $value =~ s/^\d*\.?\d+?/$text/ };
$rc = 1 if (defined ($x)); last;
} }
} }
if ($mode == 0 && $value =~ /$regexp/ && $value !~ /^[+-]?\d+$/) { if ($mode == 0 && $value =~ /$regexp/ && $value !~ /^[+-]?\d+$/) {
# my $x = eval { $value =~ s/$regexp/$text/ };
my $x = eval { $value =~ s/$regexp/$text/ }; my $x = eval { $value =~ s/$regexp/$text/ };
$rc = 1 if (defined ($x)); $rc = 1 if (defined ($x));
last; last;
} }
elsif (($mode == 1 || $value =~/^[+-]?\d+$/) && $value =~ /^$regexp$/) { elsif (($mode == 1 || $value =~/^[+-]?\d+$/) && $value =~ /^$regexp$/) {
# my $x = eval { $value =~ s/^$regexp$/$text/ };
my $x = eval { $value =~ s/^$regexp$/$text/ }; my $x = eval { $value =~ s/^$regexp$/$text/ };
$rc = 1 if (defined ($x)); $rc = 1 if (defined ($x));
last; last;
@ -1828,6 +1845,26 @@ sub HMCCU_SubstRule ($$$)
return ($rc, $value); return ($rc, $value);
} }
##################################################################
# Substitute datapoint variables in string by datapoint value.
##################################################################
sub HMCCU_SubstVariables ($$)
{
my ($clhash, $text) = @_;
# Substitute datapoint variables by value
foreach my $dp (keys %{$clhash->{hmccu}{dp}}) {
my ($chn,$dpt) = split (/\./, $dp);
if (defined ($clhash->{hmccu}{dp}{$dp}{VAL})) {
$text =~ s/\$\{$dp\}/$clhash->{hmccu}{dp}{$dp}{VAL}/g;
$text =~ s/\$\{$dpt\}/$clhash->{hmccu}{dp}{$dp}{VAL}/g;
}
}
return $text;
}
################################################################## ##################################################################
# Update all datapoint/readings of all client devices matching # Update all datapoint/readings of all client devices matching
# specified regular expression. Update will fail if device is # specified regular expression. Update will fail if device is
@ -1997,6 +2034,7 @@ sub HMCCU_UpdateClientReading ($@)
my $svalue = HMCCU_ScaleValue ($ch, $dpt, $value, 0); my $svalue = HMCCU_ScaleValue ($ch, $dpt, $value, 0);
my $fvalue = HMCCU_FormatReadingValue ($ch, $svalue); my $fvalue = HMCCU_FormatReadingValue ($ch, $svalue);
my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chn, $dpt); my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chn, $dpt);
my %calcs = HMCCU_CalculateReading ($ch, $chn, $dpt);
Log3 $name, 2, "HMCCU: $fnc device=$cn, readings=".join(',', @readings). Log3 $name, 2, "HMCCU: $fnc device=$cn, readings=".join(',', @readings).
", orgvalue=$value value=$cvalue" if ($cf =~ /trace/); ", orgvalue=$value value=$cvalue" if ($cf =~ /trace/);
@ -2004,6 +2042,9 @@ sub HMCCU_UpdateClientReading ($@)
foreach my $rn (@readings) { foreach my $rn (@readings) {
HMCCU_BulkUpdate ($ch, $rn, $value, $cvalue) if ($rn ne ''); HMCCU_BulkUpdate ($ch, $rn, $value, $cvalue) if ($rn ne '');
} }
foreach my $clcr (keys %calcs) {
HMCCU_BulkUpdate ($ch, $clcr, $calcs{$clcr}, $calcs{$clcr});
}
HMCCU_BulkUpdate ($ch, 'control', $fvalue, $cvalue) HMCCU_BulkUpdate ($ch, 'control', $fvalue, $cvalue)
if ($cd ne '' && $dpt eq $cd && $chn eq $cc); if ($cd ne '' && $dpt eq $cd && $chn eq $cc);
HMCCU_BulkUpdate ($ch, 'state', $fvalue, $cvalue) HMCCU_BulkUpdate ($ch, 'state', $fvalue, $cvalue)
@ -2011,8 +2052,8 @@ sub HMCCU_UpdateClientReading ($@)
} }
if ($ccuflags !~ /nohmstate/) { if ($ccuflags !~ /nohmstate/) {
my ($hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cn, undef); my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cn, $name, undef);
HMCCU_BulkUpdate ($ch, 'hmstate', $hms_val, $hms_val) if (defined ($hms_val)); HMCCU_BulkUpdate ($ch, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
} }
readingsEndUpdate ($ch, 1); readingsEndUpdate ($ch, 1);
@ -2841,7 +2882,7 @@ foreach (sDevice, sDevList.Split(",")) {
# and refers to an existing device or channel. # and refers to an existing device or channel.
#################################################### ####################################################
sub HMCCU_IsValidDevice ($$) sub HMCCU_IsValidDeviceOrChannel ($$)
{ {
my ($hash, $param) = @_; my ($hash, $param) = @_;
@ -2861,6 +2902,56 @@ sub HMCCU_IsValidDevice ($$)
} }
} }
####################################################
# Check if device name or address is valid
# and refers to an existing device.
####################################################
sub HMCCU_IsValidDevice ($$)
{
my ($hash, $param) = @_;
if (HMCCU_IsDevAddr ($param, 1)) {
my ($i, $a) = split (/\./, $param);
return 0 if (! exists ($hash->{hmccu}{dev}{$a}));
return $hash->{hmccu}{dev}{$a}{valid};
}
if (HMCCU_IsDevAddr ($param, 0)) {
return 0 if (! exists ($hash->{hmccu}{dev}{$param}));
return $hash->{hmccu}{dev}{$param}{valid};
}
else {
return 0 if (! exists ($hash->{hmccu}{adr}{$param}));
return $hash->{hmccu}{adr}{$param}{valid} && $hash->{hmccu}{adr}{$param}{addtype} eq 'dev';
}
}
####################################################
# Check if channel name or address is valid
# and refers to an existing channel.
####################################################
sub HMCCU_IsValidChannel ($$)
{
my ($hash, $param) = @_;
if (HMCCU_IsChnAddr ($param, 1)) {
my ($i, $a) = split (/\./, $param);
return 0 if (! exists ($hash->{hmccu}{dev}{$a}));
return $hash->{hmccu}{dev}{$a}{valid};
}
if (HMCCU_IsChnAddr ($param, 0)) {
return 0 if (! exists ($hash->{hmccu}{dev}{$param}));
return $hash->{hmccu}{dev}{$param}{valid};
}
else {
return 0 if (! exists ($hash->{hmccu}{adr}{$param}));
return $hash->{hmccu}{adr}{$param}{valid} && $hash->{hmccu}{adr}{$param}{addtype} eq 'chn';
}
}
#################################################### ####################################################
# Get CCU parameters of device or channel. Returns # Get CCU parameters of device or channel. Returns
# list containing interface, deviceaddress, name # list containing interface, deviceaddress, name
@ -3318,7 +3409,7 @@ sub HMCCU_FindIODevice ($)
next if (!exists ($ch->{TYPE})); next if (!exists ($ch->{TYPE}));
next if ($ch->{TYPE} ne 'HMCCU'); next if ($ch->{TYPE} ne 'HMCCU');
return $ch if (HMCCU_IsValidDevice ($ch, $param)); return $ch if (HMCCU_IsValidDeviceOrChannel ($ch, $param));
} }
return undef; return undef;
@ -3476,6 +3567,7 @@ sub HMCCU_GetAttrReadingFormat ($$)
###################################################################### ######################################################################
# Get attributes substitute and substexcl considering default # Get attributes substitute and substexcl considering default
# attribute ccudef-substitute defined in I/O device. # attribute ccudef-substitute defined in I/O device.
# Substitute ${xxx} by datapoint value.
###################################################################### ######################################################################
sub HMCCU_GetAttrSubstitute ($$) sub HMCCU_GetAttrSubstitute ($$)
@ -3485,9 +3577,17 @@ sub HMCCU_GetAttrSubstitute ($$)
my $clname = $clhash->{NAME}; my $clname = $clhash->{NAME};
my $ioname = $iohash->{NAME}; my $ioname = $iohash->{NAME};
my $ccuflags = AttrVal ($clname, 'ccuflags', 'null');
my $substdef = AttrVal ($ioname, 'ccudef-substitute', ''); my $substdef = AttrVal ($ioname, 'ccudef-substitute', '');
my $subst = AttrVal ($clname, 'substitute', $substdef); my $subst = AttrVal ($clname, 'substitute', $substdef);
$subst .= ";$substdef" if ($subst ne $substdef && $substdef ne ''); $subst .= ";$substdef" if ($subst ne $substdef && $substdef ne '');
Log3 $clname, 2, "HMCCU: GetAttrSubstitute: subst = $subst" if ($ccuflags =~ /trace/);
return $subst if ($subst !~ /\$\{.+\}/);
$subst = HMCCU_SubstVariables ($clhash, $subst);
Log3 $clname, 2, "HMCCU: GetAttrSubstitute: subst = $subst" if ($ccuflags =~ /trace/);
return $subst; return $subst;
} }
@ -3882,12 +3982,13 @@ sub HMCCU_UpdateSingleReading ($$$$$)
my $hmccu_hash = HMCCU_GetHash ($hash); my $hmccu_hash = HMCCU_GetHash ($hash);
return $value if (!defined ($hmccu_hash)); return $value if (!defined ($hmccu_hash));
my $ioname = $hmccu_hash->{NAME};
my $ccureadings = AttrVal ($name, 'ccureadings', 1); my $ccureadings = AttrVal ($name, 'ccureadings', 1);
my $disable = AttrVal ($name, 'disable', 0); my $disable = AttrVal ($name, 'disable', 0);
return $value if ($ccureadings == 0 || $disable == 1); return $value if ($ccureadings == 0 || $disable == 1);
my $hmccuflags = AttrVal ($hmccu_hash->{NAME}, 'ccuflags', 'null'); my $hmccuflags = AttrVal ($ioname, 'ccuflags', 'null');
my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my $readingformat = HMCCU_GetAttrReadingFormat ($hash, $hmccu_hash); my $readingformat = HMCCU_GetAttrReadingFormat ($hash, $hmccu_hash);
my $substitute = HMCCU_GetAttrSubstitute ($hash, $hmccu_hash); my $substitute = HMCCU_GetAttrSubstitute ($hash, $hmccu_hash);
@ -3898,20 +3999,24 @@ sub HMCCU_UpdateSingleReading ($$$$$)
my $svalue = HMCCU_ScaleValue ($hash, $dpt, $value, 0); my $svalue = HMCCU_ScaleValue ($hash, $dpt, $value, 0);
my $fvalue = HMCCU_FormatReadingValue ($hash, $svalue); my $fvalue = HMCCU_FormatReadingValue ($hash, $svalue);
my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chn, $dpt); my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chn, $dpt);
my %calcs = HMCCU_CalculateReading ($hash, $chn, $dpt);
readingsBeginUpdate ($hash); readingsBeginUpdate ($hash);
foreach my $rn (@$readings) { foreach my $rn (@$readings) {
HMCCU_BulkUpdate ($hash, $rn, $value, $cvalue) if ($rn ne ''); HMCCU_BulkUpdate ($hash, $rn, $value, $cvalue) if ($rn ne '');
} }
foreach my $clcr (keys %calcs) {
HMCCU_BulkUpdate ($hash, $clcr, $calcs{$clcr}, $calcs{$clcr});
}
HMCCU_BulkUpdate ($hash, 'control', $fvalue, $cvalue) HMCCU_BulkUpdate ($hash, 'control', $fvalue, $cvalue)
if ($cd ne '' && $dpt eq $cd && $chn eq $cc); if ($cd ne '' && $dpt eq $cd && $chn eq $cc);
HMCCU_BulkUpdate ($hash, 'state', $fvalue, $cvalue) HMCCU_BulkUpdate ($hash, 'state', $fvalue, $cvalue)
if ($dpt eq $sd && ($sc eq '' || $sc eq $chn)); if ($dpt eq $sd && ($sc eq '' || $sc eq $chn));
if ($hmccuflags !~ /nohmstate/) { if ($hmccuflags !~ /nohmstate/) {
my ($hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($name, undef); my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($name, $ioname, undef);
HMCCU_BulkUpdate ($hash, 'hmstate', $hms_val, $hms_val) if (defined ($hms_val)); HMCCU_BulkUpdate ($hash, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
} }
readingsEndUpdate ($hash, 1); readingsEndUpdate ($hash, 1);
@ -4322,13 +4427,14 @@ sub HMCCU_UpdateDeviceReadings ($$)
my $hmccu_hash = HMCCU_GetHash ($cl_hash); my $hmccu_hash = HMCCU_GetHash ($cl_hash);
return 0 if (!defined ($hmccu_hash)); return 0 if (!defined ($hmccu_hash));
my $ioname = $hmccu_hash->{NAME};
my $disable = AttrVal ($cn, 'disable', 0); my $disable = AttrVal ($cn, 'disable', 0);
return 0 if ($disable == 1); return 0 if ($disable == 1);
my $ccureadings = AttrVal ($cn, 'ccureadings', 1); my $ccureadings = AttrVal ($cn, 'ccureadings', 1);
return -6 if ($ccureadings == 0); return -6 if ($ccureadings == 0);
my $hmccuflags = AttrVal ($hmccu_hash->{NAME}, 'ccuflags', 'null'); my $hmccuflags = AttrVal ($ioname, 'ccuflags', 'null');
my $ccuflags = AttrVal ($cn, 'ccuflags', 'null'); my $ccuflags = AttrVal ($cn, 'ccuflags', 'null');
my $readingformat = HMCCU_GetAttrReadingFormat ($cl_hash, $hmccu_hash); my $readingformat = HMCCU_GetAttrReadingFormat ($cl_hash, $hmccu_hash);
my $substitute = HMCCU_GetAttrSubstitute ($cl_hash, $hmccu_hash); my $substitute = HMCCU_GetAttrSubstitute ($cl_hash, $hmccu_hash);
@ -4356,10 +4462,14 @@ sub HMCCU_UpdateDeviceReadings ($$)
my $svalue = HMCCU_ScaleValue ($cl_hash, $dpt, $value, 0); my $svalue = HMCCU_ScaleValue ($cl_hash, $dpt, $value, 0);
my $fvalue = HMCCU_FormatReadingValue ($cl_hash, $svalue); my $fvalue = HMCCU_FormatReadingValue ($cl_hash, $svalue);
my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chn, $dpt); my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chn, $dpt);
my %calcs = HMCCU_CalculateReading ($cl_hash, $chn, $dpt);
foreach my $rn (@readings) { foreach my $rn (@readings) {
HMCCU_BulkUpdate ($cl_hash, $rn, $value, $cvalue) if ($rn ne ''); HMCCU_BulkUpdate ($cl_hash, $rn, $value, $cvalue) if ($rn ne '');
} }
foreach my $clcr (keys %calcs) {
HMCCU_BulkUpdate ($cl_hash, $clcr, $calcs{$clcr}, $calcs{$clcr});
}
HMCCU_BulkUpdate ($cl_hash, 'control', $fvalue, $cvalue) HMCCU_BulkUpdate ($cl_hash, 'control', $fvalue, $cvalue)
if ($cd ne '' && $adrtoks[2] eq $cd && $chn eq $cc); if ($cd ne '' && $adrtoks[2] eq $cd && $chn eq $cc);
HMCCU_BulkUpdate ($cl_hash, "state", $fvalue, $cvalue) HMCCU_BulkUpdate ($cl_hash, "state", $fvalue, $cvalue)
@ -4370,8 +4480,8 @@ sub HMCCU_UpdateDeviceReadings ($$)
# Get HomeMatic state # Get HomeMatic state
if ($hmccuflags !~ /nohmstate/) { if ($hmccuflags !~ /nohmstate/) {
my ($hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cn, undef); my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cn, $ioname, undef);
HMCCU_BulkUpdate ($cl_hash, 'hmstate', $hms_val, $hms_val) if (defined ($hms_val)); HMCCU_BulkUpdate ($cl_hash, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
} }
readingsEndUpdate ($cl_hash, 1); readingsEndUpdate ($cl_hash, 1);
@ -4404,8 +4514,9 @@ sub HMCCU_GetChannel ($$)
return (-3, $result) if (!defined ($hmccu_hash));; return (-3, $result) if (!defined ($hmccu_hash));;
return (-4, $result) if ($type ne 'HMCCU' && $hash->{ccudevstate} eq 'Deleted'); return (-4, $result) if ($type ne 'HMCCU' && $hash->{ccudevstate} eq 'Deleted');
my $type_hash = $type eq 'HMCCU' ? $hmccu_hash : $hash; my $type_hash = $type eq 'HMCCU' ? $hmccu_hash : $hash;
my $ioname = $hmccu_hash->{NAME};
my $hmccuflags = AttrVal ($hmccu_hash->{NAME}, 'ccuflags', 'null'); my $hmccuflags = AttrVal ($ioname, 'ccuflags', 'null');
my $ccuget = HMCCU_GetAttribute ($hmccu_hash, $hash, 'ccuget', 'Value'); my $ccuget = HMCCU_GetAttribute ($hmccu_hash, $hash, 'ccuget', 'Value');
my $ccureadings = AttrVal ($name, 'ccureadings', 1); my $ccureadings = AttrVal ($name, 'ccureadings', 1);
my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
@ -4480,6 +4591,7 @@ foreach (sChannel, sChnList.Split(",")) {
$value = HMCCU_ScaleValue ($hash, $dpt, $dpdata[2], 0); $value = HMCCU_ScaleValue ($hash, $dpt, $dpdata[2], 0);
my $fvalue = HMCCU_FormatReadingValue ($hash, $value); my $fvalue = HMCCU_FormatReadingValue ($hash, $value);
my $cvalue = HMCCU_Substitute ($fvalue, $chnpars{$dpdata[0]}{sub}, 0, $chn, $dpt); my $cvalue = HMCCU_Substitute ($fvalue, $chnpars{$dpdata[0]}{sub}, 0, $chn, $dpt);
my %calcs = HMCCU_CalculateReading ($hash, $chn, $dpt);
my @readings = HMCCU_GetReadingName ($type_hash, $adrtoks[0], $add, $chn, $dpt, my @readings = HMCCU_GetReadingName ($type_hash, $adrtoks[0], $add, $chn, $dpt,
$dpdata[0], $readingformat); $dpdata[0], $readingformat);
@ -4490,6 +4602,10 @@ foreach (sChannel, sChnList.Split(",")) {
HMCCU_BulkUpdate ($hash, $rn, $value, $cvalue); HMCCU_BulkUpdate ($hash, $rn, $value, $cvalue);
$result .= $rn.'='.$cvalue."\n"; $result .= $rn.'='.$cvalue."\n";
} }
foreach my $clcr (keys %calcs) {
HMCCU_BulkUpdate ($hash, $clcr, $calcs{$clcr}, $calcs{$clcr});
$result .= $clcr.'='.$calcs{$clcr}."\n";
}
HMCCU_BulkUpdate ($hash, 'control', $fvalue, $cvalue) HMCCU_BulkUpdate ($hash, 'control', $fvalue, $cvalue)
if ($cd ne '' && $adrtoks[2] eq $cd && $chn eq $cc); if ($cd ne '' && $adrtoks[2] eq $cd && $chn eq $cc);
HMCCU_BulkUpdate ($hash, 'state', $fvalue, $cvalue) HMCCU_BulkUpdate ($hash, 'state', $fvalue, $cvalue)
@ -4502,8 +4618,8 @@ foreach (sChannel, sChnList.Split(",")) {
} }
if ($hmccuflags !~ /nohmstate/) { if ($hmccuflags !~ /nohmstate/) {
my ($hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($name, undef); my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($name, $ioname, undef);
HMCCU_BulkUpdate ($hash, 'hmstate', $hms_val, $hms_val) if (defined ($hms_val)); HMCCU_BulkUpdate ($hash, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
} }
readingsEndUpdate ($hash, 1) if ($type ne 'HMCCU' && $ccureadings); readingsEndUpdate ($hash, 1) if ($type ne 'HMCCU' && $ccureadings);
@ -4776,87 +4892,56 @@ sub HMCCU_QueueDeq ($)
###################################################################### ######################################################################
###################################################################### ######################################################################
# Determine Homematic state of device. # Determine HomeMatic state considering datapoint values specified
# # in attributes ccudef-hmstatevals and hmstatevals.
# Considered datapoints (sorted by priority): # Return (reading, channel, datapoint, value)
# UNREACH, ERROR.*, FAULT_REPORTING, SABOTAGE, LOWBAT/LOW_BAT
#
# Return (channelno, datapoint, value)
###################################################################### ######################################################################
sub HMCCU_GetHMState ($$) sub HMCCU_GetHMState ($$$)
{ {
my ($name, $defval) = @_; my ($name, $ioname, $defval) = @_;
my @hmstate = (undef, undef, $defval); my @hmstate = ('hmstate', undef, undef, $defval);
return @hmstate if (!exists ($defs{$name}) || !exists ($defs{$name}->{TYPE}));
my $clhash = $defs{$name}; my $clhash = $defs{$name};
my $cltype = $clhash->{TYPE}; my $cltype = $clhash->{TYPE};
return @hmstate if ($cltype ne 'HMCCUDEV' && $cltype ne 'HMCCUCHN'); return @hmstate if ($cltype ne 'HMCCUDEV' && $cltype ne 'HMCCUCHN');
my $ghmstatevals = AttrVal ($ioname, 'ccudef-hmstatevals',
'^UNREACH!(1|true):unreachable;^LOW_?BAT!(1|true):warn_battery');
my $hmstatevals = AttrVal ($name, 'hmstatevals', $ghmstatevals);
$hmstatevals .= ";".$ghmstatevals if ($hmstatevals ne $ghmstatevals);
if ($hmstatevals =~ /^=([^;]*);/) {
$hmstate[0] = $1;
$hmstatevals =~ s/^=[^;]*;//;
}
# Default hmstate is equal to state # Default hmstate is equal to state
$hmstate[2] = ReadingsVal ($name, 'state', undef) if (!defined ($defval)); $hmstate[3] = ReadingsVal ($name, 'state', undef) if (!defined ($defval));
# Check if any datapoint values are stored in device hash # Substitute variables
return @hmstate if (!exists ($clhash->{hmccu}{dp})); $hmstatevals = HMCCU_SubstVariables ($clhash, $hmstatevals);
# Priority of datapoints my @rulelist = split (";", $hmstatevals);
my @dpprio = ('UNREACH', 'ERROR', 'FAULT', 'SABOTAGE', 'LOWBAT');
# Combine datapoints: LOW_BAT => LOWBAT, ERROR.* => ERROR, FAULT.* => FAULT
my $dpsub = "^LOW_BAT:LOWBAT,^ERROR_.*:ERROR,^FAULT_REPORTING:FAULT";
my %est;
my @srules = split (",", $dpsub);
# Get substitution rules for hmstate values
my $defsub = 'LOWBAT,LOW_BAT!1:battery_low;UNREACH!1:unreachable';
my $hmstatevals = AttrVal ($name, 'hmstatevals', '');
if ($hmstatevals eq '') {
my $t = HMCCU_FindDefaults ($clhash, 0);
$hmstatevals = $t->{"hmstatevals"} if (defined ($t) && exists ($t->{"hmstatevals"}));
}
my $vlsub = $hmstatevals eq '' ? $defsub : "$hmstatevals;$defsub";
# Normalize datapoints and values
foreach my $dp (keys %{$clhash->{hmccu}{dp}}) { foreach my $dp (keys %{$clhash->{hmccu}{dp}}) {
my ($c, $d) = split (/\./, $dp); next if (!defined ($clhash->{hmccu}{dp}{$dp}{VAL}));
my $v = $clhash->{hmccu}{dp}{$dp}{VAL}; my ($chn, $dpt) = split (/\./, $dp);
my $value = $clhash->{hmccu}{dp}{$dp}{VAL};
next if (!defined ($d)); foreach my $rule (@rulelist) {
if ($d =~ /^(UNREACH|LOWBAT|LOW_BAT|ERROR.*|FAULT_REPORTING|SABOTAGE)$/) { my ($dptexpr, $subst) = split ('!', $rule, 2);
my $edp = $1; next if (!defined ($dptexpr) || !defined ($subst));
next if ($dpt !~ /$dptexpr/);
# Combine datapoints $subst =~ s/\$\{value\}/$value/g;
foreach my $r (@srules) { my ($rc, $newvalue) = HMCCU_SubstRule ($value, $subst, 0);
my ($org, $new) = split (":", $r); return ($hmstate[0], $chn, $dpt, $newvalue) if ($rc);
if ($edp =~ /$org/) {
$edp =~ s/$org/$new/;
last;
}
}
# Normalize values
$v = 1 if ($v eq 'true');
$v = 0 if ($v eq 'false');
my $n = $v;
$n = HMCCU_Substitute ($v, $vlsub, 0, undef, $d) if ($v > 0);
$est{$edp}{chn} = $c;
$est{$edp}{dpt} = $d;
$est{$edp}{val} = $v;
$est{$edp}{nvl} = $n;
}
}
# Return datapoints by priority
foreach my $e (@dpprio) {
if (exists ($est{$e}) && $est{$e}{val} > 0) {
return ($est{$e}{chn}, $est{$e}{dpt}, $est{$e}{nvl});
} }
} }
return @hmstate; return @hmstate;
} }
#################################################### ####################################################
# Aggregate readings. Valid operations are 'and', # Aggregate readings. Valid operations are 'and',
# 'or' or 'cnt'. # 'or' or 'cnt'.
@ -4949,6 +5034,60 @@ sub HMCCU_Dewpoint ($$$$)
return sprintf "%.1f", $td; return sprintf "%.1f", $td;
} }
####################################################
# Calculate special readings. Requires hash of
# client device and channel number and datapoint.
# Return readings.
####################################################
sub HMCCU_CalculateReading ($$$)
{
my ($cl_hash, $chnno, $dpt) = @_;
my $name = $cl_hash->{NAME};
my @result = ();
my $ccucalculate = AttrVal ($name, 'ccucalculate', '');
return @result if ($ccucalculate eq '');
my @calclist = split (';', $ccucalculate);
foreach my $calculation (@calclist) {
my ($valuetype, $reading, $datapoints) = split (':', $calculation);
next if (!defined ($reading));
my @dplist = defined ($datapoints) ? split (',', $datapoints) : ();
next if (@dplist > 0 && !(grep { $_ eq "$chnno.$dpt"} @dplist));
my @pars = ();
foreach my $dp (@dplist) {
if (exists ($cl_hash->{hmccu}{dp}{$dp}{VAL})) {
push @pars, $cl_hash->{hmccu}{dp}{$dp}{VAL};
}
}
if ($valuetype eq 'dewpoint') {
next if (@pars < 2);
my ($tmp, $hum) = @pars;
if ($tmp >= 0.0) {
$a = 7.5;
$b = 237.3;
}
else {
$a = 7.6;
$b = 240.7;
}
my $sdd = 6.1078*(10.0**(($a*$tmp)/($b+$tmp)));
my $dd = $hum/100.0*$sdd;
my $v = log($dd/6.1078)/log(10.0);
my $td = $b*$v/($a-$v);
push (@result, $reading, (sprintf "%.1f", $td));
}
}
return @result;
}
#################################################### ####################################################
# Encode command string for e-paper display # Encode command string for e-paper display
# #
@ -5605,6 +5744,9 @@ sub HMCCU_CCURPC_GetEventsCB ($$)
Example: Find devices with low batteries<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/> name=battery,filter:name=.*,read:(LOWBAT|LOW_BAT),if:any=yes,else:no,prefix:batt_,coll:NAME<br/>
</li><br/> </li><br/>
<li><b>ccudef-hmstatevals &lt;subst-rule[;...]&gt;</b><br/>
Set global rules for calculation of reading hmstate.
</li><br/>
<li><b>ccudef-readingfilter &lt;filter-rule[;...]&gt;</b><br/> <li><b>ccudef-readingfilter &lt;filter-rule[;...]&gt;</b><br/>
Set global reading/datapoint filter. This filter is added to the filter specified by Set global reading/datapoint filter. This filter is added to the filter specified by
client device attribute 'ccureadingfilter'. client device attribute 'ccureadingfilter'.

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 3.8 # Version 3.9
# #
# (c) 2016 zap (zap01 <at> t-online <dot> de) # (c) 2016 zap (zap01 <at> t-online <dot> de)
# #
@ -33,6 +33,7 @@
# get <name> update # get <name> update
# #
# attr <name> ccuackstate { 0 | 1 } # attr <name> ccuackstate { 0 | 1 }
# attr <name> ccucalculate <value>:<reading>[:<dp-list>][...]
# attr <name> ccuflags { altread, nochn0, trace } # attr <name> ccuflags { altread, nochn0, trace }
# attr <name> ccuget { State | Value } # attr <name> ccuget { State | Value }
# attr <name> ccureadings { 0 | 1 } # attr <name> ccureadings { 0 | 1 }
@ -80,7 +81,7 @@ sub HMCCUCHN_Initialize ($)
$hash->{AttrFn} = "HMCCUCHN_Attr"; $hash->{AttrFn} = "HMCCUCHN_Attr";
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
$hash->{AttrList} = "IODev ccuackstate:0,1 ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname ccureadings:0,1 ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint disable:0,1 hmstatevals statedatapoint statevals substitute:textField-long substexcl stripnumber ". $readingFnAttributes; $hash->{AttrList} = "IODev ccuackstate:0,1 ccucalculate ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname 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 ". $readingFnAttributes;
} }
################################################## ##################################################
@ -109,7 +110,7 @@ sub HMCCUCHN_Define ($@)
return "Cannot detect IO device" if (!defined ($hmccu_hash)); return "Cannot detect IO device" if (!defined ($hmccu_hash));
return "Invalid or unknown CCU channel name or address" return "Invalid or unknown CCU channel name or address"
if (! HMCCU_IsValidDevice ($hmccu_hash, $devspec)); if (! HMCCU_IsValidChannel ($hmccu_hash, $devspec));
my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec); my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec);
return "Invalid or unknown CCU device name or address" if (!defined ($da)); return "Invalid or unknown CCU device name or address" if (!defined ($da));
@ -760,9 +761,14 @@ sub HMCCUCHN_SetError ($$)
If set to 1 state will be set to result of command (i.e. 'OK'). Otherwise state is only If set to 1 state will be set to result of command (i.e. 'OK'). Otherwise state is only
updated if value of state datapoint has changed. updated if value of state datapoint has changed.
</li><br/> </li><br/>
<li><b>ccuflags {altread, nochn0, trace}</b><br/> <li><b>ccucalculate &lt;value&gt;:&lt;reading&gt;[:&lt;dp-list&gt;[;...]</b><br/>
Calculate special values like dewpoint based on datapoints specified in
<i>dp-list</i>. The result is stored in <i>reading</i>. The following <i>values</i>
are supported:<br/>
dewpoint = calculate dewpoint, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;
</li><br/>
<li><b>ccuflags {nochn0, trace}</b><br/>
Control behaviour of device:<br/> Control behaviour of device:<br/>
altread: Create additional CUL_HM style readings.<br/>
nochn0: Prevent update of status channel 0 datapoints / readings.<br/> nochn0: Prevent update of status channel 0 datapoints / readings.<br/>
trace: Write log file information for operations related to this device. trace: Write log file information for operations related to this device.
</li><br/> </li><br/>
@ -842,11 +848,25 @@ sub HMCCUCHN_SetError ($$)
Disable client device. Disable client device.
</li><br/> </li><br/>
<li><b>hmstatevals &lt;subst-rule&gt;[;...]</b><br/> <li><b>hmstatevals &lt;subst-rule&gt;[;...]</b><br/>
Define substitution rules for datapoint values stored in reading 'hmstate'. Parameter Define building rules and substitutions for reading hmstate. Syntax of <i>subst-rule</i>
<i>subst-rule</i> is equal to attribute 'substitute'. Default substitution rule is is<br/>
LOWBAT,LOW_BAT!1:battery_low;UNREACH!1:unreachable. The substitution rule must [=&lt;reading&gt;;]&lt;datapoint-expr&gt;!&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
contain only error conditions because 'hmstate' contains only error conditions or <br/><br/>
the 'state' value. The syntax is almost the same as of attribute 'substitute', except there's no channel
specification possible for datapoint and parameter <i>datapoint-expr</i> is a regular
expression.<br/>
The value of the I/O device attribute 'ccudef-hmstatevals' is appended to the value of
this attribute. The default value of 'ccudef-hmstatevals' is
'^UNREACH!(1|true):unreachable;LOW_?BAT!(1|true):warn_battery'.
Normally one should not specify a substitution rule for the "good" value of an error
datapoint (i.e. 0 for UNREACH). If none of the rules is matching, reading 'hmstate' is set
to value of reading 'state'.<br/>
Parameter <i>text</i> can contain variables in format ${<i>varname</i>}. The variable
$value is substituted by the original datapoint value. All other variables must match
with a valid datapoint name or a combination of channel number and datapoint name
seperated by a '.'.<br/>
Optionally the name of the HomeMatic state reading can be specified at the beginning of
the attribute in format =&lt;reading&gt;;. The default reading name is 'hmstate'.
</li><br/> </li><br/>
<li><b>statedatapoint &lt;datapoint&gt;</b><br/> <li><b>statedatapoint &lt;datapoint&gt;</b><br/>
Set state datapoint used by some commands like 'set devstate'. Set state datapoint used by some commands like 'set devstate'.
@ -877,8 +897,17 @@ sub HMCCUCHN_SetError ($$)
</li><br/> </li><br/>
<li><b>substitute &lt;subst-rule&gt;[;...]</b><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/> Define substitutions for datapoint/reading values. Syntax of <i>subst-rule</i> is<br/><br/>
[[&lt;channelno.&gt;]&lt;datapoint&gt;[,...]!]&lt;{#n1-m1|regexp1}&gt;:&lt;text1&gt;[,...] [[&lt;channelno.&gt;]&lt;datapoint&gt;[,...]!]&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
<br/> <br/>
Parameter text can contain variables in format ${<i>varname</i>}. The variable $value is
substituted by the original datapoint value. All other variables must match with a valid
datapoint name or a combination of channel number and datapoint name seperated by a '.'.
<br/><br/>
Example: Substitute the value of datapoint TEMPERATURE by the string
'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>
If rule expression starts with a hash sign a numeric datapoint value is substituted if 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. it fits in the number range n &lt;= value &lt;= m.
<br/><br/> <br/><br/>

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 3.8 # Version 3.9
# #
# (c) 2016 zap (zap01 <at> t-online <dot> de) # (c) 2016 zap (zap01 <at> t-online <dot> de)
# #
@ -34,6 +34,7 @@
# get <name> update # get <name> update
# #
# attr <name> ccuackstate { 0 | 1 } # attr <name> ccuackstate { 0 | 1 }
# attr <name> ccucalculate <value>:<reading>[:<dp-list>][...]
# attr <name> ccuflags { altread, nochn0, trace } # attr <name> ccuflags { altread, nochn0, trace }
# attr <name> ccuget { State | Value } # attr <name> ccuget { State | Value }
# attr <name> ccureadings { 0 | 1 } # attr <name> ccureadings { 0 | 1 }
@ -83,7 +84,7 @@ sub HMCCUDEV_Initialize ($)
$hash->{AttrFn} = "HMCCUDEV_Attr"; $hash->{AttrFn} = "HMCCUDEV_Attr";
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
$hash->{AttrList} = "IODev ccuackstate:0,1 ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter:textField-long ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname ccureadings:0,1 ccuget:State,Value ccuscaleval ccuverify:0,1,2 disable:0,1 hmstatevals statevals substexcl substitute:textField-long statechannel statedatapoint controldatapoint stripnumber ". $readingFnAttributes; $hash->{AttrList} = "IODev ccuackstate:0,1 ccucalculate ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter:textField-long ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname 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 ". $readingFnAttributes;
} }
##################################### #####################################
@ -134,6 +135,9 @@ sub HMCCUDEV_Define ($@)
$hmccu_hash = HMCCU_FindIODevice ($devspec) if (!defined ($hmccu_hash)); $hmccu_hash = HMCCU_FindIODevice ($devspec) if (!defined ($hmccu_hash));
return "Cannot detect IO device" if (!defined ($hmccu_hash)); return "Cannot detect IO device" if (!defined ($hmccu_hash));
return "Invalid or unknown CCU device name or address"
if (! HMCCU_IsValidDevice ($hmccu_hash, $devspec));
my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec); my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec);
return "Invalid or unknown CCU device name or address: $devspec" if (!defined ($da)); return "Invalid or unknown CCU device name or address: $devspec" if (!defined ($da));
@ -886,7 +890,14 @@ sub HMCCUDEV_Get ($@)
<li><b>ccuackstate {<u>0</u> | 1}</b><br/> <li><b>ccuackstate {<u>0</u> | 1}</b><br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a> <a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/> </li><br/>
<li><b>ccuflags {altread, nochn0, trace}</b><br/> <li><b>ccucalculate &lt;value&gt;:&lt;reading&gt;[:&lt;dp-list&gt;[;...]</b><br/>
Calculate special values like dewpoint based on datapoints specified in
<i>dp-list</i>. Datapoints in <i>dp-list</i> must be specified in format
&lt;channelno&gt;.&lt;datapoint&gt;. The result is stored in <i>reading</i>.
The following <i>values</i> are supported:<br/>
dewpoint = calculate dewpoint, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;
</li><br/>
<li><b>ccuflags {nochn0, trace}</b><br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a> <a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/> </li><br/>
<li><b>ccuget {State | <u>Value</u>}</b><br/> <li><b>ccuget {State | <u>Value</u>}</b><br/>

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 3.8 # Version 3.9
# #
# Configuration parameters for Homematic devices. # Configuration parameters for Homematic devices.
# #
@ -181,6 +181,13 @@ use vars qw(%HMCCU_DEV_DEFAULTS);
statedatapoint => "MOTION", statedatapoint => "MOTION",
substitute => "MOTION!(0|false):no,(1|true):yes;ERROR!0:no,1:sabotage" substitute => "MOTION!(0|false):no,(1|true):yes;ERROR!0:no,1:sabotage"
}, },
"HmIP-SMI" => {
_description => "Bewegungsmelder",
_channels => "1",
ccureadingfilter => "(ILLUMINATION|MOTION)",
statedatapoint => "MOTION",
substitute => "MOTION!(0|false):no,(1|true):yes"
},
"HM-Sen-LI-O" => { "HM-Sen-LI-O" => {
_description => "Lichtsensor", _description => "Lichtsensor",
_channels => "1", _channels => "1",
@ -248,7 +255,7 @@ use vars qw(%HMCCU_DEV_DEFAULTS);
%HMCCU_DEV_DEFAULTS = ( %HMCCU_DEV_DEFAULTS = (
"CCU2" => { "CCU2" => {
_description => "HomeMatic CCU2", _description => "HomeMatic CCU2",
"ccudef-readingfilter" => '.*', "ccudef-readingfilter" => '^(LOW_?BAT|UNREACH)$',
"ccudef-readingformat" => 'datapoint', "ccudef-readingformat" => 'datapoint',
"ccudef-readingname" => '^(.+\.)?AES_KEY$:sign;^(.+\.)?LOW_?BAT$:battery;^(.+\.)?BATTERY_STATE$:batteryLevel;^(.+\.)?UNREACH$:Activity;^(.+\.)?TEMPERATURE$:+temperature;^(.+\.)?SET_TEMPERATURE$:+desired-temp;^(.+\.)?HUMIDITY$:+humidity;^(.+\.)?LEVEL$:+pct;^(.+\.)?CONTROL_MODE$:+controlMode', "ccudef-readingname" => '^(.+\.)?AES_KEY$:sign;^(.+\.)?LOW_?BAT$:battery;^(.+\.)?BATTERY_STATE$:batteryLevel;^(.+\.)?UNREACH$:Activity;^(.+\.)?TEMPERATURE$:+temperature;^(.+\.)?SET_TEMPERATURE$:+desired-temp;^(.+\.)?HUMIDITY$:+humidity;^(.+\.)?LEVEL$:+pct;^(.+\.)?CONTROL_MODE$:+controlMode',
"ccudef-substitute" => 'AES_KEY!(0|false):off,(1|true):on;LOWBAT,LOW_BAT!(0|false):ok,(1|true):low;UNREACH!(0|false):alive,(1|true):dead;MOTION!(0|false):noMotion,(1|true):motion;DIRECTION!0:stop,1:up,2:down,3:undefined;WORKING!0:false,1:true;INHIBIT!(0|false):unlocked,(1|true):locked' "ccudef-substitute" => 'AES_KEY!(0|false):off,(1|true):on;LOWBAT,LOW_BAT!(0|false):ok,(1|true):low;UNREACH!(0|false):alive,(1|true):dead;MOTION!(0|false):noMotion,(1|true):motion;DIRECTION!0:stop,1:up,2:down,3:undefined;WORKING!0:false,1:true;INHIBIT!(0|false):unlocked,(1|true):locked'
@ -487,6 +494,12 @@ use vars qw(%HMCCU_DEV_DEFAULTS);
statedatapoint => "1.MOTION", statedatapoint => "1.MOTION",
substitute => "MOTION!(0|false):no,(1|true):yes;ERROR!0:no,1:sabotage" substitute => "MOTION!(0|false):no,(1|true):yes;ERROR!0:no,1:sabotage"
}, },
"HmIP-SMI" => {
_description => "Bewegungsmelder",
ccureadingfilter => "(ILLUMINATION|MOTION)",
statedatapoint => "1.MOTION",
substitute => "MOTION!(0|false):no,(1|true):yes"
},
"HM-Sen-LI-O" => { "HM-Sen-LI-O" => {
_description => "Lichtsensor", _description => "Lichtsensor",
ccureadingfilter => "LUX", ccureadingfilter => "LUX",