From ced4a6dbc2b4af918dbc3fc4d33f6fcf3fc92bd9 Mon Sep 17 00:00:00 2001 From: zap <> Date: Sun, 9 Apr 2017 11:17:32 +0000 Subject: [PATCH] HMCCU: Version 4.0 with CUxD support git-svn-id: https://svn.fhem.de/fhem/trunk@13948 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/88_HMCCU.pm | 511 +++++++++++++++++++-------------------- fhem/FHEM/88_HMCCUCHN.pm | 4 +- fhem/FHEM/88_HMCCUDEV.pm | 4 +- fhem/FHEM/88_HMCCURPC.pm | 465 +++++++++++++++++++++++++++++------ fhem/FHEM/HMCCUConf.pm | 82 ++++++- 6 files changed, 723 insertions(+), 344 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index ac752684f..0673c6e0a 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. + - update: 88_HMCCU: Version 4.0 with CUxD support - feature: RESIDENTStk wakeuptimer: wakeupEnforced may be 3 to only enforce wake-up when wake-up time is set earlier than default wake-up time diff --git a/fhem/FHEM/88_HMCCU.pm b/fhem/FHEM/88_HMCCU.pm index 5ef7b7e87..dfd1de2e1 100755 --- a/fhem/FHEM/88_HMCCU.pm +++ b/fhem/FHEM/88_HMCCU.pm @@ -4,13 +4,14 @@ # # $Id$ # -# Version 3.9.013 +# Version 4.0 # # Module for communication between FHEM and Homematic CCU2. -# Supports BidCos-RF, BidCos-Wired, HmIP-RF, virtual CCU channels, -# CCU group devices, HomeGear. # -# (c) 2016 zap (zap01 t-online de) +# Supports BidCos-RF, BidCos-Wired, HmIP-RF, virtual CCU channels, +# CCU group devices, HomeGear, CUxD, Osram Lightify. +# +# (c) 2017 zap (zap01 t-online de) # ############################################################################## # @@ -95,26 +96,32 @@ use HMCCUConf; # Import configuration data my $HMCCU_CHN_DEFAULTS = \%HMCCUConf::HMCCU_CHN_DEFAULTS; my $HMCCU_DEV_DEFAULTS = \%HMCCUConf::HMCCU_DEV_DEFAULTS; +my $HMCCU_SCRIPTS = \%HMCCUConf::HMCCU_SCRIPTS; # Custom configuration data my %HMCCU_CUST_CHN_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS; # HMCCU version -my $HMCCU_VERSION = '3.9.013'; +my $HMCCU_VERSION = '4.0'; # RPC Ports and URL extensions +my $HMCCU_RPC_PORT_DEFAULT = 2001; + my %HMCCU_RPC_NUMPORT = ( 2000 => 'BidCos-Wired', 2001 => 'BidCos-RF', 2010 => 'HmIP-RF', 9292 => 'VirtualDevices', - 2003 => 'Homegear' + 2003 => 'Homegear', 8701 => 'CUxD' ); my %HMCCU_RPC_PORT = ( 'BidCos-Wired', 2000, 'BidCos-RF', 2001, 'HmIP-RF', 2010, 'VirtualDevices', 9292, - 'Homegear', 2003 + 'Homegear', 2003, 'CUxD', 8701 ); my %HMCCU_RPC_URL = ( 9292, 'groups' ); +my %HMCCU_RPC_PROT = ( + 2000 => 'A', 2001 => 'A', 2010 => 'A', 9292 => 'A', 2003 => 'A', 8701 => 'B' +); # Initial intervals for registration of RPC callbacks and reading RPC queue # @@ -283,7 +290,6 @@ sub HMCCU_CCURPC_ReplaceDeviceCB ($$$$); sub HMCCU_CCURPC_ReaddDevicesCB ($$$); sub HMCCU_CCURPC_EventCB ($$$$$); sub HMCCU_CCURPC_ListDevicesCB ($$); -sub HMCCU_CCURPC_GetEventsCB ($$); ################################################## @@ -304,12 +310,22 @@ sub HMCCU_Initialize ($) $hash->{ShutdownFn} = "HMCCU_Shutdown"; $hash->{parseParams} = 1; - $hash->{AttrList} = "stripchar stripnumber ccuackstate:0,1 ccuaggregate:textField-long ccudefaults rpcinterfaces:multiple-strict,".join(',',sort keys %HMCCU_RPC_PORT)." ccudef-hmstatevals:textField-long ccudef-substitute:textField-long ccudef-readingname:textField-long ccudef-readingfilter:textField-long ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc ccuflags:multiple-strict,extrpc,intrpc,dptnocheck,noagg,nohmstate ccureadings:0,1 rpcdevice rpcinterval:2,3,5,7,10 rpcqueue rpcport:multiple-strict,".join(',',sort keys %HMCCU_RPC_NUMPORT)." rpcserver:on,off rpcserveraddr rpcserverport rpctimeout rpcevtimeout parfile substitute ccuget:Value,State ". $readingFnAttributes; + $hash->{AttrList} = "stripchar stripnumber ccuackstate:0,1 ccuaggregate:textField-long". + " ccudefaults rpcinterfaces:multiple-strict,".join(',',sort keys %HMCCU_RPC_PORT). + " ccudef-hmstatevals:textField-long ccudef-substitute:textField-long". + " ccudef-readingname:textField-long ccudef-readingfilter:textField-long". + " ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc". + " ccuflags:multiple-strict,extrpc,intrpc,dptnocheck,noagg,nohmstate ccureadings:0,1". + " rpcdevice rpcinterval:2,3,5,7,10 rpcqueue". + " rpcport:multiple-strict,".join(',',sort keys %HMCCU_RPC_NUMPORT). + " rpcserver:on,off rpcserveraddr rpcserverport rpctimeout rpcevtimeout parfile substitute". + " ccuget:Value,State ". + $readingFnAttributes; } -################################################## +###################################################################### # Define device -################################################## +###################################################################### sub HMCCU_Define ($$) { @@ -332,21 +348,24 @@ sub HMCCU_Define ($$) my $ch = $defs{$d}; next if (!exists ($ch->{TYPE})); $ccucount++ if ($ch->{TYPE} eq 'HMCCU' && $ch != $hash); + $ccucount++ if ($ch->{TYPE} eq 'HMCCURPC' && $ch->{noiodev} == 1); } $hash->{CCUNum} = $ccucount+1; } - Log3 $name, 1, "HMCCU: Initialized version $HMCCU_VERSION. Updating devices from ".$hash->{host}; $hash->{version} = $HMCCU_VERSION; $hash->{ccutype} = 'CCU2'; - HMCCU_GetDeviceList ($hash); $hash->{RPCState} = "stopped"; + + Log3 $name, 1, "HMCCU: Device $name. Initialized version $HMCCU_VERSION"; + my ($devcnt, $chncnt) = HMCCU_GetDeviceList ($hash); + Log3 $name, 1, "HMCCU: Read $devcnt devices with $chncnt channels read from CCU".$hash->{host}; $hash->{hmccu}{evtime} = 0; $hash->{hmccu}{evtimeout} = 0; $hash->{hmccu}{updatetime} = 0; $hash->{hmccu}{rpccount} = 0; - $hash->{hmccu}{rpcports} = '2001'; + $hash->{hmccu}{rpcports} = $HMCCU_RPC_PORT_DEFAULT; readingsBeginUpdate ($hash); readingsBulkUpdate ($hash, "state", "Initialized"); @@ -441,7 +460,7 @@ sub HMCCU_Attr ($@) delete $hash->{RPCDEV} if (exists ($hash->{RPCDEV})); } elsif ($attrname eq 'rpcport' || $attrname eq 'rpcinterfaces') { - $hash->{hmccu}{rpcports} = '2001'; + $hash->{hmccu}{rpcports} = $HMCCU_RPC_PORT_DEFAULT; } } @@ -1190,7 +1209,8 @@ sub HMCCU_Get ($@) my ($hash, $a, $h) = @_; my $name = shift @$a; my $opt = shift @$a; - my $options = "defaults:noArg exportdefaults devicelist dump vars update updateccu parfile configdesc rpcevents:noArg rpcstate:noArg deviceinfo"; + my $options = "defaults:noArg exportdefaults devicelist dump vars update updateccu parfile". + " configdesc rpcevents:noArg rpcstate:noArg deviceinfo"; my $host = $hash->{host}; if ($opt ne 'rpcstate' && HMCCU_IsRPCStateBlocking ($hash)) { @@ -1201,7 +1221,6 @@ sub HMCCU_Get ($@) my $ccuflags = AttrVal ($name, "ccuflags", "null"); my $ccureadings = AttrVal ($name, "ccureadings", 1); my $parfile = AttrVal ($name, "parfile", ''); - my $rpcport = $hash->{hmccu}{rpcports}; my $readname; my $readaddr; @@ -1333,8 +1352,10 @@ sub HMCCU_Get ($@) my @hm_pids = (); my @ex_pids = (); if (HMCCU_IsRPCServerRunning ($hash, \@hm_pids, \@ex_pids)) { - return "RPC process(es) running with pid(s) ".join (',', @hm_pids) if (scalar (@hm_pids) > 0); - return "RPC thread(s) running with tid(s) ".join (',', @ex_pids) if (scalar (@ex_pids) > 0); + return "RPC process(es) running with pid(s) ". + join (',', @hm_pids) if (scalar (@hm_pids) > 0); + return "RPC thread(s) running with tid(s) ". + join (',', @ex_pids) if (scalar (@ex_pids) > 0); } return "No RPC processes or threads are running"; } @@ -1356,7 +1377,8 @@ sub HMCCU_Get ($@) $n = 0; } else { - $result .= " Channel $n ".'"'.$hash->{hmccu}{dev}{$add}{name}.'"'." [".$add."]\n"; + $result .= " Channel $n ".'"'.$hash->{hmccu}{dev}{$add}{name}.'"'. + " [".$add."]\n"; $n++; } } @@ -1976,7 +1998,8 @@ sub HMCCU_UpdateClients ($$$$) 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, "ccudevstate=active"); + my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", undef, + "ccudevstate=active"); foreach my $d (@devlist) { my $ch = $defs{$d}; @@ -2000,7 +2023,8 @@ sub HMCCU_UpdateClients ($$$$) } } else { - my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", $devexp, "ccudevstate=active"); + my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", $devexp, + "ccudevstate=active"); Log3 $fhname, 2, "HMCCU: No client devices matching $devexp" if (scalar (@devlist) == 0); foreach my $d (@devlist) { @@ -2029,10 +2053,10 @@ sub HMCCU_UpdateClients ($$$$) ########################################################################## # Update parameters in internal device tables and client devices. -# Parameter devices is a hash reference with keys: +# Parameter devices is a hash reference with following keys: # {address} -# {address}{flag} := [N, D, R] -# {address}{addtype} := [chn, dev] +# {address}{flag} := [N, D, R] +# {address}{addtype} := [chn, dev] # {address}{channels} := Number of channels # {address}{name} := Device or channel name # {address}{type} := Homematic device type @@ -2212,13 +2236,6 @@ sub HMCCU_UpdateSingleDevice ($$$) # Get attributes of client device my $cltflags = AttrVal ($cltname, 'ccuflags', 'null'); -# my $disable = AttrVal ($cltname, 'disable', 0); -# my $update = AttrVal ($cltname, 'ccureadings', 1); -# return 0 if ($update == 0 || $disable == 1); - -# my $crf = HMCCU_GetAttrReadingFormat ($clthash, $ccuhash); -# my $substitute = HMCCU_GetAttrSubstitute ($clthash, $ccuhash); -# my ($sc, $st, $cc, $cd) = HMCCU_GetSpecialDatapoints ($clthash, '', 'STATE', '', ''); # Build device list including virtual devices my @grplist = ($cltname); @@ -2356,26 +2373,36 @@ sub HMCCU_UpdateMultipleDevices ($$) return $c; } -#################################################### -# Get list of RPC ports. Default is 2001. -#################################################### +###################################################################### +# Get list of valid RPC ports. +# Considers binary RPC ports and interfaces used by CCU devices. +# Default is 2001. +###################################################################### sub HMCCU_GetRPCPortList ($) { my ($hash) = @_; - my @ports = (2001); + my $name = $hash->{NAME}; + my @ports = ($HMCCU_RPC_PORT_DEFAULT); + + my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); if (defined ($hash->{hmccu}{rpcports})) { - @ports = split (',', $hash->{hmccu}{rpcports}); - } + foreach my $p (split (',', $hash->{hmccu}{rpcports})) { + my $ifname = $HMCCU_RPC_NUMPORT{$p}; + next if ($p == $HMCCU_RPC_PORT_DEFAULT || + ($HMCCU_RPC_PROT{$p} eq 'B' && $ccuflags !~ /extrpc/) || + !exists ($hash->{hmccu}{iface}{$ifname})); + push (@ports, $p); + } + } return @ports; } -#################################################### -# Register RPC callbacks at CCU if RPC-Server -# already in server loop -#################################################### +###################################################################### +# Register RPC callbacks at CCU if RPC-Server already in server loop +###################################################################### sub HMCCU_RPCRegisterCallback ($) { @@ -2384,13 +2411,12 @@ sub HMCCU_RPCRegisterCallback ($) my $serveraddr = $hash->{host}; my $localaddr = $hash->{hmccu}{localaddr}; -# my $rpcport = AttrVal ($name, 'rpcport', 2001); - my $rpcport = $hash->{hmccu}{rpcports}; my $rpcinterval = AttrVal ($name, 'rpcinterval', $HMCCU_INIT_INTERVAL2); my $rpcserveraddr = AttrVal ($name, 'rpcserveraddr', $localaddr); my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); + my @rpcports = HMCCU_GetRPCPortList ($hash); - foreach my $port (split (',', $rpcport)) { + foreach my $port (@rpcports) { my $clkey = 'CB'.$port; my $cburl = "http://".$localaddr.":".$hash->{hmccu}{rpc}{$clkey}{cbport}."/fh".$port; my $url = "http://$serveraddr:$port/"; @@ -2414,11 +2440,12 @@ sub HMCCU_RPCRegisterCallback ($) InternalTimer (gettimeofday()+$rpcinterval, 'HMCCU_ReadRPCQueue', $hash, 0); } -#################################################### +###################################################################### # Deregister RPC callbacks at CCU -#################################################### +###################################################################### -sub HMCCU_RPCDeRegisterCallback ($) { +sub HMCCU_RPCDeRegisterCallback ($) +{ my ($hash) = @_; my $name = $hash->{NAME}; @@ -2437,9 +2464,9 @@ sub HMCCU_RPCDeRegisterCallback ($) { } } -#################################################### +###################################################################### # Initialize statistic counters -#################################################### +###################################################################### sub HMCCU_ResetCounters ($) { @@ -2466,15 +2493,10 @@ sub HMCCU_StartExtRPCServer ($) my ($hash) = @_; my $name = $hash->{NAME}; -# if (!exists ($modules{'HMCCURPC'})) { -# Log3 $name, 0, "HMCCU: Module HMCCURPC not loaded"; -# return 0; -# } - # Search RPC device. Create one if none exists my $rpcdev = HMCCU_GetRPCDevice ($hash, 1); if ($rpcdev eq '') { - Log3 $name, 0, "HMCCU: Can't find or create RPC device"; + Log3 $name, 0, "HMCCU: Can't find or create HMCCURPC device"; return 0; } @@ -2525,11 +2547,9 @@ sub HMCCU_StartIntRPCServer ($) # Address and ports my $rpcqueue = AttrVal ($name, 'rpcqueue', '/tmp/ccuqueue'); -# my $rpcport = AttrVal ($name, 'rpcport', 2001); - my $rpcport = $hash->{hmccu}{rpcports}; my $rpcserverport = AttrVal ($name, 'rpcserverport', 5400); my $rpcinterval = AttrVal ($name, 'rpcinterval', $HMCCU_INIT_INTERVAL1); - my @rpcportlist = split (",", $rpcport); + my @rpcportlist = HMCCU_GetRPCPortList ($hash); my $serveraddr = $hash->{host}; my $fork_cnt = 0; @@ -2618,10 +2638,9 @@ sub HMCCU_StartIntRPCServer ($) return $fork_cnt; } -#################################################### -# Stop RPC server(s) -# Send SIGINT to process(es) -#################################################### +###################################################################### +# Stop RPC server(s) by sending SIGINT to process(es) +###################################################################### sub HMCCU_StopRPCServer ($) { @@ -2630,8 +2649,6 @@ sub HMCCU_StopRPCServer ($) my $pid = 0; my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); -# my $rpcport = AttrVal ($name, 'rpcport', 2001); - my $rpcport = $hash->{hmccu}{rpcports}; my $serveraddr = $hash->{host}; # Deregister callback URLs in CCU @@ -2757,9 +2774,9 @@ sub HMCCU_IsRPCServerRunning ($$$) return (@$hm_pids > 0 || @$ex_pids > 0) ? 1 : 0; } -#################################################### +###################################################################### # Get channels and datapoints of CCU device -#################################################### +###################################################################### sub HMCCU_GetDeviceInfo ($$$) { @@ -2841,7 +2858,7 @@ sub HMCCU_FormatDeviceInfo ($) } ###################################################################### -# Read list of CCU devices via Homematic Script. +# Read list of CCU devices and channels via Homematic Script. # Update data of client devices if not current. # Return (device count, channel count) or (-1, -1) on error. ###################################################################### @@ -2879,8 +2896,8 @@ foreach(devid, root.Devices().EnumUsedIDs()) { # Hash elements: # -# {address}{flag} := [N, D, R] -# {address}{addtype} := [chn, dev] +# {address}{flag} := [N, D, R] +# {address}{addtype} := [chn, dev] # {address}{channels} := Number of channels # {address}{name} := Device or channel name # {address}{type} := Homematic device type @@ -2901,7 +2918,15 @@ foreach(devid, root.Devices().EnumUsedIDs()) { $objects{$hmdata[2]}{flag} = 'N'; $objects{$hmdata[2]}{interface} = $hmdata[1]; $objects{$hmdata[2]}{name} = $hmdata[3]; - $objects{$hmdata[2]}{type} = ($hmdata[2] =~ /^CUX/) ? "CUX-".$hmdata[4] : $hmdata[4]; + $objects{$hmdata[2]}{type} = ($hmdata[2] =~ /^CUX/) ? "CUX-".$hmdata[4] : $hmdata[4]; + # Count used interfaces + $hash->{hmccu}{iface}{$hmdata[1]}++; + # CCU information + if ($hmdata[2] eq 'BidCoS-RF') { + $hash->{ccuname} = $hmdata[3]; + $hash->{ccuaddr} = $hmdata[2]; + $hash->{ccuif} = $hmdata[1]; + } } elsif ($hmdata[0] eq 'C') { # 1=Channel-Address 2=Channel-Name @@ -2913,6 +2938,9 @@ foreach(devid, root.Devices().EnumUsedIDs()) { } } + # Update some CCU I/O device information + $hash->{ccuinterfaces} = join (',', keys %{$hash->{hmccu}{iface}}); + ($devcount, $chncount) = HMCCU_UpdateDeviceTable ($hash, \%objects) if (scalar (@scrlines) > 0); HMCCU_GetDatapointList ($hash); @@ -3001,10 +3029,10 @@ foreach (sDevice, sDevList.Split(",")) { return $c; } -#################################################### -# Check if device/channel name or address is valid -# and refers to an existing device or channel. -#################################################### +###################################################################### +# Check if device/channel name or address is valid and refers to an +# existing device or channel. +###################################################################### sub HMCCU_IsValidDeviceOrChannel ($$) { @@ -3026,10 +3054,10 @@ sub HMCCU_IsValidDeviceOrChannel ($$) } } -#################################################### -# Check if device name or address is valid -# and refers to an existing device. -#################################################### +###################################################################### +# Check if device name or address is valid and refers to an existing +# device. +###################################################################### sub HMCCU_IsValidDevice ($$) { @@ -3051,10 +3079,10 @@ sub HMCCU_IsValidDevice ($$) } } -#################################################### -# Check if channel name or address is valid -# and refers to an existing channel. -#################################################### +###################################################################### +# Check if channel name or address is valid and refers to an existing +# channel. +###################################################################### sub HMCCU_IsValidChannel ($$) { @@ -3076,11 +3104,11 @@ sub HMCCU_IsValidChannel ($$) } } -#################################################### -# Get CCU parameters of device or channel. Returns -# list containing interface, deviceaddress, name -# type, channels. -#################################################### +###################################################################### +# Get CCU parameters of device or channel. +# Returns list containing interface, deviceaddress, name, type and +# channels. +###################################################################### sub HMCCU_GetCCUDeviceParam ($$) { @@ -3164,14 +3192,14 @@ sub HMCCU_GetValidDatapoints ($$$$$) return scalar (@$dplistref); } -#################################################### +###################################################################### # Find a datapoint for device type. # hash = hash of client or IO device # devtype = Homematic device type # chn = Channel number, -1=all channels # oper = Valid operation: 1=Read, 2=Write, 4=Event # Return channel of first match or -1. -#################################################### +###################################################################### sub HMCCU_FindDatapoint ($$$$$) { @@ -3184,9 +3212,8 @@ sub HMCCU_FindDatapoint ($$$$$) if ($chn >= 0) { if (exists ($hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$chn})) { foreach my $dp (sort keys %{$hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$chn}}) { - if ($dp eq $dpt && $hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$chn}{$dp}{oper} & $oper) { - return $chn; - } + return $chn if ($dp eq $dpt && + $hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$chn}{$dp}{oper} & $oper); } } } @@ -3194,9 +3221,8 @@ sub HMCCU_FindDatapoint ($$$$$) if (exists ($hmccu_hash->{hmccu}{dp}{$devtype})) { foreach my $ch (sort keys %{$hmccu_hash->{hmccu}{dp}{$devtype}{ch}}) { foreach my $dp (sort keys %{$hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$ch}}) { - if ($dp eq $dpt && $hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$ch}{$dp}{oper} & $oper) { - return $ch; - } + return $ch if ($dp eq $dpt && + $hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$ch}{$dp}{oper} & $oper); } } } @@ -3205,11 +3231,10 @@ sub HMCCU_FindDatapoint ($$$$$) return -1; } -#################################################### -# Get channel number and datapoint name for special -# datapoint. Valid modes are ontime, ramptime, -# submit, level -#################################################### +###################################################################### +# Get channel number and datapoint name for special datapoint. +# Valid modes are ontime, ramptime, submit, level +###################################################################### sub HMCCU_GetSwitchDatapoint ($$$) { @@ -3290,10 +3315,10 @@ sub HMCCU_GetMatchingDevices ($$$$) return $c; } -#################################################### +###################################################################### # Get name of a CCU device by address. # Channel number will be removed if specified. -#################################################### +###################################################################### sub HMCCU_GetDeviceName ($$$) { @@ -3309,9 +3334,9 @@ sub HMCCU_GetDeviceName ($$$) return $default; } -#################################################### +###################################################################### # Get name of a CCU device channel by address. -#################################################### +###################################################################### sub HMCCU_GetChannelName ($$$) { @@ -3326,10 +3351,10 @@ sub HMCCU_GetChannelName ($$$) return $default; } -#################################################### +###################################################################### # Get type of a CCU device by address. # Channel number will be removed if specified. -#################################################### +###################################################################### sub HMCCU_GetDeviceType ($$$) { @@ -3346,10 +3371,10 @@ sub HMCCU_GetDeviceType ($$$) } -#################################################### +###################################################################### # Get number of channels of a CCU device. # Channel number will be removed if specified. -#################################################### +###################################################################### sub HMCCU_GetDeviceChannels ($$$) { @@ -3365,10 +3390,10 @@ sub HMCCU_GetDeviceChannels ($$$) return 0; } -#################################################### +###################################################################### # Get interface of a CCU device by address. # Channel number will be removed if specified. -#################################################### +###################################################################### sub HMCCU_GetDeviceInterface ($$$) { @@ -3384,10 +3409,10 @@ sub HMCCU_GetDeviceInterface ($$$) return $default; } -#################################################### +###################################################################### # Get address of a CCU device or channel by name. # Return array with device address and channel no. -#################################################### +###################################################################### sub HMCCU_GetAddress ($$$$) { @@ -3425,10 +3450,10 @@ sub HMCCU_GetAddress ($$$$) return ($add, $chn); } -#################################################### +###################################################################### # Check if parameter is a channel address (syntax) # f=1: Interface required. -#################################################### +###################################################################### sub HMCCU_IsChnAddr ($$) { @@ -3448,10 +3473,10 @@ sub HMCCU_IsChnAddr ($$) } } -#################################################### +###################################################################### # Check if parameter is a device address (syntax) # f=1: Interface required. -#################################################### +###################################################################### sub HMCCU_IsDevAddr ($$) { @@ -3471,11 +3496,10 @@ sub HMCCU_IsDevAddr ($$) } } -#################################################### -# Split channel address into device address and -# channel number. Returns device address only if -# parameter is already a device address. -#################################################### +###################################################################### +# Split channel address into device address and channel number. +# Returns device address only if parameter is already a device address. +###################################################################### sub HMCCU_SplitChnAddr ($) { @@ -3491,11 +3515,10 @@ sub HMCCU_SplitChnAddr ($) return ('', ''); } -#################################################### -# Query object attribute from CCU. Attribute must -# be a valid method for specified object, -# i.e. Address() -#################################################### +###################################################################### +# Query object attribute from CCU. Attribute must be a valid method +# for specified object, i.e. Address() +###################################################################### sub HMCCU_GetCCUObjectAttribute ($$$) { @@ -3607,10 +3630,10 @@ sub HMCCU_GetRPCDevice ($$) return $rpcdevname; } -#################################################### -# Get hash of HMCCU IO device which is responsible -# for device or channel specified by parameter -#################################################### +###################################################################### +# Get hash of HMCCU IO device which is responsible for device or +# channel specified by parameter +###################################################################### sub HMCCU_FindIODevice ($) { @@ -3627,11 +3650,10 @@ sub HMCCU_FindIODevice ($) return undef; } -#################################################### -# Get hash of HMCCU IO device. Useful for client -# devices. Accepts hash of HMCCU, HMCCUDEV or -# HMCCUCHN device as parameter. -#################################################### +###################################################################### +# Get hash of HMCCU IO device. Useful for client devices. Accepts hash +# of HMCCU, HMCCUDEV or HMCCUCHN device as parameter. +###################################################################### sub HMCCU_GetHash ($@) { @@ -3657,10 +3679,9 @@ sub HMCCU_GetHash ($@) return undef; } -#################################################### -# Get attribute of client device with fallback to -# attribute of IO device. -#################################################### +###################################################################### +# Get attribute of client device. Fallback to attribute of IO device. +###################################################################### sub HMCCU_GetAttribute ($$$$) { @@ -3672,10 +3693,10 @@ sub HMCCU_GetAttribute ($$$$) return $value; } -#################################################### +###################################################################### # Get number of occurrences of datapoint. # Return 0 if datapoint does not exist. -#################################################### +###################################################################### sub HMCCU_GetDatapointCount ($$$) { @@ -3804,9 +3825,9 @@ sub HMCCU_GetAttrSubstitute ($$) return $subst; } -#################################################### +###################################################################### # Clear RPC queue -#################################################### +###################################################################### sub HMCCU_ResetRPCQueue ($$) { @@ -3824,9 +3845,9 @@ sub HMCCU_ResetRPCQueue ($$) $hash->{hmccu}{rpc}{$clkey}{queue} = '' if (exists ($hash->{hmccu}{rpc}{$clkey}{queue})); } -#################################################### +###################################################################### # Process RPC server event -#################################################### +###################################################################### sub HMCCU_ProcessEvent ($$) { @@ -4006,9 +4027,9 @@ sub HMCCU_ProcessEvent ($$) return undef; } -#################################################### +###################################################################### # Timer function for reading RPC queue -#################################################### +###################################################################### sub HMCCU_ReadRPCQueue ($) { @@ -4020,7 +4041,6 @@ sub HMCCU_ReadRPCQueue ($) my @deldevices; my @termpids; my $newcount = 0; -# my $delcount = 0; my $devcount = 0; my %events = (); my %devices = (); @@ -4028,13 +4048,12 @@ sub HMCCU_ReadRPCQueue ($) my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $rpcinterval = AttrVal ($name, 'rpcinterval', 5); my $rpcqueue = AttrVal ($name, 'rpcqueue', '/tmp/ccuqueue'); - my $rpcport = $hash->{hmccu}{rpcports}; my $rpctimeout = AttrVal ($name, 'rpcevtimeout', 300); my $maxevents = $rpcinterval*10; $maxevents = 50 if ($maxevents > 50); $maxevents = 10 if ($maxevents < 10); - my @portlist = split (',', $rpcport); + my @portlist = HMCCU_GetRPCPortList ($hash); foreach my $port (@portlist) { my $clkey = 'CB'.$port; next if (!exists ($hash->{hmccu}{rpc}{$clkey}{queue})); @@ -4173,10 +4192,10 @@ sub HMCCU_ReadRPCQueue ($) } } -#################################################### +###################################################################### # Execute Homematic script on CCU. # Parameters: hostname, script-code -#################################################### +###################################################################### sub HMCCU_HMScript ($$) { @@ -4200,10 +4219,9 @@ sub HMCCU_HMScript ($$) } } -#################################################### -# Bulk update of reading considering attribute -# substexcl. -#################################################### +###################################################################### +# Bulk update of reading considering attribute substexcl. +###################################################################### sub HMCCU_BulkUpdate ($$$$) { @@ -4214,9 +4232,9 @@ sub HMCCU_BulkUpdate ($$$$) readingsBulkUpdate ($hash, $reading, ($excl ne '' && $reading =~ /$excl/ ? $orgval : $subval)); } -#################################################### -# Get datapoint and update reading. -#################################################### +###################################################################### +# Get datapoint value from CCU and update reading. +###################################################################### sub HMCCU_GetDatapoint ($@) { @@ -4278,9 +4296,9 @@ sub HMCCU_GetDatapoint ($@) } } -#################################################### -# Set datapoint -#################################################### +###################################################################### +# Set datapoint on CCU +###################################################################### sub HMCCU_SetDatapoint ($$$) { @@ -4405,9 +4423,10 @@ sub HMCCU_ScaleValue ($$$$) return $value; } -#################################################### -# Get CCU system variables and update readings -#################################################### +###################################################################### +# Get CCU system variables and update readings. +# System variable readings are stored in I/O device. +###################################################################### sub HMCCU_GetVariables ($$) { @@ -4447,15 +4466,16 @@ foreach (ssysvarid, dom.GetObject(ID_SYSTEM_VARIABLES).EnumUsedIDs()) return ($count, $result); } -#################################################### -# Set CCU system variable -#################################################### +###################################################################### +# Set CCU system variable. Variable must exist in CCU. +###################################################################### sub HMCCU_SetVariable ($$$) { my ($hash, $param, $value) = @_; my $name = $hash->{NAME}; - my $url = 'http://'.$hash->{host}.':8181/do.exe?r1=dom.GetObject("'.$param.'").State("'.$value.'")'; + my $url = 'http://'.$hash->{host}.':8181/do.exe?r1=dom.GetObject("'.$param. + '").State("'.$value.'")'; my $response = GetFileFromURL ($url); if (!defined ($response) || $response =~ /nulladd_method ( - { name=>"getEvents", - signature=>["array string"], - code=>\&HMCCU_CCURPC_GetEventsCB - } - ); - # Enter server loop HMCCU_CCURPC_Write ("SL", "$$|$clkey"); @@ -5371,10 +5394,9 @@ sub HMCCU_CCURPC_OnRun ($) return 1; } -################################################## -# Subprocess -# RPC server loop terminated -################################################## +###################################################################### +# Subprocess: Called when RPC server loop is terminated +###################################################################### sub HMCCU_CCURPC_OnExit () { @@ -5384,10 +5406,9 @@ sub HMCCU_CCURPC_OnExit () } } -################################################## -# Subprocess -# Callback for new devices -################################################## +###################################################################### +# Subprocess: Callback for new devices +###################################################################### sub HMCCU_CCURPC_NewDevicesCB ($$$) { @@ -5408,16 +5429,14 @@ sub HMCCU_CCURPC_NewDevicesCB ($$$) $dev->{FIRMWARE}."|".$dev->{RX_MODE}; } HMCCU_CCURPC_Write ("ND", $msg); -# HMCCU_CCURPC_Write ("ND", $dev->{ADDRESS}."|".$dev->{TYPE}); } return; } -################################################## -# Subprocess -# Callback for deleted devices -################################################## +###################################################################### +# Subprocess: Callback for deleted devices +###################################################################### sub HMCCU_CCURPC_DeleteDevicesCB ($$$) { @@ -5433,10 +5452,9 @@ sub HMCCU_CCURPC_DeleteDevicesCB ($$$) return; } -################################################## -# Subprocess -# Callback for modified devices -################################################## +###################################################################### +# Subprocess: Callback for modified devices +###################################################################### sub HMCCU_CCURPC_UpdateDeviceCB ($$$$) { @@ -5447,10 +5465,9 @@ sub HMCCU_CCURPC_UpdateDeviceCB ($$$$) return; } -################################################## -# Subprocess -# Callback for replaced devices -################################################## +###################################################################### +# Subprocess: Callback for replaced devices +###################################################################### sub HMCCU_CCURPC_ReplaceDeviceCB ($$$$) { @@ -5461,10 +5478,9 @@ sub HMCCU_CCURPC_ReplaceDeviceCB ($$$$) return; } -################################################## -# Subprocess -# Callback for readded devices -################################################## +###################################################################### +# Subprocess: Callback for readded devices +###################################################################### sub HMCCU_CCURPC_ReaddDevicesCB ($$$) { @@ -5480,10 +5496,9 @@ sub HMCCU_CCURPC_ReaddDevicesCB ($$$) return; } -################################################## -# Subprocess -# Callback for handling CCU events -################################################## +###################################################################### +# Subprocess: Callback for handling CCU events +###################################################################### sub HMCCU_CCURPC_EventCB ($$$$$) { @@ -5506,10 +5521,9 @@ sub HMCCU_CCURPC_EventCB ($$$$$) return; } -################################################## -# Subprocess -# Callback for list devices -################################################## +###################################################################### +# Subprocess: Callback for list devices +###################################################################### sub HMCCU_CCURPC_ListDevicesCB ($$) { @@ -5523,23 +5537,6 @@ sub HMCCU_CCURPC_ListDevicesCB ($$) return RPC::XML::array->new(); } -################################################## -# Subprocess -# Callback for event query -################################################## - -sub HMCCU_CCURPC_GetEventsCB ($$) -{ - my ($server, $cb) = @_; - my @result; - my $name = $hmccu_child->{devname}; - - $cb = "unknown" if (!defined ($cb)); - Log3 $name, 1, "CCURPC: $cb GetEvents"; - - return undef; -} - 1; @@ -5799,6 +5796,7 @@ sub HMCCU_CCURPC_GetEventsCB ($$)
  • BidCos-RF (Port 2001)
  • Homegear (Port 2003)
  • HmIP (Port 2010)
  • +
  • CUxD (Port 8701)
  • VirtualDevice (Port 9292)

  • @@ -5813,6 +5811,7 @@ sub HMCCU_CCURPC_GetEventsCB ($$)
  • 2001 = BidCos-RF (wireless 868 MHz components with BidCos protocol)
  • 2003 = Homegear (experimental)
  • 2010 = HM-IP (wireless 868 MHz components with IPv6 protocol)
  • +
  • 8701 = CUxD (only supported with external RPC server HMCCURPC)
  • 9292 = CCU group devices (especially heating groups)

  • diff --git a/fhem/FHEM/88_HMCCUCHN.pm b/fhem/FHEM/88_HMCCUCHN.pm index a4fb2f803..03b3f765e 100644 --- a/fhem/FHEM/88_HMCCUCHN.pm +++ b/fhem/FHEM/88_HMCCUCHN.pm @@ -4,9 +4,9 @@ # # $Id$ # -# Version 3.9.003 +# Version 4.0 # -# (c) 2016 zap (zap01 t-online de) +# (c) 2017 zap (zap01 t-online de) # ################################################################ # diff --git a/fhem/FHEM/88_HMCCUDEV.pm b/fhem/FHEM/88_HMCCUDEV.pm index 5241cb601..d72f0ea1f 100644 --- a/fhem/FHEM/88_HMCCUDEV.pm +++ b/fhem/FHEM/88_HMCCUDEV.pm @@ -4,9 +4,9 @@ # # $Id$ # -# Version 3.9 +# Version 4.0 # -# (c) 2016 zap (zap01 t-online de) +# (c) 2017 zap (zap01 t-online de) # ##################################################################### # diff --git a/fhem/FHEM/88_HMCCURPC.pm b/fhem/FHEM/88_HMCCURPC.pm index cfcc825c2..7d5b51d0e 100644 --- a/fhem/FHEM/88_HMCCURPC.pm +++ b/fhem/FHEM/88_HMCCURPC.pm @@ -4,7 +4,7 @@ # # $Id$ # -# Version 0.92 beta +# Version 0.93 beta # # Thread based RPC Server module for HMCCU. # @@ -40,7 +40,7 @@ use SetExtensions; ###################################################################### # HMCCURPC version -my $HMCCURPC_VERSION = '0.92 beta'; +my $HMCCURPC_VERSION = '0.93 beta'; # Maximum number of events processed per call of Read() my $HMCCURPC_MAX_EVENTS = 50; @@ -69,16 +69,19 @@ my $HMCCURPC_TIMEOUT_ACCEPT = 1; # Send statistic information after specified amount of events my $HMCCURPC_STATISTICS = 500; +# Default RPC Port = BidCos-RF +my $HMCCURPC_RPC_PORT_DEFAULT = 2001; + # RPC protocol name by port number my %HMCCURPC_RPC_NUMPORT = ( 2000 => 'BidCos-Wired', 2001 => 'BidCos-RF', 2010 => 'HmIP-RF', 9292 => 'VirtualDevices', - 2003 => 'Homegear' + 2003 => 'Homegear', 8701 => 'CUxD' ); # RPC ports by protocol name my %HMCCURPC_RPC_PORT = ( 'BidCos-Wired', 2000, 'BidCos-RF', 2001, 'HmIP-RF', 2010, 'VirtualDevices', 9292, - 'Homegear', 2003 + 'Homegear', 2003, 'CUxD', 8701 ); # URL extensions @@ -161,8 +164,16 @@ sub HMCCURPC_CheckThreadState ($$$); sub HMCCURPC_IsRPCServerRunning ($); sub HMCCURPC_Housekeeping ($); sub HMCCURPC_StopRPCServer ($); +sub HMCCURPC_IsAscRPCPort ($); +sub HMCCURPC_IsBinRPCPort ($); +sub HMCCURPC_SendRequest ($@); +sub HMCCURPC_SendBinRequest ($@); + +# Helper functions +sub HMCCURPC_HexDump ($$); # RPC server functions +sub HMCCURPC_ProcessRequest ($$); sub HMCCURPC_HandleConnection ($$$$); sub HMCCURPC_TriggerIO ($$$); sub HMCCURPC_ProcessData ($$$$); @@ -236,6 +247,10 @@ sub HMCCURPC_Define ($$) my ($hash, $a, $h) = @_; my $name = $hash->{NAME}; my $hmccu_hash; + my $usage = "Usage: define $name HMCCURPC { CCUHost [noiodev] | iodev=Device_Name }"; + + $hash->{version} = $HMCCURPC_VERSION; + $hash->{noiodev} = 0; if (exists ($h->{iodev})) { my $ioname = $h->{iodev}; @@ -245,23 +260,41 @@ sub HMCCURPC_Define ($$) $hash->{host} = $hmccu_hash->{host}; } else { - return "Usage: define $name HMCCURPC { Host_or_IP | iodev=Device_Name }" if (@$a < 3); + return $usage if (scalar (@$a) < 3); $hash->{host} = $$a[2]; + if (scalar (@$a) > 3) { + return $usage if ($$a[3] ne 'noiodev'); + $hash->{noiodev} = 1; + } } # Try to find I/O device if not defined by parameter iodev - $hmccu_hash = HMCCURPC_FindHMCCUDevice ($hash) if (!defined ($hmccu_hash)); - return "Can't find HMCCU I/O device" if (!defined ($hmccu_hash)); + if (!defined ($hmccu_hash) && $hash->{noiodev} == 0) { + $hmccu_hash = HMCCURPC_FindHMCCUDevice ($hash); + return "Can't find HMCCU I/O device" if (!defined ($hmccu_hash)); + } - # Set I/O device - AssignIoPort ($hash, $hmccu_hash->{NAME}); - - # Store name of RPC device in I/O device - $hmccu_hash->{RPCDEV} = $name; + if (defined ($hmccu_hash)) { + # Set I/O device and store reference for RPC device in I/O device + AssignIoPort ($hash, $hmccu_hash->{NAME}); + $hmccu_hash->{RPCDEV} = $name; + $hash->{ccutype} = $hmccu_hash->{ccutype}; + $hash->{CCUNum} = $hmccu_hash->{CCUNum}; + } + else { + # Count CCU devices + my $ccucount = 0; + foreach my $d (keys %defs) { + my $ch = $defs{$d}; + next if (!exists ($ch->{TYPE})); + $ccucount++ if ($ch->{TYPE} eq 'HMCCU'); + $ccucount++ if ($ch->{TYPE} eq 'HMCCURPC' && $ch != $hash && $ch->{noiodev} == 1); + } + $hash->{CCUNum} = $ccucount+1; + $hash->{ccutype} = "CCU2"; + } - $hash->{version} = $HMCCURPC_VERSION; - $hash->{ccutype} = $hmccu_hash->{ccutype}; - $hash->{CCUNum} = $hmccu_hash->{CCUNum}; + Log3 $name, 1, "HMCCURPC: Device $name. Initialized version $HMCCURPC_VERSION"; # Set some attributes $attr{$name}{stateFormat} = "rpcstate/state"; @@ -353,7 +386,7 @@ sub HMCCURPC_Set ($@) my $opt = shift @$a; my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); - my $options = $ccuflags =~ /expert/ ? "rpcserver:on,off" : ""; + my $options = $ccuflags =~ /expert/ ? "rpcrequest rpcserver:on,off" : ""; my $busyoptions = $ccuflags =~ /expert/ ? "rpcserver:off" : ""; if ($opt ne 'rpcserver' && HMCCURPC_IsRPCStateBlocking ($hash)) { @@ -361,7 +394,49 @@ sub HMCCURPC_Set ($@) return "HMCCURPC: CCU busy, choose one of $busyoptions"; } - if ($opt eq 'rpcserver') { + if ($opt eq 'rpcrequest') { + my $port = shift @$a; + my $request = shift @$a; + return "Usage: set $name rpcrequest {port} {request} [{parameter} ...]" + if (!defined ($request)); + + my $response; + if (HMCCURPC_IsAscRPCPort ($port)) { + $response = HMCCURPC_SendRequest ($hash, $port, $request, @$a); + } + elsif (HMCCURPC_IsBinRPCPort ($port)) { + $response = HMCCURPC_SendBinRequest ($hash, $port, $request, @$a); + } + else { + return HMCCURPC_SetError ($hash, "Invalid RPC port $port"); + } + + return HMCCURPC_SetError ($hash, "RPC request failed") if (!defined ($response)); + + my $result = ''; + if (ref ($response) eq 'ARRAY') { + $result = join "\n", @$response; + } + elsif (ref ($response) eq 'HASH') { + foreach my $k (keys %$response) { + $result .= "$k = ".$response->{$k}."\n"; + } + } + elsif (ref ($response) eq 'SCALAR') { + $result = $$response; + } + else { + if (ref ($response)) { + $result = "Unknown response from CCU of type ".ref ($response); + } + else { + $result = ($response eq '') ? 'Request returned void' : $response; + } + } + + return $result; + } + elsif ($opt eq 'rpcserver') { my $action = shift @$a; return HMCCURPC_SetError ($hash, "Usage: set $name rpcserver {on|off}") @@ -409,21 +484,33 @@ sub HMCCURPC_Get ($@) foreach my $clkey (keys %{$hash->{hmccu}{rpc}}) { next if ($clkey eq 'DATA'); $result .= "Event statistics for server $clkey\n"; - $result .= "Average event delay = ".$hash->{hmccu}{rpc}{$clkey}{avgdelay}."\n"; + $result .= "Average event delay = ".$hash->{hmccu}{rpc}{$clkey}{avgdelay}."\n" + if (defined ($hash->{hmccu}{rpc}{$clkey}{avgdelay})); $result .= "========================================\n"; $result .= "ET Sent by RPC server Received by FHEM\n"; $result .= "----------------------------------------\n"; foreach my $et (@eventtypes) { my $snd = exists ($hash->{hmccu}{rpc}{$clkey}{snd}{$et}) ? - sprintf ("%5d", $hash->{hmccu}{rpc}{$clkey}{snd}{$et}) : " n/a"; + sprintf ("%7d", $hash->{hmccu}{rpc}{$clkey}{snd}{$et}) : " n/a"; my $rec = exists ($hash->{hmccu}{rpc}{$clkey}{rec}{$et}) ? - sprintf ("%5d", $hash->{hmccu}{rpc}{$clkey}{rec}{$et}) : " n/a"; - $result .= "$et $snd $rec\n\n"; + sprintf ("%7d", $hash->{hmccu}{rpc}{$clkey}{rec}{$et}) : " n/a"; + $result .= "$et $snd $rec\n\n"; } } return $result eq '' ? "No event statistics found" : $result; } elsif ($opt eq 'rpcstate') { + $result = ''; + foreach my $clkey (keys %{$hash->{hmccu}{rpc}}) { + if ($result eq '') { + $result .= "ID RPC-Thread State \n"; + $result .= "-----------------------\n"; + } + my $sid = sprintf ("%2d", $hash->{hmccu}{rpc}{$clkey}{tid}); + my $sname = sprintf ("%-6s", $clkey); + $result .= $sid." ".$sname." ".$hash->{hmccu}{rpc}{$clkey}{state}."\n"; + } + $result = "No RPC server running" if ($result eq ''); return $result; } else { @@ -461,7 +548,8 @@ sub HMCCURPC_Notify ($$) AssignIoPort ($hash, $hmccu_hash->{NAME}); } else { - Log3 $name, 0, "HMCCURPC: FHEM initialized but HMCCU IO device not found"; + Log3 $name, 0, "HMCCURPC: FHEM initialized but HMCCU IO device not found" + if ($hash->{noiodev} == 0); } } # return if ($rpcserver eq 'off'); @@ -501,8 +589,8 @@ sub HMCCURPC_Read ($) my $child = $hash->{hmccu}{sockchild}; return if (!defined ($hash->{hmccu}{eventqueue})); my $queue = $hash->{hmccu}{eventqueue}; - return if (!exists ($hash->{IODev})); - my $hmccu_hash = $hash->{IODev}; + my $hmccu_hash; + $hmccu_hash = $hash->{IODev} if (exists ($hash->{IODev}) && $hash->{noiodev} == 0); # Get attributes my $rpcmaxevents = AttrVal ($name, 'rpcMaxEvents', $HMCCURPC_MAX_EVENTS); @@ -559,12 +647,12 @@ sub HMCCURPC_Read ($) } } - # Update device table - HMCCU_UpdateDeviceTable ($hmccu_hash, \%devices) if ($devcount > 0); - - # Update client device readings - HMCCU_UpdateMultipleDevices ($hmccu_hash, \%events) if ($evcount > 0); - + # Update device table and client device readings + if (defined ($hmccu_hash)) { + HMCCU_UpdateDeviceTable ($hmccu_hash, \%devices) if ($devcount > 0); + HMCCU_UpdateMultipleDevices ($hmccu_hash, \%events) if ($evcount > 0); + } + $hash->{hmccu}{readqueue}->dequeue_nb (); Log3 $name, 4, "HMCCURPC: Read finished"; } @@ -637,7 +725,7 @@ sub HMCCURPC_ResetRPCState ($$) # Search HMCCU device and check for running RPC servers my $hmccu_hash; - $hmccu_hash = $hash->{IODev} if (exists ($hash->{IODev})); + $hmccu_hash = $hash->{IODev} if (exists ($hash->{IODev}) && $hash->{noiodev} == 0); $hash->{RPCState} = "stopped"; # RPC server state $hash->{RPCTID} = "0"; # List of RPC server thread IDs @@ -679,6 +767,7 @@ sub HMCCURPC_FindHMCCUDevice ($) { my ($hash) = @_; + return undef if ($hash->{noiodev} == 1); return $hash->{IODev} if (defined ($hash->{IODev})); for my $d (keys %defs) { @@ -700,7 +789,8 @@ sub HMCCURPC_ProcessEvent ($$) my ($hash, $event) = @_; my $name = $hash->{NAME}; my $rh = \%{$hash->{hmccu}{rpc}}; # Just for code simplification - my $hmccu_hash = $hash->{IODev}; + my $hmccu_hash; + $hmccu_hash = $hash->{IODev} if (exists ($hash->{IODev}) && $hash->{noiodev} == 0); # Number of arguments in RPC events (without event type and clkey) my %rpceventargs = ( @@ -804,9 +894,11 @@ sub HMCCURPC_ProcessEvent ($$) $hash->{hmccu}{rpcstarttime} = 0; HMCCURPC_SetRPCState ($hash, "running", "All RPC servers running"); HMCCURPC_SetState ($hash, "OK"); - HMCCU_SetState ($hmccu_hash, "OK"); - ($c_ok, $c_err) = HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0); - Log3 $name, 2, "HMCCURPC: Updated devices. Success=$c_ok Failed=$c_err"; + if (defined ($hmccu_hash)) { + HMCCU_SetState ($hmccu_hash, "OK"); + ($c_ok, $c_err) = HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0); + Log3 $name, 2, "HMCCURPC: Updated devices. Success=$c_ok Failed=$c_err"; + } RemoveInternalTimer ($hash); DoTrigger ($name, "RPC server running"); } @@ -911,7 +1003,7 @@ sub HMCCURPC_ProcessEvent ($$) sub HMCCURPC_GetRPCPortList ($) { my ($hash) = @_; - my @ports = (2001); + my @ports = ($HMCCURPC_RPC_PORT_DEFAULT); if (defined ($hash->{hmccu}{rpcports})) { @ports = split (',', $hash->{hmccu}{rpcports}); @@ -1000,18 +1092,37 @@ sub HMCCURPC_RegisterSingleCallback ($$) return 0 if (!exists ($hash->{hmccu}{rpc}{$clkey}) || $hash->{hmccu}{rpc}{$clkey}{state} ne 'working'); + + my $cburl = ''; + if (HMCCURPC_IsAscRPCPort ($port)) { + $cburl = "http://$rpcserveraddr:".$hash->{hmccu}{rpc}{$clkey}{cbport}."/fh".$port; + } + else { + $cburl = "xmlrpc_bin://$rpcserveraddr:".$hash->{hmccu}{rpc}{$clkey}{cbport}; + } - my $cburl = "http://$rpcserveraddr:".$hash->{hmccu}{rpc}{$clkey}{cbport}."/fh".$port; + # The client URL is only relevant for ASCII RPC my $clurl = "http://$serveraddr:$port/"; - $clurl .= $HMCCURPC_RPC_URL{$port} if (exists ($HMCCURPC_RPC_URL{$port})); + $clurl .= $HMCCURPC_RPC_URL{$port} if (exists ($HMCCURPC_RPC_URL{$port})); + $hash->{hmccu}{rpc}{$clkey}{port} = $port; $hash->{hmccu}{rpc}{$clkey}{clurl} = $clurl; $hash->{hmccu}{rpc}{$clkey}{cburl} = $cburl; $hash->{hmccu}{rpc}{$clkey}{state} = 'registered'; Log3 $name, 1, "HMCCURPC: Registering callback $cburl with ID $clkey at $clurl"; - my $rpcclient = RPC::XML::Client->new ($clurl); - $rpcclient->send_request ("init", $cburl, $clkey); +# if ($HMCCURPC_RPC_PROT{$port} eq 'A') { +# my $rpcclient = RPC::XML::Client->new ($clurl); +# $rpcclient->send_request ("init", $cburl, $clkey); +# } + + if (HMCCURPC_IsAscRPCPort ($port)) { + HMCCURPC_SendRequest ($hash, $port, "init", $cburl, $clkey); + } + else { + HMCCURPC_SendBinRequest ($hash, $port, "init", + $BINRPC_STRING, $cburl, $BINRPC_STRING, $clkey); + } Log3 $name, 1, "HMCCURPC: RPC callback with URL $cburl registered"; return 1; @@ -1035,9 +1146,15 @@ sub HMCCURPC_DeRegisterCallback ($) if (exists ($rpchash->{cburl}) && $rpchash->{cburl} ne '') { Log3 $name, 1, "HMCCURPC: Deregistering RPC server ".$rpchash->{cburl}. " with ID $clkey at ".$rpchash->{clurl}; - my $rpcclient = RPC::XML::Client->new ($rpchash->{clurl}); - $rpcclient->send_request ("init", $rpchash->{cburl}); - +# my $rpcclient = RPC::XML::Client->new ($rpchash->{clurl}); +# $rpcclient->send_request ("init", $rpchash->{cburl}); + if (HMCCURPC_IsAscRPCPort ($rpchash->{port})) { + HMCCURPC_SendRequest ($hash, $rpchash->{port}, "init", $rpchash->{cburl}); + } + else { + HMCCURPC_SendBinRequest ($hash, $rpchash->{port}, "init", $BINRPC_STRING, $rpchash->{cburl}); + } + $rpchash->{port} = 0; $rpchash->{cburl} = ''; $rpchash->{clurl} = ''; $rpchash->{cbport} = 0; @@ -1060,9 +1177,20 @@ sub HMCCURPC_InitRPCServer ($$$) { my ($name, $serverport, $callbackport) = @_; my $clkey = 'CB'.$serverport; + my $server; + + if (HMCCURPC_IsBinRPCPort ($serverport)) { + $server->{__daemon} = IO::Socket::INET->new (LocalPort => $callbackport, + Type => SOCK_STREAM, Reuse => 1, Listen => SOMAXCONN); + if (!($server->{__daemon})) { + Log3 $name, 1, "HMCCURPC: Can't create RPC callback server $clkey on port $callbackport. Port in use?"; + return undef; + } + return $server; + } # Create RPC server - my $server = RPC::XML::Server->new (port => $callbackport); + $server = RPC::XML::Server->new (port => $callbackport); if (!ref($server)) { Log3 $name, 1, "HMCCURPC: Can't create RPC callback server $clkey on port $callbackport. Port in use?"; return undef; @@ -1148,12 +1276,13 @@ sub HMCCURPC_StartRPCServer ($) my $name = $hash->{NAME}; # Search HMCCU device and check for running RPC servers - return (0, "No HMCCU IO device found") if (!exists ($hash->{IODev})); - my $hmccu_hash = $hash->{IODev}; - my @hm_pids = (); - my @ex_pids = (); - return (0, "RPC server already running for device ".$hmccu_hash->{NAME}) - if (HMCCU_IsRPCServerRunning ($hmccu_hash, \@hm_pids, \@ex_pids)); + my $hmccu_hash = $hash->{IODev} if (exists ($hash->{IODev}) && $hash->{noiodev} == 0); + if (defined ($hmccu_hash)) { + my @hm_pids = (); + my @ex_pids = (); + return (0, "RPC server already running for device ".$hmccu_hash->{NAME}) + if (HMCCU_IsRPCServerRunning ($hmccu_hash, \@hm_pids, \@ex_pids)); + } # Get parameters and attributes my %thrpar; @@ -1508,6 +1637,148 @@ sub HMCCURPC_StopRPCServer ($) return 1; } +###################################################################### +# Check if port is valid and an ascii RPC port +###################################################################### + +sub HMCCURPC_IsAscRPCPort ($) +{ + my ($port) = @_; + + return exists ($HMCCURPC_RPC_PROT{$port}) && $HMCCURPC_RPC_PROT{$port} eq 'A' ? 1 : 0; +} + +###################################################################### +# Check if port is valid and a binary RPC port +###################################################################### + +sub HMCCURPC_IsBinRPCPort ($) +{ + my ($port) = @_; + + return exists ($HMCCURPC_RPC_PROT{$port}) && $HMCCURPC_RPC_PROT{$port} eq 'B' ? 1 : 0; +} + +###################################################################### +# Send ascii RPC request to CCU +# Return response or undef on error. +###################################################################### + +sub HMCCURPC_SendRequest ($@) +{ + my ($hash, $port, $request, @param) = @_; + my $name = $hash->{NAME}; + my $serveraddr = $hash->{host}; + + return undef if (!HMCCURPC_IsAscRPCPort ($port)); + + Log3 $name, 4, "HMCCURPC: Send ASCII RPC request $request to $serveraddr:$port"; + + my $clurl = "http://$serveraddr:$port/"; + $clurl .= $HMCCURPC_RPC_URL{$port} if (exists ($HMCCURPC_RPC_URL{$port})); + my $rpcclient = RPC::XML::Client->new ($clurl); + return $rpcclient->simple_request ($request, @param); +} + +###################################################################### +# Send binary RPC request to CCU +# Return response or undef on error. Return empty string on missing +# server response. +###################################################################### + +sub HMCCURPC_SendBinRequest ($@) +{ + my ($hash, $port, $request, @param) = @_; + my $name = $hash->{NAME}; + my $serveraddr = $hash->{host}; + + return undef if (!HMCCURPC_IsBinRPCPort ($port)); + + Log3 $name, 4, "HMCCURPC: Send binary RPC request $request to $serveraddr:$port"; + my $encreq = HMCCURPC_EncodeRequest ($request, \@param); + return undef if ($encreq eq ''); + + # auto-flush on socket + $| = 1; + + # create a connecting socket + my $socket = new IO::Socket::INET (PeerHost => $serveraddr, PeerPort => $port, + Proto => 'tcp'); + return undef if (!$socket); + + my $size = $socket->send ($encreq); + if (defined ($size)) { + my $encresp = <$socket>; + $socket->close (); + + if (defined ($encresp)) { + Log3 $name, 4, "HMCCURPC: Response"; + HMCCURPC_HexDump ($name, $encresp); + my ($response, $rc) = HMCCURPC_DecodeResponse ($encresp); + return $response; + } + else { + return ''; + } + } + + $socket->close (); + return undef; +} + +###################################################################### +# Process binary RPC request +###################################################################### + +sub HMCCURPC_ProcessRequest ($$) +{ + my ($server, $connection) = @_; + my $name = $server->{hmccu}{name}; + my $clkey = $server->{hmccu}{clkey}; + my @methodlist = ('listDevices', 'listMethods', 'system.multicall'); + + # Read request + my $request = ''; + while (my $packet = <$connection>) { + $request .= $packet; + } + return if (!defined ($request) || $request eq ''); + + Log3 $name, 4, "CCURPC: $clkey raw request:"; + HMCCURPC_HexDump ($name, $request); + + # Decode request + my ($method, $params) = HMCCURPC_DecodeRequest ($request); + return if (!defined ($method)); + Log3 $name, 4, "CCURPC: request method = $method"; + + if ($method eq 'listmethods') { + $connection->send (HMCCURPC_EncodeResponse ($BINRPC_ARRAY, \@methodlist)); + } + elsif ($method eq 'listdevices') { + HMCCURPC_ListDevicesCB ($server, $clkey); + $connection->send (HMCCURPC_EncodeResponse ($BINRPC_ARRAY, undef)); + } + elsif ($method eq 'system.multicall') { + if ($server->{hmccu}{running} == 0) { + $server->{hmccu}{running} = 1; + Log3 $name, 1, "CCURPC: Binary RPC $clkey. Sending init to HMCCU"; + HMCCURPC_Write ($server, "IN", $clkey, "INIT|1"); + } + return if (ref ($params) ne 'ARRAY'); + my $a = $$params[0]; + foreach my $s (@$a) { + next if (!exists ($s->{methodName}) || !exists ($s->{params})); + next if ($s->{methodName} ne 'event'); + next if (scalar (@{$s->{params}}) < 4); + HMCCURPC_EventCB ($server, $clkey, + ${$s->{params}}[1], ${$s->{params}}[2], ${$s->{params}}[3]); + Log3 $name, 4, "CCURPC: Event ".${$s->{params}}[1]." ".${$s->{params}}[2]." " + .${$s->{params}}[3]; + } + } +} + ###################################################################### # Thread function for handling incoming RPC requests # thrpar - Hash reference with thread parameters: @@ -1526,7 +1797,7 @@ sub HMCCURPC_HandleConnection ($$$$) my $run = 1; my $tid = threads->tid (); my $clkey = 'CB'.$port; - + my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL"); # Initialize RPC server @@ -1544,23 +1815,27 @@ sub HMCCURPC_HandleConnection ($$$$) } # Store RPC server parameters - $rpcsrv->{hmccu}{name} = $name; - $rpcsrv->{hmccu}{clkey} = $clkey; + $rpcsrv->{hmccu}{name} = $name; + $rpcsrv->{hmccu}{clkey} = $clkey; $rpcsrv->{hmccu}{eventqueue} = $queue; - $rpcsrv->{hmccu}{queuesize} = $thrpar->{queuesize}; + $rpcsrv->{hmccu}{queuesize} = $thrpar->{queuesize}; $rpcsrv->{hmccu}{statistics} = $thrpar->{statistics}; + $rpcsrv->{hmccu}{running} = 0; # Initialize statistic counters $rpcsrv->{hmccu}{snd}{total} = 0; foreach my $et (@eventtypes) { + $rpcsrv->{hmccu}{rec}{$et} = 0; $rpcsrv->{hmccu}{snd}{$et} = 0; } + $rpcsrv->{hmccu}{rec}{total} = 0; + $rpcsrv->{hmccu}{snd}{total} = 0; $SIG{INT} = sub { $run = 0; }; HMCCURPC_Write ($rpcsrv, "SL", $clkey, $tid); Log3 $name, 2, "CCURPC: $clkey accepting connections. TID=$tid"; - + $rpcsrv->{__daemon}->timeout ($thrpar->{acctimeout}); while ($run) { @@ -1569,17 +1844,20 @@ sub HMCCURPC_HandleConnection ($$$$) next if (! $connection); last if (! $run); $connection->timeout ($thrpar->{conntimeout}); - Log3 $name, 4, "CCURPC: $clkey processing CCU request"; if ($prot eq 'A') { + Log3 $name, 4, "CCURPC: $clkey processing CCU request"; $rpcsrv->process_request ($connection); } else { -# HMCCURPC_ProcessRequest ($connection); + HMCCURPC_ProcessRequest ($rpcsrv, $connection); } shutdown ($connection, 2); + close ($connection); undef $connection; } + close ($rpcsrv->{__daemon}) if ($prot eq 'B'); + # Send statistic info HMCCURPC_WriteStats ($rpcsrv, $clkey); @@ -1590,7 +1868,7 @@ sub HMCCURPC_HandleConnection ($$$$) # Log statistic counters push (@eventtypes, 'EV'); foreach my $et (@eventtypes) { - Log3 $name, 4, "CCURPC: $clkey event type = $et: ".$rpcsrv->{hmccu}{snd}{$et}; + Log3 $name, 4, "CCURPC: $clkey event type = $et: ".$rpcsrv->{hmccu}{rec}{$et}; } } @@ -1660,7 +1938,7 @@ sub HMCCURPC_ProcessData ($$$$) Log3 $name, 2, "CCURPC: Thread $threadname processing RPC events. TID=$tid"; while ($run) { - # Do nothing as long as reading is active + # Do nothing as long as HMCCURPC_Read() is reading events from queue my $num_read = $rqueue->pending (); if ($num_read == 0) { # Do nothing if no more items in event queue @@ -1729,6 +2007,8 @@ sub HMCCURPC_Write ($$$$) Log3 $name, 4, "CCURPC: $cb enqueue event $et. parameter = $msg"; $queue->enqueue ($et."|".$cb."|".$msg); + $server->{hmccu}{rec}{$et}++; + $server->{hmccu}{rec}{total}++; $server->{hmccu}{snd}{$et}++; $server->{hmccu}{snd}{total}++; HMCCURPC_WriteStats ($server, $cb) @@ -1751,6 +2031,7 @@ sub HMCCURPC_WriteStats ($$) my $st = $server->{hmccu}{snd}{total}; foreach my $et (@eventtypes) { $st .= '|'.$server->{hmccu}{snd}{$et}; + $server->{hmccu}{snd}{$et} = 0; } Log3 $name, 4, "CCURPC: Event statistics = $st"; @@ -1758,6 +2039,29 @@ sub HMCCURPC_WriteStats ($$) $queue->enqueue ("ST|$clkey|$st"); } +###################################################################### +# Helper functions +###################################################################### + +###################################################################### +# Dump variable content as hex/ascii combination +###################################################################### + +sub HMCCURPC_HexDump ($$) +{ + my ($name, $data) = @_; + + my $offset = 0; + + foreach my $chunk (unpack "(a16)*", $data) { + my $hex = unpack "H*", $chunk; # hexadecimal magic + $chunk =~ tr/ -~/./c; # replace unprintables + $hex =~ s/(.{1,8})/$1 /gs; # insert spaces + Log3 $name, 4, sprintf "0x%08x (%05u) %-*s %s", $offset, $offset, 36, $hex, $chunk; + $offset += 16; + } +} + ###################################################################### # Callback functions ###################################################################### @@ -1879,6 +2183,7 @@ sub HMCCURPC_ListDevicesCB ($$) my ($server, $cb) = @_; my $name = $server->{hmccu}{name}; + $server->{hmccu}{running} = 1; $cb = "unknown" if (!defined ($cb)); Log3 $name, 1, "CCURPC: $cb ListDevices. Sending init to HMCCU"; HMCCURPC_Write ($server, "IN", $cb, "INIT|1"); @@ -1981,14 +2286,16 @@ sub HMCCURPC_EncArray ($) my $r = ''; my $s = 0; - while (my $t = shift @$a) { - my $e = shift @$a; - if ($e) { - $r .= HMCCURPC_EncType ($t, $e); - $s++; + if (defined ($a)) { + while (my $t = shift @$a) { + my $e = shift @$a; + if ($e) { + $r .= HMCCURPC_EncType ($t, $e); + $s++; + } } } - + return pack ('NN', $BINRPC_ARRAY, $s).$r; } @@ -2054,7 +2361,7 @@ sub HMCCURPC_EncType ($$) ###################################################################### # Encode RPC request with method and optional parameters. # Headers are not supported. -# Input is method name reference to parameter array. +# Input is method name and reference to parameter array. # Array must contain (type, value) pairs # Return encoded data or empty string on error ###################################################################### @@ -2101,7 +2408,7 @@ sub HMCCURPC_EncodeResponse ($$) if (defined ($t) && defined ($v)) { my $r = HMCCURPC_EncType ($t, $v); # Ggf. +8 - return pack ('NN', $BINRPC_RESPONSE, length ($r)).$r; + return pack ('NN', $BINRPC_RESPONSE, length ($r)+8).$r; } else { return pack ('NN', $BINRPC_RESPONSE); @@ -2109,7 +2416,7 @@ sub HMCCURPC_EncodeResponse ($$) } ###################################################################### -# Decoding functions +# Binary RPC decoding functions ###################################################################### ###################################################################### @@ -2253,7 +2560,7 @@ sub HMCCURPC_DecType ($$) if ($t == $BINRPC_INTEGER) { # Integer - @r = HMCCURPC_DecInteger ($d, $i, 'l'); + @r = HMCCURPC_DecInteger ($d, $i, 'N'); } elsif ($t == $BINRPC_BOOL) { # Bool @@ -2302,14 +2609,16 @@ sub HMCCURPC_DecodeRequest ($) $i += $o; my $c = unpack ('N', substr ($data, $i, 4)); + $i += 4; + for (my $n=0; $n<$c; $n++) { my ($d, $s) = HMCCURPC_DecType ($data, $i); return (undef, undef) if (!defined ($d) || !defined ($s)); push (@r, $d); $i += $s; } - - return ($method, \@r); + + return (lc ($method), \@r); } ###################################################################### @@ -2360,14 +2669,17 @@ sub HMCCURPC_DecodeResponse ($) Define

      - define <name> HMCCURPC {<HostOrIP>|iodev=<DeviceName>} + define <name> HMCCURPC {<HostOrIP>|iodev=<DeviceName>|standalone=< + HostOrIP>}

      Examples:
      define myccurpc HMCCURPC 192.168.1.10
      - define myccurpc HMCCURPC iodev=myccudev + define myccurpc HMCCURPC iodev=myccudev
      + define myccurpc HMCCURPC standalone=192.168.1.10

      The parameter HostOrIP is the hostname or IP address of a Homematic CCU2. - The I/O device can also be specified with parameter iodev. + The I/O device can also be specified with parameter iodev. If option standalone is + specified RPC servers will operate without I/O device (for development purposes).

    @@ -2385,6 +2697,9 @@ sub HMCCURPC_DecodeResponse ($)
  • get <name> rpcevent
    Show RPC server events statistics.

  • +
  • get <name> rpcstate
    + Show RPC thread states. +

  • @@ -2401,7 +2716,7 @@ sub HMCCURPC_DecodeResponse ($)
  • rpcConnTimeout <seconds>
    Specify timeout of CCU connection handling. Default is 10 second.

  • -
  • rpcInterfaces { BidCos-Wired, BidCos-RF, HmIP-RF, VirtualDevices, Homegear }
    +
  • rpcInterfaces { BidCos-Wired, BidCos-RF, HmIP-RF, VirtualDevices, CUxD, Homegear }
    Select RPC interfaces. If attribute is missing the corresponding attribute of I/O device (HMCCU device) is used. Default is BidCos-RF.

  • diff --git a/fhem/FHEM/HMCCUConf.pm b/fhem/FHEM/HMCCUConf.pm index 2945208d6..fddc463b6 100644 --- a/fhem/FHEM/HMCCUConf.pm +++ b/fhem/FHEM/HMCCUConf.pm @@ -4,13 +4,13 @@ # # $Id$ # -# Version 3.9.002 +# Version 4.0 # # Configuration parameters for Homematic devices. # # (c) 2016 zap (zap01 t-online de) # -# Datapoints LOWBAT, LOW_BAT, UNREACH, ERROR*, SABOTAGE and FAULT* must +# Datapoints LOWBAT, LOW_BAT, UNREACH, ERROR.*, SABOTAGE and FAULT.* must # not be specified in ccureadingfilter. They are always stored as readings. # Datapoints LOWBAT, LOW_BAT and UNREACH must not be specified in # substitute because they are substituted by default. @@ -25,11 +25,12 @@ use warnings; use vars qw(%HMCCU_CHN_DEFAULTS); use vars qw(%HMCCU_DEV_DEFAULTS); +use vars qw(%HMCCU_SCRIPTS); -# -# +###################################################################### # Default attributes for Homematic devices of type HMCCUCHN -# +###################################################################### + %HMCCU_CHN_DEFAULTS = ( "HM-Sec-SCo|HM-Sec-SC|HM-Sec-SC-2|HMIP-SWDO" => { _description => "Tuer/Fensterkontakt optisch und magnetisch", @@ -126,7 +127,7 @@ use vars qw(%HMCCU_DEV_DEFAULTS); webCmd => "control:on:off", widgetOverride => "control:slider,0,10,100" }, - "HM-PB-2-FM|HM-PB-2-WM55|HM-PB-2-WM55-2" => { + "HM-PB-2-FM" => { _description => "Funk-Wandtaster 2-fach", _channels => "1,2", ccureadingfilter => "PRESS", @@ -275,9 +276,10 @@ use vars qw(%HMCCU_DEV_DEFAULTS); } ); -# +###################################################################### # Default attributes for Homematic devices of type HMCCUDEV -# +###################################################################### + %HMCCU_DEV_DEFAULTS = ( "CCU2" => { _description => "HomeMatic CCU2", @@ -414,7 +416,7 @@ use vars qw(%HMCCU_DEV_DEFAULTS); webCmd => "control:on:off", widgetOverride => "control:slider,0,10,100" }, - "HM-PB-2-FM|HM-PB-2-WM55|HM-PB-2-WM55-2" => { + "HM-PB-2-FM" => { _description => "Funk-Wandtaster 2-fach", ccureadingfilter => "PRESS", substitute => "PRESS_SHORT,PRESS_LONG,PRESS_CONT!(1|true):pressed,(0|false):released;PRESS_LONG_RELEASE!(0|false):no,(1|true):yes" @@ -629,7 +631,69 @@ use vars qw(%HMCCU_DEV_DEFAULTS); eventMap => "/datapoint 3.SUBMIT:display/", substitute => "PRESS_LONG,PRESS_SHORT,PRESS_CONT!(1|true):pressed,(0|false):notPressed;PRESS_LONG_RELEASE!(1|true):release", widgetOverride => "display:textField" + }, + "CUX-HM-TC-IT-WM-W-EU" => { + _description => "CUxD Wandthermostat", + ccureadingfilter => "(TEMP|HUM|DEW)", + stripnumber => 1 + } +); +###################################################################### +# Homematic scripts +###################################################################### + +%HMCCU_SCRIPTS = ( + "CreateVariable" => { + _description => "Create CCU system variable of type STRING, NUMBER, BOOL or LIST", + _pardesc => "Type, Name, Unit, Init, Desc [, { Min, Max | Val1, Val2 | ValList } ]", + parameters => 6, + code => qq( +object oSV = dom.GetObject("p2"); +if (!oSV){ + object oSysVars = dom.GetObject(ID_SYSTEM_VARIABLES); + oSV = dom.CreateObject(OT_VARDP); + oSysVars.Add(svObj.ID()); + oSV.Name("p2"); + if ("p1" = "STRING") { + oSV.ValueType(ivtString); + oSV.ValueSubType(istChar8859); + } + if ("p1" = "NUMBER") { + oSV.ValueType(ivtFloat); + oSV.ValueSubType(istGeneric); + oSV.ValueMin(p6); + oSV.ValueMax(p7); + } + if ("p1" = "BOOL") { + oSV.ValueType(ivtBinary); + oSV.ValueSubType(istBool); + oSV.ValueName0("p6"); + oSV.ValueName1("p7"); + } + if ("p1" = "LIST") { + oSV.ValueType(ivtInteger); + oSV.ValueSubType(istEnum); + oSV.ValueList("p6"); + } + oSV.DPInfo("p5"); + oSV.ValueUnit("p3"); + oSV.State("p4"); + oSV.Internal(false); + oSV.Visible(true); + dom.RTUpdate(false); +} + ) + }, + "DeleteVariable" => { + _description => "Delete CCU system variable", + parameters => 1, + code => qq( +object oSV = dom.GetObject("p1"); +if (oSV) { + dom.DeleteObject(oSV.ID()); +} + ) } );