98_GAEBUS.pm 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436
  1. #############################################
  2. # $Id: 98_GAEBUS.pm 15600 2017-12-13 12:07:55Z jamesgo $
  3. # derived from 00_TUL.pm
  4. #
  5. # 17.07.2015 : A.Goebel : initiale Version mit loop, readingname via attribut, keine writes
  6. # 21.07.2015 : A.Goebel : start implementation for "set .. write"
  7. # 23.07.2015 : A.Goebel : event-on-change-reading added to attributes
  8. # 08.09.2015 : A.Goebel : limit number of socket-open retries in GetUpdates loop
  9. # 10.09.2015 : A.Goebel : fix html code of commandref
  10. # 11.09.2015 : A.Goebel : add attribute "ebusWritesEnable:0,1"
  11. # 11.09.2015 : A.Goebel : add set w~ commands to set attributes for writing
  12. # 11.09.2015 : A.Goebel : add set <write-reading> command to write to ebusd
  13. # 13.09.2015 : A.Goebel : increase timeout for reads from ebusd from 1.8 to 5.0
  14. # 14.09.2015 : A.Goebel : use utf-8 coding to display values from ".csv" files
  15. # 14.09.2015 : A.Goebel : add optional parameter [FIELD[.N]] of read from ebusd to reading name
  16. # 15.09.2015 : A.Goebel : get rid of perl warnings when attribute value is empty
  17. # 16.09.2015 : A.Goebel : allow write to parameters protected by #install
  18. # 21.09.2015 : A.Goebel : implement BlockingCall Interface
  19. # 07.10.2015 : A.Goebel : beautify and complete commandref
  20. # 12.10.2015 : A.Goebel : fix handling of timeouts in BlockingCall Interface (additional parameter in doEbusCmd forces restart (no shutdown restart))
  21. # timeout for reads increased
  22. # 19.10.2015 : A.Goebel : add attribute disable to disable loop to collect readings
  23. # 05.11.2015 : A.Goebel : add support for "h" (broadcast update) commands from csv, handle them equal to (r)ead
  24. # 09.11.2015 : A.Goebel : add support for multiple readings generated from one command to ebusd
  25. # ebusd may return a list of values like "52.0;43.0;8.000;41.0;45.0;error"
  26. # defining a reading "VL;RL;dummy;VLWW;RLWW" will create redings VL, RL, VLWW and RLWW
  27. # 04.12.2015 : A.Goebel : add event-min-interval to attributes
  28. # 14.12.2015 : A.Goebel : add read possible commmands for ebusd using "find -f" instead of reading the ".csv" files directly ("get ebusd_find")
  29. # 25.01.2016 : A.Goebel : fix duplicate log entries for readings
  30. # 05.02.2016 : A.Goebel : add valueFormat attribute
  31. # 18.08.2016 : A.Goebel : fix workarround for perl warning with keys of hash reference
  32. # 30.08.2016 : A.Goebel : add reading "state_ebus" containing output from "state" of ebusd
  33. # 16.09.2016 : A.Goebel : add reset "state_ebus" if ebus is not connected
  34. # 06.10.2016 : A.Goebel : add valueFormat can now be used to access all values returned from one read
  35. # 11.10.2016 : A.Goebel : add implement hex write from ebusctl
  36. # 11.10.2016 : A.Goebel : add set initial reading name after "set" to "class~variable"
  37. # 11.10.2016 : A.Goebel : fix "set hex" is only available if ebusWritesEnabled is '1'
  38. # 13.10.2016 : A.Goebel : fix "set hex" referres to "ebusctl hex"
  39. # 13.10.2016 : A.Goebel : fix "class" is now optional for ebusctl
  40. # 18.10.2016 : A.Goebel : fix removed content of <comment> from attribute names for readings
  41. # 31.10.2016 : A.Goebel : fix rename hex to ebusd_hex
  42. # 31.10.2016 : A.Goebel : fix set for writings without comments did not work
  43. # 26.12.2016 : A.Goebel : fix handling for non "userattr" attributes
  44. # 27.12.2016 : A.Goebel : fix handling if ebusctl reports "usage:"
  45. # 27.12.2016 : A.Goebel : fix scan removed from supported classes
  46. # 13.12.2017 : A.Goebel : add "+f" as additional ebus command to disable "-f" for this request
  47. package main;
  48. use strict;
  49. use warnings;
  50. use Time::HiRes qw(gettimeofday);
  51. use IO::Socket;
  52. use IO::Select;
  53. use Encode;
  54. use Blocking;
  55. sub GAEBUS_Attr(@);
  56. sub GAEBUS_OpenDev($$);
  57. sub GAEBUS_CloseDev($);
  58. sub GAEBUS_Disconnected($);
  59. sub GAEBUS_Shutdown($);
  60. sub GAEBUS_doEbusCmd($$$$$$$);
  61. sub GAEBUS_GetUpdates($);
  62. sub GAEBUS_GetUpdatesDoit($);
  63. sub GAEBUS_GetUpdatesDone($);
  64. sub GAEBUS_GetUpdatesAborted($);
  65. sub GAEBUS_State($);
  66. my %gets = ( # Name, Data to send to the GAEBUS, Regexp for the answer
  67. );
  68. my %sets = (
  69. #"reopen" => []
  70. );
  71. my %setsForWriting = ();
  72. my %getsForWriting = ();
  73. my $allSetParams = "";
  74. my $allSetParamsForWriting = "";
  75. my $allGetParams = "";
  76. my $allGetParamsForWriting = "";
  77. my $delimiter = "~";
  78. my $attrsDefault = "do_not_notify:1,0 disable:1,0 dummy:1,0 showtime:1,0 loglevel:0,1,2,3,4,5,6 event-on-change-reading event-min-interval ebusWritesEnabled:0,1 valueFormat:textField-long";
  79. my %ebusCmd = ();
  80. #####################################
  81. sub
  82. GAEBUS_Initialize($)
  83. {
  84. my ($hash) = @_;
  85. # Normal devices
  86. $hash->{DefFn} = "GAEBUS_Define";
  87. $hash->{UndefFn} = "GAEBUS_Undef";
  88. $hash->{GetFn} = "GAEBUS_Get";
  89. $hash->{SetFn} = "GAEBUS_Set";
  90. #$hash->{StateFn} = "GAEBUS_SetState";
  91. $hash->{AttrFn} = "GAEBUS_Attr";
  92. $hash->{AttrList} = $attrsDefault;
  93. $hash->{ShutdownFn} = "GAEBUS_Shutdown";
  94. %sets = ( "reopen" => [] );
  95. %gets = ( "ebusd_find" => [], "ebusd_info" => [] );
  96. %setsForWriting = ();
  97. %getsForWriting = ( "ebusd_hex" => [] );
  98. GAEBUS_initParams($hash);
  99. }
  100. #####################################
  101. sub
  102. GAEBUS_initParams ($)
  103. {
  104. my ($hash) = @_;
  105. # bulid set and get Params and store them in
  106. # $allSetParams
  107. # $allSetParamsForWriting
  108. # $allGetParams
  109. # $allGetParamsForWriting
  110. $allSetParams = "";
  111. foreach my $setval (sort keys %sets)
  112. {
  113. Log3 ($hash, 4, "GAEBUS Initialize params for set: $setval");
  114. if ( (@{$sets{$setval}}) > 0)
  115. {
  116. $allSetParams .= $setval.":".join (",", @{$sets{$setval}})." ";
  117. }
  118. else
  119. {
  120. $allSetParams .= $setval." ";
  121. }
  122. #Log3 ($hash, 2, "GAEBUS Initialize: $setval:$allSetParams");
  123. }
  124. $allSetParamsForWriting = "";
  125. foreach my $setval (sort keys %setsForWriting)
  126. {
  127. Log3 ($hash, 4, "GAEBUS Initialize params for setsForWriting: $setval");
  128. if ( (@{$setsForWriting{$setval}}) > 0)
  129. {
  130. $allSetParamsForWriting .= $setval.":".join (",", @{$setsForWriting{$setval}})." ";
  131. }
  132. else
  133. {
  134. $allSetParamsForWriting .= $setval." ";
  135. }
  136. #Log3 ($hash, 2, "GAEBUS Initialize: $setval:$allSetParamsForWriting");
  137. }
  138. $allGetParams = "";
  139. foreach my $getval (sort keys %gets)
  140. {
  141. Log3 ($hash, 4, "GAEBUS Initialize params for get: $getval");
  142. if ( (@{$gets{$getval}}) > 0)
  143. {
  144. $allGetParams .= $getval.":".join (",", @{$gets{$getval}})." ";
  145. }
  146. else
  147. {
  148. $allGetParams .= $getval." ";
  149. }
  150. #Log3 ($hash, 2, "GAEBUS Initialize: $getval:$allGetParams");
  151. }
  152. $allGetParamsForWriting = "";
  153. foreach my $setval (sort keys %getsForWriting)
  154. {
  155. Log3 ($hash, 4, "GAEBUS Initialize params for getsForWriting: $setval");
  156. if ( (@{$getsForWriting{$setval}}) > 0)
  157. {
  158. $allGetParamsForWriting .= $setval.":".join (",", @{$getsForWriting{$setval}})." ";
  159. }
  160. else
  161. {
  162. $allGetParamsForWriting .= $setval." ";
  163. }
  164. #Log3 ($hash, 2, "GAEBUS Initialize: $setval:$allSetParamsForWriting");
  165. }
  166. }
  167. #####################################
  168. sub
  169. GAEBUS_Define($$)
  170. {
  171. my ($hash, $def) = @_;
  172. my @a = split("[ \t][ \t]*", $def);
  173. if(@a < 3) {
  174. my $msg = "wrong syntax: define <name> GAEBUS <device-addr>[:<port>] [interval]";
  175. Log (2, $msg);
  176. return $msg;
  177. }
  178. GAEBUS_CloseDev($hash);
  179. my $name = $a[0];
  180. my $devaddr = $a[2];
  181. my $interval = $a[3];
  182. $hash->{DeviceName} = $hash->{NAME};
  183. $hash->{DeviceAddress} = $devaddr;
  184. $hash->{Interval} = defined ($interval) ? int ($interval) : 150;
  185. $hash->{UpdateCnt} = 0;
  186. my $ret = GAEBUS_OpenDev($hash, 0);
  187. RemoveInternalTimer($hash);
  188. InternalTimer(gettimeofday()+10, "GAEBUS_GetUpdates", $hash, 0);
  189. $hash->{helper}{longAttributesCount} = 0;
  190. return undef;
  191. }
  192. #####################################
  193. sub
  194. GAEBUS_Undef($$)
  195. {
  196. my ($hash, $arg) = @_;
  197. GAEBUS_CloseDev($hash);
  198. BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
  199. return undef;
  200. }
  201. #####################################
  202. sub GAEBUS_Shutdown($)
  203. {
  204. my ($hash) = @_;
  205. GAEBUS_CloseDev($hash);
  206. return undef;
  207. }
  208. #####################################
  209. sub
  210. GAEBUS_Set($@)
  211. {
  212. my ($hash, @a) = @_;
  213. return "\"set GAEBUS\" needs at least one parameter" if(@a < 2);
  214. my $name = shift @a;
  215. my $type = shift @a;
  216. my $arg = join(" ", @a);
  217. #return "No $a[1] for dummies" if(IsDummy($name));
  218. #Log3 ($hash, 3, "ebus1: reopen $name");
  219. #Log3 ($hash, 2, "$name: set $arg $type invalid parameter");
  220. if ($type eq "reopen") {
  221. Log3 ($hash, 3, "ebus1: reopen");
  222. GAEBUS_CloseDev($hash);
  223. GAEBUS_OpenDev($hash,0);
  224. return undef;
  225. }
  226. # handle commands defined in %sets
  227. if (defined ($sets{$type}))
  228. {
  229. unless (grep {$_ eq $arg} @{$sets{$type}})
  230. {
  231. return "invalid parameter";
  232. }
  233. my $attrname = $type.$delimiter.$arg;
  234. $attrname =~ s/\#install/install/;
  235. my ($io,$class,$var,$comment) = split ($delimiter, $attrname, 4);
  236. my $shortAttrname = join ($delimiter, ($io, $class, $var));
  237. #Log3 ($hash, 3, "$name: set $attrname");
  238. Log3 ($hash, 3, "$name: set for reading $attrname");
  239. addToDevAttrList($name, $shortAttrname);
  240. if (! defined $attr{$name}{$attrname}) {
  241. if ($class eq "") {
  242. $attr{$name}{$shortAttrname} = $var;
  243. } else {
  244. $attr{$name}{$shortAttrname} = join ("-", ($class, $var));
  245. }
  246. }
  247. return undef;
  248. }
  249. #
  250. # extend possible parameters by the readings defined for writing in attributes
  251. #
  252. my %writings = ();
  253. my $actSetParams = "$allSetParams ";
  254. my $ebusWritesEnabled = (defined($attr{$name}{"ebusWritesEnabled"})) ? $attr{$name}{"ebusWritesEnabled"} : 0;
  255. if ($ebusWritesEnabled) {
  256. $actSetParams .= "$allSetParams$allSetParamsForWriting " if ($ebusWritesEnabled);
  257. foreach my $oneattr (sort keys %{$attr{$name}})
  258. {
  259. my $readingname = $attr{$name}{$oneattr};
  260. my $readingcmdname = $oneattr;
  261. $readingname =~ s/ .*//;
  262. $readingname =~ s/:.*//;
  263. # only for "w" commands
  264. if ($oneattr =~ /^w$delimiter.{1,7}$delimiter.*/ or $oneattr =~ /^w$delimiter.{1,7}install$delimiter.*/)
  265. {
  266. unless ($readingname =~ /^\s*$/ or $readingname eq "1")
  267. {
  268. $writings{$readingname} = $readingcmdname;
  269. #Log3 ($name, 2, "$name SetParams $readingname");
  270. }
  271. }
  272. #Log3 ($name, 4, "$name Set attr name $readingname");
  273. #Log3 ($name, 4, "$name Set attr cmd $readingcmdname");
  274. }
  275. $actSetParams .= join (" ", sort keys %writings);
  276. # handle write commands (which were defined above)
  277. if (defined ($setsForWriting{$type}))
  278. {
  279. unless (grep {$_ eq $arg} @{$setsForWriting{$type}})
  280. {
  281. return "invalid parameter";
  282. }
  283. my $attrname = $type.$delimiter.$arg;
  284. $attrname =~ s/\#install/install/;
  285. my ($io,$class,$var,$comment) = split ($delimiter, $attrname, 4);
  286. my $shortAttrname = join ($delimiter, ($io, $class, $var));
  287. Log3 ($hash, 3, "$name: set for writing $attrname");
  288. #addToDevAttrList($name, $attrname);
  289. addToDevAttrList($name, $shortAttrname);
  290. if (! defined $attr{$name}{$attrname}) {
  291. if ($class eq "") {
  292. $attr{$name}{$shortAttrname} = $var;
  293. } else {
  294. $attr{$name}{$shortAttrname} = join ("-", ($class, $var));
  295. }
  296. }
  297. return undef;
  298. }
  299. if (defined ($writings{$type}))
  300. {
  301. foreach my $oneattr (sort keys %{$attr{$name}})
  302. {
  303. next unless ($oneattr =~ /^w.*$delimiter.{1,7}$delimiter.*$/ or $oneattr =~ /^w.*$delimiter.{1,7}install$delimiter.*$/);
  304. my $readingname = $attr{$name}{$oneattr};
  305. next if ($readingname ne $type);
  306. my $answer = GAEBUS_doEbusCmd ($hash, "w", $readingname, $oneattr, $arg, "", 0);
  307. return "$answer";
  308. }
  309. }
  310. }
  311. return "Unknown argument $type, choose one of " . $actSetParams
  312. if(!defined($sets{$type}));
  313. return undef;
  314. }
  315. #####################################
  316. sub
  317. GAEBUS_Get($@)
  318. {
  319. my ($hash, @a) = @_;
  320. my $name = $hash->{NAME};
  321. my $arg = (defined($a[2]) ? $a[2] : "");
  322. my $rsp;
  323. my $varname = $a[0];
  324. my $type = $a[1];
  325. my $readingname = "";
  326. my $readingcmdname = "";
  327. return "\"get GAEBUS\" needs at least one parameter" if(@a < 2);
  328. if ($type eq "ebusd_hex")
  329. {
  330. Log3 ($hash, 4, "$name Set $type $arg");
  331. my $answer = GAEBUS_doEbusCmd ($hash, "h", "", "", "$arg", "", 0);
  332. return $answer;
  333. }
  334. if ($type eq "removeCommentFromAttributeNames")
  335. {
  336. Log3 ($hash, 4, "$name Get $type $arg");
  337. my $answer = "shortened the follwing attribute names\n";
  338. foreach my $oneattr (sort keys %{$attr{$name}})
  339. {
  340. if ($oneattr =~ /$delimiter/) {
  341. my ($io,$class,$var,$comment) = split ($delimiter, $oneattr, 4);
  342. if (defined ($comment)) {
  343. # attribute name contains comment as 4-th part
  344. my $newattrname = join ($delimiter, ($io, $class, $var));
  345. $answer .= $oneattr." to ".$newattrname."\n";
  346. $attr{$name}{userattr} =~ s/$oneattr//;
  347. addToDevAttrList($name, $newattrname);
  348. $attr{$name}{$newattrname} = $attr{$name}{$oneattr};
  349. delete ($attr{$name}{$oneattr});
  350. }
  351. }
  352. }
  353. $hash->{helper}{longAttributesCount} = 0;
  354. return $answer;
  355. }
  356. # extend possible parameters by the readings defined in attributes
  357. my %readings = ();
  358. my %readingsCmdaddon = ();
  359. my $actGetParams .= "$allGetParams reading:";
  360. foreach my $oneattr (sort keys %{$attr{$name}})
  361. {
  362. my ($readingnameX, $cmdaddon) = split (" ", $attr{$name}{$oneattr}, 2);
  363. $cmdaddon = "" unless (defined ($cmdaddon));
  364. next unless defined ($readingnameX);
  365. next if ($readingnameX =~ /^\s*$/);
  366. next if ($readingnameX eq "1");
  367. my ($readingname, $doCntNo) = split (":", $readingnameX, 2); # split name from cycle number
  368. $doCntNo = 1 unless (defined ($doCntNo));
  369. #my $readingname = $attr{$name}{$oneattr};
  370. my $readingcmdname = $oneattr;
  371. $readingname =~ s/ .*//;
  372. $readingname =~ s/:.*//;
  373. # only for "r" commands
  374. if ($oneattr =~ /^r$delimiter.{1,7}$delimiter.*/)
  375. {
  376. $readings{$readingname} = $readingcmdname;
  377. $readingsCmdaddon{$readingname} = $cmdaddon;
  378. #Log3 ($name, 2, "$name GetParams $readingname");
  379. }
  380. #Log3 ($name, 4, "$name Get attr name $readingname");
  381. #Log3 ($name, 4, "$name Get attr cmd $readingcmdname");
  382. }
  383. $actGetParams .= join (",", sort keys %readings);
  384. if ($hash->{helper}{longAttributesCount} > 0) {
  385. $actGetParams .= " removeCommentFromAttributeNames";
  386. }
  387. my $ebusWritesEnabled = (defined($attr{$name}{"ebusWritesEnabled"})) ? $attr{$name}{"ebusWritesEnabled"} : 0;
  388. if ($ebusWritesEnabled) {
  389. $actGetParams .= " ".join (" ", (sort keys %getsForWriting));
  390. }
  391. # handle "read" parameters and update Reading
  392. if ($a[1] eq "reading")
  393. {
  394. my $readingname = $a[2];
  395. my $readingcmdname = $readings{$readingname};
  396. my $cmdaddon = $readingsCmdaddon{$readingname};
  397. Log3 ($name, 4, "$name Get name $readingname");
  398. Log3 ($name, 4, "$name Get cmd r $readingcmdname");
  399. my $answer = GAEBUS_doEbusCmd ($hash, "r", $readingname, $readingcmdname, "", $cmdaddon, 0);
  400. #return "$answer";
  401. return undef;
  402. }
  403. if ($a[1] eq "ebusd_find")
  404. {
  405. Log3 ($name, 4, "$name Get $a[1]");
  406. my $answer = GAEBUS_doEbusCmd ($hash, "f", "", "", "", "", 0);
  407. return $answer;
  408. }
  409. if ($a[1] eq "ebusd_info")
  410. {
  411. Log3 ($name, 4, "$name Get $a[1]");
  412. my $answer = GAEBUS_doEbusCmd ($hash, "i", "", "", "", "", 0);
  413. return $answer;
  414. }
  415. # other read commands
  416. if ($a[1] =~ /^[r]$delimiter/)
  417. {
  418. my $readingname = "";
  419. my $readingcmdname = $a[1].$delimiter.$a[2];
  420. Log3 ($name, 3, "$name get cmd v $readingcmdname");
  421. my $answer = GAEBUS_doEbusCmd ($hash, "v", $readingname, $readingcmdname, "", "", 0);
  422. #return (defined($answer ? $answer : ""));
  423. return "$answer";
  424. }
  425. # handle commands from %gets and show result from ebusd
  426. return "Unknown argument $a[1], choose one of " . $actGetParams
  427. if(!defined($gets{$a[1]}));
  428. #return "No $a[1] for dummies" if(IsDummy($varname));
  429. return "nix";
  430. }
  431. #####################################
  432. sub
  433. GAEBUS_SetState($$$$)
  434. {
  435. my ($hash, $tim, $vt, $val) = @_;
  436. return undef;
  437. }
  438. ########################
  439. sub
  440. GAEBUS_CloseDev($)
  441. {
  442. my ($hash) = @_;
  443. my $name = $hash->{NAME};
  444. my $dev = $hash->{DeviceName};
  445. return if(!$dev);
  446. if($hash->{TCPDev}) {
  447. $hash->{TCPDev}->close();
  448. delete($hash->{TCPDev});
  449. }
  450. #delete($selectlist{"$name.$dev"});
  451. #delete($readyfnlist{"$name.$dev"});
  452. delete($hash->{FD});
  453. $hash->{STATE} = "closed";
  454. readingsSingleUpdate ($hash, "state_ebus", "unknown", 1);
  455. }
  456. ########################
  457. sub
  458. GAEBUS_OpenDev($$)
  459. {
  460. my ($hash, $reopen) = @_;
  461. my $dev = $hash->{DeviceName};
  462. my $name = $hash->{NAME};
  463. my $host = $hash->{DeviceAddress};
  464. my $port = 8888;
  465. if($host =~ m/^(.+):(.+)$/) { # host[:port]
  466. $host = $1;
  467. $port = $2;
  468. }
  469. $hash->{PARTIAL} = "";
  470. Log3 $hash, 3, "GAEBUS opening $name device $host($port)"
  471. if($reopen == 0);
  472. # This part is called every time the timeout (5sec) is expired _OR_
  473. # somebody is communicating over another TCP connection. As the connect
  474. # for non-existent devices has a delay of 3 sec, we are sitting all the
  475. # time in this connect. NEXT_OPEN tries to avoid this problem.
  476. if($hash->{NEXT_OPEN} && time() < $hash->{NEXT_OPEN}) {
  477. Log3 $hash, 5, "GAEBUS NEXT_OPEN prevented opening $name device $host($port)";
  478. return;
  479. }
  480. my $conn = new IO::Socket::INET (
  481. PeerAddr => "$host",
  482. PeerPort => '8888',
  483. Proto => 'tcp',
  484. Reuse => 0,
  485. Timeout => 10
  486. );
  487. if(defined ($conn)) {
  488. delete($hash->{NEXT_OPEN});
  489. } else {
  490. Log(3, "Can't connect to $dev: $!") if(!$reopen);
  491. #$readyfnlist{"$name.$dev"} = $hash;
  492. $hash->{STATE} = "disconnected";
  493. $hash->{NEXT_OPEN} = time()+60;
  494. return "";
  495. }
  496. my $sel = new IO::Select($conn);
  497. $hash->{DevType} = 'EBUSD';
  498. $hash->{TCPDev} = $conn;
  499. $hash->{FD} = $conn->fileno();
  500. $hash->{SELECTOR} = $sel;
  501. #delete($readyfnlist{"$name.$dev"});
  502. #$selectlist{"$name.$dev"} = $hash;
  503. if($reopen) {
  504. Log3 $hash, 1, "GAEBUS $dev reappeared ($name)";
  505. } else {
  506. Log3 $hash, 3, "GAEBUS device opened ($name)";
  507. }
  508. #$hash->{STATE}="Initialized";
  509. $hash->{STATE}="Connected";
  510. DoTrigger($name, "CONNECTED") if($reopen);
  511. return 0;
  512. }
  513. sub
  514. GAEBUS_Disconnected($)
  515. {
  516. my $hash = shift;
  517. my $dev = $hash->{DeviceName};
  518. my $name = $hash->{NAME};
  519. return if(!defined($hash->{FD})); # Already deleted or RFR
  520. Log3 $hash, 1, "$dev disconnected, waiting to reappear";
  521. GAEBUS_CloseDev($hash);
  522. #$readyfnlist{"$name.$dev"} = $hash; # Start polling
  523. $hash->{STATE} = "disconnected";
  524. # Without the following sleep the open of the device causes a SIGSEGV,
  525. # and following opens block infinitely. Only a reboot helps.
  526. sleep(5);
  527. DoTrigger($name, "DISCONNECTED");
  528. }
  529. sub
  530. GAEBUS_Attr(@)
  531. {
  532. my @a = @_;
  533. my ($action, $name, $attrname, $attrval) = @a;
  534. my $hash = $defs{$name};
  535. $attrval = "" unless defined ($attrval);
  536. my $userattr = defined($attr{$name}{userattr}) ? $attr{$name}{userattr} : "";
  537. if ($action eq "del")
  538. {
  539. #my $userattr = $attr{$name}{userattr};
  540. #Log3 ($hash, 2, ">$userattr<>$attrname<");
  541. if ( " $userattr " =~ / $attrname / )
  542. {
  543. #Log3 ($hash, 2, "match");
  544. # " a" or "^a$"
  545. $userattr =~ s/ *$attrname//;
  546. if ($userattr eq "")
  547. {
  548. delete($attr{$name}{userattr});
  549. }
  550. else
  551. {
  552. $attr{$name}{userattr} = $userattr;
  553. }
  554. }
  555. # delete reading if attribute name contains $delimiter
  556. if ($attrname =~ /^.*$delimiter/) {
  557. my $reading = $attr{$name}{$attrname};
  558. $reading =~ s/ .*//;
  559. $reading =~ s/:.*//;
  560. foreach my $r (split /;/, $reading) {
  561. Log3 ($name, 3, "$name: delete reading: $reading");
  562. delete($defs{$name}{READINGS}{$reading});
  563. }
  564. }
  565. if ($attrname eq "valueFormat" and defined ($hash->{helper}{$attrname})) {
  566. delete ($hash->{helper}{$attrname});
  567. }
  568. return undef;
  569. }
  570. elsif ($action eq "set")
  571. {
  572. if ($attrname eq "valueFormat") {
  573. my $attrVal = $attrval;
  574. if( $attrVal =~ m/^{.*}$/s && $attrVal =~ m/=>/ && $attrVal !~ m/\$/ ) {
  575. my $av = eval $attrVal;
  576. if( $@ ) {
  577. Log3 ($hash->{NAME}, 3, $hash->{NAME} ."set $attrname: ". $@);
  578. } else {
  579. $attrVal = $av if( ref($av) eq "HASH" );
  580. }
  581. $hash->{helper}{$attrname} = $attrVal;
  582. foreach my $key (keys %{ $hash->{helper}{$attrname} }) {
  583. Log3 ($hash->{NAME}, 4, $hash->{NAME} ." $key ".$hash->{helper}{$attrname}{$key});
  584. }
  585. #return "set HERE??";
  586. } else {
  587. # if valueFormat is not verified sucessfully ... the helper is deleted (=not used)
  588. delete $hash->{helper}{$attrname};
  589. }
  590. return undef;
  591. }
  592. if ( " $userattr " =~ / $attrname / )
  593. {
  594. # this is an attribute form "userattr"
  595. if (!defined $attr{$name}{$attrname})
  596. {
  597. # attribute is not yet defined
  598. if ( $attrname =~ /$delimiter/ )
  599. {
  600. my ($io,$class,$var,$comment) = split ($delimiter, $attrname, 4);
  601. $hash->{helper}{longAttributesCount}++ if (defined($comment));
  602. #Log3 ($hash->{NAME}, 1, "$hash->{NAME} helper longAttributesCount set to ".$hash->{helper}{longAttributesCount});
  603. }
  604. }
  605. if (defined $attr{$name}{$attrname})
  606. {
  607. my $oldreading = $attr{$name}{$attrname};
  608. $oldreading =~ s/ .*//;
  609. $oldreading =~ s/:.*//;
  610. my $newreading = $attrval;
  611. $newreading =~ s/ .*//;
  612. $newreading =~ s/:.*//;
  613. my @or = split /;/, $oldreading;
  614. my @nr = split /;/, $newreading;
  615. for (my $i; $i <= $#or; $i++)
  616. {
  617. if ($or[$i] ne $nr[$i])
  618. {
  619. #Log3 ($name, 2, "$name: adjust reading: $or[$i]");
  620. if (defined($defs{$name}{READINGS}{$or[$i]}))
  621. {
  622. if (defined ($nr[$i] and $nr[$i] ne "dummy" ))
  623. {
  624. unless ($nr[$i] =~ /^1*$/) # matches "1" or ""
  625. {
  626. #Log3 ($name, 2, "$name: change attribute $attrname ($or[$i] -> $nr[$i])");
  627. $defs{$name}{READINGS}{$nr[$i]}{VAL} = $defs{$name}{READINGS}{$or[$i]}{VAL};
  628. $defs{$name}{READINGS}{$nr[$i]}{TIME} = $defs{$name}{READINGS}{$or[$i]}{TIME};
  629. }
  630. }
  631. delete($defs{$name}{READINGS}{$or[$i]});
  632. }
  633. }
  634. }
  635. }
  636. }
  637. }
  638. Log3 (undef, 2, "called GAEBUS_Attr($a[0],$a[1],$a[2],<$a[3]>)");
  639. return undef;
  640. }
  641. sub
  642. GAEBUS_State($)
  643. {
  644. my $hash = shift;
  645. my $name = $hash->{NAME};
  646. my $state = "";
  647. my $actMessage = "";
  648. if (($hash->{STATE} eq "Connected") and ($hash->{TCPDev}->connected()) )
  649. {
  650. my $timeout = 10;
  651. syswrite ($hash->{TCPDev}, "state\n");
  652. if ($hash->{SELECTOR}->can_read($timeout))
  653. {
  654. sysread ($hash->{TCPDev}, $actMessage, 4096);
  655. $actMessage =~ s/\n$/ /g;
  656. $actMessage =~ s/ {1,}$//;
  657. if ($actMessage =~ /^signal acquired/) {
  658. $state = "ok";
  659. }
  660. }
  661. else
  662. {
  663. $state = "no answer";
  664. Log3 ($name, 2, "$name state $state ($actMessage)");
  665. }
  666. }
  667. return ($state, $actMessage);
  668. }
  669. sub
  670. GAEBUS_doEbusCmd($$$$$$$)
  671. {
  672. my $hash = shift;
  673. my $action = shift; # "r" = get reading, "v" = verbose mode,
  674. # "w" = write to ebus, "f" = execute find to read in config, "i" = execute info
  675. # "h" = read with command specified in hex
  676. my $readingname = shift;
  677. my $readingcmdname = shift;
  678. my $writeValues = shift;
  679. my $cmdaddon = shift;
  680. my $inBlockingCall = shift;
  681. my $actMessage = "";
  682. my $name = $hash->{NAME};
  683. if (($hash->{STATE} ne "Connected") or (!$hash->{TCPDev}->connected()) )
  684. {
  685. Log3 ($name, 2, "$name device closed. Try to reopen");
  686. GAEBUS_CloseDev($hash);
  687. GAEBUS_OpenDev($hash,0);
  688. if ($hash->{STATE} ne "Connected") {
  689. if ($inBlockingCall) {
  690. return "";
  691. }
  692. else {
  693. return undef;
  694. }
  695. }
  696. }
  697. #my $timeout = 1.8;
  698. my $timeout = 15.0;
  699. $timeout = 10.0 if ($action eq "v");
  700. $timeout = 10.0 if ($action eq "w");
  701. my ($io,$class,$var,$comment) = split ($delimiter, $readingcmdname, 4);
  702. my $cmd = "";
  703. if ($action eq "w") {
  704. $class =~ s/install/#install/;
  705. $cmd = "$io ";
  706. $cmd .= "-c $class " if ($class ne "");
  707. $cmd .= "$var ";
  708. $cmd .= "$writeValues";
  709. } elsif ($action eq "f") {
  710. $cmd = "find -f -r -w";
  711. } elsif ($action eq "i") {
  712. $cmd = "info";
  713. } elsif ($action eq "r") {
  714. my $force = " -f ";
  715. $force = "" if ($io eq "h");
  716. if ($cmdaddon =~ /\+f/) {
  717. $force = "";
  718. $cmdaddon =~ s/\+f//;
  719. }
  720. $cmd = "$io ";
  721. #$cmd .= " -f " if ($io ne "h");
  722. $cmd .= "$force";
  723. $cmd .= "-c $class " if ($class ne "");
  724. $cmd .= "$var ";
  725. $cmd .= "$cmdaddon";
  726. } elsif ($action eq "v") {
  727. $cmd = "$io ";
  728. $cmd .= " -f " if ($io ne "h");
  729. $cmd .= "-v ";
  730. $cmd .= "-c $class " if ($class ne "");
  731. $cmd .= "$var ";
  732. #$cmd =~ s/^h /r /; # obsolete
  733. } elsif ($action eq "h") {
  734. $cmd = "hex $writeValues";
  735. }
  736. Log3 ($name, 3, "$name execute $cmd");
  737. if ($hash->{SELECTOR}->can_read(0.1))
  738. {
  739. sysread ($hash->{TCPDev}, $actMessage, 4096);
  740. $actMessage =~ s/\n//g;
  741. Log3 ($name, 2, "$name old answer $actMessage\n");
  742. $actMessage = "";
  743. }
  744. syswrite ($hash->{TCPDev}, $cmd."\n");
  745. if (0 and $hash->{SELECTOR}->can_read($timeout))
  746. {
  747. #Log3 ($name, 2, "$name try to read");
  748. sysread ($hash->{TCPDev}, $actMessage, 4096);
  749. $actMessage =~ s/\n//g;
  750. #$actMessage =~ s/;/ /g;
  751. }
  752. if ($hash->{SELECTOR}->can_read($timeout)) {
  753. my $rbuffer = "";
  754. while ($hash->{SELECTOR}->can_read(0.1) and sysread ($hash->{TCPDev}, $rbuffer, 4096)) {
  755. $actMessage .= $rbuffer;
  756. if ( $rbuffer =~ /\n\n$/ )
  757. {
  758. #Log3 ($name, 3, "$name answer terminated by empty line");
  759. last;
  760. }
  761. }
  762. #$actMessage =~ s/\n//g;
  763. # handle usage messages
  764. if ($actMessage =~ /^usage:/)
  765. {
  766. $actMessage = "usage: syntay error";
  767. }
  768. #Log3 ($name, 3, "$name answer $action $readingname $actMessage");
  769. }
  770. else
  771. {
  772. #return "timeout reading answer for ($readingname) $cmd";
  773. Log3 ($name, 2, "$name: timeout reading answer for $cmd");
  774. return "";
  775. }
  776. if ($action eq "f")
  777. {
  778. %sets = ( "reopen" => [] );
  779. %gets = ( "ebusd_find" => [], "ebusd_info" => [] );
  780. %setsForWriting = ();
  781. %getsForWriting = ( "ebusd_hex" => [] );
  782. my $cnt = 0;
  783. foreach my $line (split /\n/, $actMessage) {
  784. $cnt++;
  785. $line =~ s/ /_/g; # no blanks in names and comments
  786. $line =~ s/$delimiter/_/g; # clean up the delimiter within the text
  787. Log3 ($name, 4, "$name $line");
  788. #my ($io,$class,$var) = split (",", $line, 3);
  789. my ($io, $class, $var, $comment, @params) = split (",", $line, 5);
  790. $io =~ s/[0-9]//g;
  791. # drop "memory"
  792. next if ($class eq "memory");
  793. #next if ($class eq "scan");
  794. next if ($class =~ /^scan/);
  795. push @{$sets{$io.$delimiter.$class}}, $var.$delimiter.$comment if ($io eq "r" or $io eq "h");
  796. push @{$setsForWriting{$io.$delimiter.$class}}, $var.$delimiter.$comment if ($io eq "w" or $io eq "wi");
  797. push @{$gets{$io.$delimiter.$class}}, $var.$delimiter.$comment if ($io eq "r" or $io eq "h");
  798. }
  799. GAEBUS_initParams($hash);
  800. Log3 ($name, 3, "$name find done.");
  801. return "$cnt definitions processed";
  802. }
  803. if ($action eq "i" or $action eq "h")
  804. {
  805. #Log3 ($name, 3, "$name info done.");
  806. return "$actMessage";
  807. }
  808. $actMessage =~ s/\n//g;
  809. $actMessage =~ s/\|//g;
  810. Log3 ($name, 3, "$name answer $action $readingname $actMessage");
  811. my @values = split /;/, $actMessage;
  812. my @targetreading = defined ($readingname) ? split /;/, $readingname : ();
  813. if ($inBlockingCall)
  814. {
  815. $actMessage = "";
  816. # for (my $i=0; $i <= $#targetreading; $i++)
  817. # {
  818. # next if ($targetreading[$i] eq "dummy");
  819. # my $v = defined($values[$i]) ? $values[$i] : "";
  820. #
  821. # $v = GAEBUS_valueFormat ($hash, $targetreading[$i], $v);
  822. # $actMessage .= $targetreading[$i]."|".$v."|";
  823. # }
  824. foreach my $r (@targetreading)
  825. {
  826. next if ($r eq "dummy");
  827. my $v = GAEBUS_valueFormat ($hash, $r, \@values);
  828. shift @values;
  829. $actMessage .= $r."|".$v."|";
  830. }
  831. $actMessage =~ s/\|$//;
  832. # readings will be updated in main fhem process
  833. return $actMessage;
  834. }
  835. if ($action eq "r")
  836. {
  837. readingsBeginUpdate ($hash);
  838. # for (my $i=0; $i <= $#targetreading; $i++)
  839. # {
  840. # next if ($targetreading[$i] eq "dummy");
  841. # my $v = defined($values[$i]) ? $values[$i] : "";
  842. #
  843. # $v = GAEBUS_valueFormat ($hash, $targetreading[$i], $v);
  844. #
  845. # readingsBulkUpdate ($hash, $targetreading[$i], $v);
  846. # }
  847. foreach my $r (@targetreading)
  848. {
  849. next if ($r eq "dummy");
  850. my $v = GAEBUS_valueFormat ($hash, $r, \@values);
  851. shift @values;
  852. readingsBulkUpdate ($hash, $r, $v);
  853. }
  854. readingsEndUpdate($hash, 1);
  855. }
  856. #if ($inBlockingCall) {
  857. # $actMessage = $readingname."|".$actMessage;
  858. #}
  859. #else {
  860. #
  861. # if ($action eq "r") {
  862. # if (defined ($readingname)) {
  863. # # BlockingCall changes
  864. # readingsSingleUpdate ($hash, $readingname, "$actMessage", 1);
  865. # }
  866. # }
  867. #}
  868. return $actMessage;
  869. }
  870. sub
  871. GAEBUS_GetUpdates($)
  872. {
  873. my ($hash) = @_;
  874. my $name = $hash->{NAME};
  875. if (defined($attr{$name}{disable}) and ($attr{$name}{disable} == 1)) {
  876. Log3 $hash, 4, "$name GetUpdates2 is disabled";
  877. InternalTimer(gettimeofday()+$hash->{Interval}, "GAEBUS_GetUpdates", $hash, 0);
  878. return;
  879. } else {
  880. Log3 $hash, 4, "$name start GetUpdates2";
  881. }
  882. $hash->{UpdateCnt} = $hash->{UpdateCnt} + 1;
  883. $hash->{helper}{RUNNING_PID} = BlockingCall("GAEBUS_GetUpdatesDoit", $name, "GAEBUS_GetUpdatesDone", 120, "GAEBUS_GetUpdatesAborted", $hash)
  884. unless(exists($hash->{helper}{RUNNING_PID}));
  885. }
  886. sub
  887. GAEBUS_GetUpdatesDoit($)
  888. {
  889. my ($string) = (@_);
  890. #my ($name, $nochwas) = split ("|", $string);
  891. my ($name) = $string;
  892. my ($hash) = $defs{$name};
  893. my $readingname = "";
  894. my $tryOpenCnt = 2; # no of tries to open the device, before giving up
  895. my $readingsToUpdate = "";
  896. # don't use socket inherited from fhem by BlockingCall.pm
  897. delete($hash->{TCPDev});
  898. $hash->{STATE} = "pleaseReconnect";
  899. my $ret = GAEBUS_OpenDev($hash, 0);
  900. if (($hash->{STATE} ne "Connected") or (!$hash->{TCPDev}->connected()) )
  901. {
  902. return "$name";
  903. }
  904. # syncronize with ebusd
  905. my ($state, $actMessage) = GAEBUS_State($hash);
  906. if ($state ne "ok") {
  907. Log3 ($name, 2, "$name: ebusd no connection or signal state($state)");
  908. return "$name";
  909. }
  910. Log3 ($name, 5, "$name: ebusd state($actMessage)");
  911. $actMessage =~ s/,.*//;
  912. $readingsToUpdate .= "|state_ebus|".$actMessage;
  913. foreach my $oneattr (keys %{$attr{$name}})
  914. {
  915. # only for "r" commands
  916. if ($oneattr =~ /^r$delimiter.{1,7}$delimiter.*/)
  917. {
  918. my ($readingnameX, $cmdaddon) = split (" ", $attr{$name}{$oneattr}, 2);
  919. $cmdaddon = "" unless (defined ($cmdaddon));
  920. next unless defined ($readingnameX);
  921. next if ($readingnameX =~ /^\s*$/);
  922. next if ($readingnameX eq "1");
  923. my ($readingname, $doCntNo) = split (":", $readingnameX, 2); # split name from cycle number
  924. $doCntNo = 1 unless (defined ($doCntNo));
  925. Log3 ($name, 5, "$name GetUpdates: $readingname:$doCntNo");
  926. #Log3 ($name, 2, "$name check modulo ".$hash->{UpdateCnt}." mod $doCntNo -> ".($hash->{UpdateCnt} % $doCntNo));
  927. if (($hash->{UpdateCnt} % $doCntNo) == 0)
  928. {
  929. $readingsToUpdate .= "|".GAEBUS_doEbusCmd ($hash, "r", $readingname, $oneattr, "", $cmdaddon, 1);
  930. }
  931. # limit number of reopens if ebusd cannot be reached
  932. if (($hash->{STATE} ne "Connected") or (!$hash->{TCPDev}->connected()) )
  933. {
  934. if (--$tryOpenCnt <= 0)
  935. {
  936. Log3 ($name, 2, "$name: not connected, stop GetUpdates loop");
  937. last;
  938. }
  939. }
  940. }
  941. }
  942. # returnvalue for BlockingCall ... done routine
  943. return $name.$readingsToUpdate;
  944. }
  945. sub
  946. GAEBUS_GetUpdatesDone($)
  947. {
  948. my ($string) = @_;
  949. return unless(defined($string));
  950. my @a = split("\\|",$string);
  951. my ($hash) = $defs{$a[0]};
  952. my $name = $hash->{NAME};
  953. delete($hash->{helper}{RUNNING_PID});
  954. #Log3 ($name, 2, "$name: GetUpdatesDoit returned $string");
  955. readingsBeginUpdate ($hash);
  956. for (my $i = 1; $i < $#a; $i = $i + 2)
  957. {
  958. #my $v = GAEBUS_valueFormat ($hash, $$a[$i], $a[$i+1]);
  959. #readingsBulkUpdate ($hash, $a[$i], $v);
  960. readingsBulkUpdate ($hash, $a[$i], $a[$i+1]);
  961. }
  962. readingsEndUpdate($hash, 1);
  963. #HERE
  964. RemoveInternalTimer($hash);
  965. InternalTimer(gettimeofday()+$hash->{Interval}, "GAEBUS_GetUpdates", $hash, 0);
  966. }
  967. sub
  968. GAEBUS_GetUpdatesAborted($)
  969. {
  970. my ($hash) = @_;
  971. delete($hash->{helper}{RUNNING_PID});
  972. Log3 $hash->{NAME}, 3, "BlockingCall for ".$hash->{NAME}." was aborted";
  973. RemoveInternalTimer($hash);
  974. InternalTimer(gettimeofday()+$hash->{Interval}, "GAEBUS_GetUpdates", $hash, 0);
  975. }
  976. sub
  977. GAEBUS_valueFormat(@)
  978. {
  979. my ($hash, $reading, $values_ref) = @_;
  980. if (ref($hash->{helper}{valueFormat}) eq 'HASH' and defined ($reading))
  981. {
  982. if (exists($hash->{helper}{valueFormat}->{$reading})) {
  983. my $vf = $hash->{helper}{valueFormat}->{$reading};
  984. return sprintf ("$vf", @{$values_ref});
  985. }
  986. }
  987. return (defined(${$values_ref}[0]) ? ${$values_ref}[0] : "");
  988. }
  989. 1;
  990. =pod
  991. =item device
  992. =item summary device to communicate with ebusd (a communication bus for heating systems).
  993. =begin html
  994. <a name="GAEBUS"></a>
  995. <h3>GAEBUS</h3>
  996. <ul>
  997. <table>
  998. <tr><td>
  999. The GAEBUS module is the representation of a Ebus connector in FHEM.
  1000. The GAEBUS module is designed to connect to ebusd (ebus daemon) via a socket connection (default is port 8888) <br>
  1001. </td></tr>
  1002. </table>
  1003. <a name="GAEBUS"></a>
  1004. <b>Define</b>
  1005. <ul>
  1006. <code>define &lt;name&gt; GAEBUS &lt;device-addr&gt;[:&lt;port&gt;] [&lt;interval&gt;];</code> <br>
  1007. <br>
  1008. &lt;device-addr&gt;[:&lt;port&gt;] specifies the host:port of the ebusd device. E.g.
  1009. 192.168.0.244:8888 or servername:8888. When using the standard port, the port can be omitted.
  1010. <br><br>
  1011. Example:<br><br>
  1012. <code>define ebus1 GAEBUS localhost 300</code>
  1013. <br><br>
  1014. When initializing the object no device specific commands are known. Please call "get ebusd_find" to read in supported commands from ebusd.<br>
  1015. After fresh restart of ebusd it may take a while until all supported devices and their commands are visible.<br>
  1016. </ul>
  1017. <br>
  1018. <a name="GAEBUS"></a>
  1019. <b>Set </b>
  1020. <ul>
  1021. <li>reopen<br>
  1022. Will close and open the socket connection.
  1023. </li><br>
  1024. <li>[r]~&lt;class&gt; &lt;variable-name&gt;~&lt;comment&gt;<br>
  1025. Will define a attribute with the following syntax:<br>
  1026. [r]~&lt;class&gt;~&lt;variable-name&gt;~<br>
  1027. Valid combinations are read from ebusd (using "get ebusd_find") and are selectable.<br>
  1028. Values from the attributes will be used as the name for the reading which are read from ebusd in the interval specified.<br>
  1029. The content of &lt;comment$gt; is dropped and not added to the attribute name.<br>
  1030. </li><br>
  1031. <li>[w]~&lt;class&gt; &lt;variable-name&gt;~&lt;comment&gt;<br>
  1032. Will define a attribute with the following syntax:<br>
  1033. [w]~&lt;class&gt;~&lt;variable-name&gt;<br>
  1034. They will only appear if the attribute "ebusWritesEnabled" is set to "1"<br>
  1035. Valid combinations are read from ebusd (using "get ebusd_find") and are selectable.<br>
  1036. Values from the attributes will be used for set commands to modify parameters for ebus devices<br>
  1037. Hint: if the values for the attributes are prefixed by "set-" then all possible parameters will be listed in one block<br>
  1038. The content of &lt;comment$gt; is dropped and not added to the attribute name.<br>
  1039. </li><br>
  1040. </ul>
  1041. <a name="GAEBUS"></a>
  1042. <b>Get</b>
  1043. <ul>
  1044. <li>ebusd_info<br>
  1045. Execude <i>info</i> command on ebusd and show result.
  1046. </li><br>
  1047. <li>ebusd_find<br>
  1048. Execude <i>find</i> command on ebusd. Result will be used to display supported "set" and "get" commands.
  1049. </li><br>
  1050. <li>ebusd_hex<br>
  1051. Will pass the input value to the "hex" command of ebusd. See "ebusctl help hex" for valid parameters.<br>
  1052. This command is only available if "ebusWritesEnabled" is set to '1'.<br>
  1053. </li><br>
  1054. <li>reading &lt;reading-name&gt<br>
  1055. Will read the actual value form ebusd and update the reading.
  1056. </li><br>
  1057. <li>[r]~&lt;class&gt; &lt;variable-name&gt;~&lt;comment&gt;<br>
  1058. Will read this variable from the ebusd and show the result as a popup.<br>
  1059. Valid combinations are read from ebusd (using "get ebusd_find") and are selectable.<br>
  1060. </li><br>
  1061. <li>removeCommentFromAttributeNames<br>
  1062. This will migrate the former used attribute names of format "[rw]~&lt;class&gt; &lt;variable-name&gt;~&lt;comment&gt;"
  1063. into the format "[rw]~&lt;class&gt; &lt;variable-name&gt;".<br>
  1064. It is only available if such attributes are defined.<br>
  1065. </li><br>
  1066. </ul>
  1067. <br>
  1068. <a name="GAEBUS"></a>
  1069. <b>Attributes</b>
  1070. <ul>
  1071. <li><a href="#do_not_notify">do_not_notify</a></li><br>
  1072. <li><a href="#attrdummy">disable</a></li><br>
  1073. <li><a href="#attrdummy">dummy</a></li><br>
  1074. <li><a href="#showtime">showtime</a></li><br>
  1075. <li><a href="#loglevel">loglevel</a></li><br>
  1076. <li>ebusWritesEnabled 0,1<br>
  1077. disable (0) or enable (1) that commands can be send to ebus devices<br>
  1078. See also description for Set and Get<br>
  1079. If Attribute is missing, default value is 0 (disable writes)<br>
  1080. </li><br>
  1081. <li>Attributes of the format<br>
  1082. <code>[r]~&lt;class&gt;~&lt;variable-name&gt;</code><br>
  1083. define variables that can be retrieved from the ebusd.
  1084. They will appear when they are defined by a "set" command as described above.<br>
  1085. The value assigned to an attribute specifies the name of the reading for this variable.<br>
  1086. If ebusd returns a list of semicolon separated values then several semicolon separated readings can be defined.<br>
  1087. "dummy" is a placeholder for a reading that will be ignored. (e.g.: temperature;dummy;pressure).<br>
  1088. The name of the reading can be suffixed by "&lt;:number&gt;" which is a multiplicator for
  1089. the evaluation within the specified interval. (eg. OutsideTemp:3 will evaluate this reading every 3-th cycle)<br>
  1090. All text followed the reading seperated by a blank is given as an additional parameter to ebusd.
  1091. This can be used to request a single value if more than one is retrieved from ebus.<br>
  1092. If "+f" is given as an additional parameter this will remove the "-f" option from the ebusd request. This will return the value stored in ebusd instead of requesting it freshly.<br>
  1093. </li><br>
  1094. <li>Attributes of the format<br>
  1095. <code>[w]~&lt;class&gt;~&lt;variable-name&gt;</code><br>
  1096. define parameters that can be changed on ebus devices (using the write command from ebusctl)
  1097. They will appear when they are defined by a "set" command as described above.<br>
  1098. The value assigned to an attribute specifies the name that will be used in set to change a parameter for a ebus device.<br>
  1099. </li><br>
  1100. <li>valueFormat<br>
  1101. Defines a map to format values within GAEBUS.<br>
  1102. All readings can be formated using syntax of sprinf.
  1103. Values returned from ebusd are spearated by ";" and split before valueFormat is processed. This means more than one of the return values can be assigned to one reading.
  1104. <br>
  1105. Example: { "temperature" => "%0.2f"; "from-to" => "%s-%s" }<br>
  1106. </li><br>
  1107. </ul>
  1108. <br>
  1109. </ul>
  1110. =end html
  1111. =cut