10_KNX.pm 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096
  1. ##############################################
  2. # $Id: 10_KNX.pm 13111 2017-01-16 18:42:35Z andi291 $
  3. # ABU 20160307 First release
  4. # ABU 20160309 Fixed issue for sending group-indexed with dpt1. Added debug-information. Fixed issue for indexed get. Fixed regex-replace-issue.
  5. # ABU 20160312 Fixed error while receiving numeric DPT with value 0. Added factor for dpt 08.010.
  6. # ABU 20160312 Fixed Regex-Attributes. Syntax changed from space-seperated to " /".
  7. # ABU 20160322 Fixed dpt1.008
  8. # ABU 20160326 Added fix for stateFormat
  9. # ABU 20160327 Removed readingRegex, writingRegex, created stateRegex, stateCmd, added reading-name support, fixed dblog-split
  10. # ABU 20160403 Fixed various minor perl warnings
  11. # ABU 20160413 Changed SplitFn
  12. # ABU 20160414 Changed SplitFn again
  13. # ABU 20160416 Changed SplitFn again
  14. # ABU 20160422 Added dpt9.021 - mA
  15. # ABU 20160529 Changed Doku
  16. # ABU 20160605 Changed Doku, changed autocreate-naming, fixed dpt10-sending-now
  17. # ABU 20160608 changed sprintf for int-dpt from %d to %.0f
  18. # ABU 20160624 corrected Doku: till->until
  19. # ABU 20161121 cleaned get/set options
  20. # ABU 20161122 fixed set-handling
  21. # ABU 20161126 added summary
  22. # ABU 20161126 fixed doku
  23. # ABU 20161127 adjusted dpt-16-sending, added dpt16.001
  24. # ABU 20161129 fixed get-mechanism
  25. # ABU 20170106 corrected doku for time, finetuned dpt9-regex, added dpt 7.001 7.012 9.007 9.008, , added mod for extended adressing (thx to its2bit)
  26. # ABU 20170110 removed mod for extended adressing
  27. # ABU 20100114 fixed dpt9-regex
  28. # ABU 20100116 fixed dpt9-regex again
  29. package main;
  30. use strict;
  31. use warnings;
  32. use Encode;
  33. #set to 1 for debug
  34. my $debug = 0;
  35. #string constant for autocreate
  36. my $modelErr = "MODEL_NOT_DEFINED";
  37. my $OFF = "off";
  38. my $ON = "on";
  39. my $ONFORTIMER = "on-for-timer";
  40. my $ONUNTIL = "on-until";
  41. my $VALUE = "value";
  42. my $STRING = "string";
  43. my $RAW = "raw";
  44. my $RGB = "rgb";
  45. #valid set commands
  46. my %sets = (
  47. #"off" => "noArg",
  48. #"on" => "noArg",
  49. $OFF => "",
  50. $ON => "",
  51. $ONFORTIMER => "",
  52. $ONUNTIL => "",
  53. $VALUE => "",
  54. $STRING => "",
  55. $RAW => "",
  56. $RGB => "colorpicker"
  57. );
  58. #identifier for TUL
  59. my $id = 'C';
  60. #regex patterns
  61. my $PAT_GAD = qr/^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{1,3}$/;
  62. #old syntax
  63. my $PAT_GAD_HEX = qr/^[0-9a-f]{4}$/;
  64. #new syntax for extended adressing
  65. #removed, seems to be broken
  66. #my $PAT_GAD_HEX = qr/^[0-9a-f]{5}$/;
  67. my $PAT_GNO = qr/[gG][1-9][0-9]?/;
  68. #CODE is the identifier for the en- and decode algos. See encode and decode functions
  69. #UNIT is appended to state for a better reading
  70. #FACTOR and OFFSET are used to normalize a value. value = FACTOR * (RAW - OFFSET). Must be undef for non-numeric values.
  71. #PATTERN is used to check an trim the input-values
  72. #MIN and MAX are used to cast numeric values. Must be undef for non-numeric dpt. Special Usecase: DPT1 - MIN represents 00, MAX represents 01
  73. my %dpttypes = (
  74. #Binary value
  75. "dpt1" => {CODE=>"dpt1", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/([oO][nN])|([oO][fF][fF])|(0?1)|(0?0)/, MIN=>"off", MAX=>"on"},
  76. "dpt1.001" => {CODE=>"dpt1", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/([oO][nN])|([oO][fF][fF])|(0?1)|(0?0)/, MIN=>"off", MAX=>"on"},
  77. "dpt1.002" => {CODE=>"dpt1", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/([tT][rR][uU][eE])|([fF][aA][lL][sS][eE])|(0?1)|(0?0)/, MIN=>"false", MAX=>"true"},
  78. "dpt1.003" => {CODE=>"dpt1", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/(([eE][nN]|[dD][iI][sS])[aA][bB][lL][eE])|(0?1)|(0?0)/, MIN=>"disable", MAX=>"enable"},
  79. "dpt1.008" => {CODE=>"dpt1", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/([uU][pP])|([dD][oO][wW][nN])|(0?1)|(0?0)/, MIN=>"up", MAX=>"down"},
  80. "dpt1.009" => {CODE=>"dpt1", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/([cC][lL][oO][sS][eE][dD])|([oO][pP][eE][nN])|(0?1)|(0?0)/, MIN=>"open", MAX=>"closed"},
  81. "dpt1.019" => {CODE=>"dpt1", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/([cC][lL][oO][sS][eE][dD])|([oO][pP][eE][nN])|(0?1)|(0?0)/, MIN=>"closed", MAX=>"open"},
  82. #Step value (four-bit)
  83. "dpt3" => {CODE=>"dpt3", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,3}/, MIN=>-100, MAX=>100},
  84. # 1-Octet unsigned value
  85. "dpt5" => {CODE=>"dpt5", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,3}/, MIN=>0, MAX=>255},
  86. "dpt5.001" => {CODE=>"dpt5", UNIT=>"%", FACTOR=>100/255, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,3}/, MIN=>0, MAX=>100},
  87. "dpt5.003" => {CODE=>"dpt5", UNIT=>"°", FACTOR=>360/255, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,3}/, MIN=>0, MAX=>360},
  88. "dpt5.004" => {CODE=>"dpt5", UNIT=>"%", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,3}/, MIN=>0, MAX=>255},
  89. # 1-Octet signed value
  90. "dpt6" => {CODE=>"dpt6", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,3}/, MIN=>-127, MAX=>127},
  91. "dpt6.001" => {CODE=>"dpt6", UNIT=>"%", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,3}/, MIN=>0, MAX=>100},
  92. # 2-Octet unsigned Value
  93. "dpt7" => {CODE=>"dpt7", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>0, MAX=>65535},
  94. "dpt7.001" => {CODE=>"dpt7", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>0, MAX=>65535},
  95. "dpt7.005" => {CODE=>"dpt7", UNIT=>"s", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>0, MAX=>65535},
  96. "dpt7.006" => {CODE=>"dpt7", UNIT=>"m", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>0, MAX=>65535},
  97. "dpt7.012" => {CODE=>"dpt7", UNIT=>"mA", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>0, MAX=>65535},
  98. "dpt7.013" => {CODE=>"dpt7", UNIT=>"lux", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>0, MAX=>65535},
  99. # 2-Octet signed Value
  100. "dpt8" => {CODE=>"dpt8", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>-32768, MAX=>32768},
  101. "dpt8.005" => {CODE=>"dpt8", UNIT=>"s", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>-32768, MAX=>32768},
  102. "dpt8.010" => {CODE=>"dpt8", UNIT=>"%", FACTOR=>0.01, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>-32768, MAX=>32768},
  103. "dpt8.011" => {CODE=>"dpt8", UNIT=>"°", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,5}/, MIN=>-32768, MAX=>32768},
  104. # 2-Octet Float value
  105. "dpt9" => {CODE=>"dpt9", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  106. "dpt9.001" => {CODE=>"dpt9", UNIT=>"°C", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  107. "dpt9.004" => {CODE=>"dpt9", UNIT=>"lux", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  108. "dpt9.006" => {CODE=>"dpt9", UNIT=>"Pa", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  109. "dpt9.005" => {CODE=>"dpt9", UNIT=>"m/s", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  110. "dpt9.007" => {CODE=>"dpt9", UNIT=>"%", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  111. "dpt9.008" => {CODE=>"dpt9", UNIT=>"ppm", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  112. "dpt9.009" => {CODE=>"dpt9", UNIT=>"m&sup3/h", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  113. "dpt9.010" => {CODE=>"dpt9", UNIT=>"s", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  114. "dpt9.021" => {CODE=>"dpt9", UNIT=>"mA", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  115. "dpt9.024" => {CODE=>"dpt9", UNIT=>"kW", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  116. "dpt9.025" => {CODE=>"dpt9", UNIT=>"l/h", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  117. "dpt9.026" => {CODE=>"dpt9", UNIT=>"l/h", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  118. "dpt9.028" => {CODE=>"dpt9", UNIT=>"km/h", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,6}[.,]\d{1,2}/, MIN=>-670760, MAX=>670760},
  119. # Time of Day
  120. "dpt10" => {CODE=>"dpt10", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/((2[0-4]|[0?1][0-9]):(60|[0?1-5]?[0-9]):(60|[0?1-5]?[0-9]))|([nN][oO][wW])/, MIN=>undef, MAX=>undef},
  121. # Date
  122. "dpt11" => {CODE=>"dpt11", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/((3[01]|[0-2]?[0-9]).(1[0-2]|0?[0-9]).(19[0-9][0-9]|2[01][0-9][0-9]))|([nN][oO][wW])/, MIN=>undef, MAX=>undef},
  123. # 4-Octet unsigned value (handled as dpt7)
  124. "dpt12" => {CODE=>"dpt12", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,10}/, MIN=>0, MAX=>4294967295},
  125. # 4-Octet Signed Value
  126. "dpt13" => {CODE=>"dpt13", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,10}/, MIN=>-2147483647, MAX=>2147483647},
  127. "dpt13.010" => {CODE=>"dpt13", UNIT=>"Wh", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,10}/, MIN=>-2147483647, MAX=>2147483647},
  128. "dpt13.013" => {CODE=>"dpt13", UNIT=>"kWh", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,10}/, MIN=>-2147483647, MAX=>2147483647},
  129. # 4-Octet single precision float
  130. "dpt14" => {CODE=>"dpt14", UNIT=>"", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,40}[.,]?\d{1,4}/, MIN=>undef, MAX=>undef},
  131. "dpt14.019" => {CODE=>"dpt14", UNIT=>"A", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,40}[.,]?\d{1,4}/, MIN=>undef, MAX=>undef},
  132. "dpt14.027" => {CODE=>"dpt14", UNIT=>"V", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,40}[.,]?\d{1,4}/, MIN=>undef, MAX=>undef},
  133. "dpt14.056" => {CODE=>"dpt14", UNIT=>"W", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,40}[.,]?\d{1,4}/, MIN=>undef, MAX=>undef},
  134. "dpt14.068" => {CODE=>"dpt14", UNIT=>"°C", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,40}[.,]?\d{1,4}/, MIN=>undef, MAX=>undef},
  135. "dpt14.076" => {CODE=>"dpt14", UNIT=>"m³", FACTOR=>1, OFFSET=>0, PATTERN=>qr/[+-]?\d{1,40}[.,]?\d{1,4}/, MIN=>undef, MAX=>undef},
  136. # 14-Octet String
  137. "dpt16" => {CODE=>"dpt16", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/.{1,14}/, MIN=>undef, MAX=>undef},
  138. "dpt16.000" => {CODE=>"dpt16", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/.{1,14}/, MIN=>undef, MAX=>undef},
  139. "dpt16.001" => {CODE=>"dpt16", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/.{1,14}/, MIN=>undef, MAX=>undef},
  140. # Color-Code
  141. "dpt232" => {CODE=>"dpt232", UNIT=>"", FACTOR=>undef, OFFSET=>undef, PATTERN=>qr/[0-9A-Fa-f]{6}/, MIN=>undef, MAX=>undef},
  142. );
  143. #Init this device
  144. #This declares the interface to fhem
  145. #############################
  146. sub
  147. KNX_Initialize($) {
  148. my ($hash) = @_;
  149. $hash->{Match} = "^$id.*";
  150. $hash->{GetFn} = "KNX_Get";
  151. $hash->{SetFn} = "KNX_Set";
  152. $hash->{StateFn} = "KNX_State";
  153. $hash->{DefFn} = "KNX_Define";
  154. $hash->{UndefFn} = "KNX_Undef";
  155. $hash->{ParseFn} = "KNX_Parse";
  156. $hash->{AttrFn} = "KNX_Attr";
  157. $hash->{NotifyFn} = "KNX_Notify";
  158. $hash->{DbLog_splitFn} = "KNX_DbLog_split";
  159. $hash->{AttrList} = "IODev " . #tells the module the IO-Device to communicate with. Optionally set within definition.
  160. "do_not_notify:1,0 " . #supress any notification (including log)
  161. "listenonly:1,0 " . #device may not send any messages. answering is prohibited. get is prohibited.
  162. "readonly:1,0 " . #device may not send any messages. answering is prohibited. get is allowed.
  163. "showtime:1,0 " . #shows time instead of received value in state
  164. "answerReading:1,0 " . #allows FHEM to answer a read telegram
  165. "stateRegex " . #modifies state value
  166. "stateCmd " . #modify state value
  167. "stateCopy " . #backup content of state in this reading (only for received telegrams)
  168. "format " . #supplies post-string
  169. "slider " . #creates slider. Syntax: min, step, max
  170. "$readingFnAttributes "; #standard attributes
  171. }
  172. #Define this device
  173. #Is called at every define
  174. #############################
  175. sub
  176. KNX_Define($$) {
  177. my ($hash, $def) = @_;
  178. my @a = split("[ \t][ \t]*", $def);
  179. #device name
  180. my $name = $a[0];
  181. #set verbose to 5, if debug enabled
  182. $attr{$name}{verbose} = 5 if ($debug eq 1);
  183. my $tempStr = join (", ", @a);
  184. Log3 ($name, 5, "define $name: enter $hash, attributes: $tempStr");
  185. #too less arguments
  186. return "wrong syntax - define <name> KNX <group:model[:reading-name]> [<group:model[:reading-name]>*] [<IODev>]" if (int(@a) < 3);
  187. #check for IODev
  188. #is last argument a group or a group:model pair?
  189. my $lastGroupDef = int(@a);
  190. #if (($a[int(@a) - 1] !~ m/^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{1,3}$/i) and ($a[int(@a) - 1] !~ m/^[0-9a-f]{4}$/i) and ($a[int(@a) - 1] !~ m/[0-9a-fA-F]:[dD][pP][tT]/i))
  191. if (($a[int(@a) - 1] !~ m/${PAT_GAD}/i) and ($a[int(@a) - 1] !~ m/${PAT_GAD_HEX}/i) and ($a[int(@a) - 1] !~ m/[0-9a-fA-F]:[dD][pP][tT]/i))
  192. {
  193. $attr{$name}{IODev} = $a[int(@a) - 1];
  194. $lastGroupDef--;
  195. }
  196. #create groups and models, iterate through all possible args
  197. for (my $i = 2; $i < $lastGroupDef; $i++)
  198. {
  199. #backup actual GAD
  200. my $inp = lc($a[$i]);
  201. my ($group, $model, $rdname) = split /:/, $inp;
  202. my $groupc;
  203. #G-nr
  204. my $gno = $i - 1;
  205. #GAD not defined
  206. return "GAD not defined for group-number $gno" if (!defined($group));
  207. #GAD wrong syntax
  208. #either 1/2/3 or 1203
  209. #return "wrong group name format: specify as 0-15/0-15/0-255 or as hex" if (($group !~ m/^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{1,3}$/i) && (lc($group) !~ m/^[0-9a-f]{4}$/i));
  210. return "wrong group name format: specify as 0-15/0-15/0-255 or as hex" if (($group !~ m/${PAT_GAD}/i) && (lc($group) !~ m/${PAT_GAD_HEX}/i));
  211. #check if model supplied
  212. return "no model defined" if (!defined($model));
  213. #within autocreate no model is supplied - throw warning
  214. if ($model eq $modelErr)
  215. {
  216. Log3 ($name, 2, "define $name: autocreate defines no model - only restricted functions are available");
  217. }
  218. else
  219. {
  220. #check model-type
  221. return "invalid model. Use " .join(",", keys %dpttypes) if (!defined($dpttypes{$model}));
  222. }
  223. #convert to string, if supplied in Hex
  224. #old syntax
  225. $group = KNX_hexToName ($group) if ($group =~ m/^[0-9a-f]{4}$/i);
  226. #new syntax for extended adressing
  227. #$group = KNX_hexToName ($group) if ($group =~ m/^[0-9a-f]{5}$/i);
  228. $groupc = KNX_nameToHex ($group);
  229. Log3 ($name, 5, "define $name: found GAD: $group, NO: $gno, HEX: $groupc, DPT: $model");
  230. Log3 ($name, 5, "define $name: found Readings-Name: $rdname") if (defined ($rdname));
  231. #add indexed group to hash. Index starts with one
  232. #readable GAD
  233. $hash->{GADDR}{$gno} = $group;
  234. #same as hex
  235. $hash->{GCODE}{$gno} = $groupc;
  236. #model
  237. $hash->{MODEL}{$gno} = $model;
  238. #backup readings-name
  239. $hash->{READINGSNAME}{$gno} = $rdname if (defined ($rdname) and !($rdname eq ""));
  240. }
  241. #common name
  242. $hash->{NAME} = $name;
  243. #backup name for a later rename
  244. $hash->{DEVNAME} = $name;
  245. #finally create decice
  246. #defptr is needed to supress FHEM input
  247. $modules{KNX}{defptr}{$name} = $hash;
  248. #assign io-dev automatically, if not given via definition
  249. AssignIoPort($hash);
  250. Log3 ($name, 5, "exit define");
  251. return undef;
  252. }
  253. #Release this device
  254. #Is called at every delete / shutdown
  255. #############################
  256. sub
  257. KNX_Undef($$) {
  258. my ($hash, $name) = @_;
  259. Log3 ($name, 5, "enter undef $name: hash: $hash name: $name");
  260. #remove all groups
  261. foreach my $group (keys %{$hash->{GCODE}})
  262. {
  263. Log3 ($name, 5, "undef $name: remove name: $hash->{NAME}, orig.-Name: $hash->{DEVNAME}, GAD: $group");
  264. delete $hash->{GADDR}{$group};
  265. delete $hash->{GCODE}{$group};
  266. delete $hash->{MODEL}{$group};
  267. }
  268. #remove module. Refer to DevName, because module may be renamed
  269. delete $modules{KNX}{defptr}{$hash->{DEVNAME}};
  270. #remove name
  271. delete $hash->{NAME};
  272. #remove backuped name
  273. delete $hash->{DEVNAME};
  274. Log3 ($name, 5, "exit undef");
  275. return undef;
  276. }
  277. #Places a "read" Message on the KNX-Bus
  278. #The answer is treated as regular telegram
  279. #############################
  280. sub
  281. KNX_Get($@) {
  282. my ($hash, @a) = @_;
  283. my $name = $hash->{NAME};
  284. my $groupnr = 1;
  285. my $tempStr = join (", ", @a);
  286. Log3 ($name, 5, "enter get $name: hash: $hash, attributes: $tempStr");
  287. #FHEM asks with a ? at startup - no action, no log
  288. #do not use KNX_getCmdList because argument will be a group-adress
  289. return "Unknown argument ?, choose one of -" if(defined($a[1]) and ($a[1] =~ m/\?/));
  290. splice(@a, 1, 1) if (defined ($a[1]) and ($a[1] =~ m/-/));
  291. my $na = int(@a);
  292. #not more then 2 arguments allowed
  293. return "too much arguments. Only one argument allowed (group-address)." if($na>2);
  294. # the command can be send to any of the defined groups indexed starting by 1
  295. # optional last argument starting with g indicates the group
  296. if(defined ($a[1]))
  297. {
  298. #check syntax
  299. if ($a[1]=~ m/${PAT_GNO}/)
  300. {
  301. #assign group-no
  302. $groupnr = $a[1];
  303. $groupnr =~ s/^g//;
  304. } else
  305. {
  306. return "$a[1] is invalid. Second argument only may be a group g<no>";
  307. }
  308. }
  309. #get group from hash (hex)
  310. my $groupc = $hash->{GCODE}{$groupnr};
  311. #get group from hash
  312. my $group = $hash->{GADDR}{$groupnr};
  313. #return, if unknown group
  314. return "groupnr: $groupnr not known" if(!$groupc);
  315. #exit, if reat is prohibited
  316. return "did not request a value - \"listenonly\" is set." if (AttrVal ($name, "listenonly", 0) =~ m/1/);
  317. #send read-request to the bus
  318. Log3 ($name, 5, "get $name: request value for GAD $group");
  319. IOWrite($hash, $id, "r" . $groupc);
  320. Log3 ($name, 5, "exit get");
  321. return "current value for $name ($group) requested";
  322. }
  323. #Does something according the given cmd...
  324. #############################
  325. sub
  326. KNX_Set($@) {
  327. my ($hash, @a) = @_;
  328. my $name = $hash->{NAME};
  329. my $ret = "";
  330. my $na = int(@a);
  331. my $tempStr = join (", ", @a);
  332. #log only, if not called with cmd = ?
  333. Log3 ($name, 5, "enter set $name: hash: $hash, attributes: $tempStr") if ((defined ($a[1])) and (not ($a[1] eq "?")));
  334. #return, if no set value specified
  335. return "no set value specified" if($na < 2);
  336. #return, if this is a readonly-device
  337. return "this device is readonly" if(defined($hash->{readonly}));
  338. #backup values
  339. my $cmd = lc($a[1]);
  340. #remove whitespaces
  341. $cmd =~ s/^\s+|\s+$//g;
  342. #get slider definition
  343. my $slider = AttrVal ($name, "slider", undef);
  344. #hash has to be copied. Otherwise silder-operation affects all devices
  345. my %mySets = %sets;
  346. #append slider-definition, if set...Necessary for FHEM
  347. $mySets{$VALUE} = $mySets{$VALUE} . "slider,$slider" if ((defined $slider) and !($mySets{$VALUE} =~ m/slider/));
  348. #create response, if cmd is wrong or gui asks
  349. my $cmdTemp = KNX_getCmdList ($hash, $cmd, %mySets);
  350. return $cmdTemp if (defined ($cmdTemp));
  351. #the command can be send to any of the defined groups indexed starting by 1
  352. #optional last argument starting with g indicates the group
  353. #default
  354. my $groupnr = 1;
  355. my $lastArg = $na - 1;
  356. #select another group, if the last arg starts with a g
  357. if($na > 2 && $a[$lastArg]=~ m/${PAT_GNO}/)
  358. {
  359. $groupnr = $a[$lastArg];
  360. #remove "g"
  361. $groupnr =~ s/^g//g;
  362. $lastArg--;
  363. }
  364. #unknown groupnr
  365. return "group-no. not found" if(!defined($groupnr));
  366. #group
  367. my $group = $hash->{GADDR}{$groupnr};
  368. my $groupc = $hash->{GCODE}{$groupnr};
  369. #unknown groupnr
  370. return "group-no. $groupnr not known" if(!defined($group));
  371. #get model
  372. my $model = $hash->{MODEL}{$groupnr};
  373. my $code = $dpttypes{$model}{CODE};
  374. Log3 ($name, 5, "set $name: model: $model, GAD: $group, GAD hex: $groupc, gno: $groupnr");
  375. #This contains the input
  376. my $value = "";
  377. #delete any running timers
  378. if ($hash->{"ON-FOR-TIMER_G$groupnr"})
  379. {
  380. CommandDelete(undef, $name . "_timer_$groupnr");
  381. delete $hash->{"ON-FOR-TIMER_G$groupnr"};
  382. }
  383. if($hash->{"ON-UNTIL_G$groupnr"})
  384. {
  385. CommandDelete(undef, $name . "_until_$groupnr");
  386. delete $hash->{"ON-UNTIL_G$groupnr"};
  387. }
  388. #set on-for-timer
  389. if ($cmd =~ m/$ONFORTIMER/)
  390. {
  391. return "\"on-for-timer\" only allowed for dpt1" if (not($code eq "dpt1"));
  392. #get duration
  393. my $duration = sprintf("%02d:%02d:%02d", $a[2]/3600, ($a[2]%3600)/60, $a[2]%60);
  394. #$modules{KNX}{"on-for-timer"}{$name} = $duration;
  395. $hash->{"ON-FOR-TIMER_G$groupnr"} = $duration;
  396. Log3 ($name, 5, "set $name: \"on-for-timer\" for $duration");
  397. #set to on
  398. $value = 1;
  399. #place at-command for switching off
  400. CommandDefine(undef, $name . "_timer_$groupnr at +$duration set $name off g$groupnr");
  401. }
  402. #set on-till
  403. elsif ($cmd =~ m/$ONUNTIL/)
  404. {
  405. return "\"on\" only allowed for dpt1" if (not($code eq "dpt1"));
  406. #get off-time
  407. my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($a[2]);
  408. return "Error trying to parse timespec for $a[2]: $err" if (defined($err));
  409. #build of-time
  410. my @lt = localtime;
  411. my $hms_til = sprintf("%02d:%02d:%02d", $hr, $min, $sec);
  412. my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]);
  413. return "Won't switch - now ($hms_now) is later than $hms_til" if($hms_now ge $hms_til);
  414. #$modules{KNX}{"on-until"}{$name} = $hms_til;
  415. $hash->{"ON-UNTIL_G$groupnr"} = $hms_til;
  416. Log3 ($name, 5, "set $name: \"on-until\" up to $hms_til");
  417. #set to on
  418. $value = 1;
  419. #place at-command for switching off
  420. CommandDefine(undef, $name . "_until_$groupnr at $hms_til set $name off g$groupnr");
  421. }
  422. #set on
  423. elsif ($cmd =~ m/$ON/)
  424. {
  425. return "\"on\" only allowed for dpt1" if (not($code eq "dpt1"));
  426. $value = 1;
  427. }
  428. #set off
  429. elsif ($cmd =~ m/$OFF/)
  430. {
  431. return "\"off\" only allowed for dpt1" if (not($code eq "dpt1"));
  432. $value = 0;
  433. }
  434. #set raw <value>
  435. elsif ($cmd =~ m/$RAW/)
  436. {
  437. return "no data for cmd $cmd" if ($lastArg < 2);
  438. #check for 1-16 hex-digits
  439. if ($a[2] =~ m/[0-9a-fA-F]{1,16}/)
  440. {
  441. $value = lc($a[2]);
  442. } else
  443. {
  444. return "$a[2] has wrong syntax. Use hex-format only.";
  445. }
  446. }
  447. #set value <value>
  448. elsif ($cmd =~ m/$VALUE/)
  449. {
  450. #return "\"value\" not allowed for dpt1 and dpt16" if (($code eq "dpt1") or ($code eq "dpt16"));
  451. return "\"value\" not allowed for dpt1 and dpt16" if ($code eq "dpt16");
  452. return "no data for cmd $cmd" if ($lastArg < 2);
  453. $value = $a[2];
  454. #replace , with .
  455. $value =~ s/,/\./g;
  456. }
  457. #set string <val1 val2 valn>
  458. elsif ($cmd =~ m/$STRING/)
  459. {
  460. return "\"string\" only allowed for dpt16" if (not($code eq "dpt16"));
  461. return "no data for cmd $cmd" if ($lastArg < 2);
  462. #join string
  463. for (my $i=2; $i<=$lastArg; $i++)
  464. {
  465. $value.= $a[$i]." ";
  466. }
  467. }
  468. #set RGB <RRGGBB>
  469. elsif ($cmd =~ m/$RGB/)
  470. {
  471. return "\"RGB\" only allowed for dpt232" if (not($code eq "dpt232"));
  472. return "no data for cmd $cmd" if ($lastArg < 2);
  473. #check for 1-16 hex-digits
  474. if ($a[2] =~ m/[0-9A-Fa-f]{6}/)
  475. {
  476. $value = lc($a[2]);
  477. } else
  478. {
  479. return "$a[2] has wrong syntax. Use hex-format only.";
  480. }
  481. }
  482. #check and cast value
  483. my $transval = KNX_checkAndClean($hash, $value, $groupnr);
  484. return "invalid value: $value" if (!defined($transval));
  485. #exit, if sending is prohibited
  486. return "did not send value - \"listenonly\" is set." if (AttrVal ($name, "listenonly", 0) =~ m/1/);
  487. return "did not send value - \"readonly\" is set." if (AttrVal ($name, "readonly", 0) =~ m/1/);
  488. #send value
  489. $transval = KNX_encodeByDpt($hash, $transval, $groupnr);
  490. IOWrite($hash, $id, "w" . $groupc . $transval);
  491. Log3 ($name, 5, "set $name: cmd: $cmd, value: $value, translated: $transval");
  492. #build readingsName
  493. my $rdName = $hash->{READINGSNAME}{$groupnr};
  494. if (defined ($rdName) and !($rdName eq ""))
  495. {
  496. Log3 ($name, 5, "set name: $name, replaced \"getG\" with custom readingName \"$rdName\"");
  497. $rdName = $rdName . "-set";
  498. }
  499. else
  500. {
  501. $rdName = "setG" . $groupnr;
  502. }
  503. #re-read value, do not modify variable name due to usage in cmdAttr
  504. $transval = KNX_decodeByDpt($hash, $transval, $groupnr);
  505. #append post-string, if supplied
  506. my $suffix = AttrVal($name, "format",undef);
  507. $transval = $transval . " " . $suffix if (defined($suffix));
  508. #execute regex, if defined
  509. my $regAttr = AttrVal($name, "stateRegex", undef);
  510. my $state = KNX_replaceByRegex ($regAttr, $rdName . ":", $transval);
  511. Log3 ($name, 5, "set name: $name - replaced $rdName:$transval to $state") if (not ($transval eq $state));
  512. if (defined($state))
  513. {
  514. readingsBeginUpdate($hash);
  515. readingsBulkUpdate($hash, $rdName, $transval);
  516. #execute state-command if defined
  517. #must be placed after first reading, because it may have a reference
  518. my $cmdAttr = AttrVal($name, "stateCmd", undef);
  519. if (defined ($cmdAttr) and !($cmdAttr eq ""))
  520. {
  521. $state = eval $cmdAttr;
  522. Log3 ($name, 5, "set name: $name - state replaced via command, result: state:$state");
  523. }
  524. readingsBulkUpdate($hash, "state", $state);
  525. readingsEndUpdate($hash, 1);
  526. }
  527. Log3 ($name, 5, "exit set");
  528. return undef;
  529. }
  530. #In case setstate is executed, a readingsupdate is initiated
  531. #############################
  532. sub
  533. KNX_State($$$$) {
  534. my ($hash, $time, $reading, $value) = @_;
  535. my $name = $hash->{NAME};
  536. my $tempStr = join (", ", @_);
  537. Log3 ($name, 5, "enter state: hash: $hash name: $name, attributes: $tempStr");
  538. #in some cases state is submitted within value - if found, take only the stuff after state
  539. #my @strings = split("[sS][tT][aA][tT][eE]", $val);
  540. #$val = $strings[int(@strings) - 1];
  541. return undef if (not (defined($value)));
  542. return undef if (not (defined($reading)));
  543. #remove whitespaces
  544. $value =~ s/^\s+|\s+$//g;
  545. $reading =~ s/^\s+|\s+$//g;
  546. $reading = lc ($reading) if ($reading =~ m/[sS][tT][aA][tT][eE]/);
  547. Log3 ($name, 5, "state $name: update $reading with value: $value");
  548. #write value and update reading
  549. readingsSingleUpdate($hash, $reading, $value, 1);
  550. return undef;
  551. }
  552. #Get the chance to qualify attributes
  553. #############################
  554. sub
  555. KNX_Attr(@) {
  556. my ($cmd,$name,$aName,$aVal) = @_;
  557. return undef;
  558. }
  559. #Split reading for DBLOG
  560. #############################
  561. sub KNX_DbLog_split($) {
  562. my ($event) = @_;
  563. my ($reading, $value, $unit);
  564. my $tempStr = join (", ", @_);
  565. Log (5, "splitFn - enter, attributes: $tempStr");
  566. #detect reading - real reading or state?
  567. my $isReading = "false";
  568. $isReading = "true" if ($event =~ m/: /);
  569. #split input-string
  570. my @strings = split (" ", $event);
  571. my $startIndex = undef;
  572. $unit = "";
  573. return undef if (not defined ($strings[0]));
  574. #real reading?
  575. if ($isReading =~ m/true/)
  576. {
  577. #first one is always reading
  578. $reading = $strings[0];
  579. $reading =~ s/:?$//;
  580. $startIndex = 1;
  581. }
  582. #plain state
  583. else
  584. {
  585. #for reading state nothing is supplied
  586. $reading = "state";
  587. $startIndex = 0;
  588. }
  589. return undef if (not defined ($strings[$startIndex]));
  590. #per default join all single pieces
  591. $value = join(" ", @strings[$startIndex..(int(@strings) - 1)]);
  592. #numeric value?
  593. #if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+/)
  594. if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+$/)
  595. {
  596. $value = $strings[$startIndex];
  597. #single numeric value? Assume second par is unit...
  598. if ((defined ($strings[$startIndex + 1])) && !($strings[$startIndex+1] =~ /^[+-]?\d*[.,]?\d+/))
  599. {
  600. $unit = $strings[$startIndex + 1] if (defined ($strings[$startIndex + 1]));
  601. }
  602. }
  603. #numeric value?
  604. #if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+/)
  605. #{
  606. # $value = $strings[$startIndex];
  607. # $unit = $strings[$startIndex + 1] if (defined ($strings[$startIndex + 1]));
  608. #}
  609. #string or raw
  610. #else
  611. #{
  612. # $value = join(" ", @strings[$startIndex..(int(@strings) - 1)]);
  613. #}
  614. Log (5, "splitFn - READING: $reading, VALUE: $value, UNIT: $unit");
  615. return ($reading, $value, $unit);
  616. }
  617. #Handle incoming messages
  618. #############################
  619. sub
  620. KNX_Parse($$) {
  621. my ($hash, $msg) = @_;
  622. #Msg format:
  623. #C(w/r/p)<group><value> i.e. Bw00000101
  624. #we will also take reply telegrams into account,
  625. #as they will be sent if the status is asked from bus
  626. #split message into parts
  627. #old syntax
  628. $msg =~ m/^$id(.{4})(.{1})(.{4})(.*)$/;
  629. #new syntax for extended adressing
  630. #removed, seems to be broken
  631. #$msg =~ m/^$id(.{5})(.{1})(.{5})(.*)$/;
  632. my $src = $1;
  633. my $cmd = $2;
  634. my $dest = $3;
  635. my $val = $4;
  636. my @foundMsgs;
  637. Log3 ($hash->{NAME}, 5, "enter parse: hash: $hash name: $hash->{NAME}, msg: $msg");
  638. #check if the code is within the read groups
  639. foreach my $deviceName (keys %{$modules{KNX}{defptr}})
  640. {
  641. #fetch device
  642. my $deviceHash = $modules{KNX}{defptr}{$deviceName};
  643. #skip, if name not defined
  644. next if (!defined($deviceHash));
  645. #loop through all defined group-numbers
  646. foreach my $gno (keys %{$deviceHash->{GCODE}})
  647. {
  648. #fetch groupcode
  649. my $groupc = $deviceHash->{GCODE}{$gno};
  650. #GAD in message is matching GAD in device
  651. if (defined ($groupc) and ($groupc eq $dest))
  652. {
  653. #get details
  654. my $name = $deviceHash->{NAME};
  655. my $groupAddr = $deviceHash->{GADDR}{$gno};
  656. my $model = $deviceHash->{MODEL}{$gno};
  657. Log3 ($name, 5, "parse device hash: $deviceHash name: $name, GADDR: $groupAddr, GCODE: $groupc, MODEL: $model");
  658. #handle write and reply messages
  659. if ($cmd =~ /[w|p]/)
  660. {
  661. #decode message
  662. my $transval = KNX_decodeByDpt ($deviceHash, $val, $gno);
  663. #message invalid
  664. if (not defined($transval) or ($transval eq ""))
  665. {
  666. Log3 ($name, 2, "parse device hash: $deviceHash name: $name, message could not be decoded - see log for details");
  667. next;
  668. }
  669. Log3 ($name, 5, "received hash: $deviceHash name: $name, STATE: $transval, GNO: $gno, SENDER: $src");
  670. #build readingsName
  671. my $rdName = $deviceHash->{READINGSNAME}{$gno};
  672. if (defined ($rdName) and !($rdName eq ""))
  673. {
  674. Log3 ($name, 5, "parse device hash: $deviceHash name: $name, replaced \"getG\" with custom readingName \"$rdName\"");
  675. $rdName = $rdName . "-get";
  676. }
  677. else
  678. {
  679. $rdName = "getG" . $gno;
  680. }
  681. #append post-string, if supplied
  682. my $suffix = AttrVal($name, "format",undef);
  683. $transval = $transval . " " . $suffix if (defined($suffix));
  684. #execute regex, if defined
  685. my $regAttr = AttrVal($name, "stateRegex", undef);
  686. my $state = KNX_replaceByRegex ($regAttr, $rdName . ":", $transval);
  687. Log3 ($name, 5, "parse device hash: $deviceHash name: $name - replaced $rdName:$transval to $state") if (not ($transval eq $state));
  688. if (defined($state))
  689. {
  690. readingsBeginUpdate($deviceHash);
  691. readingsBulkUpdate($deviceHash, $rdName, $transval);
  692. readingsBulkUpdate($deviceHash, "last-sender", KNX_hexToName($src));
  693. #execute state-command if defined
  694. #must be placed after first readings, because it may have a reference
  695. my $cmdAttr = AttrVal($name, "stateCmd", undef);
  696. if (defined ($cmdAttr) and !($cmdAttr eq ""))
  697. {
  698. $state = eval $cmdAttr;
  699. Log3 ($name, 5, "parse device hash: $deviceHash name: $name - state replaced via command - result: state:$state");
  700. }
  701. readingsBulkUpdate($deviceHash, "state", $state);
  702. readingsEndUpdate($deviceHash, 1);
  703. }
  704. }
  705. #handle read messages, if Attribute is set
  706. elsif (($cmd =~ /[r]/) && (AttrVal($name, "answerReading",0) =~ m/1/))
  707. {
  708. Log3 ($name, 5, "received hash: $deviceHash name: $name, GET");
  709. my $transval = KNX_encodeByDpt($deviceHash, $deviceHash->{STATE}, $gno);
  710. if (defined($transval))
  711. {
  712. Log3 ($name, 5, "received hash: $deviceHash name: $name, GET: $transval, GNO: $gno");
  713. IOWrite ($deviceHash, "B", "p" . $groupc . $transval);
  714. }
  715. }
  716. #skip, if this is ignored
  717. next if (IsIgnored($name));
  718. #save to list
  719. push(@foundMsgs, $name);
  720. }
  721. }
  722. }
  723. Log3 ($hash->{NAME}, 5, "exit parse");
  724. #return values
  725. if (int(@foundMsgs))
  726. {
  727. return @foundMsgs;
  728. } else
  729. {
  730. my $gad = KNX_hexToName($dest);
  731. #remove slashes
  732. #$name =~ s/\///g;
  733. #my $name = "KNX_" . $gad;
  734. my ($line, $area, $device) = split ("/", $gad);
  735. my $name = sprintf("KNX_%.2d%.2d%.3d", $line, $area, $device);
  736. my $ret = "KNX Unknown device $dest ($gad), Value $val, please define it";
  737. Log3 ($name, 3, "KNX Unknown device $dest ($gad), Value $val, please define it");
  738. #needed for autocreate
  739. return "UNDEFINED $name KNX $gad:$modelErr";
  740. }
  741. }
  742. #Function is called at every notify
  743. #############################
  744. sub
  745. KNX_Notify($$)
  746. {
  747. my ($ownHash, $callHash) = @_;
  748. #own name / hash
  749. my $ownName = $ownHash->{NAME};
  750. #Device that created the events
  751. my $callName = $callHash->{NAME};
  752. return undef;
  753. }
  754. #Private function to convert GAD from hex to readable version
  755. #############################
  756. sub
  757. KNX_hexToName ($)
  758. {
  759. my $v = shift;
  760. #old syntax
  761. my $p1 = hex(substr($v,0,1));
  762. my $p2 = hex(substr($v,1,1));
  763. my $p3 = hex(substr($v,2,2));
  764. #new syntax for extended adressing
  765. #removed, seems to be broken
  766. #my $p1 = hex(substr($v,0,2));
  767. #my $p2 = hex(substr($v,2,1));
  768. #my $p3 = hex(substr($v,3,2));
  769. my $r = sprintf("%d/%d/%d", $p1,$p2,$p3);
  770. return $r;
  771. }
  772. #Private function to convert GAD from readable version to hex
  773. #############################
  774. sub
  775. KNX_nameToHex ($)
  776. {
  777. my $v = shift;
  778. my $r = $v;
  779. if($v =~ /^([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{1,3})$/)
  780. {
  781. #old syntax
  782. $r = sprintf("%01x%01x%02x",$1,$2,$3);
  783. #new syntax for extended adressing
  784. #removed, seems to be broken
  785. #$r = sprintf("%02x%01x%02x",$1,$2,$3);
  786. }
  787. #elsif($v =~ /^([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,3})$/)
  788. #{
  789. # $r = sprintf("%01x%01x%02x",$1,$2,$3);
  790. #}
  791. return $r;
  792. }
  793. #Private function to clean input string according DPT
  794. #############################
  795. sub
  796. KNX_checkAndClean ($$$)
  797. {
  798. my ($hash, $value, $gno) = @_;
  799. my $name = $hash->{NAME};
  800. my $orgValue = $value;
  801. Log3 ($name, 5, "check value: $value, gno: $gno");
  802. #get model
  803. my $model = $hash->{MODEL}{$gno};
  804. #return unchecked, if this is a autocreate-device
  805. return $value if ($model eq $modelErr);
  806. #get pattern
  807. my $pattern = $dpttypes{$model}{PATTERN};
  808. #trim whitespaces at the end
  809. $value =~ s/^\s+|\s+$//g;
  810. #match against model pattern
  811. my @tmp = ($value =~ m/$pattern/g);
  812. #loop through results
  813. my $found = 0;
  814. foreach my $str (@tmp)
  815. {
  816. #assign first match and exit loop
  817. if (defined($str))
  818. {
  819. $found = 1;
  820. $value = $str;
  821. last;
  822. }
  823. }
  824. return undef if ($found == 0);
  825. #get min
  826. my $min = $dpttypes{"$model"}{MIN};
  827. #if min is numeric, cast to min
  828. $value = $min if (defined ($min) and ($min =~ /^[+-]?\d*[.,]?\d+/) and ($value < $min));
  829. #get max
  830. my $max = $dpttypes{"$model"}{MAX};
  831. #if max is numeric, cast to max
  832. $value = $max if (defined ($max) and ($max =~ /^[+-]?\d*[.,]?\d+/) and ($value > $max));
  833. Log3 ($name, 3, "check value: input-value $orgValue was casted to $value") if (not($orgValue eq $value));
  834. Log3 ($name, 5, "check value: $value, gno: $gno, model: $model, pattern: $pattern");
  835. return $value;
  836. }
  837. #Private function to encode KNX-Message according DPT
  838. #############################
  839. sub
  840. KNX_encodeByDpt ($$$) {
  841. my ($hash, $value, $gno) = @_;
  842. my $name = $hash->{NAME};
  843. Log3 ($name, 5, "encode value: $value, gno: $gno");
  844. #get model
  845. my $model = $hash->{MODEL}{$gno};
  846. my $code = $dpttypes{$model}{CODE};
  847. #return unchecked, if this is a autocreate-device
  848. return $value if ($model eq $modelErr);
  849. #this one stores the translated value (readble)
  850. my $numval = undef;
  851. #this one stores the translated hex-value
  852. my $hexval = undef;
  853. Log3 ($name, 5, "encode model: $model, code: $code, value: $value");
  854. #get correction details
  855. my $factor = $dpttypes{$model}{FACTOR};
  856. my $offset = $dpttypes{$model}{OFFSET};
  857. #correct value
  858. $value /= $factor if (defined ($factor));
  859. $value -= $offset if (defined ($offset));
  860. Log3 ($name, 5, "encode normalized value: $value");
  861. #Binary value
  862. if ($code eq "dpt1")
  863. {
  864. $numval = "00" if ($value eq 0);
  865. $numval = "01" if ($value eq 1);
  866. $numval = "00" if ($value eq $dpttypes{$model}{MIN});
  867. $numval = "01" if ($value eq $dpttypes{$model}{MAX});
  868. $hexval = $numval;
  869. }
  870. #Step value (four-bit)
  871. elsif ($code eq "dpt3")
  872. {
  873. $numval = 0;
  874. #get dim-direction
  875. my $sign = 0;
  876. $sign = 1 if ($value >= 0);
  877. #trim sign
  878. $value =~ s/^-//g;
  879. #get dim-value
  880. $numval = 7 if ($value >= 1);
  881. $numval = 6 if ($value >= 3);
  882. $numval = 5 if ($value >= 6);
  883. $numval = 4 if ($value >= 12);
  884. $numval = 3 if ($value >= 25);
  885. $numval = 2 if ($value >= 50);
  886. $numval = 1 if ($value >= 75);
  887. #assign dim direction
  888. $numval += 8 if ($sign == 1);
  889. #get hex representation
  890. $hexval = sprintf("%.2x",$numval);
  891. }
  892. #1-Octet unsigned value
  893. elsif ($code eq "dpt5")
  894. {
  895. $numval = $value;
  896. $hexval = sprintf("00%.2x",($numval));
  897. }
  898. #1-Octet signed value
  899. elsif ($code eq "dpt6")
  900. {
  901. #build 2-complement
  902. $numval = $value;
  903. $numval += 0x100 if ($numval < 0);
  904. $numval = 0x00 if ($numval < 0x00);
  905. $numval = 0xFF if ($numval > 0xFF);
  906. #get hex representation
  907. $hexval = sprintf("00%.2x",$numval);
  908. }
  909. #2-Octet unsigned Value
  910. elsif ($code eq "dpt7")
  911. {
  912. $numval = $value;
  913. $hexval = sprintf("00%.4x",($numval));
  914. }
  915. #2-Octet signed Value
  916. elsif ($code eq "dpt8")
  917. {
  918. #build 2-complement
  919. $numval = $value;
  920. $numval += 0x10000 if ($numval < 0);
  921. $numval = 0x00 if ($numval < 0x00);
  922. $numval = 0xFFFF if ($numval > 0xFFFF);
  923. #get hex representation
  924. $hexval = sprintf("00%.4x",$numval);
  925. }
  926. #2-Octet Float value
  927. elsif ($code eq "dpt9")
  928. {
  929. my $sign = ($value <0 ? 0x8000 : 0);
  930. my $exp = 0;
  931. my $mant = 0;
  932. $mant = int($value * 100.0);
  933. while (abs($mant) > 0x7FF)
  934. {
  935. $mant /= 2;
  936. $exp++;
  937. }
  938. $numval = $sign | ($exp << 11) | ($mant & 0x07ff);
  939. #get hex representation
  940. $hexval = sprintf("00%.4x",$numval);
  941. }
  942. #Time of Day
  943. elsif ($code eq "dpt10")
  944. {
  945. if (lc($value) eq "now")
  946. {
  947. #get actual time
  948. my ($secs,$mins,$hours,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  949. my $hoffset;
  950. #add offsets
  951. $year+=1900;
  952. $mon++;
  953. # calculate offset for weekday
  954. $wday = 7 if ($wday eq "0");
  955. $hoffset = 32*$wday;
  956. $hours += $hoffset;
  957. $value = "$hours:$mins:$secs";
  958. $numval = $secs + ($mins<<8) + ($hours<<16);
  959. } else
  960. {
  961. my ($hh, $mm, $ss) = split (":", $value);
  962. $numval = $ss + ($mm<<8) + (($hh)<<16);
  963. }
  964. #get hex representation
  965. $hexval = sprintf("00%.6x",$numval);
  966. }
  967. #Date
  968. elsif ($code eq "dpt11")
  969. {
  970. if (lc($value) eq "now")
  971. {
  972. #get actual time
  973. my ($secs,$mins,$hours,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  974. my $hoffset;
  975. #add offsets
  976. $year+=1900;
  977. $mon++;
  978. # calculate offset for weekday
  979. $wday = 7 if ($wday eq "0");
  980. $value = "$mday.$mon.$year";
  981. $numval = ($year - 2000) + ($mon<<8) + ($mday<<16);
  982. } else
  983. {
  984. my ($dd, $mm, $yyyy) = split (/\./, $value);
  985. if ($yyyy >= 2000)
  986. {
  987. $yyyy -= 2000;
  988. } else
  989. {
  990. $yyyy -= 1900;
  991. }
  992. $numval = ($yyyy) + ($mm<<8) + ($dd<<16);
  993. }
  994. #get hex representation
  995. $hexval = sprintf("00%.6x",$numval);
  996. }
  997. #4-Octet unsigned value (handled as dpt7)
  998. elsif ($code eq "dpt12")
  999. {
  1000. $numval = $value;
  1001. $hexval = sprintf("00%.8x",($numval));
  1002. }
  1003. #4-Octet Signed Value
  1004. elsif ($code eq "dpt13")
  1005. {
  1006. #build 2-complement
  1007. $numval = $value;
  1008. $numval += 4294967296 if ($numval < 0);
  1009. $numval = 0x00 if ($numval < 0x00);
  1010. $numval = 0xFFFFFFFF if ($numval > 0xFFFFFFFF);
  1011. #get hex representation
  1012. $hexval = sprintf("00%.8x",$numval);
  1013. }
  1014. #4-Octet single precision float
  1015. elsif ($code eq "dpt14")
  1016. {
  1017. $numval = unpack("L", pack("f", $value));
  1018. #get hex representation
  1019. $hexval = sprintf("00%.8x",$numval);
  1020. }
  1021. #14-Octet String
  1022. elsif ($code eq "dpt16")
  1023. {
  1024. #convert to latin-1
  1025. $value = encode("iso-8859-1", decode("utf8", $value));
  1026. #convert to hex-string
  1027. my $dat = unpack "H*", $value;
  1028. #format for 14-byte-length
  1029. $dat = sprintf("%-028s",$dat);
  1030. #append leading zeros
  1031. $dat = "00" . $dat;
  1032. $numval = $value;
  1033. $hexval = $dat;
  1034. }
  1035. #RGB-Code
  1036. elsif ($code eq "dpt232")
  1037. {
  1038. $hexval = "00" . $value;
  1039. $numval = $value;
  1040. }
  1041. else
  1042. {
  1043. Log3 ($name, 2, "encode model: $model, no vaild model defined");
  1044. return undef;
  1045. }
  1046. Log3 ($name, 5, "encode model: $model, code: $code, value: $value, numval: $numval, hexval: $hexval");
  1047. return $hexval;
  1048. }
  1049. #Private function to replace state-values
  1050. #############################
  1051. sub
  1052. KNX_replaceByRegex ($$$) {
  1053. my ($regAttr, $prefix, $input) = @_;
  1054. my $retVal = $input;
  1055. #execute regex, if defined
  1056. if (defined($regAttr))
  1057. {
  1058. #get array of given attributes
  1059. my @reg = split(" /", $regAttr);
  1060. my $tempVal = $prefix . $input;
  1061. #loop over all regex
  1062. foreach my $regex (@reg)
  1063. {
  1064. #trim leading and trailing slashes
  1065. $regex =~ s/^\/|\/$//g;
  1066. #get pairs
  1067. my @regPair = split("\/", $regex);
  1068. #skip if not at least 2 values supplied
  1069. #next if (int(@regPair < 2));
  1070. next if (not defined($regPair[0]));
  1071. if (not defined ($regPair[1]))
  1072. {
  1073. #cut value
  1074. $tempVal =~ s/$regPair[0]//g;
  1075. }
  1076. else
  1077. {
  1078. #replace value
  1079. $tempVal =~ s/$regPair[0]/$regPair[1]/g;
  1080. }
  1081. #restore value
  1082. $retVal = $tempVal;
  1083. }
  1084. }
  1085. return $retVal;
  1086. }
  1087. #Private function to decode KNX-Message according DPT
  1088. #############################
  1089. sub
  1090. KNX_decodeByDpt ($$$) {
  1091. my ($hash, $value, $gno) = @_;
  1092. my $name = $hash->{NAME};
  1093. Log3 ($name, 5, "decode value: $value, gno: $gno");
  1094. #get model
  1095. my $model = $hash->{MODEL}{$gno};
  1096. my $code = $dpttypes{$model}{CODE};
  1097. #return unchecked, if this is a autocreate-device
  1098. return $value if ($model eq $modelErr);
  1099. #this one stores the translated value (readble)
  1100. my $numval = undef;
  1101. #this one contains the return-value
  1102. my $state = undef;
  1103. Log3 ($name, 5, "decode model: $model, code: $code, value: $value");
  1104. #get correction details
  1105. my $factor = $dpttypes{$model}{FACTOR};
  1106. my $offset = $dpttypes{$model}{OFFSET};
  1107. #Binary value
  1108. if ($code eq "dpt1")
  1109. {
  1110. my $min = $dpttypes{"$model"}{MIN};
  1111. my $max = $dpttypes{"$model"}{MAX};
  1112. $numval = $min if (lc($value) eq "00");
  1113. $numval = $max if (lc($value) eq "01");
  1114. $state = $numval;
  1115. }
  1116. #Step value (four-bit)
  1117. elsif ($code eq "dpt3")
  1118. {
  1119. #get numeric value
  1120. $numval = hex ($value);
  1121. $state = 1 if ($numval & 7);
  1122. $state = 3 if ($numval & 6);
  1123. $state = 6 if ($numval & 5);
  1124. $state = 12 if ($numval & 4);
  1125. $state = 25 if ($numval & 3);
  1126. $state = 50 if ($numval & 2);
  1127. $state = 100 if ($numval & 1);
  1128. #get dim-direction
  1129. $state = 0 - $state if (not ($numval & 8));
  1130. #correct value
  1131. $state -= $offset if (defined ($offset));
  1132. $state *= $factor if (defined ($factor));
  1133. $state = sprintf ("%.0f", $state);
  1134. }
  1135. #1-Octet unsigned value
  1136. elsif ($code eq "dpt5")
  1137. {
  1138. $numval = hex ($value);
  1139. $state = $numval;
  1140. #correct value
  1141. $state -= $offset if (defined ($offset));
  1142. $state *= $factor if (defined ($factor));
  1143. $state = sprintf ("%.0f", $state);
  1144. }
  1145. #1-Octet signed value
  1146. elsif ($code eq "dpt6")
  1147. {
  1148. $numval = hex ($value);
  1149. $numval -= 0x100 if ($numval >= 0x80);
  1150. $state = $numval;
  1151. #correct value
  1152. $state -= $offset if (defined ($offset));
  1153. $state *= $factor if (defined ($factor));
  1154. $state = sprintf ("%.0f", $state);
  1155. }
  1156. #2-Octet unsigned Value
  1157. elsif ($code eq "dpt7")
  1158. {
  1159. $numval = hex ($value);
  1160. $state = $numval;
  1161. #correct value
  1162. $state -= $offset if (defined ($offset));
  1163. $state *= $factor if (defined ($factor));
  1164. $state = sprintf ("%.0f", $state);
  1165. }
  1166. #2-Octet signed Value
  1167. elsif ($code eq "dpt8")
  1168. {
  1169. $numval = hex ($value);
  1170. $numval -= 0x10000 if ($numval >= 0x8000);
  1171. $state = $numval;
  1172. #correct value
  1173. $state -= $offset if (defined ($offset));
  1174. $state *= $factor if (defined ($factor));
  1175. $state = sprintf ("%.0f", $state);
  1176. }
  1177. #2-Octet Float value
  1178. elsif ($code eq "dpt9")
  1179. {
  1180. $numval = hex($value);
  1181. my $sign = 1;
  1182. $sign = -1 if(($numval & 0x8000) > 0);
  1183. my $exp = ($numval & 0x7800) >> 11;
  1184. my $mant = ($numval & 0x07FF);
  1185. $mant = -(~($mant-1) & 0x07FF) if($sign == -1);
  1186. $numval = (1 << $exp) * 0.01 * $mant;
  1187. #correct value
  1188. $state -= $offset if (defined ($offset));
  1189. $state *= $factor if (defined ($factor));
  1190. $state = sprintf ("%.2f","$numval");
  1191. }
  1192. #Time of Day
  1193. elsif ($code eq "dpt10")
  1194. {
  1195. $numval = hex($value);
  1196. my $hours = ($numval & 0x1F0000)>>16;
  1197. my $mins = ($numval & 0x3F00)>>8;
  1198. my $secs = ($numval & 0x3F);
  1199. $state = sprintf("%02d:%02d:%02d",$hours,$mins,$secs);
  1200. }
  1201. #Date
  1202. elsif ($code eq "dpt11")
  1203. {
  1204. $numval = hex($value);
  1205. my $day = ($numval & 0x1F0000) >> 16;
  1206. my $month = ($numval & 0x0F00) >> 8;
  1207. my $year = ($numval & 0x7F);
  1208. #translate year (21st cent if <90 / else 20th century)
  1209. $year += 1900 if($year >= 90);
  1210. $year += 2000 if($year < 90);
  1211. $state = sprintf("%02d.%02d.%04d",$day,$month,$year);
  1212. }
  1213. #4-Octet unsigned value (handled as dpt7)
  1214. elsif ($code eq "dpt12")
  1215. {
  1216. $numval = hex ($value);
  1217. $state = $numval;
  1218. #correct value
  1219. $state -= $offset if (defined ($offset));
  1220. $state *= $factor if (defined ($factor));
  1221. $state = sprintf ("%.0f", $state);
  1222. }
  1223. #4-Octet Signed Value
  1224. elsif ($code eq "dpt13")
  1225. {
  1226. $numval = hex ($value);
  1227. $numval -= 4294967296 if ($numval >= 0x80000000);
  1228. $state = $numval;
  1229. #correct value
  1230. $state -= $offset if (defined ($offset));
  1231. $state *= $factor if (defined ($factor));
  1232. $state = sprintf ("%.0f", $state);
  1233. }
  1234. #4-Octet single precision float
  1235. elsif ($code eq "dpt14")
  1236. {
  1237. $numval = unpack "f", pack "L", hex ($value);
  1238. #correct value
  1239. $state -= $offset if (defined ($offset));
  1240. $state *= $factor if (defined ($factor));
  1241. $state = sprintf ("%.3f","$numval");
  1242. }
  1243. #14-Octet String
  1244. elsif ($code eq "dpt16")
  1245. {
  1246. $numval = 0;
  1247. $state = "";
  1248. for (my $i = 0; $i < 14; $i++)
  1249. {
  1250. my $c = hex(substr($value, $i * 2, 2));
  1251. #exit at string terminator, otherwise append current char
  1252. if (($i != 0) and ($c eq 0))
  1253. {
  1254. $i = 14;
  1255. }
  1256. else
  1257. {
  1258. $state .= sprintf("%c", $c);
  1259. }
  1260. }
  1261. #convert to latin-1
  1262. $state = encode ("utf8", $state) if ($model =~ m/16.001/);
  1263. }
  1264. #RGB-Code
  1265. elsif ($code eq "dpt232")
  1266. {
  1267. $numval = hex ($value);
  1268. $state = $numval;
  1269. $state = sprintf ("%.6x", $state);
  1270. }
  1271. else
  1272. {
  1273. Log3 ($name, 2, "decode model: $model, no valid model defined");
  1274. return undef;
  1275. }
  1276. #append unit, if supplied
  1277. my $unit = $dpttypes{$model}{UNIT};
  1278. $state = $state . " " . $unit if (defined ($unit) and not($unit eq ""));
  1279. Log3 ($name, 5, "decode model: $model, code: $code, value: $value, numval: $numval, state: $state");
  1280. return $state;
  1281. }
  1282. #Private function to evaluate command-lists
  1283. #############################
  1284. sub KNX_getCmdList ($$$)
  1285. {
  1286. my ($hash, $cmd, %cmdArray) = @_;
  1287. my $name = $hash->{NAME};
  1288. #return, if cmd is valid
  1289. return undef if (defined ($cmd) and defined ($cmdArray{$cmd}));
  1290. #response for gui or the user, if command is invalid
  1291. my $retVal;
  1292. foreach my $mySet (keys %cmdArray)
  1293. {
  1294. #append set-command
  1295. $retVal = $retVal . " " if (defined ($retVal));
  1296. $retVal = $retVal . $mySet;
  1297. #get options
  1298. my $myOpt = $cmdArray{$mySet};
  1299. #append option, if valid
  1300. $retVal = $retVal . ":" . $myOpt if (defined ($myOpt) and (length ($myOpt) > 0));
  1301. $myOpt = "" if (!defined($myOpt));
  1302. Log3 ($name, 5, "parse cmd-table - Set:$mySet, Option:$myOpt, RetVal:$retVal");
  1303. }
  1304. if (!defined ($retVal))
  1305. {
  1306. $retVal = "error while parsing set-table" ;
  1307. }
  1308. else
  1309. {
  1310. $retVal = "Unknown argument $cmd, choose one of " . $retVal;
  1311. }
  1312. return $retVal;
  1313. }
  1314. 1;
  1315. =pod
  1316. =begin html
  1317. <a name="KNX"></a>
  1318. <h3>KNX</h3>
  1319. <ul>
  1320. <p>KNX is a standard for building automation / home automation.
  1321. It is mainly based on a twisted pair wiring, but also other mediums (ip, wireless) are specified.</p>
  1322. For getting started, please refer to this document: <a href="http://www.knx.org/media/docs/Flyers/KNX-Basics/KNX-Basics_de.pdf">KNX-Basics</a>
  1323. <p>While the module <a href="#TUL">TUL</a> represents the connection to the KNX network, the KNX modules represent individual KNX devices. This module provides a basic set of operations (on, off, on-until, on-for-timer)
  1324. to switch on/off KNX devices. For numeric DPT you can use value (set &lt;devname&gt; value &lt;177.45&gt;). For string-DPT you can use string (set &lt;devname&gt; string &lt;Hello World&gt;). For other, non-defined
  1325. dpt you can send raw hex values to the network (set &lt;devname&gt; raw &lt;hexval&gt;).<br>
  1326. Sophisticated setups can be achieved by combining a number of KNX module instances. Therefore you can define a number of different GAD/DPT combinations per each device.</p>
  1327. <p>KNX defines a series of Datapoint Type as standard data types used to allow general interpretation of values of devices manufactured by different companies.
  1328. These datatypes are used to interpret the status of a device, so the state in FHEM will then show the correct value. For each received telegram there will be a reading with state, getG&lt;group&gt; and the sender
  1329. address. For every set, there will be a reading with state and setG&lt;group&gt;.</p>
  1330. <p><a name="KNXdefine"></a> <b>Define</b></p>
  1331. <ul>
  1332. <code>define &lt;name&gt; KNX &lt;group&gt;:&lt;DPT&gt;:&lt[;readingName]&gt; [&lt;group&gt;:&lt;DPT&gt; ..] [IODev]</code>
  1333. <p>A KNX device need a concrete DPT. Please refer to <a href="#KNXdpt">Available DPT</a>. Otherwise the system cannot en- or decode the messages. Furthermore you can supply a IO-Device directly at startup. This can be done later on via attribute as well.</p>
  1334. <p>Define an KNX device, connected via a <a href="#TUL">TUL</a>. The &lt;group&gt; parameters are either a group name notation (0-15/0-15/0-255) or the hex representation of the value (0-f0-f0-ff).
  1335. All of the defined groups can be used for bus-communication. Without further attributes, all incoming messages are translated into state. Per default, the first group is used for sending. If you want to send
  1336. via a different group, you have to index it (set &lt;devname&gt; value &lt;17.0&gt; &lt;g2&gt;).<br>
  1337. If you use the readingName, readings are based on this name (e.g. hugo-set, hugo-get for name hugo).</p>
  1338. <p>The module <a href="#autocreate">autocreate</a> is creating a new definition for any unknown sender. The device itself will be NOT fully available, until you added a DPT to the definition. The name will be
  1339. KNX_nnmmooo where nn is the line adress, mm the area and ooo the device.</p>
  1340. <p>Example:</p>
  1341. <pre>
  1342. define lamp1 KNX 0/10/12:dpt1
  1343. define lamp1 KNX 0/10/12:dpt1:meinName 0/0/5:dpt1.001
  1344. define lamp1 KNX 0A0C:dpt1.003 myTul
  1345. </pre>
  1346. One hint regarding dpt1 (binary): all the sub-types have to be used with keyword value. Received telegrams are already encoded to their representation.
  1347. Having the on/off button (for send values) without keyword value is an absolutely special use-case and only valid for dpt1 (not the subs).<br>
  1348. <p>Example:</p>
  1349. <pre>
  1350. define rollo KNX 0/10/12:dpt1.008
  1351. set rollo value up
  1352. set rollo value down
  1353. </pre>
  1354. </ul>
  1355. <p><a name="KNXset"></a> <b>Set</b></p>
  1356. <ul>
  1357. <code>set &lt;name&gt; &lt;on, off&gt;</code> [g&lt;groupnr&gt;]
  1358. <code>set &lt;name&gt; &lt;on-for-timer, on-until&gt; &lt;time&gt; [g&lt;groupnr&gt;]</code>
  1359. <code>set &lt;name&gt; &lt;value&gt; [g&lt;groupnr&gt;]</code>
  1360. <code>set &lt;name&gt; &lt;string&gt; [g&lt;groupnr&gt;]</code>
  1361. <code>set &lt;name&gt; &lt;raw&gt; [g&lt;groupnr&gt;]</code>
  1362. <p>Example:</p>
  1363. <pre>
  1364. set lamp1 on
  1365. set lamp1 off
  1366. set lamp1 on-for-timer 10
  1367. set lamp1 on-until 13:15:00
  1368. set foobar raw 234578
  1369. set thermo value 23.44
  1370. set message value Hallo Welt
  1371. </pre>
  1372. <p>When as last argument a g&lt;groupnr&gt; is present, the command will be sent
  1373. to the KNX group indexed by the groupnr (starting by 1, in the order as given in define).</p>
  1374. <pre>
  1375. define lamp1 KNX 0/10/01:dpt1 0/10/02:dpt1
  1376. set lamp1 on g2 (will send "on" to 0/10/02)
  1377. </pre>
  1378. <p>A dimmer can be used with a slider as shown in following example:</p>
  1379. <pre>
  1380. define dim1 KNX 0/0/5:dpt5.001
  1381. attr dim1 slider 0,1,100
  1382. attr dim1 webCmd value
  1383. </pre>
  1384. <p>The current date and time can be sent to the bus by the following settings:</p>
  1385. <pre>
  1386. define timedev KNX 0/0/7:dpt10
  1387. attr timedev webCmd now
  1388. define datedev KNX 0/0/8:dpt11
  1389. attr datedev webCmd now
  1390. # send every midnight the new date
  1391. define dateset at *00:00:00 set datedev now
  1392. # send every hour the current time
  1393. define timeset at +*01:00:00 set timedev now
  1394. </pre>
  1395. </ul>
  1396. <p><a name="KNXget"></a> <b>Get</b></p>
  1397. <ul>
  1398. <p>If you execute get for a KNX-Element the status will be requested a state from the device. The device has to be able to respond to a read - this is not given for all devices.<br>
  1399. The answer from the bus-device is not shown in the toolbox, but is treated like a regular telegram.</p>
  1400. </ul>
  1401. <p><a name="KNXattr"></a> <b>Attributes</b></p>
  1402. <ul><br>
  1403. Common attributes:<br>
  1404. <a href="#DbLogInclude">DbLogInclude</a><br>
  1405. <a href="#DbLogExclude">DbLogExclude</a><br>
  1406. <a href="#IODev">IODev</a><br>
  1407. <a href="#alias">alias</a><br>
  1408. <a href="#comment">comment</a><br>
  1409. <a href="#devStateIcon">devStateIcon</a><br>
  1410. <a href="#devStateStyle">devStateStyle</a><br>
  1411. <a href="#do_not_notify">do_not_notify</a><br>
  1412. <a href="#readingFnAttributes">readingFnAttributes</a><br>
  1413. <a href="#event-aggregator">event-aggregator</a><br>
  1414. <a href="#event-min-interval">event-min-interval</a><br>
  1415. <a href="#event-on-change-reading">event-on-change-reading</a><br>
  1416. <a href="#event-on-update-reading">event-on-update-reading</a><br>
  1417. <a href="#eventMap">eventMap</a><br>
  1418. <a href="#group">group</a><br>
  1419. <a href="#icon">icon</a><br>
  1420. <a href="#room">room</a><br>
  1421. <a href="#showtime">showtime</a><br>
  1422. <a href="#sortby">sortby</a><br>
  1423. <a href="#stateFormat">stateFormat</a><br>
  1424. <a href="#userReadings">userReadings</a><br>
  1425. <a href="#userattr">userattr</a><br>
  1426. <a href="#verbose">verbose</a><br>
  1427. <a href="#webCmd">webCmd</a><br>
  1428. <a href="#widgetOverride">widgetOverride</a><br>
  1429. <br>
  1430. </ul>
  1431. <p><a name="KNXformat"></a> <b>format</b></p>
  1432. <ul>
  1433. The content of this attribute is added to every received value, before this is copied to state.
  1434. <p>Example:</p>
  1435. <pre>
  1436. define myTemperature KNX 0/1/1:dpt5
  1437. attr myTemperature format &degC;
  1438. </pre>
  1439. </ul>
  1440. <p><a name="KNXstateRegex"></a> <b>stateRegex</b></p>
  1441. <ul>
  1442. You can pass n pairs of regex-pattern and string to replace, seperated by a slash. Internally the "new" state is always in the format getG&lt;group&gt;:&lt;state-value&gt;. The substitution is done every time,
  1443. a new object is received. You can use this function for converting, adding units, having more fun with icons, ...
  1444. This function has only an impact on the content of state - no other functions are disturbed. It is executed directly after replacing the reading-names and setting the formats, but before stateCmd
  1445. <p>Example:</p>
  1446. <pre>
  1447. define myLamp KNX 0/1/1:dpt1 0/1/2:dpt1 0/1/2:dpt1
  1448. attr myLamp stateRegex /getG1:/steuern:/ /getG2:/status:/ /getG3:/sperre:/ /setG[13]:/steuern:/ /setG[3]://
  1449. attr myLamp devStateIcon status.on:general_an status.off:general_aus sperre.on:lock steuern.*:hourglass
  1450. </pre>
  1451. </ul>
  1452. <p><a name="KNXstateCmd"></a> <b>stateCmd</b></p>
  1453. <ul>
  1454. You can supply a perl-command for modifying state. This command is executed directly before updating the reading - so after renaming, format and regex.
  1455. Please supply a valid perl command like using the attribute stateFormat.
  1456. Unlike stateFormat the stateCmd modifies also the content of the reading, not only the hash-conten for visualization.
  1457. <p>Example:</p>
  1458. <pre>
  1459. define myLamp KNX 0/1/1:dpt1 0/1/2:dpt1 0/1/2:dpt1
  1460. attr myLamp stateCmd {$state = sprintf("%s", ReadingsVal($name,"getG2","undef"))}
  1461. </pre>
  1462. </ul>
  1463. <p><a name="KNXanswerReading"></a> <b>answerReading</b></p>
  1464. <ul>
  1465. If enabled, FHEM answers on read requests. The content of state is send to the bus as answer.
  1466. <p>If set to 1, read-requests are answered</p>
  1467. </ul>
  1468. <p><a name="KNXlistenonly"></a> <b>listenonly</b></p>
  1469. <ul>
  1470. If set to 1, the device may not send any messages. As well answering requests although get is prohibited.
  1471. </ul>
  1472. <p><a name="KNXreadonly"></a> <b>readonly</b></p>
  1473. <ul>
  1474. If set to 1, the device may not send any messages. Answering requests are prohibited.Get is allowed.
  1475. </ul>
  1476. <p><a name="KNXslider"></a> <b>slider</b></p>
  1477. <ul>
  1478. slider &lt;min&gt;,&lt;step&gt;,&lt;max&gt;<br>
  1479. With this attribute you can add a slider to any device.
  1480. <p>Example:</p>
  1481. <pre>
  1482. define myDimmer KNX 0/1/1:dpt5
  1483. attr myDimmer slider 0,1,100
  1484. attr myDimmer webCmd value
  1485. </pre>
  1486. </ul>
  1487. <p><a name="KNXdpt"></a> <b>DPT - datapoint-types</b></p>
  1488. <ul>
  1489. <p>The following dpt are implemented and have to be assigned within the device definition.</p>
  1490. dpt1 on, off<br>
  1491. dpt1.001 on, off<br>
  1492. dpt1.002 true, false<br>
  1493. dpt1.003 enable, disable<br>
  1494. dpt1.008 up, down<br>
  1495. dpt1.009 open, closed<br>
  1496. dpt1.019 closed, open<br>
  1497. dpt3 -100..+100<br>
  1498. dpt5 0..255<br>
  1499. dpt5.001 0..100 %<br>
  1500. dpt5.003 0..360 &deg;<br>
  1501. dpt5.004 0..255 %<br>
  1502. dpt6 -127..+127<br>
  1503. dpt6.001 0..100 %<br>
  1504. dpt7 0..65535<br>
  1505. dpt7.001 0..65535 s<br>
  1506. dpt7.005 0..65535 s<br>
  1507. dpt7.005 0..65535 m<br>
  1508. dpt7.012 0..65535 mA<br>
  1509. dpt7.013 0..65535 lux<br>
  1510. dpt8 -32768..32768<br>
  1511. dpt8.005 -32768..32768 s<br>
  1512. dpt8.010 -32768..32768 %<br>
  1513. dpt8.011 -32768..32768 &deg;<br>
  1514. dpt9 -670760.0..+670760.0<br>
  1515. dpt9.001 -670760.0..+670760.0 &deg;<br>
  1516. dpt9.004 -670760.0..+670760.0 lux<br>
  1517. dpt9.005 -670760.0..+670760.0 m/s<br>
  1518. dpt9.006 -670760.0..+670760.0 Pa<br>
  1519. dpt9.007 -670760.0..+670760.0 %<br>
  1520. dpt9.008 -670760.0..+670760.0 ppm<br>
  1521. dpt9.009 -670760.0..+670760.0 m³/h<br>
  1522. dpt9.010 -670760.0..+670760.0 s<br>
  1523. dpt9.021 -670760.0..+670760.0 mA<br>
  1524. dpt9.024 -670760.0..+670760.0 kW<br>
  1525. dpt9.025 -670760.0..+670760.0 l/h<br>
  1526. dpt9.026 -670760.0..+670760.0 l/h<br>
  1527. dpt9.028 -670760.0..+670760.0 km/h<br>
  1528. dpt10 01:00:00<br>
  1529. dpt11 01.01.2000<br>
  1530. dpt12 0..+Inf<br>
  1531. dpt13 -Inf..+Inf<br>
  1532. dpt13.010 -Inf..+Inf Wh<br>
  1533. dpt13.013 -Inf..+Inf kWh<br>
  1534. dpt14 -Inf.0..+Inf.0<br>
  1535. dpt14.019 -Inf.0..+Inf.0 A<br>
  1536. dpt14.027 -Inf.0..+Inf.0 V<br>
  1537. dpt14.056 -Inf.0..+Inf.0 W<br>
  1538. dpt14.068 -Inf.0..+Inf.0 &degC;<br>
  1539. dpt14.076 -Inf.0..+Inf.0 m&sup3;<br>
  1540. dpt16 String;<br>
  1541. dpt16.000 ASCII-String;<br>
  1542. dpt16.001 ISO-8859-1-String (Latin1);<br>
  1543. dpt232 RGB-Value RRGGBB<br>
  1544. </ul>
  1545. </ul>
  1546. =end html
  1547. =device
  1548. =item summary Communicates to KNX via module TUL
  1549. =item summary_DE Kommuniziert mit dem KNX über das Modul TUL
  1550. =begin html_DE
  1551. <a name="KNX"></a>
  1552. <h3>KNX</h3>
  1553. <ul>
  1554. <p>KNX ist ein Standard zur Haus- und Geb&auml;udeautomatisierung.
  1555. Der Standard begr&uuml;ndet sich haupts&auml;chlich auf twisted pair, findet aber auch zunehmende Verbreitung auf andere Medien (Funk, Ethernet, ...)</p>
  1556. F&uuml;r Anf&auml;nger sei folgende Lekt&uuml;re empfohlen: <a href="http://www.knx.org/media/docs/Flyers/KNX-Basics/KNX-Basics_de.pdf">KNX-Basics</a>
  1557. <p>Das Modul <a href="#TUL">TUL</a> stellt die Verbindung zum Bus her, Das KNX-Modul stellt die Verbindung zu den einzelnen KNX-/EIB-Ger&auml;ten her. Das Modul stellt Befehle (on, off, on-until, on-for-timer)
  1558. zum ein- und Ausschalten von Ger&auml;ten zur Verf&uuml;gung. F&uuml;r numerische DPT nutzt bitte value (set &lt;devname&gt; value &lt;177.45&gt;). F&uuml;r string-DPT nutzt bitte string
  1559. (set &lt;devname&gt; string &lt;Hello World&gt;). F&uuml;r andere, undefinierte DPT k&ouml;nnt Ihr raw hex Werte ans Netzwerk senden (set &lt;devname&gt; raw &lt;hexval&gt;).<br>
  1560. Komplexe Konfigurationen k&ouml;nnen aufgebaut werden, indem mehrere Modulinstanzen in einem Ger&auml;t definiert werden. Daf&uuml;r werden mehrere Kombinationen aus GAD und DPT in einem Ger&auml;t definiert werden.</p>
  1561. <p>Der KNX-Standard stellt eine Reihe vordefinierter Datentypen zur Verf&uuml;gung. Dies sichert die Hersteller&uuml;bergreifende Kompatibilit&auml;t.
  1562. Basierend auf diesen DPT wird der Status eines Ger&auml;tes interpretiert und in FHEM angezeigt. F&uuml;r jedes empfangene Telegramm wird ein reading mit state, getG&lt;group&gt; und der Absenderadresse angelegt.
  1563. F&uuml;r jedes ser-command wird ein Reading mit state und setG&lt;group&gt; angelegt.</p>
  1564. <p><a name="KNXdefine"></a> <b>Define</b></p>
  1565. <ul>
  1566. <code>define &lt;name&gt; KNX &lt;group&gt;:&lt;DPT&gt;:&lt[;readingName]&gt; [&lt;group&gt;:&lt;DPT&gt; ..] [IODev]</code>
  1567. <p>Ein KNX-device ben&ouml;tigt einen konkreten DPT. Bitte schaut die verf&uuml;gbaren DPT unter <a href="#KNXdpt">Available DPT</a> nach. Wird kein korrekter DPT angegeben, kann das system die Nachrichten nicht korrekt de- / codieren.
  1568. Weiterhin kann bei der Ger&auml;tedefinition eine IO-Schnittstelle angegeben werden. Dies kann sp&auml;ter ebenfalls per Attribut erfolgen.</p>
  1569. <p>Jedes Device muss an eine <a href="#TUL">TUL</a> gebunden sein. Die &lt;group&gt; Parameter werden entweder als Gruppenadresse (0-15/0-15/0-255) oder als Hex-notation angegeben (0-f0-f0-ff).
  1570. Alle definierten Gruppen k&ouml;nnen f&uuml;r die Buskommunikation verwendet werden. Ohne weitere Attribute, werden alle eingehenden Nachrichten in state &uuml;bersetzt.
  1571. Per default wird &uuml;ber die erste Gruppe gesendet.<br>
  1572. Wenn Ihr einen readingNamen angebt, wird dieser als Basis für die Readings benutzt (z.B. hugo-set, hugo-get for name hugo).<br>
  1573. Wollt Ihr &uuml;ber eine andere Gruppe senden. m&uuml;sst Ihr diese indizieren (set &lt;devname&gt; value &lt;17.0&gt; &lt;g2&gt;).</p>
  1574. <p>Das Modul <a href="#autocreate">autocreate</a> generiert eine Instanz f&uuml;r jede unbekannte Gruppenadresse. Das Ger&auml;t selbst wird jedoch NICHT korrekt funktionieren, so lange noch kein korrekter
  1575. DPT angelegt ist. Der Name ist immer KNX_nnmmooo wobei nn die Linie ist, mm der Bereich und ooo die Geräteadresse.</p>
  1576. <p>Example:</p>
  1577. <pre>
  1578. define lamp1 KNX 0/10/12:dpt1
  1579. define lamp1 KNX 0/10/12:dpt1:meinName 0/0/5:dpt1.001
  1580. define lamp1 KNX 0A0C:dpt1.003 myTul
  1581. </pre>
  1582. Ein Hinweis bezüglich dem binären Datentyp dpt1: alle Untertypen müssen über das Schlüsselwort value gesetzt werden. Empfangene Telegramme werden entsprechend ihrer Definition automatisch
  1583. umbenannt. Die zur Verfügung stehenden on/off Schaltflächen ohne den Schlüssel value sind ein absoluter Sonderfall und gelten nur für den dpt1 selbst (nicht die Untertypen).
  1584. <p>Example:</p>
  1585. <pre>
  1586. define rollo KNX 0/10/12:dpt1.008
  1587. set rollo value up
  1588. set rollo value down
  1589. </pre>
  1590. </ul>
  1591. <p><a name="KNXset"></a> <b>Set</b></p>
  1592. <ul>
  1593. <code>set &lt;name&gt; &lt;on, off&gt;</code> [g&lt;groupnr&gt;]
  1594. <code>set &lt;name&gt; &lt;on-for-timer, on-until&gt; &lt;time&gt; [g&lt;groupnr&gt;]</code>
  1595. <code>set &lt;name&gt; &lt;value&gt; [g&lt;groupnr&gt;]</code>
  1596. <code>set &lt;name&gt; &lt;string&gt; [g&lt;groupnr&gt;]</code>
  1597. <code>set &lt;name&gt; &lt;raw&gt; [g&lt;groupnr&gt;]</code>
  1598. <p>Example:</p>
  1599. <pre>
  1600. set lamp1 on
  1601. set lamp1 off
  1602. set lamp1 on-for-timer 10
  1603. set lamp1 on-until 13:15:00
  1604. set foobar raw 234578
  1605. set thermo value 23.44
  1606. set message value Hallo Welt
  1607. </pre>
  1608. <p>Wenn eine Gruppe angegeben wurde (g&lt;groupnr&gt;) wird das Telegramm an de indizierte Gruppe gesendet (start bei 1, wie in der Definition angegeben).</p>
  1609. <pre>
  1610. define lamp1 KNX 0/10/01:dpt1 0/10/02:dpt1
  1611. set lamp1 on g2 (will send "on" to 0/10/02)
  1612. </pre>
  1613. <p>Ein Dimmer mit Slider:</p>
  1614. <pre>
  1615. define dim1 KNX 0/0/5:dpt5.001
  1616. attr dim1 slider 0,1,100
  1617. attr dim1 webCmd value
  1618. </pre>
  1619. <p>Aktuelle Uhrzeit / Datum k&ouml;nnen wie folgt auf den Bus gelegt werden:</p>
  1620. <pre>
  1621. define timedev KNX 0/0/7:dpt10
  1622. attr timedev webCmd now
  1623. define datedev KNX 0/0/8:dpt11
  1624. attr datedev webCmd now
  1625. # send every midnight the new date
  1626. define dateset at *00:00:00 set datedev now
  1627. # send every hour the current time
  1628. define timeset at +*01:00:00 set timedev now
  1629. </pre>
  1630. </ul>
  1631. <p><a name="KNXget"></a> <b>Get</b></p>
  1632. <ul>
  1633. <p>Bei jeder Ausf&uuml;hrung wird eine Leseanfrage an die entsprechende Gruppe geschickt. Die Gruppe muss in der Lage sein, auf diese Anfrage zu antworten (dies ist nicht immer der Fall).<br>
  1634. Die Antwort der Gruppe wird nicht im FHEMWEB angezeigt. Das empfangene Telegramm wird (wie jedes andere) ausgewertet.</p>
  1635. </ul>
  1636. <p><a name="KNXattr"></a> <b>Attributes</b></p>
  1637. <ul><br>
  1638. Common attributes:<br>
  1639. <a href="#DbLogInclude">DbLogInclude</a><br>
  1640. <a href="#DbLogExclude">DbLogExclude</a><br>
  1641. <a href="#IODev">IODev</a><br>
  1642. <a href="#alias">alias</a><br>
  1643. <a href="#comment">comment</a><br>
  1644. <a href="#devStateIcon">devStateIcon</a><br>
  1645. <a href="#devStateStyle">devStateStyle</a><br>
  1646. <a href="#do_not_notify">do_not_notify</a><br>
  1647. <a href="#readingFnAttributes">readingFnAttributes</a><br>
  1648. <a href="#event-aggregator">event-aggregator</a><br>
  1649. <a href="#event-min-interval">event-min-interval</a><br>
  1650. <a href="#event-on-change-reading">event-on-change-reading</a><br>
  1651. <a href="#event-on-update-reading">event-on-update-reading</a><br>
  1652. <a href="#eventMap">eventMap</a><br>
  1653. <a href="#group">group</a><br>
  1654. <a href="#icon">icon</a><br>
  1655. <a href="#room">room</a><br>
  1656. <a href="#showtime">showtime</a><br>
  1657. <a href="#sortby">sortby</a><br>
  1658. <a href="#stateFormat">stateFormat</a><br>
  1659. <a href="#userReadings">userReadings</a><br>
  1660. <a href="#userattr">userattr</a><br>
  1661. <a href="#verbose">verbose</a><br>
  1662. <a href="#webCmd">webCmd</a><br>
  1663. <a href="#widgetOverride">widgetOverride</a><br>
  1664. <br>
  1665. </ul>
  1666. <p><a name="KNXformat"></a> <b>format</b></p>
  1667. <ul>
  1668. Der Inhalt dieses Attributes wird bei jedem empfangenen Wert angehangen, bevor der Wert in state kopeiert wird.
  1669. <p>Example:</p>
  1670. <pre>
  1671. define myTemperature KNX 0/1/1:dpt5
  1672. attr myTemperature format &degC;
  1673. </pre>
  1674. </ul>
  1675. <p><a name="KNXstateRegex"></a> <b>stateRegex</b></p>
  1676. <ul>
  1677. Es kann eine Reihe an Search/Replace Patterns &uuml;bergeben werden (getrennt durch einen Slash). Intern wird der neue Wert von state immer im Format getG&lt;group&gt;:&lt;state-value&gt;. abgebildet.
  1678. Die Ersetzungen werden bei bei jedem neuen Telegramm vorgenommen. Ihr k&ouml;nnt die Funktion f&uuml;r Konvertierungen nutzen, Einheiten hinzuf&uuml;gen, Spaß mit Icons haben, ...
  1679. Diese Funktion wirkt nur auf den Inhalt von State - sonst wird nichts beeinflusst.
  1680. Die Funktion wird direkt nach dem Ersetzen der Readings-Namen und dem ergänzen der Formate ausgeführt.
  1681. <p>Example:</p>
  1682. <pre>
  1683. define myLamp KNX 0/1/1:dpt1 0/1/2:dpt1 0/1/2:dpt1
  1684. attr myLamp stateRegex /getG1:/steuern:/ /getG2:/status:/ /getG3:/sperre:/ /setG[13]:/steuern:/ /setG[3]://
  1685. attr myLamp devStateIcon status.on:general_an status.off:general_aus sperre.on:lock steuern.*:hourglass
  1686. </pre>
  1687. </ul>
  1688. <p><a name="KNXstateCmd"></a> <b>stateCmd</b></p>
  1689. <ul>
  1690. Hier könnt Ihr ein perl-Kommando angeben, welches state beeinflusst. Die Funktion wird unmittelbar vor dem Update des Readings aufgerufen - also nach dem Umbennenen der Readings, format und regex.
  1691. Es ist ein gültiges Perl-Kommando anzugeben (vgl. stateFormat). Im Gegensatz zu StateFormat wirkt sich dieses Attribut inhaltlich auf das Reading aus, und nicht "nur" auf die Anzeige im FHEMWEB.
  1692. <p>Beispiel:</p>
  1693. <pre>
  1694. define myLamp KNX 0/1/1:dpt1 0/1/2:dpt1 0/1/2:dpt1
  1695. attr myLamp stateCmd {$state = sprintf("%s", ReadingsVal($name,"getG2","undef"))}
  1696. </pre>
  1697. </ul>
  1698. <p><a name="KNXanswerReading"></a> <b>answerReading</b></p>
  1699. <ul>
  1700. Wenn aktiviert, antwortet FHEM auf Leseanfragen. Der Inhalt von state wird auf den Bus gelegt.
  1701. <p>Leseanfragen werden beantwortet, wenn der Wert auf 1 gesetzt ist.</p>
  1702. </ul>
  1703. <p><a name="KNXlistenonly"></a> <b>listenonly</b></p>
  1704. <ul>
  1705. Wenn auf 1 gesetzt, kann das Ger&auml;t keine Nachrichten senden. Sowohl Leseanfragen als auch get sind verboten.
  1706. </ul>
  1707. <p><a name="KNXreadonly"></a> <b>readonly</b></p>
  1708. <ul>
  1709. Wenn auf 1 gesetzt, kann das Ger&auml;t keine Nachrichten senden. Leseanfragen sind verboten. Get ist erlaubt.
  1710. </ul>
  1711. <p><a name="KNXslider"></a> <b>slider</b></p>
  1712. <ul>
  1713. slider &lt;min&gt;,&lt;step&gt;,&lt;max&gt;<br>
  1714. Mit diesem Attribut k&ouml;nnt Ihr jedem Ger&auml;t einen Slider verpassen.
  1715. <p>Example:</p>
  1716. <pre>
  1717. define myDimmer KNX 0/1/1:dpt5
  1718. attr myDimmer slider 0,1,100
  1719. attr myDimmer webCmd value
  1720. </pre>
  1721. </ul>
  1722. <p><a name="KNXdpt"></a> <b>DPT - datapoint-types</b></p>
  1723. <ul>
  1724. <p>Die folgenden DPT sind implementiert und m&uuml;ssen in der Gruppendefinition angegeben werden.</p>
  1725. dpt1 on, off<br>
  1726. dpt1.001 on, off<br>
  1727. dpt1.002 true, false<br>
  1728. dpt1.003 enable, disable<br>
  1729. dpt1.008 up, down<br>
  1730. dpt1.009 open, closed<br>
  1731. dpt1.019 closed, open<br>
  1732. dpt3 -100..+100<br>
  1733. dpt5 0..255<br>
  1734. dpt5.001 0..100 %<br>
  1735. dpt5.003 0..360 &deg;<br>
  1736. dpt5.004 0..255 %<br>
  1737. dpt6 -127..+127<br>
  1738. dpt6.001 0..100 %<br>
  1739. dpt7 0..65535<br>
  1740. dpt7.001 0..65535 <br>
  1741. dpt7.005 0..65535 s<br>
  1742. dpt7.006 0..65535 m<br>
  1743. dpt7.012 0..65535 mA<br>
  1744. dpt7.013 0..65535 lux<br>
  1745. dpt8 -32768..32768<br>
  1746. dpt8.005 -32768..32768 s<br>
  1747. dpt8.010 -32768..32768 %<br>
  1748. dpt8.011 -32768..32768 &deg;<br>
  1749. dpt9 -670760.0..+670760.0<br>
  1750. dpt9.001 -670760.0..+670760.0 &deg;<br>
  1751. dpt9.004 -670760.0..+670760.0 lux<br>
  1752. dpt9.005 -670760.0..+670760.0 m/s<br>
  1753. dpt9.006 -670760.0..+670760.0 Pa<br>
  1754. dpt9.007 -670760.0..+670760.0 %<br>
  1755. dpt9.008 -670760.0..+670760.0 ppm<br>
  1756. dpt9.009 -670760.0..+670760.0 m³/h<br>
  1757. dpt9.010 -670760.0..+670760.0 s<br>
  1758. dpt9.021 -670760.0..+670760.0 mA<br>
  1759. dpt9.024 -670760.0..+670760.0 kW<br>
  1760. dpt9.025 -670760.0..+670760.0 l/h<br>
  1761. dpt9.026 -670760.0..+670760.0 l/h<br>
  1762. dpt9.028 -670760.0..+670760.0 km/h<br>
  1763. dpt10 01:00:00<br>
  1764. dpt11 01.01.2000<br>
  1765. dpt12 0..+Inf<br>
  1766. dpt13 -Inf..+Inf<br>
  1767. dpt13.010 -Inf..+Inf Wh<br>
  1768. dpt13.013 -Inf..+Inf kWh<br>
  1769. dpt14 -Inf.0..+Inf.0<br>
  1770. dpt14.019 -Inf.0..+Inf.0 A<br>
  1771. dpt14.027 -Inf.0..+Inf.0 V<br>
  1772. dpt14.056 -Inf.0..+Inf.0 W<br>
  1773. dpt14.068 -Inf.0..+Inf.0 &degC;<br>
  1774. dpt14.076 -Inf.0..+Inf.0 m&sup3;<br>
  1775. dpt16 String;<br>
  1776. dpt16.000 ASCII-String;<br>
  1777. dpt16.001 ISO-8859-1-String (Latin1);<br>
  1778. dpt232 RGB-Wert RRGGBB<br>
  1779. </ul>
  1780. </ul>
  1781. =end html_DE
  1782. =cut