09_CUL_FHTTK.pm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. #
  2. # 09_CUL_FHTTK.pm
  3. #
  4. # A module for FHEM to handle ELV's FHT80 TF-type sensors
  5. # written by Kai 'wusel' Siering, 2009-11-06 with help
  6. # from previously written FHEM code as well as members
  7. # of fhem-users at googlegroups.com! Thanks, guys!
  8. #
  9. # e-mail: wusel+source at uu punkt org
  10. #
  11. # This module reads, despite setting an IODev explicitely,
  12. # from any (CUL-) source and drops any identical message
  13. # arriving within 5 seconds. It does handle the automatic
  14. # retransmission of FHT80 TF as well as concurrent recep-
  15. # tion from multiple sources; in my system, it could happen
  16. # that the CUL in the same room "overhears" a telegram from
  17. # FHT80 TF (most likely due to other messages sent/received
  18. # at the same time) but the one downstairs still picks it up.
  19. # My implementation should be safe for the device in question,
  20. # if you see problems, the "only on this IODev"-code is still
  21. # in place but commented out.
  22. #
  23. #
  24. # Note: The sensor in question is named "FHT80 TF",
  25. # in it's (formerly current, now old) design it looks
  26. # similar to "FS20 TFK" but operates differently.
  27. #
  28. # FHT80 TF is designed to serve as a sensor to FHT80 B,
  29. # only the B receives TF's transmissions (after made
  30. # known to each FHT80 B) normally. The B then, if in-
  31. # structed that way, turns down the heating while any
  32. # of the TFs known to it signal "Window open". The TF
  33. # transmits about every 255 seconds a telegram stating
  34. # whether or nor the (reed-) contact is open (which
  35. # means Window or Door, relevant for heating, open)
  36. # and whether the battery is still full enough.
  37. #
  38. # The FS20 TFK on the other hand just directly addresses
  39. # another FS20 device on opening/closing of it's (reed-)
  40. # contact.
  41. #
  42. # Finally, the HMS100 TFK is designed to notify a HMS-
  43. # central about opened/closed contacts immediately,
  44. # but you can't directly address FS20 devices ...
  45. #
  46. # So, to notify e. g. FHEM instantly about opening
  47. # or closure of doors/windows, your best buy might be
  48. # an HMS100 TFK (as of this writing EUR 29,95 @ ELV).
  49. # You could use an FS20 TFK as well (EUR 34,95 @ ELV),
  50. # that way you could directly have FS20 switches act
  51. # on opened/closed doors or windows in parallel or
  52. # even without FHEM. The FHT80 TF (as eQ-3 FHT 80 TF
  53. # currently for EUR 14,95 available @ ELV) only sends
  54. # out a status telegram every ca. 2,5 minutes, so it's
  55. # ok for seeing where one might have left a window
  56. # open before leaving the house but by no means suit-
  57. # able for any alerting uses (unless a delay of said
  58. # amount of time doesn't matter, of course ;)).
  59. #
  60. # in charge of code: Matscher
  61. #
  62. # $Id: 09_CUL_FHTTK.pm 15426 2017-11-12 20:10:43Z Matscher $
  63. ##############################################
  64. package main;
  65. use strict;
  66. use warnings;
  67. my %fhttfk_codes = (
  68. "02" => "Window:Closed",
  69. "82" => "Window:Closed",
  70. "01" => "Window:Open",
  71. "81" => "Window:Open",
  72. "0c" => "Sync:Syncing",
  73. "91" => "Window:Open, Low Batt",
  74. "11" => "Window:Open, Low Batt",
  75. "92" => "Window:Closed, Low Batt",
  76. "12" => "Window:Closed, Low Batt",
  77. "0f" => "Test:Success");
  78. # -wusel, 2009-11-09: Map retransmission codes to major (8x) ones (0x)
  79. # As I'm somewhat lazy, I just list all codes from
  80. # %fhttfk_codes and map them to their major one.
  81. # (FIXME: it would be sufficient to have %fhttfk_codes
  82. # only list these major, "translated" ones.)
  83. my %fhttfk_translatedcodes = (
  84. "01" => "01",
  85. "11" => "11",
  86. "12" => "12",
  87. "02" => "02",
  88. "0c" => "0c",
  89. "0f" => "0f",
  90. "81" => "01",
  91. "82" => "02",
  92. "91" => "11",
  93. "92" => "12");
  94. # set
  95. my %fhttfk_c2b; # command->button hash
  96. my %canset = (
  97. "01" => "Open",
  98. "02" => "Closed",
  99. "0c" => "Pair",
  100. "ff" => "ReSync");
  101. # -wusel, 2009-11-06
  102. #
  103. # Parse messages from FHT80TK, normally interpreted only by FHT80
  104. #
  105. # Format as follows: "TCCCCCCXX" with CCCCCC being the id of the
  106. # sensor in hex, XX being the current status: 02/82 is Window
  107. # closes, 01/81 is Window open, 0C is synchronization, ?? is the
  108. # battery low warning. FIXME!
  109. #############################
  110. sub
  111. CUL_FHTTK_Initialize($)
  112. {
  113. my ($hash) = @_;
  114. foreach my $k (keys %canset) {
  115. my $v = $canset{$k};
  116. $fhttfk_c2b{$v} = $k;
  117. }
  118. $hash->{Match} = "^T[A-F0-9]{8}";
  119. $hash->{SetFn} = "CUL_FHTTK_Set";
  120. $hash->{DefFn} = "CUL_FHTTK_Define";
  121. $hash->{UndefFn} = "CUL_FHTTK_Undef";
  122. $hash->{ParseFn} = "CUL_FHTTK_Parse";
  123. $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 showtime:0,1 " .
  124. "model:FHT80TF,FHT80TF-2,dummy ".
  125. $readingFnAttributes;
  126. $hash->{AutoCreate}=
  127. { "CUL_FHTTK.*" => { GPLOT => "fht80tf:Window,", FILTER => "%NAME" } };
  128. }
  129. #############################
  130. sub
  131. CUL_FHTTK_Set($@)
  132. {
  133. my ($hash, @a) = @_;
  134. my $ret = "";
  135. return "\"set $a[0]\" needs at least two parameters" if(@a < 2);
  136. my $name = shift(@a);
  137. my $opt = shift @a;
  138. # suppress SET option
  139. if(defined($attr{$name}) && defined($attr{$name}{"model"})) {
  140. if($attr{$name}{"model"} ne "dummy") {
  141. return $ret;
  142. }
  143. }
  144. else {
  145. return $ret;
  146. }
  147. my $value = join("", @a);
  148. Log3 $name, 5, "CUL_FHTTK ($name) option: $opt and value: $value";
  149. if(!defined($fhttfk_c2b{$opt})) {
  150. my @cList = keys %fhttfk_c2b;
  151. return "Unknown argument $opt ($value), choose one of " . join(" ", @cList);
  152. }
  153. if ($opt eq "Open" ) {
  154. Log3 $name, 3, "CUL_FHTTK ($name) changed window state to open.";
  155. IOWrite($hash, "", sprintf("T%s01", $hash->{CODE})); # 0x01 - open or 0x81
  156. } elsif ($opt eq "Closed" ) {
  157. Log3 $name, 3, "CUL_FHTTK ($name) changed window state to closed.";
  158. IOWrite($hash, "", sprintf("T%s02", $hash->{CODE})); # 0x02 - closed or 0x82
  159. } elsif($opt eq "Pair" ) {
  160. Log3 $name, 3, "CUL_FHTTK ($name) pairing with FHT80b.";
  161. IOWrite($hash, "", sprintf("T%s0c", $hash->{CODE})); # 0x0c - sync
  162. # window state switch to closed through cul FW implementation
  163. $opt = "Closed";
  164. } elsif($opt eq "ReSync" ) {
  165. Log3 $name, 3, "CUL_FHTTK ($name) resyncing with FHT80b.";
  166. IOWrite($hash, "", sprintf("T%s%s", $hash->{CODE}, $fhttfk_c2b{$opt})); # 0xff - ReSync
  167. # window state switch to closed through cul FW implementation
  168. $opt = "Closed";
  169. } else {
  170. return "Unknown argument $a[1], choose one of Pair ReSync Open Closed"
  171. }
  172. # update new state
  173. readingsSingleUpdate($hash, "state", $opt, 1);
  174. readingsSingleUpdate($hash, "Window", $opt, 1);
  175. return $ret;
  176. }
  177. #############################
  178. sub
  179. CUL_FHTTK_Define($$)
  180. {
  181. my ($hash, $def) = @_;
  182. my @a = split("[ \t][ \t]*", $def);
  183. my $u= "wrong syntax: define <name> CUL_FHTTK <sensor>";
  184. return $u if((int(@a)< 3) || (int(@a)>3));
  185. my $name = $a[0];
  186. my $sensor = lc($a[2]);
  187. if($sensor !~ /^[0-9a-f]{6}$/) {
  188. return "wrong sensor specification $sensor, need a 6 digit hex number!";
  189. }
  190. $hash->{CODE} = $sensor;
  191. $modules{CUL_FHTTK}{defptr}{$sensor} = $hash;
  192. AssignIoPort($hash);
  193. return undef;
  194. }
  195. #############################
  196. sub
  197. CUL_FHTTK_Undef($$)
  198. {
  199. my ($hash, $name) = @_;
  200. delete($modules{CUL_FHTTK}{defptr}{$hash->{CODE}}) if($hash && $hash->{CODE});
  201. return undef;
  202. }
  203. #############################
  204. sub
  205. CUL_FHTTK_Parse($$)
  206. {
  207. my ($hash, $msg) = @_;
  208. my $sensor= lc(substr($msg, 1, 6));
  209. my $def = $modules{CUL_FHTTK}{defptr}{$sensor};
  210. if(!$def) {
  211. Log3 $hash, 1, "FHTTK Unknown device $sensor, please define it";
  212. return "UNDEFINED CUL_FHTTK_$sensor CUL_FHTTK $sensor";
  213. }
  214. my $name = $def->{NAME};
  215. my $state = lc(substr($msg, 7, 2));
  216. return "" if(IsIgnored($name));
  217. if(!defined($fhttfk_translatedcodes{$state})) {
  218. Log3 $name, 1, sprintf("FHTTK $def Unknown state $state");
  219. $defs{$name}{READINGS}{"Unknown"}{VAL} = $state;
  220. $defs{$name}{READINGS}{"Unknown"}{TIME} = TimeNow();
  221. return "";
  222. }
  223. $state=$fhttfk_translatedcodes{$state};
  224. # PREVIOUS
  225. # FIXME: Message regarded as similar if last char is identical;
  226. # sure that's always the differentiator? -wusel, 2009-11-09
  227. if(defined($defs{$name}{PREV}{TIMESTAMP})) {
  228. if($defs{$name}{PREV}{TIMESTAMP} > time()-5) {
  229. if(defined($defs{$name}{PREV}{STATE})) {
  230. if($defs{$name}{PREV}{STATE} eq $state) {
  231. Log3 $name, 4, sprintf("FHTTK skipping state $state as last similar telegram was received less than 5 (%s) secs ago", time()-$defs{$name}{PREV}{TIMESTAMP});
  232. return "";
  233. }
  234. }
  235. }
  236. }
  237. if (! defined($defs{$name}{READINGS}{"Previous"})) {
  238. $defs{$name}{READINGS}{"Previous"}{VAL} = "";
  239. $defs{$name}{READINGS}{"Previous"}{TIME} = "";
  240. }
  241. if (defined($defs{$name}{PREV}{STATE}) && $defs{$name}{PREV}{STATE} ne $state) {
  242. my $prevState = $defs{$name}{PREV}{STATE};
  243. my ($windowReading,$windowState) = split(/:/, $fhttfk_codes{$prevState});
  244. $defs{$name}{READINGS}{"Previous"}{VAL} = $windowState if defined($windowState) && $windowState ne "";
  245. $defs{$name}{READINGS}{"Previous"}{TIME} = TimeNow();
  246. }
  247. $def->{PREVTIMESTAMP} = defined($defs{$name}{PREV}{TIMESTAMP})?$defs{$name}{PREV}{TIMESTAMP}:time();
  248. $def->{PREVSTATE} = defined($def->{STATE})?$def->{STATE}:"Unknown";
  249. $defs{$name}{PREV}{STATE}=$state;
  250. #
  251. # from here readings are effectively updated
  252. #
  253. readingsBeginUpdate($def);
  254. #READINGS
  255. my ($reading,$val) = split(/:/, $fhttfk_codes{$state});
  256. readingsBulkUpdate($def, $reading, $val);
  257. $defs{$name}{PREV}{TIMESTAMP} = time();
  258. # -wusel, 2009-11-09: According to http://fhz4linux.info/tiki-index.php?page=FHT+protocol,
  259. # FHT80TF usually transmitts between 60 and 240 seconds. (255-256 sec in
  260. # my experience ...) If we got no fresh data for over 5 minutes (300 sec),
  261. # flag this.
  262. if($defs{$name}{PREV}{TIMESTAMP}+720 < time()) {
  263. readingsBulkUpdate($def, "Reliability", "dead");
  264. } elsif($defs{$name}{PREV}{TIMESTAMP}+600 < time()) {
  265. readingsBulkUpdate($def, "Reliability", "low");
  266. } elsif($defs{$name}{PREV}{TIMESTAMP}+300 < time()) {
  267. readingsBulkUpdate($def, "Reliability", "medium");
  268. } else {
  269. readingsBulkUpdate($def, "Reliability", "ok");
  270. }
  271. # Flag the battery warning separately
  272. if($state eq "11" || $state eq "12") {
  273. readingsBulkUpdate($def, "Battery", "Low");
  274. } else {
  275. readingsBulkUpdate($def, "Battery", "ok");
  276. }
  277. #CHANGED
  278. readingsBulkUpdate($def, "state", $val);
  279. $def->{OPEN} = lc($val) eq "open" ? 1 : 0;
  280. Log3 $name, 4, "FHTTK Device $name ($reading: $val)";
  281. #
  282. # now we are done with updating readings
  283. #
  284. readingsEndUpdate($def, 1);
  285. return $def->{NAME};
  286. }
  287. #############################
  288. 1;
  289. =pod
  290. =item summary support for the window sensor fht80tf and fht80tf-2
  291. =item summary_DE Einbindung des fht80tf und fht80tf-2 Fensterkontaktes
  292. =begin html
  293. <a name="CUL_FHTTK"></a>
  294. <h3>CUL_FHTTK</h3>
  295. <ul>
  296. This module handles messages from the FHT80 TF "Fenster-T&uuml;r-Kontakt" (Window-Door-Contact)
  297. which are normally only acted upon by the <a href="#FHT">FHT80B</a>. With this module,
  298. FHT80 TFs are in a limited way (see <a href="http://fhz4linux.info/tiki-index.php?page=FHT+protocol">Wiki</a>
  299. for detailed explanation of TF's mode of operation) usable similar to HMS100 TFK. The name
  300. of the module was chosen as a) only CUL will spill out the datagrams and b) "TF" designates
  301. usually temperature+humidity sensors (no clue, why ELV didn't label this one "TFK" like with
  302. FS20 and HMS).<br><br>
  303. As said before, FHEM can receive FHT80 TF radio (868.35 MHz) messages only through an
  304. <a href="#CUL">CUL</a> device, so this must be defined first.
  305. <br><br>
  306. With the latest build on <a href="http://sourceforge.net/p/culfw/code/HEAD/tree/trunk/culfw/Devices/">SVN</a>
  307. or next official version 1.62 or higher, it is possible to send out FHT80 TF data with a CUL or simular
  308. devices. So it can be simulate up to four window sensor with one device
  309. (see <a href="http://www.fhemwiki.de/wiki/CUL_FHTTK">FHEM Wiki</a>). To setup a window sensor, you have to
  310. add and/or change the attribute "model" to dummy. The 6 digit hex number must not equal to FHTID.<br><br>
  311. <a name="CUL_FHTTKdefine"></a>
  312. <b>Define</b>
  313. <ul>
  314. <code>define &lt;name&gt; CUL_FHTTK &lt;devicecode&gt;</code>
  315. <br><br>
  316. <code>&lt;devicecode&gt;</code> is a six digit hex number, given to the FHT80 TF during
  317. production, i. e. it is not changeable. (Yes, it keeps this code after changing batteries
  318. as well.)<br>
  319. Examples:
  320. <ul>
  321. <code>define TK_TEST CUL_FHTTK 965AB0</code>
  322. </ul>
  323. </ul>
  324. <br>
  325. <a name="CUL_FHTTKset"></a>
  326. <b>Set</b>
  327. <ul> Only available, if model is set to dummy.<br><br>
  328. <code>set &lt;name&gt; &lt;value&gt;</code>
  329. <br><br>
  330. where <code>value</code> is one of:<br>
  331. <ul><code>
  332. Pair # start pairing with FHT80B (activate FHT80B sync mode before) - state after pairing is Closed<br>
  333. Closed # set window state to Closed<br>
  334. Open # set window state to Open<br>
  335. ReSync # resync virtual sensor with FHT80b after a reset of CUL device. In other words, perform a virtual
  336. battery exchange to synchronize the sensor with FHT80b device again. (at the moment, only
  337. available with prototype cul_fw - see forum 55774)<br>
  338. </code></ul>
  339. </ul>
  340. <br>
  341. <b>Get</b>
  342. <ul> No get implemented yet ...
  343. </ul><br>
  344. <a name="CUL_FHTTKattr"></a>
  345. <b>Attributes</b>
  346. <ul>
  347. <li><a href="#do_not_notify">do_not_notify</a></li><br>
  348. <li><a href="#verbose">verbose</a></li><br>
  349. <li><a href="#model">model</a><br>Possible values are: FHT80TF, FHT80TF-2, dummy (value, which allow to simulate a window sensor)</li><br>
  350. <li><a href="#showtime">showtime</a></li><br>
  351. <li><a href="#IODev">IODev</a></li><br>
  352. <li><a href="#ignore">ignore</a></li><br>
  353. <li><a href="#eventMap">eventMap</a></li><br>
  354. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  355. </ul>
  356. <br>
  357. </ul>
  358. =end html
  359. =begin html_DE
  360. <a name="CUL_FHTTK"></a>
  361. <h3>CUL_FHTTK</h3>
  362. <ul>
  363. Dieses Modul hantiert die empfangen Daten von FHT80 TF "Fenster-T&uuml;r-Kontakt" Sensoren, welche
  364. normalerweise nur mit den <a href="#FHT">FHT80B</a> Geräten kommunizieren. Mit diesen Modul k&ouml;nnen
  365. FHT80 TFs in eingeschr&auml;nkter Weise &auml;hnlich wie HMS TFK Sensoren benutzt werden (weitere
  366. Informationen sind unter <a href="http://fhz4linux.info/tiki-index.php?page=FHT+protocol">Wiki</a> zu lesen).
  367. Der name des FHEM Moduls wurde so gewählt, weil a) nur der CUL die Daten empfangen kann und b) "TF" normalerweise
  368. Temperatur- und Feuchtigkeitssensoren suggeriert. (Keine Ahnung, warum ELV diesen Sensor nicht TFK genannt hat,
  369. wie die Sensoren von FS20 und HMS).
  370. <br><br>
  371. <a href="#CUL">CUL</a> device muss vorhr definiert sein.
  372. <br><br>
  373. Mit dem letzten Build auf <a href="http://sourceforge.net/p/culfw/code/HEAD/tree/trunk/culfw/Devices/">SVN</a>
  374. oder mit der n&auml;chsten offiziellen Version 1.62 oder h&ouml;her, ist es m&ouml;glich, FHT80 TF Daten zu senden.
  375. M&ouml;glich mit einem CUL oder &auml;hnlichen Ger&auml;ten. So k&ouml;nnen bis zu vier Fenstersensoren mit einem Ger&auml;t
  376. simuliert werden (siehe <a href="http://www.fhemwiki.de/wiki/CUL_FHTTK">FHEM Wiki</a>). Es muss lediglich das Attribut model mit dem
  377. Wert "dummy" hinzugef&uuml;gt oder ge&auml;ndert werden. Wichtig: Der Devicecode sollte nicht der FHTID entsprechen.<br><br>
  378. <a name="CUL_FHTTKdefine"></a>
  379. <b>D</b>
  380. <ul>
  381. <code>define &lt;name&gt; CUL_FHTTK &lt;devicecode&gt;</code>
  382. <br><br>
  383. <code>&lt;devicecode&gt;</code> Ist eine sechstellige Hexadezimalzahl, welche zum Zeitpunkt der Produktion
  384. des FHT80 TF gegeben wurde. Somit ist diese auch nicht mehr &auml;nderbar und bleibt auch nach einem Batteriewechsel
  385. erhalten.<br>
  386. Examples:
  387. <ul>
  388. <code>define TK_TEST CUL_FHTTK 965AB0</code>
  389. </ul>
  390. </ul>
  391. <br>
  392. <a name="CUL_FHTTKset"></a>
  393. <b>Set</b>
  394. <ul> Nur vorhanden, wenn das Attribut model mit dummy definiert wurde.<br><br>
  395. <code>set &lt;name&gt; &lt;value&gt;</code>
  396. <br><br>
  397. wobei <code>value</code> folgendes sein kann:<br>
  398. <ul><code>
  399. Pair # startet das Anlernen an das FHT80B (FHT80B muss sich im Sync mode befinden) - danach wird der state auf "Closed" gesetzt<br>
  400. Closed # setzt den Fensterstatus zu Closed<br>
  401. Open # setzt den Fensterstatus zu Open<br>
  402. ReSync # neu synchronisieren des virtuellen Sensor mit dem FHT80b Module. Damit wird ein virtueller Batteriewechsel symuliert und der angelernte
  403. Sensor wieder aufsynchronisiert. (aktuell nur mit Prototyp CUL FW verfügbar Forum 55774)<br>
  404. </code></ul>
  405. </ul>
  406. <br>
  407. <b>Get</b>
  408. <ul> N/A </ul>
  409. <br>
  410. <a name="CUL_FHTTKattr"></a>
  411. <b>Attributes</b>
  412. <ul>
  413. <li><a href="#do_not_notify">do_not_notify</a></li><br>
  414. <li><a href="#verbose">verbose</a></li><br>
  415. <li><a href="#model">model</a><br>M&ouml;gliche Werte sind: FHT80TF, FHT80TF-2, dummy (zum simulieren eines Fensterkontaktes)</li><br>
  416. <li><a href="#showtime">showtime</a></li><br>
  417. <li><a href="#IODev">IODev</a></li><br>
  418. <li><a href="#ignore">ignore</a></li><br>
  419. <li><a href="#eventMap">eventMap</a></li><br>
  420. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  421. </ul>
  422. <br>
  423. </ul>
  424. =end html_DE
  425. =cut