From 934adfc315f0baa37c8ab1bef71384e8d5659682 Mon Sep 17 00:00:00 2001 From: zap Date: Wed, 19 Sep 2018 11:39:04 +0000 Subject: [PATCH] HMCCU: Fixed delayed initialization function git-svn-id: https://svn.fhem.de/fhem/trunk@17372 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/88_HMCCU.pm | 234 +++++++++++++++++++++++++++++++++------ fhem/FHEM/88_HMCCUDEV.pm | 143 +++++++++++++++--------- fhem/FHEM/HMCCUConf.pm | 83 +++++++++++++- 3 files changed, 369 insertions(+), 91 deletions(-) diff --git a/fhem/FHEM/88_HMCCU.pm b/fhem/FHEM/88_HMCCU.pm index 333ae96fb..c9a06c200 100755 --- a/fhem/FHEM/88_HMCCU.pm +++ b/fhem/FHEM/88_HMCCU.pm @@ -4,7 +4,7 @@ # # $Id$ # -# Version 4.3.001 +# Version 4.3.002 # # Module for communication between FHEM and Homematic CCU2. # @@ -25,6 +25,7 @@ # set execute # set importdefaults # set hmscript {|!|'['']'} [dump] [= [...]] +# set rpcregister [{all|}] # set rpcserver {on|off|restart} # set var [] [= [...]] # @@ -37,7 +38,7 @@ # [defattr] [duplicates] [save] [= [...]]}] # get dump {devtypes|datapoints} [] # get dutycycle -# get exportdefaults {filename} +# get exportdefaults {filename} [csv] # get firmware [{type-expr}|full] # get parfile [] # get rpcevents @@ -245,6 +246,7 @@ sub HMCCU_AggregationRules ($$); # Handling of default attributes sub HMCCU_ExportDefaults ($); +sub HMCCU_ExportDefaultsCSV ($); sub HMCCU_ImportDefaults ($); sub HMCCU_FindDefaults ($$); sub HMCCU_SetDefaults ($); @@ -313,6 +315,7 @@ sub HMCCU_IODeviceStates (); sub HMCCU_IsFlag ($$); # Handle interfaces, devices and channels +sub HMCCU_CreateDevice ($$$$$); sub HMCCU_FormatDeviceInfo ($); sub HMCCU_GetAddress ($$$$); sub HMCCU_GetCCUDeviceParam ($$); @@ -489,7 +492,7 @@ sub HMCCU_Define ($$) if ($hash->{ccustate} eq 'active') { # If CCU is alive read devices, channels, interfaces and groups HMCCU_Log ($hash, 1, "HMCCU: Initializing device", 0); - HMCCU_InitDevice ($hash); + $rc = HMCCU_InitDevice ($hash); } if ($hash->{ccustate} ne 'active' || $rc > 0) { @@ -855,6 +858,56 @@ sub HMCCU_ExportDefaults ($) return 1; } +###################################################################### +# Export default attributes as CSV file. +###################################################################### + +sub HMCCU_ExportDefaultsCSV ($) +{ + my ($filename) = @_; + + my %attrlist = ( + '_type' => '', '_description' => '', '_channels' => '', + 'ccureadingfilter' => '', 'ccureadingname' => '', 'ccuscaleval' => '', 'cmdIcon' => '', 'controldatapoint' => '', + 'eventMap' => '', 'event-on-change-reading' => '', 'event-on-update-reading' => '', + 'genericDeviceType' => '', + 'hmstatevals' => '', + 'statedatapoint' => '', 'statevals' => '', 'stripnumber' => '', 'substexcl' => '', 'substitute' => '', + 'webCmd' => '', 'widgetOverride' => '' + ); + + return 0 if (!open (DEFFILE, ">$filename")); + + # Write header + print DEFFILE "_flag,".join (',', sort keys %attrlist)."\n"; + + # Write channel configurations + foreach my $t (keys %{$HMCCU_CHN_DEFAULTS}) { + print DEFFILE "C"; + $attrlist{'_type'} = $t; + foreach $a (sort keys %attrlist) { + my $v = exists ($HMCCU_CHN_DEFAULTS->{$t}{$a}) ? $HMCCU_CHN_DEFAULTS->{$t}{$a} : $attrlist{$a}; + print DEFFILE ",\"$v\""; + } + print DEFFILE "\n"; + } + + # Write device configurations + foreach my $t (keys %{$HMCCU_DEV_DEFAULTS}) { + print DEFFILE "D"; + $attrlist{'_type'} = $t; + foreach $a (sort keys %attrlist) { + my $v = exists ($HMCCU_DEV_DEFAULTS->{$t}{$a}) ? $HMCCU_DEV_DEFAULTS->{$t}{$a} : $attrlist{$a}; + print DEFFILE ",\"$v\""; + } + print DEFFILE "\n"; + } + + close (DEFFILE); + + return 1; +} + ###################################################################### # Import customer default attributes # Returns 1 on success. Returns negative line number on syntax errors. @@ -1327,7 +1380,12 @@ sub HMCCU_Set ($@) my $name = shift @$a; my $opt = shift @$a; my $options = "var delete execute hmscript cleardefaults:noArg defaults:noArg ". - "importdefaults rpcserver:on,off,restart datapoint ackmessages:noArg"; + "importdefaults rpcregister:all rpcserver:on,off,restart datapoint ackmessages:noArg"; + my @ifList = HMCCU_GetRPCInterfaceList ($hash); + if (scalar (@ifList) > 0) { + my $ifStr = join (',', @ifList); + $options =~ s/register:all/rpcregister:all,$ifStr/; + } my $usage = "HMCCU: Unknown argument $opt, choose one of $options"; my $host = $hash->{host}; @@ -1341,6 +1399,7 @@ sub HMCCU_Set ($@) my $ccureqtimeout = AttrVal ($name, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST); my $readingformat = HMCCU_GetAttrReadingFormat ($hash, $hash); my $substitute = HMCCU_GetAttrSubstitute ($hash, $hash); + my $result; # Add program names to command execute if (exists ($hash->{hmccu}{prg})) { @@ -1361,7 +1420,6 @@ sub HMCCU_Set ($@) my $objname = shift @$a; my $objvalue = shift @$a; $usage = "set $name $opt [{'bool'|'list'|'number'|'test'}] variable value [param=value [...]]"; - my $result; return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue)); @@ -1395,7 +1453,7 @@ sub HMCCU_Set ($@) return HMCCU_SetError ($hash, $usage) if (!defined ($objname) || $objtype !~ /^(OT_VARDP|OT_DEVICE)$/); - my $result = HMCCU_HMScriptExt ($hash, "!DeleteObject", { name => $objname, type => $objtype }); + $result = HMCCU_HMScriptExt ($hash, "!DeleteObject", { name => $objname, type => $objtype }); return HMCCU_SetError ($hash, -2) if ($result =~ /^ERROR:.*/); return HMCCU_SetState ($hash, "OK"); @@ -1469,6 +1527,25 @@ sub HMCCU_Set ($@) return defined ($dump) ? $response : undef; } + elsif ($opt eq 'rpcregister') { + return HMCCU_SetError ($hash, "HMCCU: Command not supported by internal RPC server") + if ($ccuflags !~ /procrpc/); + + my $ifName = shift @$a; + $result = ''; + @ifList = (defined ($ifName) && $ifName ne 'all') ? ($ifName) : HMCCU_GetRPCInterfaceList ($hash); + + foreach my $i (@ifList) { + my ($rpcdev, $save) = HMCCU_GetRPCDevice ($hash, 0, $i); + if ($rpcdev eq '') { + Log3 $name, 2, "HMCCU: Can't find HMCCURPCPROC device for interface $i"; + next; + } + my $res = AnalyzeCommandChain (undef, "set $rpcdev register"); + $result .= $res if (defined ($res)); + } + return HMCCU_SetState ($hash, "OK", $result); + } elsif ($opt eq 'rpcserver') { my $action = shift @$a; $action = shift @$a if ($action eq $opt); @@ -1884,10 +1961,14 @@ sub HMCCU_Get ($@) } elsif ($opt eq 'exportdefaults') { my $filename = shift @$a; - $usage = "Usage: get $name $opt filename"; - return HMCCU_SetError ($hash, $usage) if (!defined ($filename)); + my $csv = shift @$a; - my $rc = HMCCU_ExportDefaults ($filename); + $csv = 'default' if (!defined ($csv)); + $usage = "Usage: get $name $opt filename [{csv|default}]"; + return HMCCU_SetError ($hash, $usage) if (!defined ($filename)); + return HMCCU_SetError ($hash, $usage) if ($csv !~ /^(default|csv)$/); + + my $rc = $csv ne 'csv' ? HMCCU_ExportDefaults ($filename) : HMCCU_ExportDefaultsCSV ($filename); return HMCCU_SetError ($hash, -16) if ($rc == 0); return HMCCU_SetState ($hash, "OK", "Default attributes written to $filename"); } @@ -2688,7 +2769,7 @@ sub HMCCU_UpdateClients ($$$$$) } else { Log3 $fhname, 2, "HMCCU: Update of device ".$ch->{ccuaddr}." failed" - if ($ch->{ccuif} ne 'VirtualDevices'); + if ($ch->{ccuif} ne 'VirtualDevices' && $ch->{ccuif} ne 'fhem'); } $c_err++; } @@ -2701,6 +2782,61 @@ sub HMCCU_UpdateClients ($$$$$) return ($c_ok, $c_err); } +########################################################################## +# Create virtual device in internal device tables. +# If sourceAddr is specified, parameter newType will be ignored. +# Return 0 on success or error code: +# 1 = newType not defined +# 2 = Device with newType not found in internal tables +########################################################################## + +sub HMCCU_CreateDevice ($$$$$) +{ + my ($hash, $newAddr, $newName, $newType, $sourceAddr) = @_; + + my %object; + + if (!defined ($sourceAddr)) { + # Search for type in device table + return 1 if (!defined ($newType)); + for my $da (keys %{$hash->{hmccu}{dev}}) { + if ($hash->{hmccu}{dev}{$da}{type} eq $newType) { + $sourceAddr = $da; + last; + } + } + return 2 if (!defined ($sourceAddr)); + } + else { + $newType = $hash->{hmccu}{dev}{$sourceAddr}{type}; + } + + # Device attributes + $object{$newAddr}{flag} = 'N'; + $object{$newAddr}{addtype} = 'dev'; + $object{$newAddr}{channels} = $hash->{hmccu}{dev}{$sourceAddr}{channels}; + $object{$newAddr}{name} = $newName; + $object{$newAddr}{type} = $newType; + $object{$newAddr}{interface} = 'fhem'; + $object{$newAddr}{chndir} = 0; + + # Channel attributes + for (my $chn=0; $chn<$object{$newAddr}{channels}; $chn++) { + my $ca = "$newAddr:$chn"; + $object{$ca}{flag} = 'N'; + $object{$ca}{addtype} = 'chn'; + $object{$ca}{channels} = 1; + $object{$ca}{name} = "$newName:$chn"; + $object{$ca}{chndir} = $hash->{hmccu}{dev}{"$sourceAddr:$chn"}{chndir}; + $object{$ca}{rxmode} = $hash->{hmccu}{dev}{"$sourceAddr:$chn"}{rxmode}; + $object{$ca}{usetype} = $hash->{hmccu}{dev}{"$sourceAddr:$chn"}{usetype}; + } + + HMCCU_UpdateDeviceTable ($hash, \%object); + + return 0; +} + ########################################################################## # Update parameters in internal device tables and client devices. # Parameter devices is a hash reference with following keys: @@ -2768,9 +2904,11 @@ sub HMCCU_UpdateDeviceTable ($$) if (defined ($devices->{$da}{rxmode})); $hash->{hmccu}{dev}{$da}{chndir} = $devices->{$da}{chndir} if (defined ($devices->{$da}{chndir})); - $hash->{hmccu}{adr}{$nm}{address} = $da; - $hash->{hmccu}{adr}{$nm}{addtype} = $hash->{hmccu}{dev}{$da}{addtype}; - $hash->{hmccu}{adr}{$nm}{valid} = 1 if (defined ($nm)); + if (defined ($nm)) { + $hash->{hmccu}{adr}{$nm}{address} = $da; + $hash->{hmccu}{adr}{$nm}{addtype} = $hash->{hmccu}{dev}{$da}{addtype}; + $hash->{hmccu}{adr}{$nm}{valid} = 1; + } } elsif ($devices->{$da}{flag} eq 'D' && exists ($hash->{hmccu}{dev}{$da})) { # Device deleted, mark as invalid @@ -2932,7 +3070,7 @@ sub HMCCU_UpdateSingleDevice ($$$) # Build device list including virtual devices my @grplist = ($cltname); - my @virlist = HMCCU_FindClientDevices ($ccuhash, "HMCCUDEV", undef, "ccuif=VirtualDevices"); + my @virlist = HMCCU_FindClientDevices ($ccuhash, "HMCCUDEV", undef, "ccuif=(VirtualDevices|fhem)"); foreach my $vd (@virlist) { my $vh = $defs{$vd}; next if (!defined ($vh->{ccugroup})); @@ -2974,7 +3112,7 @@ sub HMCCU_UpdateSingleDevice ($$$) my @devlist = ($ch->{ccuaddr}); push @devlist, split (",", $ch->{ccugroup}) - if ($ch->{ccuif} eq 'VirtualDevices' && exists ($ch->{ccugroup})); + if (($ch->{ccuif} eq 'VirtualDevices' || $ch->{ccuif} eq 'fhem') && exists ($ch->{ccugroup})); readingsBeginUpdate ($ch); @@ -3730,27 +3868,39 @@ sub HMCCU_GetDeviceInfo ($$$) my ($hash, $device, $ccuget) = @_; my $name = $hash->{NAME}; my $devname = ''; + my $response = ''; my $hmccu_hash = HMCCU_GetHash ($hash); return '' if (!defined ($hmccu_hash)); - $ccuget = HMCCU_GetAttribute ($hmccu_hash, $hash, 'ccuget', 'Value') if ($ccuget eq 'Attr'); - - my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($hmccu_hash, $device, 0); - if ($flags == $HMCCU_FLAG_ADDRESS) { - $devname = HMCCU_GetDeviceName ($hmccu_hash, $add, ''); - return '' if ($devname eq ''); + my @devlist; + if ($hash->{ccuif} eq 'fhem' && exists ($hash->{ccugroup})) { + push @devlist, split (",", $hash->{ccugroup}); } else { - $devname = $nam; + push @devlist, $device; } + return '' if (scalar (@devlist) == 0); + + $ccuget = HMCCU_GetAttribute ($hmccu_hash, $hash, 'ccuget', 'Value') if ($ccuget eq 'Attr'); - my $response = HMCCU_HMScriptExt ($hmccu_hash, "!GetDeviceInfo", - { devname => $devname, ccuget => $ccuget }); - HMCCU_Trace ($hash, 2, undef, - "Device=$device Devname=$devname
". - "Script response = \n".$response."
". - "Script = GetDeviceInfo"); + for my $dev (@devlist) { + my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($hmccu_hash, $dev, 0); + if ($flags == $HMCCU_FLAG_ADDRESS) { + $devname = HMCCU_GetDeviceName ($hmccu_hash, $add, ''); + return '' if ($devname eq ''); + } + else { + $devname = $nam; + } + + $response .= HMCCU_HMScriptExt ($hmccu_hash, "!GetDeviceInfo", + { devname => $devname, ccuget => $ccuget }); + HMCCU_Trace ($hash, 2, undef, + "Device=$devname Devname=$devname
". + "Script response = \n".$response."
". + "Script = GetDeviceInfo"); + } return $response; } @@ -4786,7 +4936,8 @@ sub HMCCU_GetRPCDevice ($$$) if (!defined ($ifname)); $rpcdevname = HMCCU_GetRPCServerInfo ($hash, $ifname, 'device'); $rpchost = HMCCU_GetRPCServerInfo ($hash, $ifname, 'host'); - return ($rpcdevname, 0) if (defined ($rpcdevname) || !defined ($rpchost)); + return ($rpcdevname, 0) if (defined ($rpcdevname)); + return ('', 0) if (!defined ($rpchost)); # $rpcdevtype = 'HMCCURPCPROC'; } # elsif ($ccuflags =~ /extrpc/) { @@ -6035,11 +6186,12 @@ sub HMCCU_GetUpdate ($$$) elsif (HMCCU_IsValidDevice ($hmccu_hash, $addr, $HMCCU_FL_ADDRESS)) { $nam = HMCCU_GetDeviceName ($hmccu_hash, $addr, ''); return -1 if ($nam eq ''); - $list = $nam; + $list = $nam if ($cl_hash->{ccuif} ne 'fhem'); $script = "!GetDatapointsByDevice"; # Consider members of group device - if ($type eq 'HMCCUDEV' && $cl_hash->{ccuif} eq 'VirtualDevices' && + if ($type eq 'HMCCUDEV' && + ($cl_hash->{ccuif} eq 'VirtualDevices' || $cl_hash->{ccuif} eq 'fhem') && exists ($cl_hash->{ccugroup})) { foreach my $gd (split (",", $cl_hash->{ccugroup})) { $nam = HMCCU_GetDeviceName ($hmccu_hash, $gd, ''); @@ -6078,6 +6230,21 @@ sub HMCCU_GetUpdate ($$$) $events{$add}{$chn}{$dpt} = $value; } + if ($cl_hash->{ccuif} eq 'fhem') { + # Calculate datapoints of virtual group device + if ($cl_hash->{ccutype} ne 'n/a') { + foreach my $da (split (",", $cl_hash->{ccugroup})) { + foreach my $cn (keys %{$events{$da}}) { + foreach my $dp (keys %{$events{$da}{$cn}}) { + if (defined ($events{$da}{$cn}{$dp})) { + $events{$cl_hash->{ccuaddr}}{$cn}{$dp} = $events{$da}{$cn}{$dp} + } + } + } + } + } + } + HMCCU_UpdateSingleDevice ($hmccu_hash, $cl_hash, \%events); return 1; @@ -7373,6 +7540,9 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
  • set <name> importdefaults <filename>
    Import default attributes from file.

  • +
  • set <name> rpcregister [{all | <interface>}]
    + Register RPC servers at CCU. +

  • set <name> rpcserver {on | off | restart}
    Start, stop or restart RPC server(s). This command executed with option 'on' will fork a RPC server process for each RPC interface defined in attribute 'rpcinterfaces'. @@ -7441,7 +7611,7 @@ sub HMCCU_CCURPC_ListDevicesCB ($$) iface_conn_n = interface connection state (1=connected, 0=disconnected)
    iface_ducy_n = duty cycle of interface (0-100)

  • -
  • get <name> exportdefaults <filename>
    +
  • get <name> exportdefaults <filename> [{default|csv}]
    Export default attributes into file.

  • get <name> firmware [{<type-expr> | full}]
    diff --git a/fhem/FHEM/88_HMCCUDEV.pm b/fhem/FHEM/88_HMCCUDEV.pm index fe5ff7ef0..0ba1af0c1 100644 --- a/fhem/FHEM/88_HMCCUDEV.pm +++ b/fhem/FHEM/88_HMCCUDEV.pm @@ -4,7 +4,7 @@ # # $Id$ # -# Version 4.3.002 +# Version 4.3.003 # # (c) 2018 zap (zap01 t-online de) # @@ -108,6 +108,16 @@ sub HMCCUDEV_Define ($@) "['readonly'] ['defaults'] [iodev={iodev-name}] ". "[{groupexp=regexp|group={device|channel}[,...]]"; return $usage if (scalar (@$a) < 3); + + my @errmsg = ( + "OK", + "Invalid or unknown CCU device name or address", + "Can't assign I/O device", + "No devices in group", + "No matching CCU devices found", + "Type of virtual device not defined", + "Device type not found" + ); my $devname = shift @$a; my $devtype = shift @$a; @@ -144,22 +154,6 @@ sub HMCCUDEV_Define ($@) # The following call will fail during FHEM start if CCU is not ready $hmccu_hash = $devspec eq 'virtual' ? HMCCU_GetHash (0) : HMCCU_FindIODevice ($devspec); } - - if ($devspec eq 'virtual') { - # Virtual device FHEM only - my $no = 0; - foreach my $d (sort keys %defs) { - my $ch = $defs{$d}; - next if (!exists ($ch->{TYPE})); - next if ($ch->{TYPE} ne 'HMCCUDEV' || $d eq $name); - next if ($ch->{ccuif} ne 'VirtualDevices' || $ch->{ccuname} ne 'none'); - $no++; - } - $hash->{ccuif} = "VirtualDevices"; - $hash->{ccuaddr} = sprintf ("VIR%07d", $no+1); - $hash->{ccuname} = "none"; - $hash->{statevals} = 'readonly'; - } if ($init_done) { # Interactive define command while CCU not ready @@ -185,9 +179,7 @@ sub HMCCUDEV_Define ($@) # Initialize FHEM device, set IO device my $rc = HMCCUDEV_InitDevice ($hmccu_hash, $hash); - return "Invalid or unknown CCU device name or address" if ($rc == 1); - return "Can't assign I/O device ".$hmccu_hash->{NAME} if ($rc == 2); - return "No devices in group" if ($rc == 3); + return $errmsg[$rc] if ($rc > 0); return undef; } @@ -199,64 +191,107 @@ sub HMCCUDEV_Define ($@) # 1 = Invalid channel name or address # 2 = Cannot assign IO device # 3 = No devices in group +# 4 = No matching CCU devices found +# 5 = Type of virtual device not defined +# 6 = Device type not found ###################################################################### sub HMCCUDEV_InitDevice ($$) { my ($hmccu_hash, $dev_hash) = @_; + my $name = $dev_hash->{NAME}; my $devspec = $dev_hash->{hmccu}{devspec}; my $gdcount = 0; my $gdname = $devspec; - return 1 if (! HMCCU_IsValidDevice ($hmccu_hash, $devspec, 7)); + if ($devspec eq 'virtual') { + # Virtual device FHEM only, search for free address + my $no = 0; + foreach my $d (sort keys %defs) { + my $ch = $defs{$d}; + next if (!exists ($ch->{TYPE})); + next if ($ch->{TYPE} ne 'HMCCUDEV' || $d eq $name); + next if ($ch->{ccuif} ne 'fhem' || $ch->{ccuname} ne 'virtual'); + $no++; + } + $dev_hash->{ccuif} = 'fhem'; + $dev_hash->{ccuaddr} = sprintf ("VIR%07d", $no+1); + $dev_hash->{ccuname} = 'virtual'; + } + else { + return 1 if (!HMCCU_IsValidDevice ($hmccu_hash, $devspec, 7)); - my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec); - return 1 if (!defined ($da)); - $gdname = $dn; + my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec); + return 1 if (!defined ($da)); + $gdname = $dn; + + $dev_hash->{ccuif} = $di; + $dev_hash->{ccuaddr} = $da; + $dev_hash->{ccuname} = $dn; + $dev_hash->{ccutype} = $dt; + $dev_hash->{channels} = $dc; + } - $dev_hash->{ccuif} = $di; - $dev_hash->{ccuaddr} = $da; - $dev_hash->{ccuname} = $dn; - $dev_hash->{ccutype} = $dt; - $dev_hash->{channels} = $dc; - # Parse group options - if ($dev_hash->{ccuif} eq "VirtualDevices") { + if ($dev_hash->{ccuif} eq 'VirtualDevices' || $dev_hash->{ccuif} eq 'fhem') { + my @devlist = (); if (exists ($dev_hash->{hmccu}{groupexp})) { - my @devlist; + # Group devices specified by name expression $gdcount = HMCCU_GetMatchingDevices ($hmccu_hash, $dev_hash->{hmccu}{groupexp}, 'dev', \@devlist); - return "No matching CCU devices found" if ($gdcount == 0); - $dev_hash->{ccugroup} = join (',', @devlist); + return 4 if ($gdcount == 0); } elsif (exists ($dev_hash->{hmccu}{group})) { + # Group devices specified by comma separated name list my @gdevlist = split (",", $dev_hash->{hmccu}{group}); $dev_hash->{ccugroup} = '' if (@gdevlist > 0); foreach my $gd (@gdevlist) { my ($gda, $gdc, $gdo) = ('', '', '', ''); - return "Invalid device or channel $gd" if (!HMCCU_IsValidDevice ($hmccu_hash, $gd, 7)); + return 1 if (!HMCCU_IsValidDevice ($hmccu_hash, $gd, 7)); ($gda, $gdc) = HMCCU_GetAddress ($hmccu_hash, $gd, '', ''); $gdo = $gda; $gdo .= ':'.$gdc if ($gdc ne ''); - - if (exists ($dev_hash->{ccugroup}) && $dev_hash->{ccugroup} ne '') { - $dev_hash->{ccugroup} .= ",".$gdo; - } - else { - $dev_hash->{ccugroup} = $gdo; - } - + push @devlist, $gdo; $gdcount++; } } else { - my @devlist = HMCCU_GetGroupMembers ($hmccu_hash, $gdname); + # Group specified by CCU virtual group name + @devlist = HMCCU_GetGroupMembers ($hmccu_hash, $gdname); $gdcount = scalar (@devlist); - $dev_hash->{ccugroup} = join (',', @devlist); + return 5 if ($gdcount == 0); } return 3 if ($gdcount == 0); + + $dev_hash->{ccugroup} = join (',', @devlist); + if ($devspec eq 'virtual') { + my $dev = shift @devlist; + my $devtype = HMCCU_GetDeviceType ($hmccu_hash, $dev, 'n/a'); + my $devna = $devtype eq 'n/a' ? 1 : 0; + for my $d (@devlist) { + if (HMCCU_GetDeviceType ($hmccu_hash, $d, 'n/a') ne $devtype) { + $devna = 1; + last; + } + } + + my $rc = 0; + if ($devna) { + $dev_hash->{ccutype} = 'n/a'; + $dev_hash->{statevals} = 'readonly'; + $rc = HMCCU_CreateDevice ($hmccu_hash, $dev_hash->{ccuaddr}, $name, undef, $dev); + } + else { + $dev_hash->{ccutype} = $devtype; + $rc = HMCCU_CreateDevice ($hmccu_hash, $dev_hash->{ccuaddr}, $name, $devtype, $dev); + } + return $rc+4 if ($rc > 0); + + # Set default attributes + $attr{$name}{ccureadingformat} = 'name'; + } } # Inform HMCCU device about client device @@ -642,7 +677,7 @@ sub HMCCUDEV_Get ($@) my $result = ''; my $rc; - if ($ccuif eq "VirtualDevices" && $hash->{ccuname} eq "none" && $opt ne 'update') { + if ($ccuif eq "VirtualDevices" && $hash->{ccuname} eq "virtual" && $opt ne 'update') { return "HMCCUDEV: Unknown argument $opt, choose one of update:noArg"; } @@ -688,19 +723,19 @@ sub HMCCUDEV_Get ($@) return HMCCU_SetError ($hash, "Usage: get $name update [{'State'|'Value'}]"); } - if ($hash->{ccuname} ne 'none') { + if ($hash->{ccuname} ne 'virtual') { $rc = HMCCU_GetUpdate ($hash, $ccuaddr, $ccuget); return HMCCU_SetError ($hash, $rc) if ($rc < 0); } # Update other devices belonging to group - if ($hash->{ccuif} eq "VirtualDevices" && exists ($hash->{ccugroup})) { - my @vdevs = split (",", $hash->{ccugroup}); - foreach my $vd (@vdevs) { - $rc = HMCCU_GetUpdate ($hash, $vd, $ccuget); - return HMCCU_SetError ($hash, $rc) if ($rc < 0); - } - } +# if ($hash->{ccuif} eq "VirtualDevices" && exists ($hash->{ccugroup})) { +# my @vdevs = split (",", $hash->{ccugroup}); +# foreach my $vd (@vdevs) { +# $rc = HMCCU_GetUpdate ($hash, $vd, $ccuget); +# return HMCCU_SetError ($hash, $rc) if ($rc < 0); +# } +# } return undef; } diff --git a/fhem/FHEM/HMCCUConf.pm b/fhem/FHEM/HMCCUConf.pm index 48340bc8b..2d1789e6b 100644 --- a/fhem/FHEM/HMCCUConf.pm +++ b/fhem/FHEM/HMCCUConf.pm @@ -4,7 +4,7 @@ # # $Id$ # -# Version 4.2.005 +# Version 4.3 # # Configuration parameters for HomeMatic devices. # @@ -131,6 +131,21 @@ use vars qw(%HMCCU_SCRIPTS); webCmd => "control:on:off", widgetOverride => "control:slider,0,10,100" }, + "HmIP-BDT" => { + _description => "Dimmaktor", + _channels => "4", + ccureadingfilter => "(ERROR_CODE|ERROR_OVERHEAT|ACTUAL_TEMPERATURE|ACTIVITY_STATE|LEVEL)", + ccuscaleval => "LEVEL:0:1:0:100", + controldatapoint => "LEVEL", + hmstatevals => "ACTUAL_TEMPERATURE_STATUS!2:tempOverflow,3:tempUnderflow;ERROR_OVERHEAT!(1|true):overheat", + statedatapoint => "LEVEL", + statevals => "on:100,off:0", + stripnumber => 1, + substexcl => "control", + substitute => "LEVEL!#0-0:off,#1-100:on;ACTIVITY_STATE!0:unknown,1:up,2:down,3:stop;ERROR_OVERHEAT!(0|false):no,(1|true):yes;ACTUAL_TEMPERATURE_STATUS!0:normal,1:unknown,2:overflow,3:underflow", + webCmd => "control:on:off", + widgetOverride => "control:slider,0,10,100" + }, "HM-LC-Dim1T-Pl|HM-LC-Dim1T-CV|HM-LC-Dim1T-FM|HM-LC-Dim1T-CV-2|HM-LC-Dim2T-SM|HM-LC-Dim2T-SM-2|HM-LC-Dim1T-DR|HM-LC-Dim1T-FM-LF|HM-LC-Dim1T-FM-2|HM-LC-Dim1T-Pl-3|HM-LC-Dim1TPBU-FM|HM-LC-Dim1TPBU-FM-2" => { _description => "Funk-Abschnitt-Dimmaktor", _channels => "1", @@ -276,6 +291,23 @@ use vars qw(%HMCCU_SCRIPTS); webCmd => "control:up:stop:down", widgetOverride => "control:slider,0,10,100" }, + "HmIP-BROLL" => { + _description => "Rollladenaktor", + _channels => "4", + ccureadingfilter => "(ERROR_CODE|ERROR_OVERHEAT|ACTUAL_TEMPERATURE|LEVEL|ACTIVITY_STATE)", + ccureadingname => "LEVEL:+pct", + ccuscaleval => "LEVEL:0:1:0:100", + cmdIcon => "up:fts_shutter_up stop:fts_shutter_manual down:fts_shutter_down", + controldatapoint => "LEVEL", + hmstatevals => "ACTUAL_TEMPERATURE_STATUS!2:tempOverflow,3:tempUnderflow;ERROR_OVERHEAT!(1|true):overheat", + eventMap => "/datapoint STOP true:stop/datapoint LEVEL 0:down/datapoint LEVEL 100:up/", + statedatapoint => "LEVEL", + stripnumber => 1, + substexcl => "control|pct", + substitute => "LEVEL!#0-0:closed,#100-100:open;ACTIVITY_STATE!0:unknown,1:up,2:down,3:stop;ERROR_OVERHEAT!(0|false):no,(1|true):yes;ACTUAL_TEMPERATURE_STATUS!0:normal,1:unknown,2:overflow,3:underflow", + webCmd => "control:up:stop:down", + widgetOverride => "control:slider,0,10,100" + }, "HM-WDS40-TH-I|HM-WDS10-TH-O|HM-WDS20-TH-O|IS-WDS-TH-OD-S-R3|ASH550I|ASH550" => { _description => "Temperatur/Luftfeuchte Sensor", _channels => "1", @@ -504,7 +536,8 @@ use vars qw(%HMCCU_SCRIPTS); substitute => "STATE!(true|1):on,(false|0):off", webCmd => "control", widgetOverride => "control:uzsuToggle,off,on" - }, "HM-LC-Dim1L-Pl|HM-LC-Dim1L-Pl-2|HM-LC-Dim1L-CV|HM-LC-Dim2L-CV|HM-LC-Dim2L-SM|HM-LC-Dim1L-Pl-3|HM-LC-Dim1L-CV-2" => { + }, + "HM-LC-Dim1L-Pl|HM-LC-Dim1L-Pl-2|HM-LC-Dim1L-CV|HM-LC-Dim2L-CV|HM-LC-Dim2L-SM|HM-LC-Dim1L-Pl-3|HM-LC-Dim1L-CV-2" => { _description => "Funk-Anschnitt-Dimmaktor", ccureadingfilter => "(^LEVEL\$|DIRECTION)", ccuscaleval => "LEVEL:0:1:0:100", @@ -549,6 +582,20 @@ use vars qw(%HMCCU_SCRIPTS); webCmd => "control:on:off", widgetOverride => "control:slider,0,10,100" }, + "HmIP-BDT" => { + _description => "Dimmaktor", + ccureadingfilter => "(ERROR_CODE|ERROR_OVERHEAT|ACTUAL_TEMPERATURE|ACTIVITY_STATE|LEVEL)", + ccuscaleval => "LEVEL:0:1:0:100", + controldatapoint => "4.LEVEL", + hmstatevals => "ACTUAL_TEMPERATURE_STATUS!2:tempOverflow,3:tempUnderflow;ERROR_OVERHEAT!(1|true):overheat", + statedatapoint => "4.LEVEL", + statevals => "on:100,off:0", + stripnumber => 1, + substexcl => "control", + substitute => "LEVEL!#0-0:off,#1-100:on;ACTIVITY_STATE!0:unknown,1:up,2:down,3:stop;ERROR_OVERHEAT!(0|false):no,(1|true):yes;ACTUAL_TEMPERATURE_STATUS!0:normal,1:unknown,2:overflow,3:underflow", + webCmd => "control:on:off", + widgetOverride => "control:slider,0,10,100" + }, "HM-PB-2-FM" => { _description => "Funk-Wandtaster 2-fach", ccureadingfilter => "PRESS", @@ -639,6 +686,22 @@ use vars qw(%HMCCU_SCRIPTS); webCmd => "control:up:stop:down", widgetOverride => "control:slider,0,10,100" }, + "HmIP-BROLL" => { + _description => "Rollladenaktor", + ccureadingfilter => "(ERROR_CODE|ERROR_OVERHEAT|ACTUAL_TEMPERATURE|LEVEL|ACTIVITY_STATE|SELF_CALIBRATION_RESULT)", + ccureadingname => "LEVEL:+pct", + ccuscaleval => "LEVEL:0:1:0:100", + cmdIcon => "up:fts_shutter_up stop:fts_shutter_manual down:fts_shutter_down", + controldatapoint => "4.LEVEL", + hmstatevals => "ACTUAL_TEMPERATURE_STATUS!2:tempOverflow,3:tempUnderflow;ERROR_OVERHEAT!(1|true):overheat", + eventMap => "/datapoint 4.STOP true:stop/datapoint 4.LEVEL 0:down/datapoint 4.LEVEL 100:up/datapoint 3.SELF_CALIBRATION 0:stopCalibration/datapoint 3.SELF_CALIBRATION 1:startCalibration/", + statedatapoint => "4.LEVEL", + stripnumber => 1, + substexcl => "control|pct", + substitute => "LEVEL!#0-0:closed,#100-100:open;ACTIVITY_STATE!0:unknown,1:up,2:down,3:stop;ERROR_OVERHEAT!(0|false):no,(1|true):yes;ACTUAL_TEMPERATURE_STATUS!0:normal,1:unknown,2:overflow,3:underflow;SELF_CALIBRATION_RESULT!(0|false):failed,(1|true):ok", + webCmd => "control:up:stop:down", + widgetOverride => "control:slider,0,10,100" + }, "HM-TC-IT-WM-W-EU" => { _description => "Wandthermostat", ccureadingfilter => "(^HUMIDITY|^TEMPERATURE|^SET_TEMPERATURE|^WINDOW_OPEN)", @@ -683,7 +746,7 @@ use vars qw(%HMCCU_SCRIPTS); webCmd => "control:Boost:Auto:Manual:Holiday:on:off", widgetOverride => "control:slider,4.5,0.5,30.5,1" }, - "HmIP-WTH|HmIP-WTH-2" => { + "HmIP-WTH|HmIP-WTH-2|HmIP-BWTH" => { _description => "Wandthermostat HM-IP", controldatapoint => "1.SET_POINT_TEMPERATURE", eventMap => "/datapoint 1.BOOST_MODE true:Boost/datapoint 1.CONTROL_MODE 0:Auto/datapoint 1.CONTROL_MODE 1:Manual/datapoint 1.CONTROL_MODE 2:Holiday/datapoint 1.SET_POINT_TEMPERATURE 4.5:off/datapoint 1.SET_POINT_TEMPERATURE 30.5:on/", @@ -730,16 +793,18 @@ use vars qw(%HMCCU_SCRIPTS); }, "HM-CC-VG-1" => { _description => "Heizungsgruppe", - ccureadingfilter => "(^SET_TEMPERATURE|^TEMPERATURE|^HUMIDITY|^VALVE|^CONTROL|^WINDOW_OPEN)", + ccucalculate => "dewpoint:DEWPOINT:1.ACTUAL_TEMPERATURE,1.ACTUAL_HUMIDITY", + ccureadingfilter => "1.(^SET_TEMPERATURE|^ACTUAL|^VALVE|^CONTROL);2.^WINDOW_OPEN;4.^VALVE", cmdIcon => "Auto:sani_heating_automatic Manu:sani_heating_manual Boost:sani_heating_boost on:general_an off:general_aus", controldatapoint => "1.SET_TEMPERATURE", eventMap => "/datapoint 1.MANU_MODE 20.0:Manu/datapoint 1.AUTO_MODE 1:Auto/datapoint 1.BOOST_MODE 1:Boost/datapoint 1.MANU_MODE 4.5:off/datapoint 1.MANU_MODE 30.5:on/", statedatapoint => "1.SET_TEMPERATURE", + stateFormat => "T: 1.ACTUAL_TEMPERATURE° H: 1.ACTUAL_HUMIDITY% D: 1.SET_TEMPERATURE° P: DEWPOINT° V: 4.VALVE_STATE% 1.CONTROL_MODE", stripnumber => 1, substexcl => "control", substitute => "CONTROL_MODE!0:AUTO,1:MANU,2:PARTY,3:BOOST;WINDOW_OPEN_REPORTING!(true|1):open,(false|0):closed;SET_TEMPERATURE!#0-4.5:off,#30.5-40:on", webCmd => "control:Auto:Manu:Boost:on:off", - widgetOverride => "control:slider,3.5,0.5,30.5,1" + widgetOverride => "control:slider,4.5,0.5,30.5,1" }, "HM-Sec-MD|HM-Sec-MDIR|HM-Sec-MDIR-2|HM-Sec-MDIR-3" => { _description => "Bewegungsmelder", @@ -755,6 +820,14 @@ use vars qw(%HMCCU_SCRIPTS); statedatapoint => "1.MOTION", substitute => "MOTION!(0|false):no,(1|true):yes" }, + "HmIP-SMI55" => { + _description => "Bewegungsmelder", + ccureadingfilter => "(ILLUMINATION|MOTION|PRESS)", + "event-on-update-reading" => ".*", + eventMap => "/datapoint 3.MOTION_DETECTION_ACTIVE 1:detection-on/datapoint 3.MOTION_DETECTION_ACTIVE 0:detection-off/datapoint 3.RESET_MOTION 1:reset/", + statedatapoint => "3.MOTION", + substitute => "PRESS_LONG,PRESS_SHORT!(1|true):pressed,(0|false):released;MOTION,MOTION_DETECTION_ACTIVE!(0|false):no,(1|true):yes;ILLUMINATION_STATUS!0:normal,1:unknown,2:overflow" + }, "HmIP-SPI" => { _description => "Anwesenheitssensor", ccureadingfilter => "(ILLUMINATION|PRESENCE)",