diff --git a/CHANGED b/CHANGED index c96a9bcd6..236cb36dc 100644 --- a/CHANGED +++ b/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. + - change: 88_HMCCU: Minor changes - change: 71_ZM_Monitor: now writing internal 'model' - feature: 74_AMADDevice: add class support for openApp, fix bug then change attr remoteServer set Internal MODEL diff --git a/FHEM/88_HMCCU.pm b/FHEM/88_HMCCU.pm index a3f38ae9e..aba0eb1a2 100755 --- a/FHEM/88_HMCCU.pm +++ b/FHEM/88_HMCCU.pm @@ -4,7 +4,7 @@ # # $Id$ # -# Version 4.3.018 +# Version 4.3.019 # # Module for communication between FHEM and Homematic CCU2/3. # @@ -52,7 +52,7 @@ my %HMCCU_CUST_CHN_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS; # HMCCU version -my $HMCCU_VERSION = '4.3.018'; +my $HMCCU_VERSION = '4.3.019'; # Constants and default values my $HMCCU_MAX_IOERRORS = 100; @@ -212,7 +212,7 @@ sub HMCCU_SetDefaults ($); # Status and logging functions sub HMCCU_Trace ($$$$); -sub HMCCU_Log ($$$$); +sub HMCCU_Log ($$$;$); sub HMCCU_LogError ($$$); sub HMCCU_SetError ($@); sub HMCCU_SetState ($@); @@ -639,7 +639,8 @@ sub HMCCU_Attr ($@) # Return empty string on success or error message on error. ###################################################################### -sub HMCCU_AttrInterfacesPorts ($$$) { +sub HMCCU_AttrInterfacesPorts ($$$) +{ my ($hash, $attr, $attrval) = @_; my $name = $hash->{NAME}; @@ -1465,11 +1466,6 @@ sub HMCCU_Set ($@) return HMCCU_SetError ($hash, $result) if ($result < 0); return HMCCU_SetState ($hash, "OK"); } -# elsif ($opt eq 'test') { -# my $backend = shift @$a; -# my $url = defined ($backend) ? HMCCU_BuildURL ($hash, $backend) : ''; -# return "URL=$url"; -# } elsif ($opt eq 'initialize') { return HMCCU_SetError ($hash, "State of CCU must be unreachable") if ($hash->{ccustate} ne 'unreachable'); @@ -1508,51 +1504,60 @@ sub HMCCU_Set ($@) return HMCCU_SetState ($hash, "OK"); } elsif ($opt eq 'datapoint') { - $usage = "set $name $opt FHEM-Device[.Channel].Datapoint=Value [...]"; - return HMCCU_SetError ($hash, $usage) if (scalar (keys %$h) < 1); + $usage = "set $name $opt DevSpec [Channel].Datapoint=Value [...]\n"; + my $devSpec = shift @$a; + + return HMCCU_SetError ($hash, $usage) if (scalar (keys %$h) < 1 || !defined($devSpec)); my $cmd = 1; my %dpValues; + my @devList = devspec2array ($devSpec); + return HMCCU_SetError ($hash, "No FHEM device matching $devSpec in command set datapoint") + if (scalar (@devList) == 0); + foreach my $dptSpec (keys %$h) { my $adr; my $chn; my $dpt; - my ($devName, $t1, $t2) = split (/\./, $dptSpec); + my ($t1, $t2) = split (/\./, $dptSpec); - return HMCCU_SetError ($hash, "FHEM device $devName not defined") - if (!exists ($defs{$devName})); - - my $dh = $defs{$devName}; - my $ccuif = $dh->{ccuif}; - - if ($dh->{TYPE} eq 'HMCCUCHN') { - return HMCCU_SetError ($hash, "Channel number not allowed for FHEM device $devName") - if (defined ($t2)); - ($adr, $chn) = HMCCU_SplitChnAddr ($dh->{ccuaddr}); - $dpt = $t1; - } - elsif ($dh->{TYPE} eq 'HMCCUDEV') { - return HMCCU_SetError ($hash, "Missing channel number for device $devName") - if (!defined ($t2)); - return HMCCU_SetError ($hash, "Invalid channel number specified for device $devName") - if ($t1 !~ /^[0-9]+$/ || $t1 > $dh->{channels}); - $adr = $dh->{ccuaddr}; - $chn = $t1; - $dpt = $t2; - } - else { - return HMCCU_SetError ($hash, "FHEM device $devName has illegal type"); - } + foreach my $devName (@devList) { + my $dh = $defs{$devName}; + my $ccuif = $dh->{ccuif}; - return HMCCU_SetError ($hash, "Invalid datapoint $dpt specified for device $devName") - if (!HMCCU_IsValidDatapoint ($dh, $dh->{ccutype}, $chn, $dpt, 2)); - - my $statevals = AttrVal ($dh->{NAME}, 'statevals', ''); + if ($dh->{TYPE} eq 'HMCCUCHN') { + if (defined ($t2)) { + HMCCU_Log ($hash, 3, "Ignored channel in set datapoint for device $devName"); + $dpt = $t2; + } + else { + $dpt = $t1; + } + ($adr, $chn) = HMCCU_SplitChnAddr ($dh->{ccuaddr}); + } + elsif ($dh->{TYPE} eq 'HMCCUDEV') { + return HMCCU_SetError ($hash, "Missing channel number for device $devName") + if (!defined ($t2)); + return HMCCU_SetError ($hash, "Invalid channel number specified for device $devName") + if ($t1 !~ /^[0-9]+$/ || $t1 > $dh->{channels}); + $adr = $dh->{ccuaddr}; + $chn = $t1; + $dpt = $t2; + } + else { + return HMCCU_SetError ($hash, "FHEM device $devName has illegal type"); + } - my $no = sprintf ("%03d", $cmd); - $dpValues{"$no.$ccuif.$devName:$chn.$dpt"} = HMCCU_Substitute ($h->{$dptSpec}, $statevals, 1, undef, ''); - $cmd++; + return HMCCU_SetError ($hash, "Invalid datapoint $dpt specified for device $devName") + if (!HMCCU_IsValidDatapoint ($dh, $dh->{ccutype}, $chn, $dpt, 2)); + + my $statevals = AttrVal ($dh->{NAME}, 'statevals', ''); + + my $no = sprintf ("%03d", $cmd); + $dpValues{"$no.$ccuif.$devName:$chn.$dpt"} = HMCCU_Substitute ($h->{$dptSpec}, $statevals, 1, undef, ''); + $cmd++; + } } my $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpValues); @@ -2590,9 +2595,10 @@ sub HMCCU_Trace ($$$$) # Log message and return parameter rc. ###################################################################### -sub HMCCU_Log ($$$$) +sub HMCCU_Log ($$$;$) { my ($hash, $level, $msg, $rc) = @_; + $rc = 0 if (!defined($rc)); my $name = "n/a"; my $type = "n/a"; $name = $hash->{NAME} if (exists ($hash->{NAME})); @@ -2618,9 +2624,10 @@ sub HMCCU_LogError ($$$) ###################################################################### # Set error state and write log file message -# Parameter text can be an error code (integer < 0) or an error text. +# Parameter text can be an error code (integer <= 0) or an error text. +# If text is 0 or 'OK' call HMCCU_SetState which returns undef. +# Otherwise error message is returned. # Parameter addinfo is optional. -# Return error message. ###################################################################### sub HMCCU_SetError ($@) @@ -2653,19 +2660,23 @@ sub HMCCU_SetError ($@) -21 => 'Device disabled' ); - $msg = exists ($errlist{$text}) ? $errlist{$text} : $text; - $msg = $type.": ".$name." ". $msg; - if (defined ($addinfo) && $addinfo ne '') { - $msg .= ". $addinfo"; + if ($text ne 'OK' && $text ne '0') { + $msg = exists ($errlist{$text}) ? $errlist{$text} : $text; + $msg = $type.": ".$name." ". $msg; + if (defined ($addinfo) && $addinfo ne '') { + $msg .= ". $addinfo"; + } + HMCCU_Log ($hash, 1, $msg, undef); + return HMCCU_SetState ($hash, "Error", $msg); + } + else { + return HMCCU_SetState ($hash, "OK"); } - - HMCCU_Log ($hash, 1, $msg, undef); - - return HMCCU_SetState ($hash, "Error", $msg); } ###################################################################### # Set state of device if attribute ccuflags = ackState +# Return undef or $retval ###################################################################### sub HMCCU_SetState ($@) @@ -2932,19 +2943,18 @@ sub HMCCU_UpdateClients ($$$$$$) my ($hash, $devexp, $ccuget, $fromccu, $ifname, $nonBlock) = @_; my $fhname = $hash->{NAME}; my $c = 0; + my $dc = 0; my $filter = "ccudevstate=active"; $filter .= ",ccuif=$ifname" if (defined ($ifname)); $ccuget = AttrVal ($fhname, 'ccuget', 'Value') if ($ccuget eq 'Attr'); my $list = ''; - HMCCU_Log ($hash, 2, "Updating devices for filter $filter", 0); - if ($fromccu) { foreach my $name (sort keys %{$hash->{hmccu}{adr}}) { next if ($name !~ /$devexp/ || !($hash->{hmccu}{adr}{$name}{valid})); - my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", undef, $filter); - + my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", undef, $filter); + $dc += scalar(@devlist); foreach my $d (@devlist) { my $ch = $defs{$d}; next if (!defined ($ch->{IODev}) || !defined ($ch->{ccuaddr})); @@ -2958,8 +2968,7 @@ sub HMCCU_UpdateClients ($$$$$$) } else { my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", $devexp, $filter); - Log3 $fhname, 2, "HMCCU: Found ".scalar(@devlist)." client devices matching $devexp"; - + $dc = scalar(@devlist); foreach my $d (@devlist) { my $ch = $defs{$d}; next if (!defined ($ch->{IODev}) || !defined ($ch->{ccuaddr}) || $ch->{ccuif} eq 'fhem'); @@ -2970,6 +2979,9 @@ sub HMCCU_UpdateClients ($$$$$$) $c++; } } + + return HMCCU_Log ($hash, 2, "HMCCU: Found no devices to update", 0) if ($c == 0); + HMCCU_Log ($hash, 2, "Updating $c of $dc client devices matching devexp=$devexp filter=$filter"); if (HMCCU_IsFlag ($fhname, 'nonBlocking') || $nonBlock) { HMCCU_HMScriptExt ($hash, '!GetDatapointsByDevice', { list => $list, ccuget => $ccuget }, @@ -6140,7 +6152,7 @@ sub HMCCU_ReadRPCQueue ($) } ###################################################################### -# Execute Homematic command on CCU. +# Execute Homematic command on CCU (blocking). # If parameter mode is 1 an empty string is a valid result. # Return undef on error. ###################################################################### @@ -6162,7 +6174,6 @@ sub HMCCU_HMCommand ($$$) $param->{sslargs} = { SSL_verify_mode => 0 }; my ($err, $response) = HttpUtils_BlockingGet ($param); -# my $response = GetFileFromURL ($url, $ccureqtimeout, $cmd); if ($err eq '') { $value = $response; $value =~ s/(.*)<\/xml>//; @@ -6184,7 +6195,7 @@ sub HMCCU_HMCommand ($$$) } ###################################################################### -# Execute Homematic command on CCU without waiting for response. +# Execute Homematic command on CCU (non blocking). ###################################################################### sub HMCCU_HMCommandNB ($$$) @@ -6251,9 +6262,6 @@ sub HMCCU_HMScriptExt ($$$$$) my $host = $hash->{host}; my $ccureqtimeout = AttrVal ($hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST); -# if (!defined ($nonBlocking)) { -# $nonBlocking = HMCCU_IsFlag ($name, 'nonBlocking') ? 1 : 0; -# } if ($hmscript =~ /^!(.*)$/) { # Internal script @@ -6301,6 +6309,8 @@ sub HMCCU_HMScriptExt ($$$$$) } } + HMCCU_Trace ($hash, 2, "HMScriptEx", $code); + # Execute script on CCU my $url = HMCCU_BuildURL ($hash, 'rega'); if (defined ($cbFunc)) { @@ -6535,19 +6545,17 @@ sub HMCCU_SetMultipleDatapoints ($$) { } } - # Execute command (non blocking) if ($ccuFlags =~ /nonBlocking/) { + # Execute command (non blocking) HMCCU_HMCommandNB ($clHash, $cmd, undef); return 0; } - - # Execute command (blocking) - my $response = HMCCU_HMCommand ($clHash, $cmd, 1); - return -2 if (!defined ($response)); - - # Datapoint verification ??? - - return 0; + else { + # Execute command (blocking) + my $response = HMCCU_HMCommand ($clHash, $cmd, 1); + return defined ($response) ? 0 : -2; + # Datapoint verification ??? + } } ###################################################################### @@ -8520,9 +8528,10 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
  • set <name> cleardefaults
    Clear default attributes imported from file.

  • -
  • set <name> datapoint <FHEM-Device>[.<channel-number>].<datapoint>=<value>
    +
  • set <name> datapoint <FHEM-DevSpec> [<channel-number>].<datapoint>=<value>
    Set datapoint values on multiple devices. If FHEM-Device is of type HMCCUDEV - a channel-number must be specified. + a channel-number must be specified. The channel number is ignored for devices of + type HMCCUCHN.

  • set <name> defaults
    Set default attributes for I/O device. diff --git a/FHEM/88_HMCCUCHN.pm b/FHEM/88_HMCCUCHN.pm index 6b88f5eb1..eb590a077 100644 --- a/FHEM/88_HMCCUCHN.pm +++ b/FHEM/88_HMCCUCHN.pm @@ -4,7 +4,7 @@ # # $Id$ # -# Version 4.3.008 +# Version 4.3.009 # # (c) 2019 zap (zap01 t-online de) # @@ -41,7 +41,7 @@ sub HMCCUCHN_Initialize ($) $hash->{parseParams} = 1; $hash->{AttrList} = "IODev ccucalculate ". - "ccuflags:multiple-strict,ackState,nochn0,trace ccureadingfilter ". + "ccuflags:multiple-strict,ackState,logCommand,nochn0,trace ccureadingfilter ". "ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ". "ccureadingname:textField-long ccuSetOnChange ". "ccureadings:0,1 ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint ". @@ -228,12 +228,16 @@ sub HMCCUCHN_Set ($@) my $ccutype = $hash->{ccutype}; my $ccuaddr = $hash->{ccuaddr}; my $ccuif = $hash->{ccuif}; + my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $statevals = AttrVal ($name, 'statevals', ''); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', ''); my $result = ''; my $rc; + # Log commands + HMCCU_Log ($hash, 3, "set $name $opt ".join (' ', @$a)) if ($ccuflags =~ /logCommand/); + if ($opt eq 'datapoint') { my $usage = "Usage: set $name datapoint {datapoint} {value} [...]"; my %dpval; @@ -255,9 +259,7 @@ sub HMCCUCHN_Set ($@) return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1); $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'control') { return HMCCU_SetError ($hash, -14) if ($cd eq ''); @@ -270,9 +272,7 @@ sub HMCCUCHN_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$ccuif.$ccuaddr.$cd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } ); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt =~ /^($hash->{statevals})$/) { my $cmd = $1; @@ -287,9 +287,7 @@ sub HMCCUCHN_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$ccuif.$ccuaddr.$sd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } ); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'toggle') { return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals})); @@ -324,9 +322,7 @@ sub HMCCUCHN_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$objname" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } ); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'pct' || $opt eq 'up' || $opt eq 'down') { return HMCCU_SetError ($hash, "Can't find LEVEL datapoint for device type $ccutype") @@ -374,8 +370,7 @@ sub HMCCUCHN_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$objname" => $objvalue }); } - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') { return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals})); @@ -400,9 +395,7 @@ sub HMCCUCHN_Set ($@) "001.$ccuif.$ccuaddr.ON_TIME" => $timespec, "002.$ccuif.$ccuaddr.$sd" => HMCCU_Substitute ("on", $statevals, 1, undef, '') }); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'clear') { my $rnexp = shift @$a; @@ -418,10 +411,8 @@ sub HMCCUCHN_Set ($@) if (defined ($par) && $par eq 'device') { ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr); } - my ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $ccuobj, "MASTER", $h); -# my $rc = HMCCU_RPCSetConfig ($hash, $ccuobj, $h); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - return HMCCU_SetState ($hash, "OK"); + ($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $ccuobj, "MASTER", $h); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'rpcparameter') { return HMCCU_SetError ($hash, "Usage: set $name rpcparameter [MASTER|VALUES] {parameter}={value} [...]") @@ -429,46 +420,42 @@ sub HMCCUCHN_Set ($@) my $key = shift @$a; $key = 'VALUES' if (!defined ($key)); - my $rc; - my $res; - if ($key eq 'VALUES') { - ($rc, $res) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h); + ($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h); } elsif ($key eq 'MASTER') { - ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $key, $h); + ($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $key, $h); } else { return HMCCU_SetError ($hash, "Key must be MASTER or VALUES"); } - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'defaults') { - my $rc = HMCCU_SetDefaults ($hash); - return HMCCU_SetError ($hash, "HMCCU: No default attributes found") if ($rc == 0); - return HMCCU_SetState ($hash, "OK"); + $rc = HMCCU_SetDefaults ($hash); + return HMCCU_SetError ($hash, $rc == 0 ? "No default attributes found" : "OK"); } else { - return "HMCCUCHN: Unknown argument $opt, choose one of $rocmds" - if ($hash->{statevals} eq 'readonly'); - my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of $rwcmds"; - if ($hash->{statevals} ne '') { - my @cmdlist = split /\|/,$hash->{statevals}; - shift @cmdlist; - $retmsg .= ':'.join(',',@cmdlist) if (scalar(@cmdlist) > 0); - foreach my $sv (@cmdlist) { - $retmsg .= ' '.$sv.':noArg'; - } - $retmsg .= " toggle:noArg"; - $retmsg .= " on-for-timer on-till" - if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "ON_TIME", 2)); - $retmsg .= " pct up down" - if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "LEVEL", 2)); - } + my $retmsg = "clear defaults:noArg"; + if ($hash->{statevals} ne 'readonly') { + $retmsg .= " config control datapoint rpcparameter devstate"; - return $retmsg; + if ($hash->{statevals} ne '') { + my @cmdlist = split /\|/,$hash->{statevals}; + shift @cmdlist; + $retmsg .= ':'.join(',',@cmdlist) if (scalar(@cmdlist) > 0); + foreach my $sv (@cmdlist) { + $retmsg .= ' '.$sv.':noArg'; + } + $retmsg .= " toggle:noArg"; + $retmsg .= " on-for-timer on-till" + if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "ON_TIME", 2)); + $retmsg .= " pct up down" + if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $ccuaddr, "LEVEL", 2)); + } + } + return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); } } @@ -500,11 +487,15 @@ sub HMCCUCHN_Get ($@) my $ccuaddr = $hash->{ccuaddr}; my $ccuif = $hash->{ccuif}; my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', ''); + my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $ccureadings = AttrVal ($name, "ccureadings", 1); my $result = ''; my $rc; + # Log commands + HMCCU_Log ($hash, 3, "set $name $opt ".join (' ', @$a)) if ($ccuflags =~ /logCommand/); + if ($opt eq 'devstate') { return HMCCU_SetError ($hash, -13) if ($sd eq ''); return HMCCU_SetError ($hash, -8) @@ -560,10 +551,9 @@ sub HMCCUCHN_Get ($@) } $par = '.*' if (!defined ($par)); - my ($rc, $res) = HMCCU_RPCRequest ($hash, "getParamset", $ccuobj, "MASTER", undef, $par); -# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamset", $par); - return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0); - return $ccureadings ? undef : $res; + ($rc, $result) = HMCCU_RPCRequest ($hash, "getParamset", $ccuobj, "MASTER", undef, $par); + return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0); + return $ccureadings ? undef : $result; } elsif ($opt eq 'configlist') { my $ccuobj = $ccuaddr; @@ -576,10 +566,9 @@ sub HMCCUCHN_Get ($@) } $par = '.*' if (!defined ($par)); - my ($rc, $res) = HMCCU_RPCRequest ($hash, "listParamset", $ccuobj, "MASTER", undef, $par); -# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "listParamset", $par); - return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0); - return $res; + ($rc, $result) = HMCCU_RPCRequest ($hash, "listParamset", $ccuobj, "MASTER", undef, $par); + return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0); + return $result; } elsif ($opt eq 'configdesc') { my $ccuobj = $ccuaddr; @@ -588,14 +577,12 @@ sub HMCCUCHN_Get ($@) ($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr); } - my ($rc, $res) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "MASTER", undef); -# my ($rc, $res) = HMCCU_RPCGetConfig ($hash, $ccuobj, "getParamsetDescription", undef); - return HMCCU_SetError ($hash, $rc, $res) if ($rc < 0); - return $res; + ($rc, $result) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "MASTER", undef); + return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0); + return $result; } elsif ($opt eq 'defaults') { - $result = HMCCU_GetDefaults ($hash, 0); - return $result; + return HMCCU_GetDefaults ($hash, 0); } else { my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of devstate:noArg defaults:noArg datapoint"; @@ -812,9 +799,10 @@ sub HMCCUCHN_Get ($@) Example:
    dewpoint:taupunkt:1.TEMPERATURE,1.HUMIDITY

  • -
  • ccuflags {nochn0, trace}
    +
  • ccuflags {ackState, logCommand, nochn0, trace}
    Control behaviour of device:
    ackState: Acknowledge command execution by setting STATE to error or success.
    + logCommand: Write get and set commands to FHEM log with verbose level 3.
    nochn0: Prevent update of status channel 0 datapoints / readings.
    trace: Write log file information for operations related to this device.

  • diff --git a/FHEM/88_HMCCUDEV.pm b/FHEM/88_HMCCUDEV.pm index bad71aa9d..170bb851e 100644 --- a/FHEM/88_HMCCUDEV.pm +++ b/FHEM/88_HMCCUDEV.pm @@ -4,7 +4,7 @@ # # $Id$ # -# Version 4.3.010 +# Version 4.3.011 # # (c) 2019 zap (zap01 t-online de) # @@ -43,7 +43,7 @@ sub HMCCUDEV_Initialize ($) $hash->{parseParams} = 1; $hash->{AttrList} = "IODev ccuaggregate:textField-long ccucalculate:textField-long ". - "ccuflags:multiple-strict,ackState,nochn0,trace ccureadingfilter:textField-long ". + "ccuflags:multiple-strict,ackState,logCommand,nochn0,trace ccureadingfilter:textField-long ". "ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ". "ccureadingname:textField-long ". "ccureadings:0,1 ccuget:State,Value ccuscaleval ccuSetOnChange ccuverify:0,1,2 disable:0,1 ". @@ -281,9 +281,9 @@ sub HMCCUDEV_InitDevice ($$) return 0; } -##################################### +###################################################################### # Delete device -##################################### +###################################################################### sub HMCCUDEV_Delete ($$) { @@ -296,9 +296,9 @@ sub HMCCUDEV_Delete ($$) return undef; } -##################################### +###################################################################### # Set attribute -##################################### +###################################################################### sub HMCCUDEV_Attr ($@) { @@ -330,9 +330,9 @@ sub HMCCUDEV_Attr ($@) return; } -##################################### +###################################################################### # Set commands -##################################### +###################################################################### sub HMCCUDEV_Set ($@) { @@ -342,9 +342,6 @@ sub HMCCUDEV_Set ($@) return "No set command specified" if (!defined ($opt)); - # Valid commands for read only devices - my $rocmds = "clear config defaults:noArg"; - # Get I/O device, check device state return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' || !defined ($hash->{IODev})); @@ -374,6 +371,9 @@ sub HMCCUDEV_Set ($@) my $result = ''; my $rc; + # Log commands + HMCCU_Log ($hash, 3, "set $name $opt ".join (' ', @$a)) if ($ccuflags =~ /logCommand/); + if ($opt eq 'datapoint') { my $usage = "Usage: set $name datapoint [{channel-number}.]{datapoint} {value} [...]"; my %dpval; @@ -414,9 +414,7 @@ sub HMCCUDEV_Set ($@) return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1); $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'control') { return HMCCU_SetError ($hash, -12) if ($cc eq ''); @@ -431,9 +429,7 @@ sub HMCCUDEV_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } ); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt =~ /^($hash->{statevals})$/) { my $cmd = $1; @@ -447,9 +443,7 @@ sub HMCCUDEV_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$ccuif.$ccuaddr:$sc.$sd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } ); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'toggle') { return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals})); @@ -488,9 +482,7 @@ sub HMCCUDEV_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$objname" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } ); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'pct' || $opt eq 'up' || $opt eq 'down') { return HMCCU_SetError ($hash, -11) if ($sc eq '' && $cc eq ''); @@ -550,8 +542,7 @@ sub HMCCUDEV_Set ($@) $rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$objname" => $objvalue }); } - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') { return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{statevals})); @@ -575,9 +566,7 @@ sub HMCCUDEV_Set ($@) "001.$ccuif.$ccuaddr:$sc.ON_TIME" => $timespec, "002.$ccuif.$ccuaddr:$sc.$sd" => HMCCU_Substitute ("on", $statevals, 1, undef, '') }); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'clear') { my $rnexp = shift @$a; @@ -596,10 +585,7 @@ sub HMCCUDEV_Set ($@) } my ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $objname, "MASTER", $h); -# my $rc = HMCCU_RPCSetConfig ($hash, $objname, $h); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'rpcparameter') { return HMCCU_SetError ($hash, "Usage: set $name rpcparameter { channel VALUES | [channel] MASTER } {parameter}={value} [...]") @@ -607,8 +593,6 @@ sub HMCCUDEV_Set ($@) my $key; my $chn; - my $rc; - my $res; while (my $p = shift @$a) { if (uc($p) =~ /^(MASTER|VALUES)$/ && !defined ($key)) { @@ -624,53 +608,51 @@ sub HMCCUDEV_Set ($@) my $addr = defined ($chn) ? "$ccuaddr:$chn" : $ccuaddr; if ($key eq 'VALUES') { - ($rc, $res) = HMCCU_SetMultipleParameters ($hash, $addr, $h); + ($rc, $result) = HMCCU_SetMultipleParameters ($hash, $addr, $h); } elsif ($key eq 'MASTER') { - ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $addr, $key, $h); + ($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $addr, $key, $h); } else { return HMCCU_SetError ($hash, "Key must be MASTER or VALUES"); } - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'defaults') { my $rc = HMCCU_SetDefaults ($hash); - return HMCCU_SetError ($hash, "HMCCU: No default attributes found") if ($rc == 0); - return HMCCU_SetState ($hash, "OK"); + return HMCCU_SetError ($hash, $rc == 0 ? "No default attributes found" : "OK"); } else { - return "HMCCUCHN: Unknown argument $opt, choose one of ".$rocmds - if ($hash->{statevals} eq 'readonly'); - - my $retmsg = "HMCCUDEV: Unknown argument $opt, choose one of clear config control datapoint rpcparameter defaults:noArg"; - if ($sc ne '') { - $retmsg .= " devstate"; - if ($hash->{statevals} ne '') { - my @cmdlist = split /\|/,$hash->{statevals}; - shift @cmdlist; - $retmsg .= ':'.join(',',@cmdlist) if (@cmdlist > 0); - foreach my $sv (@cmdlist) { - $retmsg .= ' '.$sv.':noArg'; + my $retmsg = "clear config defaults:noArg"; + + if ($hash->{statevals} ne 'readonly') { + $retmsg .= " control datapoint rpcparameter"; + if ($sc ne '') { + $retmsg .= " devstate"; + if ($hash->{statevals} ne '') { + my @cmdlist = split /\|/,$hash->{statevals}; + shift @cmdlist; + $retmsg .= ':'.join(',',@cmdlist) if (@cmdlist > 0); + foreach my $sv (@cmdlist) { + $retmsg .= ' '.$sv.':noArg'; + } + $retmsg .= " toggle:noArg"; + $retmsg .= " on-for-timer on-till" + if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "ON_TIME", 2)); + $retmsg .= " pct up down" + if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "LEVEL", 2) || + HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $cc, "LEVEL", 2)); } - $retmsg .= " toggle:noArg"; - $retmsg .= " on-for-timer on-till" - if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "ON_TIME", 2)); - $retmsg .= " pct up down" - if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "LEVEL", 2) || - HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $cc, "LEVEL", 2)); } } - - return $retmsg; + return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); } } -##################################### +###################################################################### # Get commands -##################################### +###################################################################### sub HMCCUDEV_Get ($@) { @@ -700,6 +682,7 @@ sub HMCCUDEV_Get ($@) my $ccutype = $hash->{ccutype}; my $ccuaddr = $hash->{ccuaddr}; my $ccuif = $hash->{ccuif}; + my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $ccureadings = AttrVal ($name, 'ccureadings', 1); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', ''); @@ -711,6 +694,9 @@ sub HMCCUDEV_Get ($@) return "HMCCUDEV: Unknown argument $opt, choose one of update:noArg"; } + # Log commands + HMCCU_Log ($hash, 3, "set $name $opt ".join (' ', @$a)) if ($ccuflags =~ /logCommand/); + if ($opt eq 'devstate') { return HMCCU_SetError ($hash, -11) if ($sc eq ''); return HMCCU_SetError ($hash, -13) if ($sd eq ''); diff --git a/FHEM/lib/AttrTemplate/hmccu.template b/FHEM/lib/AttrTemplate/hmccu.template new file mode 100644 index 000000000..40a973752 --- /dev/null +++ b/FHEM/lib/AttrTemplate/hmccu.template @@ -0,0 +1,54 @@ +###################################################################### +# $Id: hmccu.template 18592 2019-02-14 06:27:39Z Beta-User $ +# +# Comments start with #. Empty lines are ignored. +# Syntax of one entry: +# name: line, +# one optional filter: line +# zero or more par: lines +# FHEM-Commands +# filter:INTERNAL=VALUE (optional) +# par: name of the parameter; comment; perl_code (optional) +# perl_code returns a value for the parameter, or undef. +# If undef, the user has to specify them (the comment is shown to the user) +###################################################################### + +###################################################################### +# Door or window sensor +name:DoorWindowSensor +filter:TYPE=HMCCUCHN|HMCCUDEV:FILTER=ccutype=HM-Sec-SCo|HM-Sec-SC|HM-Sec-SC-2|HMIP-SWDO|HmIP-SWDO-I +par:channelNo;Channel number;{ InternalVal("DEVICE","TYPE","") eq "HMCCUDEV" ? "1." : "" } +desc: Door/window sensor +attr DEVICE ccureadingfilter STATE +attr DEVICE devStateIcon closed:10px-kreis-gruen open:10px-kreis-rot +attr DEVICE event-on-change-reading .* +attr DEVICE genericDeviceType ContactSensor +attr DEVICE hmstatevals ERROR!7:sabotage;SABOTAGE!1:sabotage +attr DEVICE statedatapoint channelNoSTATE +attr DEVICE substitute STATE!(0|false):closed,(1|true):open + +###################################################################### +# Window handle sensor +name WindowHandleSensor +filter:TYPE=HMCCUCHN|HMCCUDEV:FILTER=ccutype=HM-Sec-RHS|HM-Sec-RHS-2 +attr DEVICE ccureadingfilter STATE +attr DEVICE hmstatevals ERROR!1:sabotage +attr DEVICE statedatapoint channelNoSTATE +attr DEVICE substitute STATE!0:closed,1:tilted,2:open;ERROR!0:no,1:sabotage + +###################################################################### +# Power socket +name PowerSocket +filter:TYPE=HMCCUCHN|HMCCUDEV:FILTER=ccutype=HM-LC-Sw1-Pl-2|HM-LC-Sw1-Pl-DN-R1|HmIP-PS +par:channelNo;Channel number;{ InternalVal("DEVICE","TYPE","") eq "HMCCUDEV" ? (InternalVal("DEVICE","ccuif","") eq "BidCos-RF" ? "1." : "3.") : "" } +desc: Power socket BidCos +attr DEVICE ccureadingfilter STATE +attr DEVICE statedatapoint channelNoSTATE +attr DEVICE controldatapoint channelNoSTATE +attr DEVICE statevals on:true,off:false +attr DEVICE substitute STATE!(1|true):on,(0|false):off +attr DEVICE webCmd devstate +attr DEVICE widgetOverride devstate:uzsuToggle,off,on + + +