From 1069d54cd02e75d073e94af95b5920cf15db9d3f Mon Sep 17 00:00:00 2001 From: zap <> Date: Wed, 22 Dec 2021 07:50:08 +0000 Subject: [PATCH] HMCCU: Fixed ENUM conversion bug git-svn-id: https://svn.fhem.de/fhem/trunk@25365 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/88_HMCCU.pm | 116 +++++++++++++++-------------------- fhem/FHEM/88_HMCCUCHN.pm | 2 +- fhem/FHEM/88_HMCCUDEV.pm | 2 +- fhem/FHEM/88_HMCCURPCPROC.pm | 5 +- 5 files changed, 56 insertions(+), 70 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index b57ec9fb9..ec2c2bbbe 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -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. + - bugfix: 88_HMCCU: Fixed ENUM conversion bug - feature: 31_HUEDevice: allow json in set commands for lights. see https://forum.fhem.de/index.php/topic,11020 posting #1864 and #1866 diff --git a/fhem/FHEM/88_HMCCU.pm b/fhem/FHEM/88_HMCCU.pm index 4a4c5b1cd..503faa4fa 100755 --- a/fhem/FHEM/88_HMCCU.pm +++ b/fhem/FHEM/88_HMCCU.pm @@ -31,7 +31,7 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch'; use strict; use warnings; -use Data::Dumper; +# use Data::Dumper; use Encode qw(decode encode); use RPC::XML::Client; use RPC::XML::Server; @@ -57,7 +57,7 @@ my %HMCCU_CUST_CHN_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS; # HMCCU version -my $HMCCU_VERSION = '5.0 213491649'; +my $HMCCU_VERSION = '5.0 213551543'; # Timeout for CCU requests (seconds) my $HMCCU_TIMEOUT_REQUEST = 4; @@ -638,8 +638,6 @@ sub HMCCU_Attr ($@) } elsif ($attrname eq 'ccuflags') { my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); - my @flags = ($attrval =~ /(intrpc|extrpc|procrpc)/g); - return "HMCCU: [$name] Flags extrpc, procrpc and intrpc cannot be combined" if (scalar (@flags) > 1); if ($attrval =~ /(intrpc|extrpc)/) { HMCCU_Log ($hash, 1, "HMCCU: [$name] RPC server mode $1 no longer supported. Using procrpc instead"); $attrval =~ s/(extrpc|intrpc)/procrpc/; @@ -2884,19 +2882,9 @@ sub HMCCU_Substitute ($$$$$;$$) 'BOOL' => { '0' => 'false', '1' => 'true' } ); my $parType = $paramDef->{TYPE}; - if ($parType eq 'ENUM' && defined($paramDef->{VALUE_LIST})) { - my $i = defined($paramDef->{MIN}) ? $paramDef->{MIN} : 0; - if ($mode == 1) { - my %enumVals = map { $_ => $i++ } split(',', $paramDef->{VALUE_LIST}); - return $enumVals{$value} if (exists($enumVals{$value})); - } - else { - my @enumList = split(',', $paramDef->{VALUE_LIST}); - if (HMCCU_IsIntNum ($value)) { - my $idx = $value-$i; - return $enumList[$idx] if ($idx >= 0 && $idx < scalar(@enumList)); - } - } + if ($parType eq 'ENUM' && defined($paramDef->{VALUE_LIST}) && HMCCU_IsIntNum($value) + ) { + return HMCCU_GetEnumValues ($ioHash, $paramDef, undef, $value); } elsif (exists($ct{$parType}) && exists($ct{$parType}{$value})) { return $ct{$parType}{$value}; @@ -2926,7 +2914,7 @@ sub HMCCU_SubstRule ($$$) $substitutes =~ s/\$\{value\}/$value/g; - my @sub_list = split /[, ]/,$substitutes; + my @sub_list = split /,/,$substitutes; foreach my $s (@sub_list) { my ($regexp, $text) = split /:/,$s,2; next if (!defined($regexp) || !defined($text)); @@ -4391,11 +4379,13 @@ sub HMCCU_FindParamDef ($$$) ###################################################################### # Get values of ENUM datapoint # object - Hash with parameter defintion or channel address -# dpt - Datapoint name -# value - Either a numeric value or an enumeration constant -# If value is not specified, a comma separated list of enumeration -# constants is returned. -# Return value or undef if datapoint is not of type ENUM. +# dpt - Datapoint name. Can be undef if object is a paramDef hash. +# value - Either '#', a numeric value or an enumeration constant +# If value is not specified, a string with a comma separated list of +# enumeration constants is returned. +# Return value, constant or list of constants depending on parameter +# $value: +# $value = '#' : Return list of constant:value pairs ###################################################################### sub HMCCU_GetEnumValues ($$$;$) @@ -4405,19 +4395,22 @@ sub HMCCU_GetEnumValues ($$$;$) my $paramDef = ref($object) eq 'HASH' ? $object : HMCCU_GetParamDef ($ioHash, $object, 'VALUES', $dpt); if (defined($paramDef) && defined($paramDef->{TYPE}) && $paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) { my $i = defined($paramDef->{MIN}) && HMCCU_IsIntNum($paramDef->{MIN}) ? $paramDef->{MIN} : 0; + $i--; my $j = $i; my @valList = split(',',$paramDef->{VALUE_LIST}); - my %valIndex = map { $_ => $i++ } @valList; + my %valIndex = map { $i++; $_ => $i if ($_ ne '') } @valList; # Consider blanks in value list if (defined($value)) { if ($value eq '#') { - $j--; + # Return list of Constant:Value pairs return join(',', map { $j++; $_ ne '' ? "$_:$j" : () } @valList); } elsif (HMCCU_IsIntNum($value)) { + # Return Constant for value. Constant might be '' return $valList[$value] if ($value >= 0 && $value < scalar(@valList)); } else { - return $valIndex{$value} if (exists($valIndex{$value})); + # Return Value for Constant + return $valIndex{$value} if ($value ne '' && exists($valIndex{$value})); } } else { @@ -5117,7 +5110,7 @@ sub HMCCU_IsRPCType ($$$) ###################################################################### # Start external RPC server via RPC device. -# Return number of RPC servers or 0 on error. +# Return number of started/running RPC servers or 0 on error. ###################################################################### sub HMCCU_StartExtRPCServer ($) @@ -5127,22 +5120,10 @@ sub HMCCU_StartExtRPCServer ($) my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $attrset = 0; - - # Change RPC type to procrpc - if ($ccuflags =~ /(extrpc|intrpc)/) { - $ccuflags =~ s/(extrpc|intrpc)/procrpc/g; - CommandAttr (undef, "$name ccuflags $ccuflags"); - $attrset = 1; - - # Disable existing devices of type HMCCURPC - foreach my $d (keys %defs) { - my $ch = $defs{$d}; - next if (!exists ($ch->{TYPE}) || !exists ($ch->{NAME}) || $ch->{TYPE} ne 'HMCCURPC'); - CommandAttr (undef, $ch->{NAME}." disable 1") if (IsDisabled ($ch->{NAME}) != 1); - } - } - my $c = 0; + my $c = 0; # Started RPC servers + my $r = 0; # Running RPC servers + my $f = 0; # Failed RPC servers my $d = 0; my $s = 0; my $interfaces = HMCCU_GetRPCInterfaceList ($hash, 0); @@ -5166,15 +5147,20 @@ sub HMCCU_StartExtRPCServer ($) my $dh = $defs{$hash->{hmccu}{interfaces}{$ifname2}{device}}; $hash->{hmccu}{interfaces}{$ifname2}{manager} = 'HMCCU'; my ($rc, $msg) = HMCCURPCPROC_StartRPCServer ($dh); - if (!$rc) { + if ($rc == 0) { + $f++; HMCCU_SetRPCState ($hash, 'error', $ifname2, $msg); } - else { + elsif ($rc == 1) { $c++; } + elsif ($rc == 2) { + $r++; + } } HMCCU_SetRPCState ($hash, 'starting') if ($c > 0); - return $c; + HMCCU_Log ($hash, 2, "RPC server start: $c started, $r already running, $f failed to start"); + return $c+$r; } else { HMCCU_Log ($hash, 0, 'Definition of some RPC devices failed'); @@ -7017,20 +7003,19 @@ sub HMCCU_UpdateRoleCommands ($$;$) $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{fnc} = $fnc // ''; if ($paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) { # Build lookup table - my @el = split(',', $paramDef->{VALUE_LIST}); - my $i = 0; - foreach my $e (@el) { - $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$e} = $i; - $i++; + my $el = HMCCU_GetEnumValues ($ioHash, $paramDef, undef, '#'); + my $min; + my $max; + foreach my $e (split(',',$el)) { + my ($cNam, $cVal) = split (':', $e); + $min = $cVal if (!defined($min) || $cVal<$min); + $max = $cVal if (!defined($max) || $cVal>$max); + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$cNam} = $cVal; } # Parameter definition contains names for min and max value - $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{min} = - $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$paramDef->{MIN}} - if (exists($clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$paramDef->{MIN}})); - $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{max} = - $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$paramDef->{MAX}} - if (exists($clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$paramDef->{MAX}})); + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{min} = $min; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{max} = $max; } if (defined($par) && $par ne '') { @@ -7325,7 +7310,7 @@ sub HMCCU_ExecuteRoleCommand ($@) } # Align new value with min/max boundaries - if (exists($cmd->{min}) && exists($cmd->{max})) { + if (exists($cmd->{min}) && exists($cmd->{max}) && HMCCU_IsFltNum($cmd->{min}) && HMCCU_IsFltNum($cmd->{max})) { # Use mode = 0 in HMCCU_ScaleValue to get the min and max value allowed HMCCU_Trace ($clHash, 2, "MinMax: value=$value, min=$cmd->{min}, max=$cmd->{max}"); my $scMin = HMCCU_ScaleValue ($clHash, $channel, $cmd->{dpt}, $cmd->{min}, 2); @@ -9230,9 +9215,7 @@ sub HMCCU_SetMultipleDatapoints ($$) $v = "'".$v."'"; } elsif ($paramDef->{TYPE} eq 'ENUM' && !HMCCU_IsIntNum($v)) { - HMCCU_Log ($clHash, 2, "Enum datapoint value = $v"); $v = HMCCU_GetEnumValues ($ioHash, $paramDef, $dpt, $v); - HMCCU_Log ($clHash, 2, "Enum datapoint number = $v"); } } # my $dptType = HMCCU_GetDatapointAttr ($ioHash, $ccuType, $chn, $dpt, 'type'); @@ -9293,8 +9276,8 @@ sub HMCCU_ScaleValue ($$$$$;$) } my $paramDef = HMCCU_GetParamDef ($ioHash, $ccuaddr, $paramSet, $dpt); if (defined($paramDef)) { - $min = $paramDef->{MIN} if (defined($paramDef->{MIN}) && $paramDef->{MIN} ne ''); - $max = $paramDef->{MAX} if (defined($paramDef->{MAX}) && $paramDef->{MAX} ne ''); + $min = $paramDef->{MIN} if (defined($paramDef->{MIN}) && $paramDef->{MIN} ne '' && HMCCU_IsFltNum($paramDef->{MIN})); + $max = $paramDef->{MAX} if (defined($paramDef->{MAX}) && $paramDef->{MAX} ne '' && HMCCU_IsFltNum($paramDef->{MAX})); $unit = $paramDef->{UNIT}; $unit = '100%' if (!defined($unit) && ($dpt eq 'LEVEL' || $dpt eq 'LEVEL_2' || $dpt eq 'LEVEL_SLATS')); } @@ -10014,8 +9997,8 @@ sub HMCCU_Max ($$) sub HMCCU_MinMax ($$$) { my ($v, $min, $max) = @_; - $min = $v if (!defined($min) || $min eq ''); - $max = $min if (!defined($max) || $max eq ''); + $min = $v if (!defined($min) || $min eq '' || !HMCCU_IsFltNum($min)); + $max = $min if (!defined($max) || $max eq '' || !HMCCU_IsFltNum($max)); return HMCCU_Max (HMCCU_Min ($v, $max), $min); } @@ -10683,11 +10666,12 @@ sub HMCCU_MaxHashEntries ($$)


