diff --git a/fhem/FHEM/10_KNX.pm b/fhem/FHEM/10_KNX.pm index 706b2e65a..4877b2c9b 100644 --- a/fhem/FHEM/10_KNX.pm +++ b/fhem/FHEM/10_KNX.pm @@ -169,6 +169,9 @@ # additional dpts 14.xxx - see cmdref # fix dpt14 min/max values # performance tuning in define +# MH 20240305 change dpt1.009 max-value from closed->close +# prevent gadName 'state' in define when nosuffix specified +# add on-for...|off-for... to forbidden gadNames # # todo replace cascading if..elsif with given # todo-11/2023 final removal of attr answerReading conversion @@ -248,7 +251,8 @@ my $PAT_GAD_OPTIONS = 'get|set|listenonly'; #pattern for GAD-suffixes my $PAT_GAD_SUFFIX = 'nosuffix'; #pattern for forbidden GAD-Names -my $PAT_GAD_NONAME = '^(on|off|value|raw|' . $PAT_GAD_OPTIONS . q{|} . $PAT_GAD_SUFFIX . ')'; +#my $PAT_GAD_NONAME = '^(on|off|value|raw|' . $PAT_GAD_OPTIONS . q{|} . $PAT_GAD_SUFFIX . ')'; +my $PAT_GAD_NONAME = 'on|off|on-for-timer|on-until|off-for-timer|off-until|toggle|raw|rgb|string|value'; #pattern for DPT my $PAT_GAD_DPT = 'dpt\d+\.?\d*'; #pattern for dpt1 (standard) @@ -265,10 +269,11 @@ my $PAT_DPT16_CLR = qr/>CLR {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT)/ixms, MIN=>'off', MAX=>'on', SETLIST=>'on,off,toggle', @@ -282,7 +287,7 @@ my %dpttypes = ( 'dpt1.006' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|low|high)/ixms, MIN=>'low', MAX=>'high'}, 'dpt1.007' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|decrease|increase)/ixms, MIN=>'decrease', MAX=>'increase'}, 'dpt1.008' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|up|down)/ixms, MIN=>'up', MAX=>'down'}, - 'dpt1.009' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|closed|open)/ixms, MIN=>'open', MAX=>'closed'}, + 'dpt1.009' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|close|open)/ixms, MIN=>'open', MAX=>'close'}, 'dpt1.010' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|start|stop)/ixms, MIN=>'stop', MAX=>'start'}, 'dpt1.011' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|inactive|active)/ixms, MIN=>'inactive', MAX=>'active'}, 'dpt1.012' => {CODE=>'dpt1', UNIT=>q{}, PATTERN=>qr/($PAT_DPT1_PAT|not_inverted|inverted)/ixms, MIN=>'not_inverted', MAX=>'inverted'}, @@ -651,7 +656,8 @@ sub KNX_Define2 { $attr{$name}->{disable} = 1 if (AttrVal($name,'disable',0) != 1); } elsif (!defined($dpttypes{$gadModel})) { #check model-type - push(@logarr,qq{invalid model $gadModel for group-number $gadNo, consult commandref - avaliable DPT}); + push(@logarr,qq{invalid dpt $gadModel for group-number $gadNo, consult commandref - avaliable DPT}); + $attr{$name}->{disable} = 1 if (AttrVal($name,'disable',0) != 1); next; } elsif ($gadNo == 1) { # gadModel ok - use first gad as mdl reference for fheminfo @@ -663,10 +669,16 @@ sub KNX_Define2 { $gadOption = lc(pop(@gadArgs)) if (@gadArgs && $gadArgs[-1] =~ /^($PAT_GAD_OPTIONS)$/ixms); $gadName = pop(@gadArgs) if (@gadArgs); - if ($gadName =~ /^$PAT_GAD_NONAME$/ixms) { - push(@logarr,qq{forbidden gad-name $gadName}); +# if ($gadName =~ /^($PAT_GAD_NONAME)$/ixms) { + if ($gadName =~ /^($PAT_GAD_NONAME)$/xms) { # allow mixed case + push(@logarr,qq{forbidden gadName $gadName}); next; } + + if ($gadName eq q{state} && defined($gadNoSuffix)) { + $gadName = q{g} . $gadNo; + push(@logarr,qq{forbidden gadName: state - modified to: $gadName}); + } } if (defined($hash->{GADTABLE}->{$gadCode})) { @@ -1214,22 +1226,7 @@ sub KNX_Parse { elsif ($cmd =~ /[r]/ixms) { my $cmdAttr = AttrVal($deviceName, 'putCmd', undef); next if (! defined($cmdAttr) || $cmdAttr eq q{}); -=begin comment -# replaced by block below !! - # special experiment for Amenophis86 - if ($cmdAttr eq 'noReply') { - if ($iohash->{PhyAddr} eq KNX_hexToName2($src)) { # match src-address with phy of IOdev - # from fhem - delete ignore reply flag - delete $deviceHash->{GADDETAILS}->{$gadName}->{noreplyflag}; # allow when sent from fhem - } - else { - KNX_Log ($deviceName, 4, q{read msg from } . KNX_hexToName2($src) . qq{ for $deviceName $gadName IODev= $iohash->{PhyAddr}}); - $deviceHash->{GADDETAILS}->{$gadName}->{noreplyflag} = gettimeofday() + 2; - } - next; # cannot use putCmd logic! - } -=end comment -=cut + # generate my $putName = $getName =~ s/get/put/irxms; $putName .= ($putName eq $getName)?q{-put}:q{}; # nosuffix @@ -1241,6 +1238,7 @@ sub KNX_Parse { KNX_Log ($deviceName, 2, qq{putCmd eval error gadName=$gadName - no reply sent!}); next; # dont send! } + ## special experiment for Amenophis86 elsif ($value eq 'noReply') { if ($iohash->{PhyAddr} eq KNX_hexToName2($src)) { # match src-address with phy of IOdev @@ -1300,7 +1298,12 @@ sub KNX_autoCreate { ### KNX_SetReadings is called from KNX_Set and KNX_Parse # calling param: $hash, $gadName, $value, caller (set/parse), trigger (event yes/no) sub KNX_SetReadings { - my ($hash, $gadName, $value, $src, $trigger) = @_; +# my ($hash, $gadName, $value, $src, $trigger) = @_; + my $hash = shift; + my $gadName = shift; + my $value = shift; + my $src = shift // q{fhem}; # undef when called from set + my $trigger = shift // 1; # trigger if undef my $name = $hash->{NAME}; @@ -1314,13 +1317,14 @@ sub KNX_SetReadings { $value .= q{ } . $unit; } - my $lsvalue = 'fhem'; # called from set + my $lsvalue = q{fhem}; # called from set my $rdName = $hash->{GADDETAILS}->{$gadName}->{RDNAMESET}; - if (defined($src) && ($src ne q{})) { # called from parse + if ($src ne q{fhem}) { # called from parse +# if (defined($src) && ($src ne q{})) { # called from parse $lsvalue = KNX_hexToName2($src); $rdName = $hash->{GADDETAILS}->{$gadName}->{RDNAMEGET}; } - my $trievents = (defined($trigger))?$trigger:1; +# my $trievents = (defined($trigger))?$trigger:1; #execute stateRegex my $state = KNX_replaceByRegex ($hash, $rdName, $value); @@ -1347,7 +1351,8 @@ sub KNX_SetReadings { } readingsBulkUpdate($hash, 'state', $state); } - readingsEndUpdate($hash, $trievents); +# readingsEndUpdate($hash, $trievents); + readingsEndUpdate($hash, $trigger); return; } @@ -2143,6 +2148,7 @@ sub KNX_chkIO { sub doKNX_scan { my $iohash = shift // return; + return if (! exists($iohash->{Helper}->{knxscan})); my $count = scalar(@{$iohash->{Helper}->{knxscan}}); if ($count > 0 ) { my ($devName,$gadName) = split(/\s/xms, shift(@{$iohash->{Helper}->{knxscan}}),2); @@ -2223,11 +2229,11 @@ This module provides a basic set of operations (on, off, toggle, on-until, on-fo devices and to send values to the bus. 

