93_FHEM2FHEM.pm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. ##############################################
  2. # $Id: 93_FHEM2FHEM.pm 15006 2017-09-05 09:37:33Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use Time::HiRes qw(gettimeofday);
  7. use HttpUtils;
  8. sub FHEM2FHEM_Read($);
  9. sub FHEM2FHEM_Ready($);
  10. sub FHEM2FHEM_OpenDev($$);
  11. sub FHEM2FHEM_CloseDev($);
  12. sub FHEM2FHEM_Disconnected($);
  13. sub FHEM2FHEM_Define($$);
  14. sub FHEM2FHEM_Undef($$);
  15. sub
  16. FHEM2FHEM_Initialize($)
  17. {
  18. my ($hash) = @_;
  19. # Provider
  20. $hash->{ReadFn} = "FHEM2FHEM_Read";
  21. $hash->{WriteFn} = "FHEM2FHEM_Write";
  22. $hash->{ReadyFn} = "FHEM2FHEM_Ready";
  23. $hash->{SetFn} = "FHEM2FHEM_Set";
  24. $hash->{AttrFn} = "FHEM2FHEM_Attr";
  25. $hash->{noRawInform} = 1;
  26. # Normal devices
  27. $hash->{DefFn} = "FHEM2FHEM_Define";
  28. $hash->{UndefFn} = "FHEM2FHEM_Undef";
  29. $hash->{AttrList}= "addStateEvent:1,0 dummy:1,0 disable:0,1 ".
  30. "disabledForIntervals eventOnly:1,0 excludeEvents";
  31. }
  32. #####################################
  33. sub
  34. FHEM2FHEM_Define($$)
  35. {
  36. my ($hash, $def) = @_;
  37. my @a = split("[ \t][ \t]*", $def);
  38. if(@a < 4 || @a > 5 || !($a[3] =~ m/^(LOG|RAW):(.*)$/)) {
  39. my $msg = "wrong syntax: define <name> FHEM2FHEM host[:port][:SSL] ".
  40. "[LOG:regexp|RAW:device] {portpasswort}";
  41. Log3 $hash, 2, $msg;
  42. return $msg;
  43. }
  44. $hash->{informType} = $1;
  45. if($1 eq "LOG") {
  46. $hash->{regexp} = $2;
  47. } else {
  48. my $rdev = $2;
  49. my $iodev = $defs{$rdev};
  50. return "Undefined local device $rdev" if(!$iodev);
  51. $hash->{rawDevice} = $rdev;
  52. $hash->{Clients} = $iodev->{Clients};
  53. $hash->{Clients} = $modules{$iodev->{TYPE}}{Clients}
  54. if(!$hash->{Clients});
  55. }
  56. my $dev = $a[2];
  57. if($dev =~ m/^(.*):SSL$/) {
  58. $dev = $1;
  59. $hash->{SSL} = 1;
  60. }
  61. if($dev !~ m/^.+:[0-9]+$/) { # host:port
  62. $dev = "$dev:7072";
  63. $hash->{Host} = $dev;
  64. }
  65. if($hash->{OLDDEF} && $hash->{OLDDEF} =~ m/^([^ \t]+)/) {; # Forum #30242
  66. delete($readyfnlist{"$hash->{NAME}.$1"});
  67. }
  68. $hash->{Host} = $dev;
  69. $hash->{portpassword} = $a[4] if(@a == 5);
  70. FHEM2FHEM_CloseDev($hash); # Modify...
  71. return FHEM2FHEM_OpenDev($hash, 0);
  72. }
  73. #####################################
  74. sub
  75. FHEM2FHEM_Undef($$)
  76. {
  77. my ($hash, $arg) = @_;
  78. FHEM2FHEM_CloseDev($hash);
  79. return undef;
  80. }
  81. sub
  82. FHEM2FHEM_Write($$)
  83. {
  84. my ($hash,$fn,$msg) = @_;
  85. my $dev = $hash->{Host};
  86. if(!$hash->{TCPDev2}) {
  87. my $conn;
  88. if($hash->{SSL}) {
  89. $conn = IO::Socket::SSL->new(PeerAddr => $dev);
  90. } else {
  91. $conn = IO::Socket::INET->new(PeerAddr => $dev);
  92. }
  93. return if(!$conn); # Hopefuly it is reported elsewhere
  94. $hash->{TCPDev2} = $conn;
  95. syswrite($hash->{TCPDev2}, $hash->{portpassword} . "\n")
  96. if($hash->{portpassword});
  97. }
  98. my $rdev = $hash->{rawDevice};
  99. syswrite($hash->{TCPDev2}, "iowrite $rdev $fn $msg\n");
  100. }
  101. #####################################
  102. # called from the global loop, when the select for hash->{FD} reports data
  103. sub
  104. FHEM2FHEM_Read($)
  105. {
  106. my ($hash) = @_;
  107. my $buf = FHEM2FHEM_SimpleRead($hash);
  108. my $name = $hash->{NAME};
  109. ###########
  110. # Lets' try again: Some drivers return len(0) on the first read...
  111. if(defined($buf) && length($buf) == 0) {
  112. $buf = FHEM2FHEM_SimpleRead($hash);
  113. }
  114. if(!defined($buf) || length($buf) == 0) {
  115. FHEM2FHEM_Disconnected($hash);
  116. return;
  117. }
  118. return if(IsDisabled($name));
  119. my $excl = AttrVal($name, "excludeEvents", undef);
  120. my $data = $hash->{PARTIAL};
  121. #Log3 $hash, 5, "FHEM2FHEM/RAW: $data/$buf";
  122. $data .= $buf;
  123. while($data =~ m/\n/) {
  124. my $rmsg;
  125. ($rmsg,$data) = split("\n", $data, 2);
  126. $rmsg =~ s/\r//;
  127. if($hash->{informType} eq "LOG") {
  128. my ($type, $rname, $msg) = split(" ", $rmsg, 3);
  129. next if(!defined($msg)); # Bogus data
  130. my $re = $hash->{regexp};
  131. next if($re && !($rname =~ m/^$re$/ || "$rname:$msg" =~ m/^$re$/));
  132. next if($excl && ($rname =~ m/^$excl$/ || "$rname:$msg" =~ m/^$excl$/));
  133. Log3 $name, 4, "$rname: $rmsg";
  134. if(!$defs{$rname}) {
  135. $defs{$rname}{NAME} = $rname;
  136. $defs{$rname}{TYPE} = $type;
  137. $defs{$rname}{STATE} = $msg;
  138. $defs{$rname}{FAKEDEVICE} = 1; # Avoid set/attr/delete/etc in notify
  139. $defs{$rname}{TEMPORARY} = 1; # Do not save it
  140. DoTrigger($rname, $msg);
  141. delete($defs{$rname});
  142. delete($attr{$rname}); # Forum #73490
  143. } else {
  144. if(AttrVal($name,"eventOnly",0)) {
  145. DoTrigger($rname, $msg);
  146. } else {
  147. if($msg =~ m/^([^:]*): (.*)$/) {
  148. readingsSingleUpdate($defs{$rname}, $1, $2, 1);
  149. } else {
  150. readingsSingleUpdate($defs{$rname}, "state", $msg, 1);
  151. }
  152. }
  153. }
  154. } else { # RAW
  155. my ($type, $rname, $msg) = split(" ", $rmsg, 3);
  156. my $rdev = $hash->{rawDevice};
  157. next if($rname ne $rdev);
  158. Log3 $name, 4, "$name: $rmsg";
  159. Dispatch($defs{$rdev}, $msg, undef);
  160. }
  161. }
  162. $hash->{PARTIAL} = $data;
  163. }
  164. #####################################
  165. sub
  166. FHEM2FHEM_Ready($)
  167. {
  168. my ($hash) = @_;
  169. return FHEM2FHEM_OpenDev($hash, 1);
  170. }
  171. ########################
  172. sub
  173. FHEM2FHEM_CloseDev($)
  174. {
  175. my ($hash) = @_;
  176. my $name = $hash->{NAME};
  177. my $dev = $hash->{Host};
  178. return if(!$dev);
  179. $hash->{TCPDev}->close() if($hash->{TCPDev});
  180. $hash->{TCPDev2}->close() if($hash->{TCPDev2});
  181. delete($hash->{NEXT_OPEN});
  182. delete($hash->{TCPDev});
  183. delete($hash->{TCPDev2});
  184. delete($selectlist{"$name.$dev"});
  185. delete($readyfnlist{"$name.$dev"});
  186. delete($hash->{FD});
  187. }
  188. ########################
  189. sub
  190. FHEM2FHEM_OpenDev($$)
  191. {
  192. my ($hash, $reopen) = @_;
  193. my $dev = $hash->{Host};
  194. my $name = $hash->{NAME};
  195. $hash->{PARTIAL} = "";
  196. Log3 $name, 3, "FHEM2FHEM opening $name at $dev"
  197. if(!$reopen);
  198. return if($hash->{NEXT_OPEN} && time() <= $hash->{NEXT_OPEN});
  199. return if(IsDisabled($name));
  200. my $doTailWork = sub($$$) {
  201. my ($h, $err, undef) = @_;
  202. if($err) {
  203. Log3($name, 3, "Can't connect to $dev: $!") if(!$reopen);
  204. $readyfnlist{"$name.$dev"} = $hash;
  205. $hash->{STATE} = "disconnected";
  206. $hash->{NEXT_OPEN} = time()+60;
  207. return;
  208. }
  209. my $conn = $h->{conn};
  210. delete($hash->{NEXT_OPEN});
  211. $conn->setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1);
  212. $hash->{TCPDev} = $conn;
  213. $hash->{FD} = $conn->fileno();
  214. delete($readyfnlist{"$name.$dev"});
  215. $selectlist{"$name.$dev"} = $hash;
  216. if($reopen) {
  217. Log3 $name, 1, "FHEM2FHEM $dev reappeared ($name)";
  218. } else {
  219. Log3 $name, 3, "FHEM2FHEM device opened ($name)";
  220. }
  221. $hash->{STATE}= "connected";
  222. DoTrigger($name, "CONNECTED") if($reopen);
  223. syswrite($hash->{TCPDev}, $hash->{portpassword} . "\n")
  224. if($hash->{portpassword});
  225. my $type = AttrVal($hash->{NAME},"addStateEvent",0) ? "onWithState" : "on";
  226. my $msg = $hash->{informType} eq "LOG" ?
  227. "inform $type $hash->{regexp}" : "inform raw";
  228. syswrite($hash->{TCPDev}, $msg . "\n");
  229. };
  230. return HttpUtils_Connect({ # Nonblocking
  231. url => $hash->{SSL} ? "https://$dev/" : "http://$dev/",
  232. NAME => $name,
  233. noConn2 => 1,
  234. callback=> $doTailWork
  235. });
  236. }
  237. sub
  238. FHEM2FHEM_Disconnected($)
  239. {
  240. my $hash = shift;
  241. my $dev = $hash->{Host};
  242. my $name = $hash->{NAME};
  243. return if(!defined($hash->{FD})); # Already deleted
  244. Log3 $name, 1, "$dev disconnected, waiting to reappear";
  245. FHEM2FHEM_CloseDev($hash);
  246. $readyfnlist{"$name.$dev"} = $hash; # Start polling
  247. $hash->{STATE} = "disconnected";
  248. return if(IsDisabled($name)); #Forum #39386
  249. # Without the following sleep the open of the device causes a SIGSEGV,
  250. # and following opens block infinitely. Only a reboot helps.
  251. sleep(5);
  252. DoTrigger($name, "DISCONNECTED");
  253. }
  254. ########################
  255. sub
  256. FHEM2FHEM_SimpleRead($)
  257. {
  258. my ($hash) = @_;
  259. my $buf;
  260. if(!defined(sysread($hash->{TCPDev}, $buf, 256))) {
  261. FHEM2FHEM_Disconnected($hash);
  262. return undef;
  263. }
  264. return $buf;
  265. }
  266. sub
  267. FHEM2FHEM_Set($@)
  268. {
  269. my ($hash, @a) = @_;
  270. return "set needs at least one parameter" if(@a < 2);
  271. return "Unknown argument $a[1], choose one of reopen:noArg"
  272. if($a[1] ne "reopen");
  273. FHEM2FHEM_CloseDev($hash);
  274. FHEM2FHEM_OpenDev($hash, 0);
  275. return undef;
  276. }
  277. sub
  278. FHEM2FHEM_Attr(@)
  279. {
  280. my ($type, $devName, $attrName, @param) = @_;
  281. my $hash = $defs{$devName};
  282. return undef if($attrName ne "addStateEvent");
  283. $attr{$devName}{$attrName} = 1;
  284. FHEM2FHEM_CloseDev($hash);
  285. FHEM2FHEM_OpenDev($hash, 1);
  286. return undef;
  287. }
  288. 1;
  289. =pod
  290. =item helper
  291. =item summary connect two FHEM instances
  292. =item summary_DE verbindet zwei FHEM Installationen
  293. =begin html
  294. <a name="FHEM2FHEM"></a>
  295. <h3>FHEM2FHEM</h3>
  296. <ul>
  297. FHEM2FHEM is a helper module to connect separate FHEM installations.
  298. <br><br>
  299. <a name="FHEM2FHEMdefine"></a>
  300. <b>Define</b>
  301. <ul>
  302. <code>define &lt;name&gt; FHEM2FHEM &lt;host&gt;[:&lt;portnr&gt;][:SSL]
  303. [LOG:regexp|RAW:devicename] {portpassword}
  304. </code>
  305. <br>
  306. <br>
  307. Connect to the <i>remote</i> FHEM on &lt;host&gt;. &lt;portnr&gt; is a telnet
  308. port on the remote FHEM, defaults to 7072. The optional :SSL suffix is
  309. needed, if the remote FHEM configured SSL for this telnet port. In this case
  310. the IO::Socket::SSL perl module must be installed for the local host too.<br>
  311. Note: if the remote FHEM is on a separate host, the telnet port on the remote
  312. FHEM musst be specified with the global option.<br>
  313. The next parameter specifies the connection
  314. type:
  315. <ul>
  316. <li>LOG<br>
  317. Using this type you will receive all events generated by the remote FHEM,
  318. just like when using the <a href="#inform">inform on</a> command, and you
  319. can use these events just like any local event for <a
  320. href="#FileLog">FileLog </a> or <a href="#notify">notify</a>.
  321. The regexp will prefilter the events distributed locally, for the syntax
  322. see the notify definition.<br>
  323. Drawbacks: the remote devices wont be created locally, so list wont
  324. show them and it is not possible to manipulate them from the local
  325. FHEM. It is possible to create a device with the same name on both FHEM
  326. instances, but if both of them receive the same event (e.g. because both
  327. of them have a CUL attached), then all associated FileLogs/notifys will be
  328. triggered twice.<br>
  329. If the remote device is created with the same name locally (e.g. as dummy),
  330. then the local readings are also updated.
  331. </li>
  332. <li>RAW<br>
  333. By using this type the local FHEM will receive raw events from the remote
  334. FHEM device <i>devicename</i>, just like if it would be attached to the
  335. local FHEM.
  336. Drawback: only devices using the Dispatch function (CUL, FHZ, CM11,
  337. SISPM, RFXCOM, TCM, TRX, TUL) generate raw messages, and you must create a
  338. FHEM2FHEM instance for each remote device.<br>
  339. <i>devicename</i> must exist on the local
  340. FHEM server too with the same name and same type as the remote device, but
  341. with the device-node "none", so it is only a dummy device.
  342. All necessary attributes (e.g. <a href="#rfmode">rfmode</a> if the remote
  343. CUL is in HomeMatic mode) must also be set for the local device.
  344. Do not reuse a real local device, else duplicate filtering (see dupTimeout)
  345. won't work correctly.
  346. </li>
  347. </ul>
  348. The last parameter specifies an optional portpassword, if the remote server
  349. activated <a href="#portpassword">portpassword</a>.
  350. <br>
  351. Examples:
  352. <ul>
  353. <code>define ds1 FHEM2FHEM 192.168.178.22:7072 LOG:.*</code><br>
  354. <br>
  355. <code>define RpiCUL CUL none 0000</code><br>
  356. <code>define ds2 FHEM2FHEM 192.168.178.22:7072 RAW:RpiCUL</code><br>
  357. and on the RPi (192.168.178.22):<br>
  358. <code>rename CUL_0 RpiCUL</code><br>
  359. </ul>
  360. </ul>
  361. <br>
  362. <a name="FHEM2FHEMset"></a>
  363. <b>Set </b>
  364. <ul>
  365. <li>reopen<br>
  366. Reopens the connection to the device and reinitializes it.</li><br>
  367. </ul>
  368. <a name="FHEM2FHEMget"></a>
  369. <b>Get</b> <ul>N/A</ul><br>
  370. <a name="FHEM2FHEMattr"></a>
  371. <b>Attributes</b>
  372. <ul>
  373. <li><a href="#dummy">dummy</a></li>
  374. <li><a href="#disable">disable</a></li>
  375. <li><a href="#disabledForIntervals">disabledForIntervals</a></li>
  376. <li><a name="#eventOnly">eventOnly</a><br>
  377. if set, generate only events, do not set corresponding readings.
  378. This is a compatibility feature, available only for LOG-Mode.
  379. </li>
  380. <li><a name="#addStateEvent">addStateEvent</a><br>
  381. if set, state events are transmitted correctly. Notes: this is relevant
  382. only with LOG mode, setting it will generate an additional "reappeared"
  383. Log entry, and the remote FHEM must support inform onWithState (i.e. must
  384. be up to date).
  385. </li>
  386. <li><a name="#excludeEvents">excludeEvents &lt;regexp&gt;</a>
  387. do not publish events matching &lt;regexp&gt;
  388. </li>
  389. </ul>
  390. </ul>
  391. =end html
  392. =begin html_DE
  393. <a name="FHEM2FHEM"></a>
  394. <h3>FHEM2FHEM</h3>
  395. <ul>
  396. FHEM2FHEM ist ein Hilfsmodul, um mehrere FHEM-Installationen zu verbinden.
  397. <br><br>
  398. <a name="FHEM2FHEMdefine"></a>
  399. <b>Define</b>
  400. <ul>
  401. <code>define &lt;name&gt; FHEM2FHEM &lt;host&gt;[:&lt;portnr&gt;][:SSL] [LOG:regexp|RAW:devicename] {portpassword}
  402. </code>
  403. <br>
  404. <br>
  405. Zum <i>remote (entfernten)</i> FHEM auf Rechner &lt;host&gt; verbinden.
  406. &lt;portnr&gt; ist der telnetPort des remote FHEM, Standardport ist 7072.
  407. Der Zusatz :SSL wird ben&ouml;tigt, wenn das remote FHEM
  408. SSL-Verschl&uuml;sselung voraussetzt. Auch auf dem lokalen Host muss dann
  409. das Perl-Modul IO::Socket::SSL installiert sein.<br>
  410. Anmerkung: Wenn das remote FHEM auf einem eigenen Host l&auml;uft, muss
  411. "telnetPort" des remote FHEM als global festgelegt sein. <br>
  412. Der n&auml;chste Parameter spezifiziert den Verbindungs-Typ:
  413. <ul>
  414. <li>LOG<br>
  415. Bei Verwendung dieses Verbindungstyps werden alle Ereignisse (Events) der
  416. remote FHEM-Installation empfangen. Die Ereignisse sehen aus wie die, die
  417. nach <a href="#inform">inform on</a> Befehl erzeugt werden. Sie k&ouml;nnen
  418. wie lokale Ereignisse durch <a href="#FileLog">FileLog </a> oder <a
  419. href="#notify">notify</a> genutzt werden und mit einem regul&auml;ren
  420. Ausdruck gefiltert werden. Die Syntax daf&uuml;r ist unter der
  421. notify-Definition beschrieben.<br>
  422. Einschr&auml;nkungen: die Ger&auml;te der remote Installation werden nicht
  423. lokal angelegt und k&ouml;nnen weder mit list angezeigt noch lokal
  424. angesprochen werden. Auf beiden FHEM-Installationen k&ouml;nnen
  425. Ger&auml;te gleichen Namens angelegt werden, aber wenn beide dasselbe
  426. Ereignis empfangen (z.B. wenn an beiden Installationen CULs angeschlossen
  427. sind), werden alle FileLogs und notifys doppelt ausgel&ouml;st.<br>
  428. Falls man lokal Ger&auml;te mit dem gleichen Namen (z.Bsp. als dummy)
  429. angelegt hat, dann werden die Readings von dem lokalen Ger&auml;t
  430. aktualisiert.
  431. </li>
  432. <li>RAW<br>
  433. Bei diesem Verbindungstyp werden unaufbereitete Ereignisse (raw messages)
  434. des remote FHEM-Ger&auml;ts <i>devicename</i> genau so empfangen, als
  435. w&auml;re das Ger&auml;t lokal verbunden.<br>
  436. Einschr&auml;nkungen: nur Ger&auml;te, welche die "Dispatch-Funktion"
  437. unterst&uuml;tzen (CUL, FHZ, CM11, SISPM, RFXCOM, TCM, TRX, TUL) erzeugen
  438. raw messages, und f&uuml;r jedes entfernte Ger&auml;t muss ein eigenes
  439. FHEM2FHEM Objekt erzeugt werden.<br>
  440. <i>devicename</i> muss mit demselben Namen und Typ wie das Remote Devive
  441. angelegt sein, aber als Dummy, d.h. als device-node "none".
  442. Zus&auml;tzlich m&uuml;ssen alle notwendigen Attribute lokal gesetzt sein
  443. (z.B. <a href="#rfmode">rfmode</a>, wenn die remote CUL im HomeMatic-Modus
  444. l&auml;uft). Die Verwendung bereits bestehender lokaler Ger&auml;te ist zu
  445. vermeiden, weil sonst die Duplikatsfilterung nicht richtig funktioniert
  446. (siehe dupTimeout). </li>
  447. </ul>
  448. Der letzte Parameter enth&auml;lt das Passwort des Remote-Servers, wenn dort
  449. eines aktiviert ist <a href="#portpassword">portpassword</a>.
  450. <br>
  451. Beispiele:
  452. <ul>
  453. <code>define ds1 FHEM2FHEM 192.168.178.22:7072 LOG:.*</code><br>
  454. <br>
  455. <code>define RpiCUL CUL none 0000</code><br>
  456. <code>define ds2 FHEM2FHEM 192.168.178.22:7072 RAW:RpiCUL</code><br> und auf dem RPi (192.168.178.22):<br>
  457. <code>rename CUL_0 RpiCUL</code><br>
  458. </ul>
  459. </ul>
  460. <br>
  461. <a name="FHEM2FHEMset"></a>
  462. <b>Set </b>
  463. <ul>
  464. <li>reopen<br>
  465. &Ouml;ffnet die Verbindung erneut.</li>
  466. </ul>
  467. <a name="FHEM2FHEMget"></a>
  468. <b>Get</b> <ul>N/A</ul><br>
  469. <a name="FHEM2FHEMattr"></a>
  470. <b>Attribute</b>
  471. <ul>
  472. <li><a href="#dummy">dummy</a></li>
  473. <li><a href="#disable">disable</a></li>
  474. <li><a href="#disabledForIntervals">disabledForIntervals</a></li>
  475. <li><a name="#eventOnly">eventOnly</a><br>
  476. falls gesetzt, werden nur die Events generiert, und es wird kein
  477. Reading aktualisiert. Ist nur im LOG-Mode aktiv.
  478. </li>
  479. <li><a name="#addStateEvent">addStateEvent</a><br>
  480. falls gesetzt, werden state Events als solche uebertragen. Zu beachten:
  481. das Attribut ist nur f&uuml;r LOG-Mode relevant, beim Setzen wird eine
  482. zus&auml;tzliche reopened Logzeile generiert, und die andere Seite muss
  483. aktuell sein.
  484. </li>
  485. <li><a name="#excludeEvents">excludeEvents &lt;regexp&gt;</a>
  486. die auf das &lt;regexp&gt; zutreffende Events werden nicht
  487. bereitgestellt.
  488. </li>
  489. </ul>
  490. </ul>
  491. =end html_DE
  492. =cut