diff --git a/contrib/HMCCU/FHEM/88_HMCCU.pm b/contrib/HMCCU/FHEM/88_HMCCU.pm index 51f73b817..7ff68a133 100644 --- a/contrib/HMCCU/FHEM/88_HMCCU.pm +++ b/contrib/HMCCU/FHEM/88_HMCCU.pm @@ -3659,12 +3659,11 @@ sub HMCCU_UpdateDeviceRoles ($$;$$) my ($ioHash, $clHash, $iface, $address) = @_; my $clType = $clHash->{TYPE}; - return if ($clType ne 'HMCCUCHN'); $iface = $clHash->{ccuif} if (!defined($iface)); $address = $clHash->{ccuaddr} if (!defined($address)); return if (!defined($address)); - + my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $address, $iface); if (defined($devDesc)) { if ($clType eq 'HMCCUCHN' && defined($devDesc->{TYPE})) { @@ -3680,7 +3679,7 @@ sub HMCCU_UpdateDeviceRoles ($$;$$) } $clHash->{ccurole} = join(',', @roles) if (scalar(@roles) > 0); } - } + } } ###################################################################### @@ -6922,57 +6921,90 @@ sub HMCCU_GetSpecialDatapoints ($$$$$) my $type = $hash->{TYPE}; my $ccutype = $hash->{ccutype}; + # F: 1=Channel, 2=Device, 3=Both + # S: State Datapoint, C: Control datapoint + my %roleDPs = ( + 'SHUTTER_CONTACT' => { F => 3, S => 'STATE', C => '' }, + 'KEY' => { F => 3, S => 'PRESS_SHORT', C => 'PRESS_SHORT' }, + 'BLIND' => { F => 3, S => 'LEVEL', C => 'LEVEL' }, + 'SWITCH' => { F => 3, S => 'STATE', C => 'STATE' }, + 'DIMMER' => { F => 3, S => 'LEVEL', C => 'LEVEL' }, + 'WEATHER_TRANSMIT' => { F => 1, S => 'TEMPERATURE', C => 'TEMPERATURE' }, + 'THERMALCONTROL_TRANSMIT' => { F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE' }, + 'CLIMATECONTROL_RT_TRANSCEIVER' => { F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE' } + ); + my $statedatapoint = AttrVal ($name, 'statedatapoint', ''); my $statechannel = AttrVal ($name, 'statechannel', ''); my $controldatapoint = AttrVal ($name, 'controldatapoint', $statedatapoint); + # If attribute statedatapoint is specified, use it if ($statedatapoint ne '') { if ($statedatapoint =~ /^([0-9]+)\.(.+)$/) { ($sc, $sd) = ($1, $2); } else { $sd = $statedatapoint; + if ($statechannel eq '') { + # Try to find state channel + my $c = HMCCU_FindDatapoint ($hash, $type, -1, $sd, 3); + $sc = $c if ($c >= 0); + } + else { + $sc = $statechannel; + } } } - $sc = $statechannel if ($statechannel ne '' && $sc eq ''); + # If attribute controldatapoint is specified, use it if ($controldatapoint ne '') { if ($controldatapoint =~ /^([0-9]+)\.(.+)$/) { ($cc, $cd) = ($1, $2); } else { $cd = $controldatapoint; + # Try to find control channel + my $c = HMCCU_FindDatapoint ($hash, $type, -1, $cd, 3); + $cc = $c if ($c >= 0); } } - # For devices of type HMCCUCHN extract channel numbers from CCU device address - if ($type eq 'HMCCUCHN') { - $sc = $hash->{ccuaddr}; - $sc =~ s/^[\*]*[0-9A-Z]+://; - $cc = $sc; - if ($sd eq '') { - if (HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, 'STATE', 3)) { $sd = 'STATE'; } - elsif (HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, 'LEVEL', 3)) { $sd = 'LEVEL'; } - elsif (HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, 'PRESS_SHORT', 3)) { $sd = 'PRESS_SHORT'; } + if (exists($hash->{ccurole})) { + my $ccuRole = $hash->{ccurole}; + if ($type eq 'HMCCUCHN') { + my ($da, $dc) = HMCCU_SplitChnAddr ($hash->{ccuaddr}); + $sc = $dc; + $cc = $dc; + if (exists($roleDPs{$ccuRole}) && $roleDPs{$ccuRole}{F} & 1) { + $sd = $roleDPs{$ccuRole}{S} if ($roleDPs{$ccuRole}{S} ne ''); + $cd = $roleDPs{$ccuRole}{C} if ($roleDPs{$ccuRole}{C} ne ''); + } } - } - else { - # Try to find state channel - my $c = -1; - if ($sc eq '' && $sd ne '') { - $c = HMCCU_FindDatapoint ($hash, $type, -1, $sd, 3); - $sc = $c if ($c >= 0); - } - # Try to find control channel - if ($cc eq '' && $cd ne '') { - $c = HMCCU_FindDatapoint ($hash, $type, -1, $cd, 3); - $cc = $c if ($c >= 0); + elsif ($type eq 'HMCCUDEV') { + foreach my $roleDef (split(',', $ccuRole)) { + my ($dc, $role) = split(':', $roleDef); + if (exists($roleDPs{$role}) && $roleDPs{$role}{F} & 2) { + if ($roleDPs{$role}{S} ne '' && $sd eq '') { + $sd = $roleDPs{$role}{S}; + $sc = $dc; + } + if ($roleDPs{$role}{C} ne '' && $cd eq '') { + $cd = $roleDPs{$role}{C} ; + $cc = $dc; + } + } + last if ($sd ne '' && $cd ne ''); + } } } # By default set control channel and datapoint to state channel and datapoint $cc = $sc if ($cc eq ''); $cd = $sd if ($cd eq ''); + $hash->{hmccu}{state}{dpt} = $sd; + $hash->{hmccu}{state}{chn} = $sc; + $hash->{hmccu}{control}{dpt} = $cd; + $hash->{hmccu}{control}{chn} = $cc; return ($sc, $sd, $cc, $cd); } diff --git a/contrib/HMCCU/FHEM/88_HMCCUCHN.pm b/contrib/HMCCU/FHEM/88_HMCCUCHN.pm index 108c761e7..32c97443a 100644 --- a/contrib/HMCCU/FHEM/88_HMCCUCHN.pm +++ b/contrib/HMCCU/FHEM/88_HMCCUCHN.pm @@ -254,7 +254,7 @@ sub HMCCUCHN_Set ($@) return undef if ($disable == 1); my $ioHash = $hash->{IODev}; - my $hmccu_name = $ioHash->{NAME}; + my $ioName = $ioHash->{NAME}; if (HMCCU_IsRPCStateBlocking ($ioHash)) { return undef if ($opt eq '?'); return "HMCCUCHN: CCU busy"; @@ -274,7 +274,7 @@ sub HMCCUCHN_Set ($@) # Log commands HMCCU_Log ($hash, 3, "set $name $opt ".join (' ', @$a)) - if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($hmccu_name, 'logCommand')); + if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand')); if ($opt eq 'datapoint') { my $usage = "Usage: set $name datapoint {{datapoint} {value} | {datapoint}={value}} [...]"; @@ -329,7 +329,7 @@ sub HMCCUCHN_Set ($@) return HMCCU_SetError ($hash, min(0, $rc)); } elsif (exists($stateCmds{$opt})) { - return HMCCU_SetError ($hash, -13) if ($sd eq ''); + return HMCCU_SetError ($hash, -14) if ($cd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2)); @@ -340,7 +340,8 @@ sub HMCCUCHN_Set ($@) } elsif ($opt eq 'toggle') { return HMCCU_SetError ($hash, -15) if ($stateVals eq ''); - return HMCCU_SetError ($hash, -13) if ($cd eq ''); + return HMCCU_SetError ($hash, -12) if ($cc eq ''); + return HMCCU_SetError ($hash, -14) if ($cd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2)); @@ -427,7 +428,7 @@ sub HMCCUCHN_Set ($@) return HMCCU_SetError ($hash, -15) if ($stateVals eq ''); return HMCCU_SetError ($hash, "No state value for 'on' defined") if (!exists($stateCmds{"on"})); - return HMCCU_SetError ($hash, -13) if ($cd eq ''); + return HMCCU_SetError ($hash, -14) if ($cd eq ''); return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2)); return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type") @@ -504,15 +505,22 @@ sub HMCCUCHN_Set ($@) return HMCCU_SetError ($hash, "Receiver $receiver is not a HMCCUCHN or HMCCUDEV device"); } } + elsif (!HMCCU_IsChnAddr ($receiver, 0)) { + my ($rcvAdd, $rcvChn) = HMCCU_GetAddress ($ioHash, $receiver, '', ''); + return HMCCU_SetError ($hash, "$receiver is not a valid CCU channel name") + if ($rcvAdd eq '' || $rcvChn eq ''); + $receiver = "$rcvAdd:$rcvChn"; + } + + return HMCCU_SetError ($hash, "$receiver is not a link receiver of $name") + if (!HMCCU_IsValidReceiver ($ioHash, $ccuaddr, $ccuif, $receiver)); + push @rcvList, $receiver; } else { push @rcvList, HMCCU_GetReceivers ($ioHash, $ccuaddr, $ccuif); } - return HMCCU_SetError ($hash, "$receiver is not a link receiver of $name") - if (!HMCCU_IsValidReceiver ($ioHash, $ccuaddr, $ccuif, $receiver)); - my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $ccuaddr, $ccuif); return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc)); @@ -568,7 +576,7 @@ sub HMCCUCHN_Get ($@) return undef if ($disable == 1); my $ioHash = $hash->{IODev}; - my $hmccu_name = $ioHash->{NAME}; + my $ioName = $ioHash->{NAME}; if (HMCCU_IsRPCStateBlocking ($ioHash)) { return undef if ($opt eq '?'); return "HMCCUCHN: CCU busy"; @@ -577,7 +585,6 @@ sub HMCCUCHN_Get ($@) my $ccutype = $hash->{ccutype}; my $ccuaddr = $hash->{ccuaddr}; my $ccuif = $hash->{ccuif}; - my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', ''); my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $result = ''; @@ -585,7 +592,7 @@ sub HMCCUCHN_Get ($@) # Log commands HMCCU_Log ($hash, 3, "get $name $opt ".join (' ', @$a)) - if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($hmccu_name, 'logCommand')); + if ($opt ne '?' && $ccuflags =~ /logCommand/ || HMCCU_IsFlag ($ioName, 'logCommand')); if ($opt eq 'datapoint') { my $objname = shift @$a; @@ -768,8 +775,9 @@ sub HMCCUCHN_Get ($@)
  • set <name> link <receiver> [<channel>] <parameter>=<value>[:<type>]
    Set multiple link parameters (parameter set LINK). Parameter receiver is the - name of a FHEM device of type HMCCUDEV or HMCCUCHN or a channel address. For FHEM - devices of type HMCCUDEV a channel number must be specified. Parameter parameter must be a valid + name of a FHEM device of type HMCCUDEV or HMCCUCHN or a channel address or a CCU + channel name. For FHEM devices of type HMCCUDEV a channel number must be specified. + Parameter parameter must be a valid link configuration parameter name. If type is not specified, it's taken from parameter set definition. The default type is STRING. Valid types are STRING, BOOL, INTEGER, FLOAT, DOUBLE. diff --git a/contrib/HMCCU/FHEM/88_HMCCUDEV.pm b/contrib/HMCCU/FHEM/88_HMCCUDEV.pm index b46658120..dfa790db4 100644 --- a/contrib/HMCCU/FHEM/88_HMCCUDEV.pm +++ b/contrib/HMCCU/FHEM/88_HMCCUDEV.pm @@ -389,8 +389,11 @@ sub HMCCUDEV_Set ($@) my $ccuif = $hash->{ccuif}; my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $statevals = AttrVal ($name, 'statevals', ''); - my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', ''); - + my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', '', '', ''); + my $stateVals = HMCCU_GetStateValues ($hash, $cd, 2); + my %stateCmds = split (/[:,]/, $stateVals); + my @states = keys %stateCmds; + my $result = ''; my $rc; @@ -455,44 +458,33 @@ sub HMCCUDEV_Set ($@) ); return HMCCU_SetError ($hash, min(0, $rc)); } - elsif ($opt =~ /^($hash->{hmccu}{statevals})$/) { - my $cmd = $1; - my $objvalue = ($cmd ne 'devstate') ? $cmd : shift @$a; + elsif (exists($stateCmds{$opt})) { + return HMCCU_SetError ($hash, -12) if ($cc eq ''); + return HMCCU_SetError ($hash, -14) if ($cd eq ''); + return HMCCU_SetError ($hash, -8) + if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2)); - return HMCCU_SetError ($hash, -11) if ($sc eq ''); - return HMCCU_SetError ($hash, -13) if ($sd eq ''); - return HMCCU_SetError ($hash, "Usage: set $name devstate {value}") if (!defined ($objvalue)); - - $objvalue =~ s/\\_/%20/g; $rc = HMCCU_SetMultipleDatapoints ($hash, - { "001.$ccuif.$ccuaddr:$sc.$sd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } + { "001.$ccuif.$ccuaddr:$cc.$cd" => $stateCmds{$opt} } ); return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'toggle') { - return HMCCU_SetError ($hash, -15) if ($statevals eq '' || !exists($hash->{hmccu}{statevals})); - return HMCCU_SetError ($hash, -11) if ($sc eq ''); - return HMCCU_SetError ($hash, -13) if ($sd eq ''); - return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, $sd, 2)); + return HMCCU_SetError ($hash, -15) if ($stateVals eq ''); + return HMCCU_SetError ($hash, -12) if ($cc eq ''); + return HMCCU_SetError ($hash, -14) if ($cd eq ''); + return HMCCU_SetError ($hash, -8) + if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2)); - my $tstates = $hash->{hmccu}{statevals}; - $tstates =~ s/devstate\|//; - my @states = split /\|/, $tstates; my $stc = scalar (@states); + my $curState = defined($hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL}) ? + $hash->{hmccu}{dp}{"$cc.$cd"}{VALUES}{SVAL} : $states[0]; - my $objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.'.$sd; - - # Read current value of datapoint without updating reading - ($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 1); - Log3 $name, 2, "HMCCU: set toggle: GetDatapoint returned $rc, $result" - if ($ccuflags =~ /trace/); - return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0); - - my $objvalue = ''; + my $newState = ''; my $st = 0; while ($st < $stc) { - if ($states[$st] eq $result) { - $objvalue = ($st == $stc-1) ? $states[0] : $states[$st+1]; + if ($states[$st] eq $curState) { + $newState = ($st == $stc-1) ? $states[0] : $states[$st+1]; last; } else { @@ -500,11 +492,11 @@ sub HMCCUDEV_Set ($@) } } - return HMCCU_SetError ($hash, "Current device state doesn't match statevals") - if ($objvalue eq ''); + return HMCCU_SetError ($hash, "Current device state doesn't match any state value") + if ($newState eq ''); $rc = HMCCU_SetMultipleDatapoints ($hash, - { "001.$objname" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') } + { "001.$ccuif.$ccuaddr:$cc.$cd" => $stateCmds{$newState} } ); return HMCCU_SetError ($hash, min(0, $rc)); }