Sophisticated setups can be achieved by combining multiple KNX-groupaddresses:datapoints (GAD's:dpt's) in one KNX device instance.

-

KNX defines a series of Datapoint Type as standard data types used to allow general interpretation of values - of devices manufactured by different vendors. +

KNX defines a series of Data-Point-Types (dpt) as standard data types to allow + interpretation/encoding of messages from/to devices manufactured by different vendors. These datatypes are used to interpret the status of a device, so the readings in FHEM will show the correct value and optional unit.

-

For each received telegram there will be a reading containing the received value and the sender address.
+

For each received message there will be a reading containing the received value and the sender address.
For every set, there will be a reading containing the sent value.
The reading <state> will be updated with the last sent or received value. 

A (german) wiki page is avaliable here: FHEM Wiki

@@ -2236,26 +2242,27 @@ The reading <state> will be updated with the last sent or received value.&
  • Define

    define <name> KNX <group>:<dpt>[:[<gadName>]:[set|get|listenonly]:[nosuffix]] [<group>:<dpt> ..] [IODev]

    -

    Important: a KNX device needs at least one valid DPT. Please refer to avaliable DPT. - Otherwise the system cannot en- or decode messages.
    -Devices defined by autocreate have to be reworked with the suitable dpt and the disable attribute deleted. +

    Important: a KNX device needs at least one valid DPT. + The system cannot en- or de-code messages without a valid dpt defined.
    +Devices defined by autocreate have to be configured with a correct dpt and the disable attribute deleted. Otherwise they won't do anything.

    The <group> parameter is either a group name notation (0-31/0-7/0-255) or the hex representation of it ([00-1f][0-7][00-ff]) (5 digits). All of the defined groups can be used for bus-communication. - It is not allowed to have the same group-address more then once in one device. You can have multiple devices containing + It is not allowed to have the same group-address more then once in one device. You can have multiple FHEM-devices containing the same group-adresses.
    As described above the parameter <dpt> has to contain the corresponding DPT - matching the dpt-spec of the KNX-Hardware.

    -

    The gadNames are default named "g<number>". The corresponding reading-names are getG<number> +

    The gadName default is "g<number>". The corresponding reading-names are getG<number> and setG<number>.
    The optional parameteter <gadName> may contain an alias for the GAD. The following gadNames are not allowed: - on, off, on-for-timer, on-until, off-for-timer, off-until, toggle, raw, rgb, string, value, set, get, listenonly, nosuffix + state, on, off, on-for-timer, on-until, off-for-timer, off-until, toggle, raw, rgb, string, value, set, get, listenonly, nosuffix - because of conflict with cmds & parameters.
    If you supply <gadName> this name is used instead. The readings are <gadName>-get and <gadName>-set. The synonyms <getName> and <setName> are used in this documentation.
    -If you add the option "nosuffix", <getName> and <setName> have the identical name - only <gadName>.
    +If you add the option "nosuffix", <getName> and <setName> have the identical name - <gadName>. +Both sent and received bus messages will be stored in the same reading <gadName>
    If you want to restrict the GAD, you can use the options "get", "set", or "listenonly". The usage should be self-explanatory. It is not possible to combine the options.

    -

    Specifying an IO-Device in define is now deprecated! Use attribute IODev instead, +

    Specifying an IO-Device in define is deprecated! Use attribute IODev instead, but only if absolutely required!

    The first group is used for sending by default. If you want to send to a different group, you have to address it. E.g: set <name> <gadName> <value> @@ -2283,10 +2290,11 @@ Examples:

  • Set
    -

    set <deviceName> [<gadName>] <on|off|toggle>
    - set <deviceName> [<gadName>] <on-for-timer|off-for-timer> <duration seconds>
    - set <deviceName> [<gadName>] <on-until|off-until> <timespec>
    - set <deviceName> [<gadName>] <value>

    +

    set <deviceName> [<gadName>] on|off|toggle
    + set <deviceName> <gadName> blink <nr of blinks> <duration seconds>
    + set <deviceName> <gadName> on-for-timer|off-for-timer <duration seconds>
    + set <deviceName> <gadName> on-until|off-until <timespec (HH:MM[:SS])>
    +

    Set sends the given value to the bus.
    If <gadName> is omitted, the first listed GAD of the device is used. If the GAD is restricted in the definition with "get" or "listenonly", the set-command will be refused.
    For dpt1 and dpt1.001 valid values are on, off, toggle and blink. Also the timer-functions can be used. @@ -2443,7 +2451,7 @@ Examples:

  • Events

    Events are generated for each reading sent or received to/from KNX-Bus unless restricted by event-xxx attributes or modified by eventMap, stateRegex attributes. - KNX-events have this format:

    +
    KNX-events have this format:

       <device> <readingName>: <value> # reading event
        <device> <value>                # state event
  • @@ -2462,7 +2470,7 @@ Examples:
  • dpt1.006 low, high
  • dpt1.007 decrease, increase
  • dpt1.008 up, down
  • -
  • dpt1.009 open, closed
  • +
  • dpt1.009 open, close
  • dpt1.010 stop, start
  • dpt1.011 inactive, active
  • dpt1.012 not_inverted, inverted