98_GAEBUS.pm 39 KB

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