When RPC servers are started for the first time, HMCCU will create a HMCCURPCPROC device for - each interface defined in attribut 'rpcinterfaces'.
+ each interface defined in attribut 'rpcinterfaces'. These devices are assigned xto the same room + as I/O device.
After I/O device has been defined, start with the definition of client devices using modules HMCCUDEV (CCU devices) and HMCCUCHN (CCU channels) or with commands 'get createDev' or 'get create'.
diff --git a/fhem/FHEM/88_HMCCUCHN.pm b/fhem/FHEM/88_HMCCUCHN.pm index d2c5b26a8..5dec55aac 100644 --- a/fhem/FHEM/88_HMCCUCHN.pm +++ b/fhem/FHEM/88_HMCCUCHN.pm @@ -30,7 +30,7 @@ sub HMCCUCHN_Set ($@); sub HMCCUCHN_Get ($@); sub HMCCUCHN_Attr ($@); -my $HMCCUCHN_VERSION = '5.0 213491649'; +my $HMCCUCHN_VERSION = '5.0 213551543'; ###################################################################### # Initialize module diff --git a/fhem/FHEM/88_HMCCUDEV.pm b/fhem/FHEM/88_HMCCUDEV.pm index 82a808fa2..c61c72d9e 100644 --- a/fhem/FHEM/88_HMCCUDEV.pm +++ b/fhem/FHEM/88_HMCCUDEV.pm @@ -31,7 +31,7 @@ sub HMCCUDEV_Set ($@); sub HMCCUDEV_Get ($@); sub HMCCUDEV_Attr ($@); -my $HMCCUDEV_VERSION = '5.0 213491649'; +my $HMCCUDEV_VERSION = '5.0 213551543'; ###################################################################### # Initialize module diff --git a/fhem/FHEM/88_HMCCURPCPROC.pm b/fhem/FHEM/88_HMCCURPCPROC.pm index b177cb458..7853d432b 100755 --- a/fhem/FHEM/88_HMCCURPCPROC.pm +++ b/fhem/FHEM/88_HMCCURPCPROC.pm @@ -39,7 +39,7 @@ require "$attr{global}{modpath}/FHEM/88_HMCCU.pm"; ###################################################################### # HMCCURPC version -my $HMCCURPCPROC_VERSION = '5.0 213491649'; +my $HMCCURPCPROC_VERSION = '5.0 213551543'; # Maximum number of events processed per call of Read() my $HMCCURPCPROC_MAX_EVENTS = 100; @@ -1447,6 +1447,7 @@ sub HMCCURPCPROC_InitRPCServer ($$$$) ###################################################################### # Start RPC server process # Return (State, Msg) +# State: 0=Error, 1=Started, 2=Already running ###################################################################### sub HMCCURPCPROC_StartRPCServer ($) @@ -1461,7 +1462,7 @@ sub HMCCURPCPROC_StartRPCServer ($) if (!exists($hash->{hmccu}{localaddr}) || !exists($hash->{rpcid})); # Check if RPC server is already running - return (0, 'RPC server already running') if (HMCCURPCPROC_CheckProcessState ($hash, 'running')); + return (2, 'RPC server already running') if (HMCCURPCPROC_CheckProcessState ($hash, 'running')); # Get parameters and attributes my $ping = AttrVal ($ioHash->{NAME}, 'rpcPingCCU', $HMCCURPCPROC_TIME_PING);