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

HMCCU: Fixed several bugs in version 4.4 beta

git-svn-id: https://svn.fhem.de/fhem/trunk@22145 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2020-06-09 11:30:45 +00:00
parent 4bb28cb1fc
commit c64cdf21da
5 changed files with 320 additions and 351 deletions

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCU.pm 18745 2019-02-26 17:33:23Z zap $
#
# Version 4.4.034
# Version 4.4.038
#
# Module for communication between FHEM and Homematic CCU2/3.
#
@ -55,7 +55,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
my $HMCCU_VERSION = '4.4.034';
my $HMCCU_VERSION = '4.4.038';
# Timeout for CCU requests
my $HMCCU_TIMEOUT_REQUEST = 4;
@ -231,7 +231,7 @@ sub HMCCU_GetAttribute ($$$$);
sub HMCCU_GetFlags ($);
sub HMCCU_GetAttrReadingFormat ($$);
sub HMCCU_GetAttrStripNumber ($);
sub HMCCU_GetAttrSubstitute ($$);
sub HMCCU_GetAttrSubstitute ($;$);
sub HMCCU_IODeviceStates ();
sub HMCCU_IsFlag ($$);
@ -245,6 +245,7 @@ sub HMCCU_CreateDevice ($$$$$);
sub HMCCU_DeleteDevice ($);
sub HMCCU_DeviceDescToStr ($$);
sub HMCCU_ExecuteRoleCommand ($@);
sub HMCCU_ExecuteGetParameterCommand ($$$$);
sub HMCCU_DisplayWeekProgram ($;$);
sub HMCCU_ExistsDeviceModel ($$$;$);
sub HMCCU_FindParamDef ($$$);
@ -456,11 +457,7 @@ sub HMCCU_Define ($$)
InternalTimer (gettimeofday()+$hash->{hmccu}{ccu}{delay}, "HMCCU_InitDevice", $hash);
}
$hash->{hmccu}{evtime} = 0;
$hash->{hmccu}{evtimeout} = 0;
$hash->{hmccu}{updatetime} = 0;
$hash->{hmccu}{rpccount} = 0;
$hash->{hmccu}{defaults} = 0;
$hash->{hmccu}{$_} = 0 for ('evtime', 'evtimeout', 'updatetime', 'rpccount', 'defaults');
HMCCU_UpdateReadings ($hash, { 'state' => 'Initialized', 'rpcstate' => 'inactive' });
@ -917,13 +914,13 @@ sub HMCCU_SetDefaultsTemplate ($$)
my ($hash, $template) = @_;
my $name = $hash->{NAME};
$hash->{hmccu}{defaults} = 1;
$hash->{hmccu}{semDefaults} = 1;
foreach my $a (keys %{$template}) {
next if ($a =~ /^_/);
my $v = $template->{$a};
CommandAttr (undef, "$name $a $v");
}
$hash->{hmccu}{defaults} = 0;
$hash->{hmccu}{semDefaults} = 0;
}
######################################################################
@ -1286,7 +1283,7 @@ sub HMCCU_Set ($@)
my $name = shift @$a;
my $opt = shift @$a // return 'No set command specified';
my $options = "var clear delete execute hmscript cleardefaults:noArg datapoint defaults:noArg ".
"importdefaults rpcregister:all rpcserver:on,off,restart ackmessages:noArg authentication ".
"importdefaults rpcregister:all rpcserver:on,off ackmessages:noArg authentication ".
"prgActivate prgDeactivate";
$opt = lc($opt);
@ -1309,7 +1306,7 @@ sub HMCCU_Set ($@)
my $ccureadings = AttrVal ($name, "ccureadings", $ccuflags =~ /noReadings/ ? 0 : 1);
my $ccureqtimeout = AttrVal ($name, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $readingformat = HMCCU_GetAttrReadingFormat ($hash, $hash);
my $substitute = HMCCU_GetAttrSubstitute ($hash, $hash);
my $substitute = HMCCU_GetAttrSubstitute ($hash);
my $result;
# Add program names to command execute
@ -1570,28 +1567,24 @@ sub HMCCU_Set ($@)
my $res = AnalyzeCommandChain (undef, "set $rpcdev register");
$result .= $res if (defined($res));
}
return HMCCU_SetState ($hash, "OK", $result);
return HMCCU_SetState ($hash, 'OK', $result);
}
elsif ($opt eq 'rpcserver') {
my $action = shift @$a;
$action = shift @$a if ($action eq $opt);
$usage = "Usage: set $name $opt {'on'|'off'|'restart'}";
# $action = shift @$a if ($action eq $opt);
$usage = "Usage: set $name $opt {'on'|'off'}";
return HMCCU_SetError ($hash, $usage)
if (!defined($action) || $action !~ /^(on|off|restart)$/);
if (!defined($action) || $action !~ /^(on|off)$/);
if ($action eq 'on') {
return HMCCU_SetError ($hash, 'Start of RPC server failed')
if (!HMCCU_StartExtRPCServer ($hash));
}
elsif ($action eq 'off') {
else {
return HMCCU_SetError ($hash, 'Stop of RPC server failed')
if (!HMCCU_StopExtRPCServer ($hash));
}
elsif ($action eq 'restart') {
return "HMCCU: No RPC server running" if (!HMCCU_IsRPCServerRunning ($hash));
return HMCCU_SetError ($hash, 'HMCCU: restart of RPC server not supported');
}
return HMCCU_SetState ($hash, 'OK');
}
@ -2113,9 +2106,9 @@ sub HMCCU_ParseObject ($$$)
# 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
# [N:]{Channel-No[,Channel-No]|Channel-Name-Expr}!Datapoint-Expr
# or
# [N:][Channel-Number.]Datapoint-Expr
# [N:][Channel-No[,Channel-No].]Datapoint-Expr
# Multiple filter rules must be separated by ;
######################################################################
@ -2155,6 +2148,7 @@ sub HMCCU_FilterReading ($$$;$)
foreach my $r (split (';', $rf)) {
my $rm = 1;
my $cn = '';
my $cnl = '';
# Negative filter
if ($r =~ /^N:/) {
@ -2164,9 +2158,10 @@ sub HMCCU_FilterReading ($$$;$)
# Get filter criteria
my ($c, $f) = split ("!", $r);
if (defined ($f)) {
if (defined($f)) {
next if ($c eq '' || $chnnam eq '' || $chnnum eq '');
$cn = $c if ($c =~ /^([0-9]{1,2})$/);
$cnl = $c if ($c =~ /^[0-9]{1,2}(,[0-9]{1,2})+$/);
}
else {
$c = '';
@ -2174,18 +2169,24 @@ sub HMCCU_FilterReading ($$$;$)
$cn = $1;
$f = $2;
}
elsif ($r =~ /^[0-9]{1,2}(,[0-9]{1,2})+\.(.+)$/) {
($cnl, $f) = split /\./, $r, 2;
}
else {
$cn = '';
$f = $r;
}
}
HMCCU_Trace ($hash, 2, " check rm=$rm f=$f cn=$cn c=$c");
$cnl = ",$cnl," if ($cnl ne '');
HMCCU_Trace ($hash, 2, " check rm=$rm f=$f cn=$cn cnl=$cnl c=$c");
# Positive filter
return 1 if (
$rm && (
(
($cn ne '' && "$chnnum" eq "$cn") ||
($cnl ne '' && $cnl =~ /,$chnnum,/) ||
($c ne '' && $chnnam =~ /$c/) ||
($cn eq '' && $c eq '') ||
($chnnum eq 'd')
@ -2659,23 +2660,19 @@ sub HMCCU_Substitute ($$$$$;$$)
my $substrule = '';
my $ioHash;
my $rc = 0;
my $newvalue;
if (defined($hashOrRule)) {
if (ref($hashOrRule) eq 'HASH') {
$ioHash = HMCCU_GetHash ($hashOrRule);
my $substitute = HMCCU_GetAttrSubstitute ($hashOrRule, $ioHash)
if (defined($ioHash));
$substrule = HMCCU_GetAttrSubstitute ($hashOrRule, $ioHash);
}
else {
$substrule = $hashOrRule;
}
}
my $rc = 0;
my $newvalue;
# return $value if (!defined ($substrule) || $substrule eq '');
# Remove channel number from datapoint if specified
if ($dpt =~ /^([0-9]{1,2})\.(.+)$/) {
($chn, $dpt) = ($1, $2);
@ -2699,7 +2696,7 @@ sub HMCCU_Substitute ($$$$$;$$)
}
if ($d eq $dpt && ($c == -1 || !defined($chn) || $c == $chn)) {
($rc, $newvalue) = HMCCU_SubstRule ($value, $ruletoks[1], $mode);
return $newvalue;
return $newvalue if ($rc == 1);
}
}
}
@ -2714,6 +2711,17 @@ sub HMCCU_Substitute ($$$$$;$$)
# Original value not modified by rules. Use default conversion depending on type/role
# Default conversion can be overriden by attribute ccudef-substitute in I/O device
# Substitute by rules defined in CONVERSIONS table
if (!defined($type) || $type eq '') {
$type = defined($devDesc) && defined($devDesc->{INDEX}) ? $devDesc->{TYPE} : 'DEFAULT';
}
if (exists($HMCCU_CONVERSIONS->{$type}{$dpt}{$value})) {
return $HMCCU_CONVERSIONS->{$type}{$dpt}{$value};
}
elsif (exists($HMCCU_CONVERSIONS->{DEFAULT}{$dpt}{$value})) {
return $HMCCU_CONVERSIONS->{DEFAULT}{$dpt}{$value};
}
# Substitute enumerations
if (defined($devDesc) && defined($ioHash)) {
my $paramDef = HMCCU_GetParamDef ($ioHash, $devDesc, 'VALUES', $dpt);
@ -2731,18 +2739,6 @@ sub HMCCU_Substitute ($$$$$;$$)
}
}
}
if ((!defined($type) || $type eq '') && defined($devDesc) && defined($devDesc->{INDEX})) {
$type = $devDesc->{TYPE};
}
$type = 'DEFAULT' if (!defined($type) || $type eq '');
if (exists($HMCCU_CONVERSIONS->{$type}{$dpt}{$value})) {
return $HMCCU_CONVERSIONS->{$type}{$dpt}{$value};
}
elsif (exists($HMCCU_CONVERSIONS->{DEFAULT}{$dpt}{$value})) {
return $HMCCU_CONVERSIONS->{DEFAULT}{$dpt}{$value};
}
return $value;
}
@ -3376,7 +3372,7 @@ sub HMCCU_GetChannelRole ($;$)
my ($clHash, $chnNo) = @_;
return '' if (!defined($clHash->{hmccu}{role}) || $clHash->{hmccu}{role} eq '');
if (!defined($chnNo)) {
if ($clHash->{TYPE} eq 'HMCCUCHN') {
my ($ad, $cc) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
@ -3407,17 +3403,23 @@ sub HMCCU_GetDeviceConfig ($)
my ($ioHash) = @_;
my ($cDev, $cPar, $cLnk) = (0, 0, 0);
my $c = 0;
foreach my $iface (keys %{$ioHash->{hmccu}{interfaces}}) {
# next if ($ioHash->{hmccu}{interfaces}{$iface}{type} eq 'B');
if (exists($ioHash->{hmccu}{interfaces}{$iface}{device})) {
my $rpcHash = $defs{$ioHash->{hmccu}{interfaces}{$iface}{device}};
HMCCU_Log ($ioHash, 2, "Reading Device Descriptions for interface $iface");
$cDev += HMCCURPCPROC_GetDeviceDesc ($rpcHash);
$c = HMCCURPCPROC_GetDeviceDesc ($rpcHash);
HMCCU_Log ($ioHash, 2, "Read $c Device Descriptions for interface $iface");
$cDev += $c;
HMCCU_Log ($ioHash, 2, "Reading Paramset Descriptions for interface $iface");
$cPar += HMCCURPCPROC_GetParamsetDesc ($rpcHash);
$c = HMCCURPCPROC_GetParamsetDesc ($rpcHash);
HMCCU_Log ($ioHash, 2, "Read $c Paramset Descriptions for interface $iface");
$cPar += $c;
HMCCU_Log ($ioHash, 2, "Reading Peer Descriptions for interface $iface");
$cLnk += HMCCURPCPROC_GetPeers ($rpcHash);
$c = HMCCURPCPROC_GetPeers ($rpcHash);
HMCCU_Log ($ioHash, 2, "Read $c Peer Descriptions for interface $iface");
$cLnk += $c;
}
else {
HMCCU_Log ($ioHash, 2, "No RPC device found for interface $iface. Can't read device config.");
@ -4276,7 +4278,7 @@ sub HMCCU_RefreshReadings ($)
{
my ($clHash) = @_;
return if ($clHash->{hmccu}{defaults} == 1);
return if ($clHash->{hmccu}{semDefaults} == 1);
my $ioHash = HMCCU_GetHash ($clHash) // return;
@ -4314,12 +4316,21 @@ sub HMCCU_UpdateInternalValues ($$$$$)
my %weekDay = ('SUNDAY', 0, 'MONDAY', 1, 'TUESDAY', 2, 'WEDNESDAY', 3,
'THURSDAY', 4, 'FRIDAY', 5, 'SATURDAY', 6);
my $weekDayExp = join('|', keys %weekDay);
# Store time/value tables
if ($type eq 'SVAL' && $chkey =~ /^[0-9d]+\.P([0-9])_([A-Z]+)_([A-Z]+)_([0-9]+)$/) {
my ($prog, $valName, $day, $time) = ($1, $2, $3, $4);
if (exists($weekDay{$day})) {
$ch->{hmccu}{tt}{$prog}{$valName}{$weekDay{$day}}{$time} = $value;
if ($type eq 'SVAL') {
if ($chkey =~ /^[0-9d]+\.P([0-9])_([A-Z]+)_($weekDayExp)_([0-9]+)$/) {
my ($prog, $valName, $day, $time) = ($1, $2, $3, $4);
if (exists($weekDay{$day})) {
$ch->{hmccu}{tt}{$prog}{$valName}{$weekDay{$day}}{$time} = $value;
}
}
elsif ($chkey =~ /^[0-9d]+\.([A-Z]+)_($weekDayExp)_([0-9]+)$/) {
my ($valName, $day, $time) = ($1, $2, $3);
if (exists($weekDay{$day})) {
$ch->{hmccu}{tt}{1}{$valName}{$weekDay{$day}}{$time} = $value;
}
}
}
@ -6126,14 +6137,14 @@ sub HMCCU_SetDefaultAttributes ($;$)
my ($clHash, $parRef) = @_;
my $clName = $clHash->{NAME};
$parRef //= { mode => 'update', role => undef, ctrlChn => '' };
$parRef //= { mode => 'update', role => undef, ctrlChn => undef };
my $role = $parRef->{role} // HMCCU_GetChannelRole ($clHash, $parRef->{ctrlChn});
if ($role ne '' && exists($HMCCU_ATTR->{$role})) {
HMCCU_Log ($clHash, 2, "Default attributes found for role $role");
$clHash->{hmccu}{defaults} = 1;
$clHash->{hmccu}{semDefaults} = 1;
if ($parRef->{mode} eq 'reset') {
my @removeAttr = ('ccureadingname', 'ccuscaleval', 'eventMap', 'substexcl',
my @removeAttr = ('ccureadingname', 'ccuscaleval', 'eventMap',
'substitute', 'webCmd', 'widgetOverride'
);
foreach my $a (@removeAttr) {
@ -6143,10 +6154,11 @@ sub HMCCU_SetDefaultAttributes ($;$)
foreach my $a (keys %{$HMCCU_ATTR->{$role}}) {
CommandAttr (undef, "$clName $a ".$HMCCU_ATTR->{$role}{$a});
}
$clHash->{hmccu}{defaults} = 0;
$clHash->{hmccu}{semDefaults} = 0;
return 1;
}
else {
HMCCU_Log ($clHash, 2, "Cannot detect control channel role of $clName");
return 0;
}
}
@ -6319,8 +6331,13 @@ sub HMCCU_UpdateRoleCommands ($$;$)
elsif ($parTypes[0] == 0 && $parTypes[1] == 0) {
$cmdDef .= ':noArg';
}
$clHash->{hmccu}{roleCmds}{$cmd}{channel} = $cmdChn;
if (exists($clHash->{hmccu}{roleCmds}{$cmd}{channel})) {
$clHash->{hmccu}{roleCmds}{$cmd}{channel} = '?';
}
else {
$clHash->{hmccu}{roleCmds}{$cmd}{channel} = $cmdChn;
}
$clHash->{hmccu}{roleCmds}{$cmd}{usage} = $usage;
$clHash->{hmccu}{roleCmds}{$cmd}{subcount} = $cnt;
push @cmdList, $cmdDef;
@ -6338,16 +6355,21 @@ sub HMCCU_UpdateRoleCommands ($$;$)
sub HMCCU_ExecuteRoleCommand ($@)
{
my ($ioHash, $clHash, $command, $a, $h) = @_;
my ($ioHash, $clHash, $command, $cc, $a, $h) = @_;
my $rc;
my %dpval;
my %cfval;
my ($devAddr, undef) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
my $usage = $clHash->{hmccu}{roleCmds}{$command}{usage};
my $channel = $clHash->{hmccu}{roleCmds}{$command}{channel};
my $chnAddr = "$devAddr:$channel";
my $c = 0;
my $channel = $clHash->{hmccu}{roleCmds}{$command}{channel};
if ("$channel" eq '?') {
return HMCCU_SetError ($clHash, -12) if ($cc eq '');
$channel = $cc;
}
my $chnAddr = "$devAddr:$channel";
foreach my $cmdNo (sort keys %{$clHash->{hmccu}{roleCmds}{$command}{subcmd}}) {
my $cmd = $clHash->{hmccu}{roleCmds}{$command}{subcmd}{$cmdNo};
@ -6413,6 +6435,106 @@ sub HMCCU_ExecuteRoleCommand ($@)
return HMCCU_SetError ($clHash, "Command $command not executed");
}
######################################################################
# Execute toggle command
######################################################################
sub HMCCU_ExecuteToggleCommand ($@)
{
my ($clHash, $cc, $cd) = @_;
# Get state values related to control channel and datapoint
my $stateVals = HMCCU_GetStateValues ($clHash, $cd, $cc);
my %stateCmds = split (/[:,]/, $stateVals);
my @states = keys %stateCmds;
my $ccuif = $clHash->{ccuif};
my ($devAddr, undef) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
my $stc = scalar(@states);
return HMCCU_SetError ($clHash, -15) if ($stc == 0);
my $curState = defined($clHash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ?
$clHash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0];
my $newState = '';
my $st = 0;
while ($st < $stc) {
if ($states[$st] eq $curState ) {
$newState = ($st == $stc-1) ? $states[0] : $states[$st+1];
last;
}
$st++;
}
return HMCCU_SetError ($clHash, "Current device state doesn't match any state value")
if ($newState eq '');
my $rc = HMCCU_SetMultipleDatapoints ($clHash,
{ "001.$ccuif.$devAddr:$cc.$cd" => $stateCmds{$newState} }
);
return HMCCU_SetError ($clHash, HMCCU_Min(0, $rc))
}
######################################################################
# Execute commands to fetch device parameters
######################################################################
sub HMCCU_ExecuteGetParameterCommand ($$$$)
{
my ($ioHash, $clHash, $command, $addList) = @_;
my %parSets = ('config' => 'MASTER,LINK', 'values' => 'VALUES', 'update' => 'VALUES,MASTER,LINK');
my $defParamset = $parSets{$command};
my %objects;
foreach my $a (@$addList) {
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $a, $clHash->{ccuif});
return HMCCU_SetError ($clHash, "Can't get device description") if (!defined($devDesc));
my $paramset = $defParamset eq '' ? $devDesc->{PARAMSETS} : $defParamset;
my ($da, $dc) = HMCCU_SplitChnAddr ($a);
$dc = 'd' if ($dc eq '');
foreach my $ps (split (',', $paramset)) {
next if ($devDesc->{PARAMSETS} !~ /$ps/);
if ($ps eq 'LINK') {
foreach my $rcv (HMCCU_GetReceivers ($ioHash, $a, $clHash->{ccuif})) {
my ($rc, $result) = HMCCU_RPCRequest ($clHash, 'getRawParamset', $a, $rcv, undef);
next if ($rc < 0);
foreach my $p (keys %$result) { $objects{$da}{$dc}{"LINK.$rcv"}{$p} = $result->{$p}; }
}
}
else {
my ($rc, $result) = HMCCU_RPCRequest ($clHash, 'getRawParamset', $a, $ps, undef);
if ($rc >= 0) {
foreach my $p (keys %$result) { $objects{$da}{$dc}{$ps}{$p} = $result->{$p}; }
}
}
}
}
my $res = '';
if (scalar(keys %objects) > 0) {
my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $clHash, \%objects);
if (defined($convRes)) {
foreach my $da (sort keys %$convRes) {
$res .= "Device $da\n";
foreach my $dc (sort keys %{$convRes->{$da}}) {
foreach my $ps (sort keys %{$convRes->{$da}{$dc}}) {
$res .= " Channel $dc [$ps]\n".
join ("\n", map {
" ".$_.' = '.$convRes->{$da}{$dc}{$ps}{$_}
} sort keys %{$convRes->{$da}{$dc}{$ps}})."\n";
}
}
}
}
}
return $res eq '' ? 'No data found' : $res;
}
######################################################################
# Get week program(s) as html table
######################################################################
@ -6432,10 +6554,9 @@ sub HMCCU_DisplayWeekProgram ($;$)
$s .= '<p><b>Week Program '.$w.'</b></p><br/><table border="1">';
foreach my $d (sort keys %{$p->{ENDTIME}}) {
$s .= '<tr><td><b>'.$weekDay[$d].'</b></td>';
my $h24 = 0;
foreach my $h (sort { $a <=> $b } keys %{$p->{ENDTIME}{$d}}) {
$s .= '<td>'.($h24 == 0 ? $p->{ENDTIME}{$d}{$h}.' / '.$p->{TEMPERATURE}{$d}{$h} : '&nbsp;').'</td>';
$h24 = 1 if ($h24 == 0 && $p->{ENDTIME}{$d}{$h} eq '24:00');
$s .= '<td>'.$p->{ENDTIME}{$d}{$h}.' / '.$p->{TEMPERATURE}{$d}{$h}.'</td>';
last if ($p->{ENDTIME}{$d}{$h} eq '24:00');
}
$s .= '</tr>';
}
@ -6510,7 +6631,7 @@ sub HMCCU_CheckParameter ($$;$$$)
# datapoint name.
# If controldatapoint is not specified it will synchronized with
# statedatapoint.
# Return (sc, sd, cc, cd)
# Return (sc, sd, cc, cd, sdCnt, cdCnt)
######################################################################
sub HMCCU_GetSpecialDatapoints ($)
@ -6529,6 +6650,7 @@ sub HMCCU_GetSpecialDatapoints ($)
HMCCU_Log ($hash, 2, "No CCU address defined");
}
my ($sc, $sd, $cc, $cd) = ($dc // '', '', $dc // '', '');
my ($rsdCnt, $rcdCnt) = (0, 0);
my $statedatapoint = AttrVal ($name, 'statedatapoint', '');
my $controldatapoint = AttrVal ($name, 'controldatapoint', '');
@ -6580,7 +6702,7 @@ sub HMCCU_GetSpecialDatapoints ($)
}
}
elsif ($type eq 'HMCCUDEV') {
my ($rsdCnt, $rcdCnt) = (0, 0);
# Count matching roles to prevent ambiguous definitions
my ($rsc, $rsd, $rcc, $rcd) = ('', '', '', '');
foreach my $roleDef (split(',', $hash->{hmccu}{role})) {
my ($rc, $role) = split(':', $roleDef);
@ -6623,7 +6745,7 @@ sub HMCCU_GetSpecialDatapoints ($)
$hash->{hmccu}{control}{dpt} = $cd;
$hash->{hmccu}{control}{chn} = $cc;
return ($sc, $sd, $cc, $cd);
return ($sc, $sd, $cc, $cd, $rsdCnt, $rcdCnt);
}
######################################################################
@ -6711,24 +6833,15 @@ sub HMCCU_GetAttrStripNumber ($)
# Substitute ${xxx} by datapoint value.
######################################################################
sub HMCCU_GetAttrSubstitute ($$)
sub HMCCU_GetAttrSubstitute ($;$)
{
my ($clhash, $iohash) = @_;
my $clname = $clhash->{NAME};
my $ioname = $iohash->{NAME};
my $substdef = AttrVal ($ioname, 'ccudef-substitute', '');
my $subst = AttrVal ($clname, 'substitute', $substdef);
my $substdef = defined($iohash) ? AttrVal ($iohash->{NAME}, 'ccudef-substitute', '') : '';
my $subst = AttrVal ($clhash->{NAME}, 'substitute', $substdef);
$subst .= ";$substdef" if ($subst ne $substdef && $substdef ne '');
HMCCU_Trace ($clhash, 2, "subst = $subst");
return $subst if ($subst !~ /\$\{.+\}/);
$subst = HMCCU_SubstVariables ($clhash, $subst, undef);
HMCCU_Trace ($clhash, 2, "subst_vars = $subst");
return $subst;
return $subst !~ /\$\{.+\}/ ? $subst : HMCCU_SubstVariables ($clhash, $subst, undef);
}
######################################################################
@ -6930,7 +7043,7 @@ sub HMCCU_BulkUpdate ($$$$)
{
my ($hash, $reading, $orgval, $subval) = @_;
my $excl = AttrVal ($hash->{NAME}, 'substexcl', 'control|pct');
my $excl = AttrVal ($hash->{NAME}, 'substexcl', '');
readingsBulkUpdate ($hash, $reading, ($excl ne '' && $reading =~ /$excl/ ? $orgval : $subval));
}

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCUCHN.pm 18552 2019-02-10 11:52:28Z zap $
#
# Version 4.4.019
# Version 4.4.021
#
# (c) 2020 zap (zap01 <at> t-online <dot> de)
#
@ -81,7 +81,8 @@ sub HMCCUCHN_Define ($@)
# Defaults
$hash->{readonly} = 'no';
$hash->{hmccu}{channels} = 1;
$hash->{hmccu}{defaults} = 0;
$hash->{hmccu}{nodefaults} = $init_done ? 0 : 1;
$hash->{hmccu}{semDefaults} = 0;
# Parse optional command line parameters
my $n = 0;
@ -152,11 +153,11 @@ sub HMCCUCHN_InitDevice ($$)
# Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}));
$devHash->{ccuif} = $di;
$devHash->{ccuaddr} = $da;
$devHash->{ccuname} = $dn;
$devHash->{ccutype} = $dt;
$devHash->{ccudevstate} = 'active';
$devHash->{ccuif} = $di;
$devHash->{ccuaddr} = $da;
$devHash->{ccuname} = $dn;
$devHash->{ccutype} = $dt;
$devHash->{ccudevstate} = 'active';
if ($init_done) {
# Interactive device definition
@ -259,7 +260,7 @@ sub HMCCUCHN_Set ($@)
# Get state and control datapoints
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
# Get additional commands, including state commands
# Additional commands, including state commands
my $cmdList = $hash->{hmccu}{cmdlist} // '';
# Get state values related to control command and datapoint
@ -269,7 +270,7 @@ sub HMCCUCHN_Set ($@)
my @states = keys %stateCmds;
# Some commands require a control datapoint
if ($opt =~ /^(control|toggle|on-for-timer|on-till)$/) {
if ($opt =~ /^(control|toggle)$/) {
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2));
}
@ -283,7 +284,6 @@ sub HMCCUCHN_Set ($@)
if ($opt eq 'control') {
my $value = shift @$a // return HMCCU_SetError ($hash, "Usage: set $name control {value}");
$value =~ s/\\_/%20/g;
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr.$cd" => HMCCU_Substitute ($value, $stateVals, 1, undef, '') }
);
@ -302,7 +302,6 @@ sub HMCCUCHN_Set ($@)
$i++;
my $no = sprintf ("%03d", $i);
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $stateVals, 1, undef, '')
if ($stateVals ne '' && $objname eq $cd);
$dpval{"$no.$ccuif.$ccuaddr.$objname"} = $objvalue;
@ -314,31 +313,10 @@ sub HMCCUCHN_Set ($@)
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'toggle') {
my $stc = scalar (@states);
return HMCCU_SetError ($hash, -15) if ($stc == 0);
my $curState = defined($hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ?
$hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0];
my $newState = '';
my $st = 0;
while ($st < $stc) {
if ($states[$st] eq $curState) {
$newState = ($st == $stc-1) ? $states[0] : $states[$st+1];
last;
}
$st++;
}
return HMCCU_SetError ($hash, "Current device state doesn't match any state value")
if ($newState eq '');
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr.$cd" => $stateCmds{$newState} }
);
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
return HMCCU_ExecuteToggleCommand ($hash, $cc, $cd);
}
elsif (exists($hash->{hmccu}{roleCmds}{$opt})) {
return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $a, $h);
return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $cc, $a, $h);
}
elsif ($opt eq 'clear') {
my $rnexp = shift @$a;
@ -366,8 +344,7 @@ sub HMCCUCHN_Set ($@)
}
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $ccuobj, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description")
if (!defined($devDesc));
return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
return HMCCU_SetError ($hash, "Paramset $paramset not supported by device or channel")
if ($devDesc->{PARAMSETS} !~ /$paramset/);
if (!HMCCU_IsValidParameter ($ioHash, $devDesc, $paramset, $h)) {
@ -481,59 +458,10 @@ sub HMCCUCHN_Get ($@)
return $devInfo;
}
elsif ($opt =~ /^(config|values|update)$/) {
my %parSets = ('config' => 'MASTER,LINK', 'values' => 'VALUES', 'update' => 'VALUES,MASTER,LINK');
my $defParamset = $parSets{$opt};
my ($devAddr, undef) = HMCCU_SplitChnAddr ($ccuaddr);
my @addList = ($devAddr, "$devAddr:0", $ccuaddr);
my %objects;
foreach my $a (@addList) {
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $a, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
my $paramset = $defParamset eq '' ? $devDesc->{PARAMSETS} : $defParamset;
my ($da, $dc) = HMCCU_SplitChnAddr ($a);
$dc = 'd' if ($dc eq '');
foreach my $ps (split (',', $paramset)) {
next if ($devDesc->{PARAMSETS} !~ /$ps/);
if ($ps eq 'LINK') {
foreach my $rcv (HMCCU_GetReceivers ($ioHash, $ccuaddr, $ccuif)) {
($rc, $result) = HMCCU_RPCRequest ($hash, 'getRawParamset', $a, $rcv, undef);
next if ($rc < 0);
foreach my $p (keys %$result) {
$objects{$da}{$dc}{"LINK.$rcv"}{$p} = $result->{$p};
}
}
}
else {
($rc, $result) = HMCCU_RPCRequest ($hash, 'getRawParamset', $a, $ps, undef);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
foreach my $p (keys %$result) { $objects{$da}{$dc}{$ps}{$p} = $result->{$p}; }
}
}
}
my $res = '';
if (scalar(keys %objects) > 0) {
my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $hash, \%objects);
if (defined($convRes)) {
foreach my $da (sort keys %$convRes) {
$res .= "Device $da\n";
foreach my $dc (sort keys %{$convRes->{$da}}) {
foreach my $ps (sort keys %{$convRes->{$da}{$dc}}) {
$res .= " Channel $dc [$ps]\n".
join ("\n", map {
" ".$_.' = '.$convRes->{$da}{$dc}{$ps}{$_}
} sort keys %{$convRes->{$da}{$dc}{$ps}})."\n";
}
}
}
}
}
return $res eq '' ? 'No data found' : $res;
return HMCCU_ExecuteGetParameterCommand ($ioHash, $hash, $opt, \@addList);
}
elsif ($opt eq 'paramsetdesc') {
$result = HMCCU_ParamsetDescToStr ($ioHash, $hash);
@ -782,6 +710,7 @@ sub HMCCUCHN_Get ($@)
To reduce the amount of events it's recommended to set attribute 'event-on-change-reading'
to '.*'.
<br/><br/>
<a name="calculate"></a>
<li><b>ccucalculate &lt;value-type&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>. For datapoints in <i>dp-list</i>
@ -799,6 +728,7 @@ sub HMCCUCHN_Get ($@)
Example:<br/>
<code>dewpoint:taupunkt:1.TEMPERATURE,1.HUMIDITY</code>
</li><br/>
<a name="ccuflags"></a>
<li><b>ccuflags {ackState, logCommand, noReadings, showDeviceReadings, showLinkReadings, showConfigReadings, trace}</b><br/>
Control behaviour of device:<br/>
ackState: Acknowledge command execution by setting STATE to error or success.<br/>
@ -809,16 +739,18 @@ sub HMCCUCHN_Get ($@)
showMasterReadings: Show configuration readings.<br/>
trace: Write log file information for operations related to this device.
</li><br/>
<a name="ccuget"></a>
<li><b>ccuget {State | <u>Value</u>}</b><br/>
Set read access method for CCU channel datapoints. Method 'State' is slower than 'Value'
because each request is sent to the device. With method 'Value' only CCU is queried.
Default is 'Value'.
</li><br/>
<a name="ccureadingfilter"></a>
<li><b>ccureadingfilter &lt;filter-rule[;...]&gt;</b><br/>
Only datapoints matching specified expression <i>RegExp</i> are stored as readings.<br/>
Syntax for <i>filter-rule</i> is either:<br/>
[N:]{&lt;channel-name&gt;}!RegExp&gt; or:<br/>
[N:][&lt;channel-number&gt;.]&lt;RegExp&gt;<br/>
[N:]{&lt;channel-name-expr&gt;}!RegExp&gt; or:<br/>
[N:][&lt;channel-number&gt;[,&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.<br/>
If a rule starts with 'N:' the filter is negated which means that a reading is
@ -843,6 +775,7 @@ sub HMCCUCHN_Get ($@)
attr mydev ccureadingfilter MyBlindChannel!^LEVEL$<br/>
</code>
</li><br/>
<a name="ccureadingformat"></a>
<li><b>ccureadingformat {address[lc] | name[lc] | datapoint[lc]}</b><br/>
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
@ -850,6 +783,7 @@ sub HMCCUCHN_Get ($@)
channel-name.datapoint. If set to 'datapoint' format is channel-number.datapoint. With
suffix 'lc' reading names are converted to lowercase.
</li><br/>
<a name="ccureadingname"></a>
<li><b>ccureadingname &lt;old-readingname-expr&gt;:[+]&lt;new-readingname&gt[,...];[;...]</b><br/>
Set alternative or additional reading names or group readings. Only part of old reading
name matching <i>old-readingname-exptr</i> is substituted by <i>new-readingname</i>.

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCUDEV.pm 18552 2019-02-10 11:52:28Z zap $
#
# Version 4.4.022
# Version 4.4.025
#
# (c) 2020 zap (zap01 <at> t-online <dot> de)
#
@ -79,7 +79,8 @@ sub HMCCUDEV_Define ($@)
"No matching CCU devices found",
"Type of virtual device not defined",
"Device type not found",
"Too many virtual devices"
"Too many virtual devices",
"Control channel ambiguous. Please specify control channel in device definition"
);
my ($devname, $devtype, $devspec) = splice (@$a, 0, 3);
@ -90,7 +91,8 @@ sub HMCCUDEV_Define ($@)
$hash->{hmccu}{devspec} = $devspec;
$hash->{hmccu}{groupexp} = $h->{groupexp} if (exists ($h->{groupexp}));
$hash->{hmccu}{group} = $h->{group} if (exists ($h->{group}));
$hash->{hmccu}{defaults} = 0;
$hash->{hmccu}{nodefaults} = $init_done ? 0 : 1;
$hash->{hmccu}{semDefaults} = 0;
if (exists($h->{address})) {
return 'Option address not allowed' if ($init_done || $devspec ne 'virtual');
@ -155,6 +157,7 @@ sub HMCCUDEV_Define ($@)
# 5 = Type of virtual device not defined
# 6 = Device type not found
# 7 = Too many virtual devices
# 8 = Control channel must be specified
######################################################################
sub HMCCUDEV_InitDevice ($$)
@ -214,9 +217,17 @@ sub HMCCUDEV_InitDevice ($$)
HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME});
HMCCU_UpdateDevice ($ioHash, $devHash);
HMCCU_UpdateDeviceRoles ($ioHash, $devHash);
my ($sc, $sd, $cc, $cd, $sdCnt, $cdCnt) = HMCCU_GetSpecialDatapoints ($devHash);
return 8 if ($cdCnt > 2);
HMCCU_UpdateRoleCommands ($ioHash, $devHash, $attr{$devHash->{NAME}}{controlchannel});
if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) {
if (!HMCCU_SetDefaultAttributes ($devHash)) {
if (!HMCCU_SetDefaultAttributes ($devHash, {
mode => 'update', role => undef, ctrlChn => $cc eq '' ? undef : $cc
})) {
HMCCU_Log ($devHash, 2, "No role attributes found");
HMCCU_SetDefaults ($devHash);
}
}
@ -378,7 +389,7 @@ sub HMCCUDEV_Set ($@)
my @states = keys %stateCmds;
# Some commands require a control channel and datapoint
if ($opt =~ /^(control|toggle|on-for-timer|on-till)$/) {
if ($opt =~ /^(control|toggle)$/) {
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2));
@ -394,7 +405,6 @@ sub HMCCUDEV_Set ($@)
if ($opt eq 'control') {
my $value = shift @$a // return HMCCU_SetError ($hash, "Usage: set $name control {value}");
$value =~ s/\\_/%20/g;
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ($value, $stateVals, 1, undef, '') }
);
@ -427,7 +437,6 @@ sub HMCCUDEV_Set ($@)
}
my $no = sprintf ("%03d", $i);
$value =~ s/\\_/%20/g;
$dpval{"$no.$ccuif.$ccuaddr:$objname"} = HMCCU_Substitute ($value, $stateVals, 1, undef, '');
}
@ -437,32 +446,10 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'toggle') {
my $stc = scalar(@states);
return HMCCU_SetError ($hash, -15) if ($stc == 0);
my $curState = defined($hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ?
$hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0];
my $newState = '';
my $st = 0;
while ($st < $stc) {
if ($states[$st] eq $curState) {
$newState = ($st == $stc-1) ? $states[0] : $states[$st+1];
last;
}
$st++;
}
return HMCCU_SetError ($hash, "Current device state doesn't match any state value")
if ($newState eq '');
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$cc.$cd" => $stateCmds{$newState} }
);
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
return HMCCU_ExecuteToggleCommand ($hash, $cc, $cd);
}
elsif (exists($hash->{hmccu}{roleCmds}{$opt})) {
return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $a, $h);
return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $cc, $a, $h);
}
elsif ($opt eq 'clear') {
my $rnexp = shift @$a;
@ -622,65 +609,13 @@ sub HMCCUDEV_Get ($@)
return $devInfo;
}
elsif ($opt =~ /^(config|values|update)$/) {
my %parSets = ('config' => 'MASTER,LINK', 'values' => 'VALUES', 'update' => 'VALUES,MASTER,LINK');
my $defParamset = $parSets{$opt};
my @addList = ($ccuaddr);
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $ccuaddr, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
push @addList, split (',', $devDesc->{CHILDREN});
my %objects;
foreach my $a (@addList) {
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $a, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
my $paramset = $defParamset eq '' ? $devDesc->{PARAMSETS} : $defParamset;
my ($da, $dc) = HMCCU_SplitChnAddr ($a);
$dc = 'd' if ($dc eq '');
foreach my $ps (split (',', $paramset)) {
next if ($devDesc->{PARAMSETS} !~ /$ps/);
if ($ps eq 'LINK') {
foreach my $rcv (HMCCU_GetReceivers ($ioHash, $a, $ccuif)) {
($rc, $result) = HMCCU_RPCRequest ($hash, 'getRawParamset', $a, $rcv, undef);
next if ($rc < 0);
foreach my $p (keys %$result) {
$objects{$da}{$dc}{"LINK.$rcv"}{$p} = $result->{$p};
}
}
}
else {
# The following request could fail if device description or parameter set
# description is not correct.
($rc, $result) = HMCCU_RPCRequest ($hash, 'getRawParamset', $a, $ps, undef);
if ($rc >= 0) {
foreach my $p (keys %$result) { $objects{$da}{$dc}{$ps}{$p} = $result->{$p}; }
}
}
}
}
my $res = '';
if (scalar(keys %objects) > 0) {
my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $hash, \%objects);
if (defined($convRes)) {
foreach my $da (sort keys %$convRes) {
$res .= "Device $da\n";
foreach my $dc (sort keys %{$convRes->{$da}}) {
foreach my $ps (sort keys %{$convRes->{$da}{$dc}}) {
$res .= " Channel $dc [$ps]\n".
join ("\n", map {
" ".$_.' = '.$convRes->{$da}{$dc}{$ps}{$_}
} sort keys %{$convRes->{$da}{$dc}{$ps}})."\n";
}
}
}
}
}
return $res;
return HMCCU_ExecuteGetParameterCommand ($ioHash, $hash, $opt, \@addList);
}
elsif ($opt eq 'paramsetdesc') {
$result = HMCCU_ParamsetDescToStr ($ioHash, $hash);
@ -704,7 +639,7 @@ sub HMCCUDEV_Get ($@)
my @valuelist;
my $valuecount = HMCCU_GetValidDatapoints ($hash, $ccutype, -1, 1, \@valuelist);
$retmsg .= ':'.join(",", @valuelist) if ($valuecount > 0);
$retmsg .= ' defaults:noArg update:noArg config'.
$retmsg .= ' defaults:noArg update:noArg config:noArg'.
' paramsetDesc:noArg deviceDesc:noArg deviceInfo:noArg values:noArg';
$retmsg .= ' weekProgram:all,'.join(',', sort keys %{$hash->{hmccu}{tt}})
if (exists($hash->{hmccu}{tt}));

View File

@ -362,9 +362,9 @@ sub HMCCURPCPROC_Define ($$)
sub HMCCURPCPROC_InitDevice ($$)
{
my ($ioHash, $dev_hash) = @_;
my $name = $dev_hash->{NAME};
my $iface = $dev_hash->{hmccu}{devspec};
my ($ioHash, $devHash) = @_;
my $name = $devHash->{NAME};
my $iface = $devHash->{hmccu}{devspec};
# Check if interface is valid
my ($ifname, $ifport) = HMCCU_GetRPCServerInfo ($ioHash, $iface, 'name,port');
@ -375,37 +375,37 @@ sub HMCCURPCPROC_InitDevice ($$)
my $dh = $defs{$d};
next if (!exists($dh->{TYPE}) || !exists($dh->{NAME}));
if ($dh->{TYPE} eq 'HMCCURPCPROC' && $dh->{NAME} ne $name && IsDisabled ($dh->{NAME}) != 1) {
return 4 if ($dev_hash->{host} eq $dh->{host} && exists ($dh->{rpcport}) &&
return 4 if ($devHash->{host} eq $dh->{host} && exists ($dh->{rpcport}) &&
$dh->{rpcport} == $ifport);
}
}
# Detect local IP address and check if CCU is reachable
my $localaddr = HMCCU_TCPConnect ($dev_hash->{host}, $ifport);
my $localaddr = HMCCU_TCPConnect ($devHash->{host}, $ifport);
return 5 if ($localaddr eq '');
$dev_hash->{hmccu}{localaddr} = $localaddr;
$dev_hash->{hmccu}{defaultaddr} = $dev_hash->{hmccu}{localaddr};
$devHash->{hmccu}{localaddr} = $localaddr;
$devHash->{hmccu}{defaultaddr} = $devHash->{hmccu}{localaddr};
# Get unique ID for RPC server: last 2 segments of local IP address
# Do not append random digits because of https://forum.fhem.de/index.php/topic,83544.msg797146.html#msg797146
my $id1 = HMCCU_GetIdFromIP ($dev_hash->{hmccu}{localaddr}, '');
my $id1 = HMCCU_GetIdFromIP ($devHash->{hmccu}{localaddr}, '');
my $id2 = HMCCU_GetIdFromIP ($ioHash->{ccuip}, '');
return 3 if ($id1 eq '' || $id2 eq '');
$dev_hash->{rpcid} = $id1.$id2;
$devHash->{rpcid} = $id1.$id2;
# Set I/O device and store reference for RPC device in I/O device
my $ioname = $ioHash->{NAME};
return 2 if (!HMCCU_AssignIODevice ($dev_hash, $ioname, $ifname));
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioname, $ifname));
# Store internals
$dev_hash->{rpcport} = $ifport;
$dev_hash->{rpcinterface} = $ifname;
$dev_hash->{ccuip} = $ioHash->{ccuip};
$dev_hash->{ccutype} = $ioHash->{ccutype};
$dev_hash->{CCUNum} = $ioHash->{CCUNum};
$dev_hash->{ccustate} = $ioHash->{ccustate};
$devHash->{rpcport} = $ifport;
$devHash->{rpcinterface} = $ifname;
$devHash->{ccuip} = $ioHash->{ccuip};
$devHash->{ccutype} = $ioHash->{ccutype};
$devHash->{CCUNum} = $ioHash->{CCUNum};
$devHash->{ccustate} = $ioHash->{ccustate};
HMCCU_Log ($dev_hash, 1, "Initialized version $HMCCURPCPROC_VERSION for interface $ifname with I/O device $ioname");
HMCCU_Log ($devHash, 1, "Initialized version $HMCCURPCPROC_VERSION for interface $ifname with I/O device $ioname");
# Set some attributes
if ($init_done) {
@ -414,8 +414,8 @@ sub HMCCURPCPROC_InitDevice ($$)
}
# RPC device ready
HMCCURPCPROC_ResetRPCState ($dev_hash);
HMCCURPCPROC_SetState ($dev_hash, 'Initialized');
HMCCURPCPROC_ResetRPCState ($devHash);
HMCCURPCPROC_SetState ($devHash, 'Initialized');
return 0;
}
@ -1284,7 +1284,7 @@ sub HMCCURPCPROC_RegisterCallback ($$)
return (0, "Can't get RPC parameters for ID $clkey")
if (!defined($cburl) || !defined($clurl) || !defined($rpctype));
$hash->{hmccu}{rpc}{port} = $port;
$hash->{hmccu}{rpc}{port} = $port;
$hash->{hmccu}{rpc}{clurl} = $clurl;
$hash->{hmccu}{rpc}{cburl} = $cburl;
@ -1319,8 +1319,8 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
return (0, "RPC server $clkey not in state registered or running")
if ($rpchash->{state} ne 'registered' && $rpchash->{state} ne 'running' && $force == 0);
$cburl = $rpchash->{cburl} if (exists ($rpchash->{cburl}));
$clurl = $rpchash->{clurl} if (exists ($rpchash->{clurl}));
$cburl = $rpchash->{cburl} if (exists($rpchash->{cburl}));
$clurl = $rpchash->{clurl} if (exists($rpchash->{clurl}));
$cburl = HMCCU_GetRPCCallbackURL ($ioHash, $localaddr, $rpchash->{cbport}, $clkey, $port) if ($cburl eq '');
$clurl = HMCCU_BuildURL ($ioHash, $port) if ($clurl eq '');
return (0, "Can't get RPC parameters for ID $clkey") if ($cburl eq '' || $clurl eq '');
@ -1335,8 +1335,8 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
HMCCURPCPROC_SetRPCState ($hash, $force == 0 ? 'deregistered' : $rpchash->{state},
"Callback for RPC server $clkey deregistered", 1);
$rpchash->{cburl} = '';
$rpchash->{clurl} = '';
$rpchash->{cburl} = '';
$rpchash->{clurl} = '';
$rpchash->{cbport} = 0;
return (1, 'working');
@ -1373,68 +1373,61 @@ sub HMCCURPCPROC_InitRPCServer ($$$$)
# Callback for events
HMCCU_Log ($name, 4, "Adding callback for events for server $clkey");
$server->add_method (
{ name => "event",
signature => ["string string string string string","string string string string int",
"string string string string double","string string string string boolean",
"string string string string i4"],
code => \&HMCCURPCPROC_EventCB
}
);
$server->add_method ({
name => "event",
signature => ["string string string string string","string string string string int",
"string string string string double","string string string string boolean",
"string string string string i4"],
code => \&HMCCURPCPROC_EventCB
});
# Callback for new devices
HMCCU_Log ($name, 4, "Adding callback for new devices for server $clkey");
$server->add_method (
{ name => "newDevices",
signature => ["string string array"],
code => \&HMCCURPCPROC_NewDevicesCB
}
);
$server->add_method ({
name => "newDevices",
signature => ["string string array"],
code => \&HMCCURPCPROC_NewDevicesCB
});
# Callback for deleted devices
HMCCU_Log ($name, 4, "Adding callback for deleted devices for server $clkey");
$server->add_method (
{ name => "deleteDevices",
signature => ["string string array"],
code => \&HMCCURPCPROC_DeleteDevicesCB
}
);
$server->add_method ({
name => "deleteDevices",
signature => ["string string array"],
code => \&HMCCURPCPROC_DeleteDevicesCB
});
# Callback for modified devices
HMCCU_Log ($name, 4, "Adding callback for modified devices for server $clkey");
$server->add_method (
{ name => "updateDevice",
signature => ["string string string int", "string string string i4"],
code => \&HMCCURPCPROC_UpdateDeviceCB
}
);
$server->add_method ({
name => "updateDevice",
signature => ["string string string int", "string string string i4"],
code => \&HMCCURPCPROC_UpdateDeviceCB
});
# Callback for replaced devices
HMCCU_Log ($name, 4, "Adding callback for replaced devices for server $clkey");
$server->add_method (
{ name => "replaceDevice",
signature => ["string string string string"],
code => \&HMCCURPCPROC_ReplaceDeviceCB
}
);
$server->add_method ({
name => "replaceDevice",
signature => ["string string string string"],
code => \&HMCCURPCPROC_ReplaceDeviceCB
});
# Callback for readded devices
HMCCU_Log ($name, 4, "Adding callback for readded devices for server $clkey");
$server->add_method (
{ name => "readdedDevice",
signature => ["string string array"],
code => \&HMCCURPCPROC_ReaddDeviceCB
}
);
$server->add_method ({
name => "readdedDevice",
signature => ["string string array"],
code => \&HMCCURPCPROC_ReaddDeviceCB
});
# Dummy implementation, always return an empty array
HMCCU_Log ($name, 4, "Adding callback for list devices for server $clkey");
$server->add_method (
{ name => "listDevices",
signature => ["array string"],
code => \&HMCCURPCPROC_ListDevicesCB
}
);
$server->add_method ({
name => "listDevices",
signature => ["array string"],
code => \&HMCCURPCPROC_ListDevicesCB
});
return $server;
}
@ -2087,12 +2080,10 @@ sub HMCCURPCPROC_HandleConnection ($$$$)
$rpcsrv->{hmccu}{evttime} = time ();
# Initialize statistic counters
foreach my $et (@RPC_EVENT_TYPES) {
foreach my $et (@RPC_EVENT_TYPES, 'total') {
$rpcsrv->{hmccu}{rec}{$et} = 0;
$rpcsrv->{hmccu}{snd}{$et} = 0;
}
$rpcsrv->{hmccu}{rec}{total} = 0;
$rpcsrv->{hmccu}{snd}{total} = 0;
# Signal handler
$SIG{INT} = sub { $run = 0; HMCCU_Log ($name, 2, "$clkey received signal INT"); };
@ -2561,9 +2552,7 @@ sub HMCCURPCPROC_ReaddDevicesCB ($$$)
my $devcount = scalar(@$a);
HMCCU_Log ($name, 2, "$cb ReaddDevice received $devcount device addresses");
foreach my $dev (@$a) {
HMCCURPCPROC_Write ($server, 'RA', $cb, $dev);
}
foreach my $dev (@$a) { HMCCURPCPROC_Write ($server, 'RA', $cb, $dev); }
return;
}
@ -2619,19 +2608,10 @@ sub HMCCURPCPROC_EncValue ($$)
# Try to detect type if type not specified
if (!defined($type)) {
if (lc($value) =~ /^(true|false)$/) {
$type = 'boolean';
}
elsif ($value =~ /^[-+]?\d+$/) {
$type = 'integer';
}
elsif ($value =~ /^[-+]?[0-9]*\.[0-9]+$/) {
# A float must contain at least a dot followed by a digit
$type = 'float';
}
elsif ($value eq '' || $value =~ /^([a-zA-Z_ ]+|'.+'|".+")$/) {
$type = 'string';
}
if (lc($value) =~ /^(true|false)$/) { $type = 'boolean'; }
elsif ($value =~ /^[-+]?\d+$/) { $type = 'integer'; }
elsif ($value =~ /^[-+]?[0-9]*\.[0-9]+$/) { $type = 'float'; }
elsif ($value eq '' || $value =~ /^([a-zA-Z_ ]+|'.+'|".+")$/) { $type = 'string'; }
}
if (defined($type)) {

View File

@ -4,7 +4,7 @@
#
# $Id: HMCCUConf.pm 18552 2019-02-10 11:52:28Z zap $
#
# Version 4.8.002
# Version 4.8.003
#
# Configuration parameters for HomeMatic devices.
#
@ -212,15 +212,18 @@ use vars qw(%HMCCU_SCRIPTS);
%HMCCU_ATTR = (
'BLIND' => {
'webCmd' => 'up:down:stop:pct',
'substexcl' => 'pct',
'webCmd' => 'open:close:stop:pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
'BLIND_VIRTUAL_RECEIVER' => {
'webCmd' => 'up:down:stop:pct',
'substexcl' => 'pct',
'webCmd' => 'open:close:stop:pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
'SHUTTER_VIRTUAL_RECEIVER' => {
'webCmd' => 'up:down:stop:pct',
'substexcl' => 'pct',
'webCmd' => 'open:close:stop:pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
'SWITCH' => {
@ -232,25 +235,29 @@ use vars qw(%HMCCU_SCRIPTS);
'widgetOverride' => 'toggle:uzsuToggle,off,on'
},
'DIMMER' => {
'substexcl' => 'pct',
'webCmd' => 'pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
'DIMMER_VIRTUAL_RECEIVER' => {
'ccureadingname' => 'LEVEL$:pct',
'substexcl' => 'pct',
'webCmd' => 'pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
'THERMALCONTROL_TRANSMIT' => {
'substexcl' => 'desired-temp',
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp:auto:manu:boost:on:off',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'
},
'CLIMATECONTROL_RT_TRANSCEIVER' => {
'substexcl' => 'desired-temp',
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp:auto:manu:boost:on:off',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'
},
'HEATING_CLIMATECONTROL_TRANSCEIVER' => {
'substexcl' => 'desired-temp',
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp:auto:manu:boost:on:off',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'
@ -280,10 +287,10 @@ use vars qw(%HMCCU_SCRIPTS);
'STATE' => { '0' => 'closed', '1' => 'open', 'false' => 'closed', 'true' => 'open' }
},
'ROTARY_HANDLE_SENSOR' => {
'STATE' => { '0' => 'closed', '1' => 'open', 'false' => 'closed', 'true' => 'open' }
'STATE' => { '0' => 'closed', '1' => 'tilted', '2' => 'open' }
},
'ROTARY_HANDLE_TRANSCEIVER' => {
'STATE' => { '0' => 'closed', '1' => 'open', 'false' => 'closed', 'true' => 'open' }
'STATE' => { '0' => 'closed', '1' => 'tilted', '2' => 'open' }
},
'ALARM_SWITCH_VIRTUAL_RECEIVER' => {
'STATE' => { '0' => 'ok', '1' => 'alarm', 'false' => 'ok', 'true' => 'alarm' }