10_KNX.pm 76 KB

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