36_JeeLink.pm 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  1. # $Id: 36_JeeLink.pm 14707 2017-07-13 18:08:33Z justme1968 $
  2. package main;
  3. use strict;
  4. use warnings;
  5. use Time::HiRes qw(gettimeofday);
  6. use Time::Local;
  7. sub JeeLink_Attr(@);
  8. sub JeeLink_Clear($);
  9. sub JeeLink_HandleWriteQueue($);
  10. sub JeeLink_Parse($$$$);
  11. sub JeeLink_Read($);
  12. sub JeeLink_ReadAnswer($$$$);
  13. sub JeeLink_Ready($);
  14. sub JeeLink_Write($$);
  15. sub JeeLink_SimpleWrite(@);
  16. sub JeeLink_ResetDevice($);
  17. my $clientsJeeLink = ":PCA301:EC3000:RoomNode:LaCrosse:ETH200comfort:CUL_IR:HX2272:FS20:AliRF:Level:EMT7110:KeyValueProtocol";
  18. my %matchListPCA301 = (
  19. "1:PCA301" => "^\\S+\\s+24",
  20. "2:EC3000" => "^\\S+\\s+22",
  21. "3:RoomNode" => "^\\S+\\s+11",
  22. "4:LaCrosse" => "^(\\S+\\s+9 |OK\\sWS\\s)",
  23. "5:AliRF" => "^\\S+\\s+5 ",
  24. "6:EMT7110" => "^OK\\sEMT7110\\s",
  25. "7:KeyValueProtocol" => "^OK\\sVALUES\\s",
  26. );
  27. my %matchListJeeLink433 = (
  28. "1:CUL_IR" => "^I............\$", #I
  29. "2:HX2272" => "^O01[A-F0-9]{4}\$", #O0112A0
  30. );
  31. my %matchListJeeLink868 = (
  32. "1:LaCrosse" => "^F01[A-F0-9]{8}\$", #F019205396A
  33. "2:ETH200comfort" => "^F020[AC][0-9A-F]{8}\$", #F020A01004200
  34. "3:CUL_IR" => "^I............\$", #I
  35. "4:FS20" => "^O02[A-F0-9]{8}\$", #O02D28C0000
  36. );
  37. my %RxListJeeLink = (
  38. "HX2272" => "Or",
  39. "FS20" => "Or",
  40. "LaCrosse" => "Fr01",
  41. );
  42. #my %JeeLinkCmds = (
  43. # "868" => {
  44. # "FS20" => "Or",
  45. # "LaCrosse" => "Fr01",
  46. # },
  47. # "433" => {
  48. # "HX2272" => "Or",
  49. # },
  50. #);
  51. sub
  52. JeeLink_Initialize($)
  53. {
  54. my ($hash) = @_;
  55. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  56. # Provider
  57. $hash->{ReadFn} = "JeeLink_Read";
  58. $hash->{WriteFn} = "JeeLink_Write";
  59. $hash->{ReadyFn} = "JeeLink_Ready";
  60. # Normal devices
  61. $hash->{DefFn} = "JeeLink_Define";
  62. $hash->{FingerprintFn} = "JeeLink_Fingerprint";
  63. $hash->{UndefFn} = "JeeLink_Undef";
  64. $hash->{GetFn} = "JeeLink_Get";
  65. $hash->{SetFn} = "JeeLink_Set";
  66. $hash->{AttrFn} = "JeeLink_Attr";
  67. $hash->{AttrList} = "Clients MatchList"
  68. ." sendpool"
  69. ." dummy"
  70. ." initCommands"
  71. ." flashCommand"
  72. ." timeout"
  73. ." DebounceTime BeepLong BeepShort BeepDelay"
  74. ." tune " . join(" ", map { "tune_$_" } keys %RxListJeeLink)
  75. ." $readingFnAttributes";
  76. $hash->{ShutdownFn} = "JeeLink_Shutdown";
  77. }
  78. sub
  79. JeeLink_Fingerprint($$)
  80. {
  81. }
  82. #####################################
  83. sub
  84. JeeLink_Define($$)
  85. {
  86. my ($hash, $def) = @_;
  87. my @a = split("[ \t][ \t]*", $def);
  88. if(@a != 3) {
  89. my $msg = "wrong syntax: define <name> JeeLink {none | devicename[\@baudrate] ".
  90. "| devicename\@directio | hostname:port}";
  91. Log3 undef, 2, $msg;
  92. return $msg;
  93. }
  94. DevIo_CloseDev($hash);
  95. my $name = $a[0];
  96. my $dev = $a[2];
  97. $hash->{Clients} = $clientsJeeLink;
  98. $hash->{MatchList} = \%matchListPCA301;
  99. if( !defined( $attr{$name}{flashCommand} ) ) {
  100. $attr{$name}{flashCommand} = "avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]"
  101. }
  102. if($dev eq "none") {
  103. Log3 $name, 1, "$name device is none, commands will be echoed only";
  104. $attr{$name}{dummy} = 1;
  105. return undef;
  106. }
  107. $dev .= "\@57600" if( $dev !~ m/\@/ && $def !~ m/:/ );
  108. $hash->{DeviceName} = $dev;
  109. my $ret = DevIo_OpenDev($hash, 0, "JeeLink_DoInit");
  110. return $ret;
  111. }
  112. #####################################
  113. sub
  114. JeeLink_Undef($$)
  115. {
  116. my ($hash, $arg) = @_;
  117. my $name = $hash->{NAME};
  118. foreach my $d (sort keys %defs) {
  119. if(defined($defs{$d}) &&
  120. defined($defs{$d}{IODev}) &&
  121. $defs{$d}{IODev} == $hash)
  122. {
  123. my $lev = ($reread_active ? 4 : 2);
  124. Log3 $name, $lev, "deleting port for $d";
  125. delete $defs{$d}{IODev};
  126. }
  127. }
  128. JeeLink_Shutdown($hash);
  129. DevIo_CloseDev($hash);
  130. return undef;
  131. }
  132. #####################################
  133. sub
  134. JeeLink_Shutdown($)
  135. {
  136. my ($hash) = @_;
  137. ###JeeLink_SimpleWrite($hash, "X00");
  138. return undef;
  139. }
  140. sub
  141. JeeLink_RemoveLaCrossePair($)
  142. {
  143. my $hash = shift;
  144. delete($hash->{LaCrossePair});
  145. }
  146. #####################################
  147. sub
  148. JeeLink_Set($@)
  149. {
  150. my ($hash, @a) = @_;
  151. my $name = shift @a;
  152. my $cmd = shift @a;
  153. my $arg = join(" ", @a);
  154. my $list = "beep raw led:on,off led-on-for-timer reset LaCrossePairForSec setReceiverMode:LaCrosse,HX2272,FS20 flash parse";
  155. return $list if( $cmd eq '?' || $cmd eq '');
  156. if($cmd eq "raw") {
  157. Log3 $name, 4, "set $name $cmd $arg";
  158. JeeLink_SimpleWrite($hash, $arg);
  159. } elsif( $cmd eq "beep" ) {
  160. # + = Langer Piep
  161. # - = Kurzer Piep
  162. # anderes = Pause
  163. my $longbeep = AttrVal($name, "BeepLong", "250");
  164. my $shortbeep = AttrVal($name, "BeepShort", "100");
  165. my $delaybeep = AttrVal($name, "BeepDelay", "0.25");
  166. for(my $i=0;$i<length($arg);$i++) {
  167. my $x=substr($arg,$i,1);
  168. if($x eq "+") {
  169. # long beep
  170. JeeLink_Write($hash, "bFF" . $longbeep);
  171. } elsif($x eq "-") {
  172. # short beep
  173. JeeLink_Write($hash, "bFF" . $shortbeep);
  174. }
  175. select(undef, undef, undef, $delaybeep);
  176. }
  177. }
  178. elsif( $cmd eq "flash" ) {
  179. my @args = split(' ', $arg);
  180. my $log = "";
  181. my $hexFile = "";
  182. my @deviceName = split('@', $hash->{DeviceName});
  183. my $port = $deviceName[0];
  184. my $firmwareFolder = "./FHEM/firmware/";
  185. my $logFile = AttrVal("global", "logdir", "./log") . "/JeeLinkFlash.log";
  186. my $detectedFirmware = $arg ? $args[0] . ($args[0] eq "LaCrosseGateway" ? ".bin" : ".hex") : "";
  187. if(!$detectedFirmware) {
  188. if($hash->{model} =~ /LaCrosse/ ) {
  189. if($hash->{model} =~ /Gateway/ ) {
  190. $detectedFirmware = "LaCrosseGateway.bin";
  191. }
  192. else {
  193. $detectedFirmware = "LaCrosse.hex";
  194. }
  195. }
  196. elsif($hash->{model} =~ /pcaSerial/ ) {
  197. $detectedFirmware = "PCA301.hex";
  198. }
  199. elsif($hash->{model} =~ /ec3kSerial/ ) {
  200. $detectedFirmware = "EC3000.hex";
  201. }
  202. }
  203. $hexFile = $firmwareFolder . "JeeLink_$detectedFirmware";
  204. return "No firmware detected. Please use the firmwareName parameter" if(!$detectedFirmware);
  205. return "The file '$hexFile' does not exist" if(!-e $hexFile);
  206. $log .= "flashing JeeLink $name\n";
  207. $log .= "detected Firmware: $detectedFirmware\n";
  208. $log .= "hex file: $hexFile\n";
  209. if($detectedFirmware eq "LaCrosseGateway.bin") {
  210. eval "use LWP::UserAgent";
  211. return "\nERROR: Please install LWP::UserAgent" if($@);
  212. eval "use HTTP::Request::Common";
  213. return "\nERROR: Please install HTTP::Request::Common" if($@);
  214. $log .= "Mode is LaCrosseGateway OTA-update\n";
  215. DevIo_CloseDev($hash);
  216. readingsSingleUpdate($hash, "state", "disconnected", 1);
  217. $log .= "$name closed\n";
  218. my @spl = split(':', $hash->{DeviceName});
  219. my $targetIP = $spl[0];
  220. my $targetURL = "http://" . $targetIP . "/ota/firmware.bin";
  221. $log .= "target: $targetURL\n";
  222. my $request = POST($targetURL, Content_Type => 'multipart/form-data', Content => [ file => [$hexFile, "firmware.bin"] ]);
  223. my $userAgent = LWP::UserAgent->new;
  224. $userAgent->timeout(60);
  225. my $response = $userAgent->request($request);
  226. if ($response->is_success) {
  227. $log .= "\n\nSketch reports:\n";
  228. $log .= $response->decoded_content;
  229. }
  230. else {
  231. $log .= "\nERROR: " . $response->code . " " . $response->decoded_content;
  232. }
  233. DevIo_OpenDev($hash, 0, "JeeLink_DoInit");
  234. $log .= "$name opened\n";
  235. }
  236. else {
  237. $log .= "port: $port\n";
  238. $log .= "log file: $logFile\n";
  239. my $flashCommand = AttrVal($name, "flashCommand", "");
  240. if($flashCommand ne "") {
  241. if (-e $logFile) {
  242. unlink $logFile;
  243. }
  244. DevIo_CloseDev($hash);
  245. readingsSingleUpdate($hash, "state", "disconnected", 1);
  246. $log .= "$name closed\n";
  247. my $avrdude = $flashCommand;
  248. $avrdude =~ s/\Q[PORT]\E/$port/g;
  249. $avrdude =~ s/\Q[HEXFILE]\E/$hexFile/g;
  250. $avrdude =~ s/\Q[LOGFILE]\E/$logFile/g;
  251. $log .= "command: $avrdude\n\n";
  252. `$avrdude`;
  253. local $/=undef;
  254. if (-e $logFile) {
  255. open FILE, $logFile;
  256. my $logText = <FILE>;
  257. close FILE;
  258. $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n";
  259. $log .= $logText;
  260. $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n\n";
  261. }
  262. else {
  263. $log .= "WARNING: avrdude created no log file\n\n";
  264. }
  265. }
  266. else {
  267. $log .= "\n\nNo flashCommand found. Please define this attribute.\n\n";
  268. }
  269. DevIo_OpenDev($hash, 0, "JeeLink_DoInit");
  270. $log .= "$name opened\n";
  271. }
  272. return $log;
  273. }
  274. elsif( $cmd eq "LaCrossePairForSec" ) {
  275. my @args = split(' ', $arg);
  276. return "Usage: set $name LaCrossePairForSec <seconds_active> [ignore_battery]" if(!$arg || $args[0] !~ m/^\d+$/ || ($args[1] && $args[1] ne "ignore_battery") );
  277. $hash->{LaCrossePair} = $args[1]?2:1;
  278. InternalTimer(gettimeofday()+$args[0], "JeeLink_RemoveLaCrossePair", $hash, 0);
  279. } elsif( $cmd eq "setReceiverMode" ) {
  280. return "Usage: set $name setReceiverMode (LaCrosse,HX2272,FS20)" if($arg !~ m/^(LaCrosse|HX2272|FS20)$/);
  281. #Get tune values of Transceiver if needed (TX+RX)
  282. my $TuneStr = undef;
  283. my $AttrStr = AttrVal($name, "tune_" . $arg, undef);
  284. $AttrStr = AttrVal($name, "tune", undef) if(!(defined $AttrStr));
  285. $TuneStr = JeeLink_CalcTuneCmd($AttrStr) if(defined $AttrStr);
  286. JeeLink_Write($hash, $RxListJeeLink{$arg}); #set receiver
  287. JeeLink_Write($hash, "t" . $TuneStr) if(defined $TuneStr); #set modified tune
  288. #reset debounce time for OOK Signals
  289. if($RxListJeeLink{$arg} =~ m/^O/) {
  290. my $DebStr = AttrVal($name, "DebounceTime", undef);
  291. JeeLink_Write($hash, "Od" . $DebStr) if(defined $DebStr);
  292. }
  293. JeeLink_Write($hash, "f"); # update RFM configuration in FHEM (returns e.g. "FSK-868MHz")
  294. Log3 $name, 4, "set $name $cmd $arg";
  295. } elsif ($cmd =~ m/^led$/i) {
  296. return "Unknown argument $cmd, choose one of $list" if($arg !~ m/^(on|off)$/i);
  297. Log3 $name, 4, "set $name $cmd $arg";
  298. if($hash->{model} =~ m/LaCrosseITPlusReader./i ) {
  299. JeeLink_Write($hash, ($arg eq "on" ? "1" : "0") ."a" );
  300. }
  301. else {
  302. JeeLink_Write($hash, "l" . ($arg eq "on" ? "1" : "0") );
  303. }
  304. } elsif ($cmd =~ m/led-on-for-timer/i) {
  305. return "Unknown argument $cmd, choose one of $list" if($arg !~ m/^[0-9]+$/i);
  306. #remove timer if there is one active
  307. if($modules{JeeLink}{ldata}{$name}) {
  308. CommandDelete(undef, $name . "_timer");
  309. delete $modules{JeeLink}{ldata}{$name};
  310. }
  311. Log3 $name, 4, "set $name on";
  312. if($hash->{model} =~ m/LaCrosseITPlusReader./i ) {
  313. JeeLink_Write($hash, "1a");
  314. }
  315. else {
  316. JeeLink_Write($hash, "l" . "1");
  317. }
  318. my $to = sprintf("%02d:%02d:%02d", $arg/3600, ($arg%3600)/60, $arg%60);
  319. $modules{JeeLink}{ldata}{$name} = $to;
  320. Log3 $name, 4, "Follow: +$to setstate $name off";
  321. CommandDefine(undef, $name."_timer at +$to {fhem(\"set $name led" ." off\")}");
  322. } elsif ($cmd =~ m/reset/i) {
  323. return JeeLink_ResetDevice($hash);
  324. } elsif( $cmd eq 'parse' ) {
  325. JeeLink_Parse($hash, $hash, $name, $arg);
  326. } else {
  327. return "Unknown argument $cmd, choose one of ".$list;
  328. }
  329. return undef;
  330. }
  331. #####################################
  332. sub
  333. JeeLink_Get($@)
  334. {
  335. my ($hash, $name, $cmd, @msg ) = @_;
  336. my $arg = join(" ", @msg);
  337. return "No $cmd for dummies" if(IsDummy($name));
  338. my $list = "devices:noArg initJeeLink:noArg RFMconfig:noArg updateAvailRam:noArg raw";
  339. if( $cmd eq "devices" ) {
  340. if($hash->{model} =~m/JeeNode -- HomeControl -/ ) {
  341. JeeLink_SimpleWrite($hash, "h");
  342. } else {
  343. JeeLink_SimpleWrite($hash, "l");
  344. }
  345. } elsif( $cmd eq "initJeeLink" ) {
  346. readingsSingleUpdate($hash, "state", "opened", 1);
  347. if($hash->{model} =~m/JeeNode -- HomeControl -/ ) {
  348. JeeLink_SimpleWrite($hash, "o");
  349. } else {
  350. JeeLink_SimpleWrite($hash, "0c");
  351. JeeLink_SimpleWrite($hash, "2c");
  352. }
  353. } elsif ($cmd eq "raw" ) {
  354. return "raw => 01" if($arg =~ m/^Ir/); ## Needed for CUL_IR usage (IR-Receive is always on for JeeLinks
  355. } elsif ($cmd eq "RFMconfig" ) {
  356. JeeLink_SimpleWrite($hash, "f");
  357. } elsif ($cmd eq "updateAvailRam" ) {
  358. JeeLink_SimpleWrite($hash, "m");
  359. } else {
  360. return "Unknown argument $cmd, choose one of ".$list;
  361. }
  362. return undef;
  363. }
  364. sub
  365. JeeLink_Clear($)
  366. {
  367. my $hash = shift;
  368. # Clear the pipe
  369. $hash->{RA_Timeout} = 1;
  370. for(;;) {
  371. my ($err, undef) = JeeLink_ReadAnswer($hash, "Clear", 0, undef);
  372. last if($err && $err =~ m/^Timeout/);
  373. }
  374. delete($hash->{RA_Timeout});
  375. }
  376. #####################################
  377. sub
  378. JeeLink_DoInit($)
  379. {
  380. my $hash = shift;
  381. my $name = $hash->{NAME};
  382. my $err;
  383. my $msg = undef;
  384. my $val;
  385. JeeLink_Clear($hash);
  386. readingsSingleUpdate($hash, "state", "opened", 1);
  387. # Reset the counter
  388. delete($hash->{XMIT_TIME});
  389. delete($hash->{NR_CMD_LAST_H});
  390. return undef;
  391. }
  392. #####################################
  393. # This is a direct read for commands like get
  394. # Anydata is used by read file to get the filesize
  395. sub
  396. JeeLink_ReadAnswer($$$$)
  397. {
  398. my ($hash, $arg, $anydata, $regexp) = @_;
  399. my $type = $hash->{TYPE};
  400. return ("No FD", undef)
  401. if(!$hash || ($^O !~ /Win/ && !defined($hash->{FD})));
  402. my ($mpandata, $rin) = ("", '');
  403. my $buf;
  404. my $to = 3; # 3 seconds timeout
  405. $to = $hash->{RA_Timeout} if($hash->{RA_Timeout}); # ...or less
  406. for(;;) {
  407. if($^O =~ m/Win/ && $hash->{USBDev}) {
  408. $hash->{USBDev}->read_const_time($to*1000); # set timeout (ms)
  409. # Read anstatt input sonst funzt read_const_time nicht.
  410. $buf = $hash->{USBDev}->read(999);
  411. return ("Timeout reading answer for get $arg", undef)
  412. if(length($buf) == 0);
  413. } else {
  414. return ("Device lost when reading answer for get $arg", undef)
  415. if(!$hash->{FD});
  416. vec($rin, $hash->{FD}, 1) = 1;
  417. my $nfound = select($rin, undef, undef, $to);
  418. if($nfound < 0) {
  419. next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
  420. my $err = $!;
  421. DevIo_Disconnected($hash);
  422. return("JeeLink_ReadAnswer $arg: $err", undef);
  423. }
  424. return ("Timeout reading answer for get $arg", undef)
  425. if($nfound == 0);
  426. $buf = DevIo_SimpleRead($hash);
  427. return ("No data", undef) if(!defined($buf));
  428. }
  429. if($buf) {
  430. Log3 $hash->{NAME}, 5, "JeeLink/RAW (ReadAnswer): $buf";
  431. $mpandata .= $buf;
  432. }
  433. chop($mpandata);
  434. chop($mpandata);
  435. return (undef, $mpandata)
  436. }
  437. }
  438. #####################################
  439. # Check if the 1% limit is reached and trigger notifies
  440. sub
  441. JeeLink_XmitLimitCheck($$)
  442. {
  443. my ($hash,$fn) = @_;
  444. my $now = time();
  445. if(!$hash->{XMIT_TIME}) {
  446. $hash->{XMIT_TIME}[0] = $now;
  447. $hash->{NR_CMD_LAST_H} = 1;
  448. return;
  449. }
  450. my $nowM1h = $now-3600;
  451. my @b = grep { $_ > $nowM1h } @{$hash->{XMIT_TIME}};
  452. if(@b > 163) { # 163 comes from fs20. todo: verify if correct for JeeLink modulation
  453. my $name = $hash->{NAME};
  454. Log3 $name, 2, "JeeLink TRANSMIT LIMIT EXCEEDED";
  455. DoTrigger($name, "TRANSMIT LIMIT EXCEEDED");
  456. } else {
  457. push(@b, $now);
  458. }
  459. $hash->{XMIT_TIME} = \@b;
  460. $hash->{NR_CMD_LAST_H} = int(@b);
  461. }
  462. #####################################
  463. sub
  464. JeeLink_Write($$)
  465. {
  466. my ($hash, $cmd, $msg) = @_;
  467. my $name = $hash->{NAME};
  468. my $arg = $cmd;
  469. $arg .= " " . $msg if(defined($msg));
  470. #Modify command for CUL_IR
  471. $arg =~ s/^\s+|\s+$//g;
  472. $arg =~ s/^Is/I/i; #SendIR command is "I" not "Is" for JeeLink devices
  473. Log3 $name, 5, "$name sending $arg";
  474. JeeLink_AddQueue($hash, $arg);
  475. #JeeLink_SimpleWrite($hash, $msg);
  476. }
  477. sub
  478. JeeLink_SendFromQueue($$)
  479. {
  480. my ($hash, $bstring) = @_;
  481. my $name = $hash->{NAME};
  482. my $to = 0.05;
  483. if($bstring ne "") {
  484. my $sp = AttrVal($name, "sendpool", undef);
  485. if($sp) { # Is one of the JeeLink-fellows sending data?
  486. my @fellows = split(",", $sp);
  487. foreach my $f (@fellows) {
  488. if($f ne $name &&
  489. $defs{$f} &&
  490. $defs{$f}{QUEUE} &&
  491. $defs{$f}{QUEUE}->[0] ne "")
  492. {
  493. unshift(@{$hash->{QUEUE}}, "");
  494. InternalTimer(gettimeofday()+$to, "JeeLink_HandleWriteQueue", $hash, 0);
  495. return;
  496. }
  497. }
  498. }
  499. JeeLink_XmitLimitCheck($hash,$bstring);
  500. JeeLink_SimpleWrite($hash, $bstring);
  501. }
  502. InternalTimer(gettimeofday()+$to, "JeeLink_HandleWriteQueue", $hash, 0);
  503. }
  504. sub
  505. JeeLink_AddQueue($$)
  506. {
  507. my ($hash, $bstring) = @_;
  508. if(!$hash->{QUEUE}) {
  509. $hash->{QUEUE} = [ $bstring ];
  510. JeeLink_SendFromQueue($hash, $bstring);
  511. } else {
  512. push(@{$hash->{QUEUE}}, $bstring);
  513. }
  514. }
  515. #####################################
  516. sub
  517. JeeLink_HandleWriteQueue($)
  518. {
  519. my $hash = shift;
  520. my $arr = $hash->{QUEUE};
  521. if(defined($arr) && @{$arr} > 0) {
  522. shift(@{$arr});
  523. if(@{$arr} == 0) {
  524. delete($hash->{QUEUE});
  525. return;
  526. }
  527. my $bstring = $arr->[0];
  528. if($bstring eq "") {
  529. JeeLink_HandleWriteQueue($hash);
  530. } else {
  531. JeeLink_SendFromQueue($hash, $bstring);
  532. }
  533. }
  534. }
  535. #####################################
  536. # called from the global loop, when the select for hash->{FD} reports data
  537. sub
  538. JeeLink_Read($)
  539. {
  540. my ($hash) = @_;
  541. my $buf = DevIo_SimpleRead($hash);
  542. return "" if(!defined($buf));
  543. my $name = $hash->{NAME};
  544. my $pandata = $hash->{PARTIAL};
  545. Log3 $name, 5, "JeeLink/RAW: $pandata/$buf";
  546. $pandata .= $buf;
  547. while($pandata =~ m/\n/) {
  548. my $rmsg;
  549. ($rmsg,$pandata) = split("\n", $pandata, 2);
  550. $rmsg =~ s/\r//;
  551. JeeLink_Parse($hash, $hash, $name, $rmsg) if($rmsg);
  552. }
  553. $hash->{PARTIAL} = $pandata;
  554. }
  555. sub
  556. JeeLink_Parse($$$$)
  557. {
  558. my ($hash, $iohash, $name, $rmsg) = @_;
  559. my $dmsg = $rmsg;
  560. #my $l = length($dmsg);
  561. my $rssi;
  562. #my $rssi = hex(substr($dmsg, 1, 2));
  563. #$rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74));
  564. my $lqi;
  565. #my $lqi = hex(substr($dmsg, 3, 2));
  566. #$dmsg = substr($dmsg, 6, $l-6);
  567. #Log3, $name, 5, "$name: $dmsg $rssi $lqi";
  568. next if(!$dmsg || length($dmsg) < 1); # Bogus messages
  569. return if($dmsg =~ m/^Available commands:/ ); # ignore startup messages
  570. return if($dmsg =~ m/^ / ); # ignore startup messages
  571. return if($dmsg =~ m/^-> ack/ ); # ignore send ack
  572. return if($dmsg =~ m/^LGW/); # ignore LGW communication
  573. if( $dmsg =~ /^INIT / ) {
  574. $hash->{initMessages} .= "\n" if( $hash->{initMessages} );
  575. $hash->{initMessages} .= $dmsg;
  576. return;
  577. }
  578. if($dmsg =~ m/^\[/ ) {
  579. if($dmsg =~ m/^\[LaCrosseITPlusReader/) {
  580. my $model = "";
  581. my $settings = "";
  582. ($model, $settings) = split(/ /, $dmsg, 2);
  583. chop($settings);
  584. $hash->{model} = substr($model, 1);
  585. $hash->{settings} = $settings;
  586. }
  587. else {
  588. $hash->{model} = $dmsg;
  589. }
  590. if( ReadingsVal($name,"state","" ) eq "opened" ) {
  591. if( my $initCommandsString = AttrVal($name, "initCommands", undef) ) {
  592. my @initCommands = split(' ', $initCommandsString);
  593. foreach my $command (@initCommands) {
  594. JeeLink_SimpleWrite($hash, $command);
  595. }
  596. } elsif( $dmsg =~m /pcaSerial/ ) {
  597. $hash->{MatchList} = \%matchListPCA301;
  598. JeeLink_SimpleWrite($hash, "1a" ); # led on
  599. JeeLink_SimpleWrite($hash, "1q" ); # quiet mode
  600. #JeeLink_SimpleWrite($hash, "0x" ); # hex mode off
  601. JeeLink_SimpleWrite($hash, "0a" ); # led off
  602. JeeLink_SimpleWrite($hash, "l" ); # list known devices
  603. }
  604. elsif( $dmsg =~m /LaCrosseITPlusReader/ ) {
  605. $hash->{MatchList} = \%matchListPCA301;
  606. } elsif( $dmsg =~m /ec3kSerial/ ) {
  607. $hash->{MatchList} = \%matchListPCA301;
  608. #JeeLink_SimpleWrite($hash, "ec", 1);
  609. } elsif( $dmsg =~m /JeeNode -- HomeControl -/ ) {
  610. $hash->{MatchList} = \%matchListJeeLink433 if($dmsg =~ m/433MHz/);
  611. $hash->{MatchList} = \%matchListJeeLink868 if($dmsg =~ m/868MHz/);
  612. JeeLink_SimpleWrite($hash, "q1"); # turn quiet mode on
  613. JeeLink_SimpleWrite($hash, "a0"); # turn activity led off
  614. JeeLink_SimpleWrite($hash, "f"); # get RFM frequence config
  615. JeeLink_SimpleWrite($hash, "m"); # show used ram on jeenode
  616. }
  617. readingsSingleUpdate($hash, "state", "initialized", 1);
  618. $hash->{initMessages} = '';
  619. }
  620. return;
  621. } elsif ( $dmsg =~ m/^(OOK|FSK)\-(433|868)MHz/ ) {
  622. readingsSingleUpdate($hash,"RFM-config",$dmsg,0);
  623. return;
  624. } elsif ( $dmsg =~ m/^Ram available: </ ) {
  625. $dmsg =~ s/^.*<(.*)>.*$/$1/;
  626. readingsSingleUpdate($hash,"RAM-Available",$dmsg,0);
  627. return;
  628. } elsif( $dmsg =~ m/drecvintr exit/ ) {
  629. # command "ec" will not work with the EC3000, use reset instead
  630. Log3 $hash, 0, "$name: drecvintr detected";
  631. JeeLink_ResetDevice($hash);
  632. #JeeLink_SimpleWrite($hash, "ec",1);
  633. } elsif( $dmsg =~ m/RFM12 hang/ ) {
  634. # EC3000 seems not to recover from an RFM12 hang, so do a reset
  635. Log3 $hash, 0, "$name: RFM12 hang detected";
  636. JeeLink_ResetDevice($hash);
  637. return;
  638. }
  639. $hash->{"${name}_MSGCNT"}++;
  640. $hash->{"${name}_TIME"} = TimeNow();
  641. readingsSingleUpdate($hash, "state", $hash->{READINGS}{state}{VAL}, 0);
  642. $hash->{RAWMSG} = $rmsg;
  643. my %addvals = (RAWMSG => $rmsg);
  644. if(defined($rssi)) {
  645. $hash->{RSSI} = $rssi;
  646. $addvals{RSSI} = $rssi;
  647. }
  648. if(defined($lqi)) {
  649. $hash->{LQI} = $lqi;
  650. $addvals{LQI} = $lqi;
  651. }
  652. #Adapt JeeLink command (O02D28C0000) to match FS20 command ("^81..(04|0c)..0101a001") from CUL
  653. my $dmsgMod = $dmsg;
  654. if( $dmsg =~ m/^O02[A-F0-9]{8}/ ) { #O02D28C0100
  655. my $dev = substr($dmsg, 3, 4);
  656. my $btn = substr($dmsg, 7, 2);
  657. my $cde = substr($dmsg, 9, 2);
  658. # Msg format:
  659. # 81 0b 04 f7 0101 a001 HHHH 01 00 11
  660. $dmsgMod = "810b04f70101a001" . lc($dev) . lc($btn) . "00" . lc($cde);
  661. #Log 1, "Modified F20 command: " . $dmsgMod;
  662. }
  663. #Adapt JeeLink command (F019204356A) to LaCrosse module standard syntax "OK 9 32 1 4 91 62" ("^\\S+\\s+9 ")
  664. elsif( $dmsg =~ m/^F01[A-F0-9]{8}/ ) {
  665. #
  666. # Message Format:
  667. #
  668. # .- [0] -. .- [1] -. .- [2] -. .- [3] -. .- [4] -.
  669. # | | | | | | | | | |
  670. # SSSS.DDDD DDN_.TTTT TTTT.TTTT WHHH.HHHH CCCC.CCCC
  671. # | | | || | | | | | | || | | |
  672. # | | | || | | | | | | || | `--------- CRC
  673. # | | | || | | | | | | |`-------- Humidity
  674. # | | | || | | | | | | |
  675. # | | | || | | | | | | `---- weak battery
  676. # | | | || | | | | | |
  677. # | | | || | | | | `----- Temperature T * 0.1
  678. # | | | || | | | |
  679. # | | | || | | `---------- Temperature T * 1
  680. # | | | || | |
  681. # | | | || `--------------- Temperature T * 10
  682. # | | | | `--- new battery
  683. # | | `---------- ID
  684. # `---- START
  685. #
  686. #
  687. my( $addr, $type, $channel, $temperature, $humidity, $batInserted ) = 0.0;
  688. $addr = ((hex(substr($dmsg,3,2)) & 0x0F) << 2) | ((hex(substr($dmsg,5,2)) & 0xC0) >> 6);
  689. $type = (hex(substr($dmsg,5,2)) & 0xF0) >> 4; # not needed by LaCrosse Module
  690. #$channel = 1; ## $channel = (hex(substr($dmsg,5,2)) & 0x0F);
  691. $temperature = ( ( ((hex(substr($dmsg,5,2)) & 0x0F) * 100) + (((hex(substr($dmsg,7,2)) & 0xF0) >> 4) * 10) + (hex(substr($dmsg,7,2)) & 0x0F) ) / 10) - 40;
  692. return if($temperature >= 60 || $temperature <= -40);
  693. $humidity = hex(substr($dmsg,9,2));
  694. $batInserted = ( (hex(substr($dmsg,5,2)) & 0x20) << 2 );
  695. #build string for 36_LaCrosse.pm
  696. $dmsgMod = "OK 9 $addr ";
  697. #bogus check humidity + eval 2 channel TX25IT
  698. if (($humidity >= 0 && $humidity <= 99) || $humidity == 106 || ($humidity >= 128 && $humidity <= 227) || $humidity == 234) {
  699. $dmsgMod .= (1 | $batInserted);
  700. } elsif ($humidity == 125 || $humidity == 253 ) {
  701. $dmsgMod .= (2 | $batInserted);
  702. }
  703. $temperature = (($temperature* 10 + 1000) & 0xFFFF);
  704. $dmsgMod .= " " . (($temperature >> 8) & 0xFF) . " " . ($temperature & 0xFF) . " $humidity";
  705. }
  706. # if( $rmsg =~ m/(\S* )(\d+)(.*)/ ) {
  707. # my $node = $2 & 0x1F; #mask HDR -> it is handled by the skech
  708. # $dmsg = $1.$node.$3;
  709. # }
  710. Dispatch($hash, $dmsgMod, \%addvals);
  711. }
  712. #####################################
  713. sub
  714. JeeLink_Ready($)
  715. {
  716. my ($hash) = @_;
  717. return DevIo_OpenDev($hash, 1, "JeeLink_DoInit")
  718. if($hash->{STATE} eq "disconnected");
  719. # This is relevant for windows/USB only
  720. my $po = $hash->{USBDev};
  721. my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags);
  722. if($po) {
  723. ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
  724. }
  725. return ($InBytes && $InBytes>0);
  726. }
  727. ########################
  728. sub
  729. JeeLink_SimpleWrite(@)
  730. {
  731. my ($hash, $msg, $nocr) = @_;
  732. return if(!$hash);
  733. my $name = $hash->{NAME};
  734. Log3 $name, 5, "SW: $msg";
  735. $msg .= "\n" unless($nocr);
  736. $hash->{USBDev}->write($msg) if($hash->{USBDev});
  737. syswrite($hash->{TCPDev}, $msg) if($hash->{TCPDev});
  738. syswrite($hash->{DIODev}, $msg) if($hash->{DIODev});
  739. # Some linux installations are broken with 0.001, T01 returns no answer
  740. select(undef, undef, undef, 0.01);
  741. }
  742. sub
  743. JeeLink_ResetDevice($)
  744. {
  745. my ($hash) = @_;
  746. DevIo_CloseDev($hash);
  747. my $ret = DevIo_OpenDev($hash, 0, "JeeLink_DoInit");
  748. return $ret;
  749. }
  750. sub JeeLink_OnTimer($) {
  751. my ($timerName) = @_;
  752. my ($name, $suffix) = split("#", $timerName);
  753. my $hash = $defs{$name};
  754. my $attrVal = AttrVal($name, "timeout", undef);
  755. if(defined($attrVal)) {
  756. my ($timeout, $interval) = split(',', $attrVal);
  757. InternalTimer(gettimeofday() + $interval, "JeeLink_OnTimer", $timerName, 0);
  758. my $jeeLinkTime = InternalVal($name, "${name}_TIME", "2000-01-01 00:00:00");
  759. my ($date, $time, $year, $month, $day, $hour, $min, $sec, $timestamp);
  760. ($date, $time) = split( ' ', $jeeLinkTime);
  761. ($year, $month, $day) = split( '-', $date);
  762. ($hour, $min, $sec) = split( ':', $time);
  763. $month -= 01;
  764. $timestamp = timelocal($sec, $min, $hour, $day, $month, $year);
  765. if (gettimeofday() - $timestamp > $timeout) {
  766. return JeeLink_ResetDevice($hash);
  767. }
  768. }
  769. }
  770. sub
  771. JeeLink_Attr(@)
  772. {
  773. my ($cmd,$name,$aName,$aVal) = @_;
  774. my $hash = $defs{$name};
  775. if( $aName eq "Clients" ) {
  776. $hash->{Clients} = $aVal;
  777. $hash->{Clients} = $clientsJeeLink if( !$hash->{Clients}) ;
  778. } elsif( $aName eq "timeout" ) {
  779. return "Usage: attr $name $aName <timeout,checkInterval>" if($aVal && $aVal !~ m/^[0-9]{1,6},[0-9]{1,6}$/);
  780. my $timerName = $name . "#ResetTimer";
  781. RemoveInternalTimer($timerName);
  782. if($aVal) {
  783. my ($timeout, $interval) = split(',', $aVal);
  784. InternalTimer(gettimeofday()+$interval, "JeeLink_OnTimer", $timerName, 0);
  785. }
  786. } elsif( $aName eq "MatchList" ) {
  787. my $match_list;
  788. if( $cmd eq "set" ) {
  789. $match_list = eval $aVal;
  790. if( $@ ) {
  791. Log3 $name, 2, $name .": $aVal: ". $@;
  792. }
  793. }
  794. if( ref($match_list) eq 'HASH' ) {
  795. $hash->{MatchList} = $match_list;
  796. } else {
  797. $hash->{MatchList} = \%matchListPCA301;
  798. Log3 $name, 2, $name .": $aVal: not a HASH" if( $aVal );
  799. }
  800. } elsif($aName =~ m/^tune/i) { #tune attribute freq / rx:bWidth / rx:rAmpl / rx:sens / tx:deviation / tx:power
  801. # Frequenze: Fc =860+ F x0.0050MHz
  802. # LNA Gain [dB] = MAX -6, -14, -20
  803. # RX Bandwidth [kHz] = -, 400, 340, 270, 200, 134, 67
  804. # DRSSI [dB] = -103, -97, -91, -85, -79, -73
  805. # Deviation [kHz] = 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240
  806. # OuputPower [dBm] = 0, -3, -6, -9, -12, -15, -18, -21
  807. return "Usage: attr $name $aName <Frequence> <Rx:Bandwidth> <Rx:Amplitude> <Rx:Sens> <Tx:Deviation> <Tx:Power>"
  808. if(!$aVal || $aVal !~ m/^(4|8)[\d]{2}.[\d]{3} (0|400|340|270|200|134|67) (0|\-6|\-14|\-20) (\-103|\-97|\-91|\-85|\-79|\-73) (15|30|45|60|75|90|105|120|135|150|165|180|195|210|225|240) (0|\-3|\-6|\-9|\-12|\-15|\-18|\-21)/ );
  809. my $TuneStr = JeeLink_CalcTuneCmd($aVal);
  810. JeeLink_Write($hash, "t" . $TuneStr);
  811. } elsif ($aName eq "DebounceTime") {
  812. return "Usage: attr $name $aName <OOK-Protocol-Number><DebounceTime>"
  813. if($aVal !~ m/^[0-9]{3,5}$/);
  814. #Log3 $name, 4, "set $name $cmd $arg";
  815. JeeLink_Write($hash, "Od" . $aVal);
  816. }
  817. return undef;
  818. }
  819. sub JeeLink_CalcTuneCmd($) {
  820. my ($str) = @_;
  821. my ($freq, $rxbwidth, $rxampl, $rxsens, $txdev, $txpower) = split(' ', $str ,6);
  822. my $sfreq;
  823. if($freq < 800) {
  824. $sfreq = sprintf("%03X", ($freq-430)/0.0025);
  825. } else {
  826. $sfreq = sprintf("%03X", ($freq-860)/0.0050);
  827. }
  828. my $sbwidth = sprintf("%01X", JeeLink_getIndexOfArray($rxbwidth,(0, 400, 340, 270, 200, 134, 67)));
  829. my $sampl = sprintf("%01X", JeeLink_getIndexOfArray($rxampl,(0, -6, -14, -20)));
  830. my $ssens = sprintf("%01X", JeeLink_getIndexOfArray($rxsens, (-103, -97, -91, -85, -79, -73)));
  831. my $sdev = sprintf("%01X", JeeLink_getIndexOfArray($txdev, (15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240)));
  832. my $soutpupower = sprintf("%01X", JeeLink_getIndexOfArray($txpower, (0, -3, -6, -9, -12, -15, -18, -21)));
  833. return $sfreq . $sbwidth . $sampl . $ssens . $sdev . $soutpupower;
  834. }
  835. sub JeeLink_getIndexOfArray($@) {
  836. my ($value, @array) = @_;
  837. my ($ivalue) = grep { $array[$_] == $value } 0..$#array;
  838. return $ivalue;
  839. }
  840. 1;
  841. =pod
  842. =item summary connect JeeLink/Arduino based RF devices
  843. =item summary_DE Anbindung von JeeLink/Arduino basierten RF Ger&auml;ten
  844. =begin html
  845. <a name="JeeLink"></a>
  846. <h3>JeeLink</h3>
  847. <ul>
  848. The JeeLink is a family of RF devices sold by <a href="http://jeelabs.com">jeelabs.com</a>.
  849. It is possible to attach more than one device in order to get better
  850. reception, fhem will filter out duplicate messages.<br><br>
  851. This module provides the IODevice for:
  852. <ul>
  853. <li><a href="#PCA301">PCA301</a> modules that implement the PCA301 protocol.</li>
  854. <li><a href="#LaCrosse">LaCrosse</a> modules that implement the IT+ protocol (Sensors like TX29DTH, TX35, ...).</li>
  855. <li>LevelSender for measuring tank levels</li>
  856. <li>EMT7110 energy meter</li>
  857. <li>Other Sensors like WT440XH (their protocol gets transformed to IT+)</li>
  858. </ul>
  859. <br>
  860. Note: this module may require the Device::SerialPort or Win32::SerialPort module if you attach the device via USB
  861. and the OS sets strange default parameters for serial devices.
  862. <br><br>
  863. <a name="JeeLink_Define"></a>
  864. <b>Define</b>
  865. <ul>
  866. <code>define &lt;name&gt; JeeLink &lt;device&gt;</code> <br>
  867. <br>
  868. USB-connected devices:<br><ul>
  869. &lt;device&gt; specifies the serial port to communicate with the JeeLink.
  870. The name of the serial-device depends on your distribution, under
  871. linux the cdc_acm kernel module is responsible, and usually a
  872. /dev/ttyACM0 device will be created. If your distribution does not have a
  873. cdc_acm module, you can force usbserial to handle the JeeLink by the
  874. following command:<ul>modprobe usbserial vendor=0x0403
  875. product=0x6001</ul>In this case the device is most probably
  876. /dev/ttyUSB0.<br><br>
  877. You can also specify a baudrate if the device name contains the @
  878. character, e.g.: /dev/ttyACM0@57600<br><br>
  879. If the baudrate is "directio" (e.g.: /dev/ttyACM0@directio), then the
  880. perl module Device::SerialPort is not needed, and fhem opens the device
  881. with simple file io. This might work if the operating system uses sane
  882. defaults for the serial parameters, e.g. some Linux distributions and
  883. OSX. <br>
  884. </ul>
  885. <br>
  886. </ul>
  887. <a name="JeeLink_Set"></a>
  888. <b>Set</b>
  889. <ul>
  890. <li>raw &lt;data&gt;<br>
  891. send &lt;data&gt; to the JeeLink. Depending on the sketch running on the JeeLink, different commands are available. Most of the sketches support the v command to get the version info and the ? command to get the list of available commands.
  892. </li><br>
  893. <li>reset<br>
  894. force a device reset closing and reopening the device.
  895. </li><br>
  896. <li>LaCrossePairForSec &lt;sec&gt; [ignore_battery]<br>
  897. enable autocreate of new LaCrosse sensors for &lt;sec&gt; seconds. If ignore_battery is not given only sensors
  898. sending the 'new battery' flag will be created.
  899. </li><br>
  900. <li>flash [firmwareName]<br>
  901. The JeeLink needs the right firmware to be able to receive and deliver the sensor data to fhem. In addition to the way using the
  902. arduino IDE to flash the firmware into the JeeLink this provides a way to flash it directly from FHEM.<br><br>
  903. The firmwareName argument is optional. If not given, set flash checks the firmware type that is currently installed on the JeeLink and
  904. updates it with the same type.<br><br>
  905. There are some requirements:
  906. <ul>
  907. <li>avrdude must be installed on the host<br>
  908. On a linux systems like Cubietruck or Raspberry Pi this can be done with: sudo apt-get install avrdude</li>
  909. <li>the flashCommand attribute must be set.<br>
  910. This attribute defines the command, that gets sent to avrdude to flash the JeeLink.<br>
  911. The default is: avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]<br>
  912. It contains some place-holders that automatically get filled with the according values:<br>
  913. <ul>
  914. <li>[PORT]<br>
  915. is the port the JeeLink is connectd to (e.g. /dev/ttyUSB0)</li>
  916. <li>[HEXFILE]<br>
  917. is the .hex file that shall get flashed. There are three options (applied in this order):<br>
  918. - passed in set flash<br>
  919. - taken from the hexFile attribute<br>
  920. - the default value defined in the module<br>
  921. </li>
  922. <li>[LOGFILE]<br>
  923. The logfile that collects information about the flash process. It gets displayed in FHEM after finishing the flash process</li>
  924. </ul>
  925. </li>
  926. </ul>
  927. </li><br>
  928. <li>led &lt;on|off&gt;<br>
  929. Is used to disable the blue activity LED
  930. </li><br>
  931. <li>beep<br>
  932. ...
  933. </li><br>
  934. <li>setReceiverMode<br>
  935. ...
  936. </li><br>
  937. </ul>
  938. <a name="JeeLink_Get"></a>
  939. <b>Get</b>
  940. <ul>
  941. </ul>
  942. <br>
  943. <a name="JeeLink_Attr"></a>
  944. <b>Attributes</b>
  945. <ul>
  946. <li>Clients<br>
  947. The received data gets distributed to a client (e.g. LaCrosse, EMT7110, ...) that handles the data.
  948. This attribute tells, which are the clients, that handle the data. If you add a new module to FHEM, that shall handle
  949. data distributed by the JeeLink module, you must add it to the Clients attribute.</li>
  950. <li>MatchList<br>
  951. can be set to a perl expression that returns a hash that is used as the MatchList<br>
  952. <code>attr myJeeLink MatchList {'5:AliRF' => '^\\S+\\s+5 '}</code></li>
  953. <li>initCommands<br>
  954. Space separated list of commands to send for device initialization.<br>
  955. This can be used e.g. to bring the LaCrosse Sketch into the data rate toggle mode. In this case initCommands would be: 30t
  956. </li>
  957. <li>flashCommand<br>
  958. See "Set flash"
  959. </li>
  960. <li>timeout<br>
  961. format: &lt;timeout, checkInterval&gt;
  962. Checks every 'checkInterval' seconds if the last data reception is longer than 'timout' seconds ago.<br>
  963. If this is the case, a reset is done for the IO-Device.
  964. </li><br>
  965. </ul>
  966. <br>
  967. </ul>
  968. =end html
  969. =cut