10_CUL_IR.pm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. ######################################################
  2. # CUL InfraRed handler as FHM-Module
  3. #
  4. # (c) Olaf Droegehorn / DHS-Computertechnik GmbH
  5. #
  6. # Published under GNU GPL License
  7. ######################################################
  8. # $Id: 10_CUL_IR.pm 3580 2013-08-02 16:17:38Z betateilchen $
  9. package main;
  10. use strict;
  11. use warnings;
  12. sub CUL_IR_Define($$);
  13. sub CUL_IR_Undef($$);
  14. sub CUL_IR_Initialize($);
  15. sub CUL_IR_Parse($$);
  16. sub CUL_IR_SendCmd($$);
  17. sub CUL_IR_Set($@);
  18. sub CUL_IR_Attr(@);
  19. my %sets = (
  20. "irLearnForSec" => "",
  21. "irSend" => ""
  22. );
  23. sub
  24. CUL_IR_Initialize($)
  25. {
  26. my ($hash) = @_;
  27. $hash->{Match} = "^I............";
  28. $hash->{DefFn} = "CUL_IR_Define";
  29. $hash->{UndefFn} = "CUL_IR_Undef";
  30. $hash->{ParseFn} = "CUL_IR_Parse";
  31. $hash->{SetFn} = "CUL_IR_Set";
  32. $hash->{AttrFn} = "CUL_IR_Attr";
  33. $hash->{AttrList} = "do_not_notify:1,0 ignore:0,1 " .
  34. "loglevel:0,1,2,3,4,5,6 learnprefix learncount " .
  35. "Button.* Group.* irReceive:OFF,ON,ON_NR";
  36. }
  37. #############################
  38. sub
  39. CUL_IR_Define($$)
  40. {
  41. my ($hash, $def) = @_;
  42. my @a = split("[ \t][ \t]*", $def);
  43. my $testhash = "";
  44. my $u = "wrong syntax: define <name> CUL_IR <IODEV:CUL/CUN_Device>";
  45. return $u if(int(@a) < 3);
  46. #Assign CUL/CUN within definition as IODev
  47. for my $p (sort { $defs{$b}{NR} <=> $defs{$a}{NR} } keys %defs) {
  48. my $cl = $defs{$p}{Clients};
  49. $cl = $modules{$defs{$p}{TYPE}}{Clients} if(!$cl);
  50. if((defined($cl) && $cl =~ m/:CUL_IR:/) &&
  51. $defs{$p}{NAME} eq $a[2]) {
  52. $hash->{IODev} = $defs{$p};
  53. last;
  54. }
  55. }
  56. if(!$hash->{IODev}) {
  57. Log 3, "No I/O device found for $hash->{NAME}";
  58. return "Wrong IODev specified or IODev doesn't support CUL_IR";
  59. }
  60. #Check if we have already an CUL_IR Device for IODEV
  61. foreach my $name (keys %{ $modules{CUL_IR}{defptr} }) {
  62. $testhash = ($modules{CUL_IR}{defptr}{$name})
  63. if($modules{CUL_IR}{defptr}{$name}->{IODev} == $hash->{IODev});
  64. }
  65. if ($testhash) { #found another CUL_IR for this IODEV!!
  66. Log 2, "CUL_IR already defined for this I/O device";
  67. return "CUL_IR already defined for this I/O device, it's: $testhash->{NAME}";
  68. }
  69. #Everything is fine, let's finish definition
  70. $modules{CUL_IR}{defptr}{("IR_" . $a[2])} = $hash;
  71. $hash->{STATE} = "Initialized";
  72. if (!$attr{$hash->{NAME}}{'learnprefix'}) {
  73. $attr{$hash->{NAME}}{'learnprefix'} = "A";
  74. }
  75. if (!$attr{$hash->{NAME}}{'learncount'}) {
  76. $attr{$hash->{NAME}}{'learncount'} = 0;
  77. }
  78. Log 4, "Sending $hash->{IODev}->{NAME}: Ir";
  79. my $msg = CallFn($hash->{IODev}->{NAME}, "GetFn", $hash->{IODev}, (" ", "raw", "Ir"));
  80. Log 4, "Answer from $hash->{IODev}->{NAME}: $msg";
  81. if ($msg =~ m/raw => 00/) {
  82. $hash->{irReceive} = "OFF";
  83. } elsif ($msg =~ m/raw => 01/) {
  84. $hash->{irReceive} = "ON";
  85. } elsif ($msg =~ m/raw => 02/) {
  86. $hash->{irReceive} = "ON_NR";
  87. } elsif ($msg =~ m/No answer/) {
  88. $hash->{irReceive} = "NoAnswer";
  89. } else {
  90. Log 2, "CUL_IR IODev device didn't answer Ir command correctly: $msg";
  91. $hash->{irReceive} = "UNKNOWN";
  92. }
  93. return undef;
  94. }
  95. #############################
  96. sub
  97. CUL_IR_Undef($$)
  98. {
  99. my ($hash, $name) = @_;
  100. # As after a rename the $name my be different from the $defptr{$n}
  101. # we look for the hash.
  102. foreach my $name (keys %{ $modules{CUL_IR}{defptr} }) {
  103. delete($modules{CUL_IR}{defptr}{$name})
  104. if($modules{CUL_IR}{defptr}{$name} == $hash);
  105. }
  106. return undef;
  107. }
  108. #############################
  109. sub
  110. CUL_IR_Parse($$)
  111. {
  112. my ($iohash, $msg) = @_;
  113. my $myhash = "";
  114. my $found = 0;
  115. foreach my $name (keys %{ $modules{CUL_IR}{defptr} }) {
  116. $myhash = ($modules{CUL_IR}{defptr}{$name})
  117. if($modules{CUL_IR}{defptr}{$name}->{IODev} == $iohash);
  118. }
  119. if(!$myhash) {
  120. Log 4, "IR-Message from $iohash->{NAME}: $msg";
  121. Log 2, "No CUL_IR device found for $iohash->{NAME}, please define a new one";
  122. return "UNDEFINED CUL_IR_$iohash->{NAME} CUL_IR $iohash->{NAME}";
  123. }
  124. Log 4, "IR-Reception: $msg";
  125. # Search for Button-Group
  126. foreach my $name (keys %{ $attr{$myhash->{NAME}} }) {
  127. if ($name =~ m/^Group.*/) {
  128. my ($ir, $cmd) = split("[ \t]", $attr{$myhash->{NAME}}{$name}, 2);
  129. if ($msg =~ m/$ir.*/) {
  130. if (!$cmd) {
  131. Log 5, "Group found; IR:$ir Def:-";
  132. } else {
  133. Log 5, "Group found; IR:$ir Def:$cmd";
  134. AnalyzeCommandChain(undef, $cmd);
  135. }
  136. }
  137. }
  138. }
  139. # Search for single Button(s)
  140. foreach my $name (keys %{ $attr{$myhash->{NAME}} }) {
  141. if ($name =~ m/^Button.*/) {
  142. my ($ir, $cmd) = split("[ \t]", $attr{$myhash->{NAME}}{$name}, 2);
  143. if ($msg eq $ir) {
  144. $found++;
  145. if (!$cmd) {
  146. Log 5, "Button found; IR:$ir Def:-";
  147. } else {
  148. Log 5, "Button found; IR:$ir Def:$cmd";
  149. AnalyzeCommandChain(undef, $cmd);
  150. }
  151. }
  152. }
  153. }
  154. if (!$found) { # No Button identified yet !!
  155. if (!$myhash->{irLearn}) { # OK, No Learning, then leave
  156. return "";
  157. } else { # Let's learn Buttons
  158. my $buttonname = "";
  159. if (!$attr{$myhash->{NAME}}{'learncount'}) {
  160. $attr{$myhash->{NAME}}{'learncount'} = 0;
  161. }
  162. if (!$attr{$myhash->{NAME}}{'learnprefix'}) { # is the learnprefix there?
  163. $buttonname = sprintf("Button%03d", $attr{$myhash->{NAME}}{'learncount'});
  164. } else {
  165. $buttonname = sprintf("Button%s%03d", $attr{$myhash->{NAME}}{'learnprefix'}, $attr{$myhash->{NAME}}{'learncount'});
  166. }
  167. $attr{$myhash->{NAME}}{'learncount'}++;
  168. $attr{$myhash->{NAME}}{$buttonname} = $msg;
  169. }
  170. }
  171. return "";
  172. }
  173. sub
  174. CUL_IR_RemoveIRLearn($)
  175. {
  176. my $hash = shift;
  177. delete($hash->{irLearn});
  178. }
  179. ###################################
  180. sub
  181. CUL_IR_Set($@)
  182. {
  183. my ($hash, @a) = @_;
  184. return "\"set CUL_IR\" needs at least one parameter" if(@a < 2);
  185. return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
  186. if(!defined($sets{$a[1]}));
  187. my $name = shift @a;
  188. my $type = shift @a;
  189. my $arg = join("", @a);
  190. my $ll = GetLogLevel($name,3);
  191. my $ret = "";
  192. my $reccommand = "";
  193. if($type eq "irLearnForSec") { ####################################
  194. return "Usage: set $name irLearnForSec <seconds_active>"
  195. if(!$arg || $arg !~ m/^\d+$/);
  196. $hash->{irLearn} = 1;
  197. InternalTimer(gettimeofday()+$arg, "CUL_IR_RemoveIRLearn", $hash, 1);
  198. }
  199. if($type eq "irSend") { ####################################
  200. return "Usage: set $name irSend <IR-Code | ButtonName>"
  201. if(!$arg || $arg !~ m/^\w+$/);
  202. CUL_IR_SendCmd ($hash, $arg);
  203. }
  204. return $ret;
  205. }
  206. ###################################
  207. sub
  208. CUL_IR_SendCmd($$)
  209. {
  210. my ($hash, $arg) = @_;
  211. my $l4 = GetLogLevel($hash->{NAME},4);
  212. my $found = 0;
  213. my $ir;
  214. my $cmd;
  215. my $bcmd;
  216. if ($arg =~ m/^Button.*/) { #Argument is a ButtonName
  217. # Search for single Button(s)
  218. foreach my $name (keys %{ $attr{$hash->{NAME}} }) {
  219. if ($name eq $arg) {
  220. ($ir, $bcmd) = split("[ \t]", $attr{$hash->{NAME}}{$name}, 2);
  221. $found++;
  222. }
  223. }
  224. if (!$found) {
  225. Log 2, "$hash->{NAME}->irSend: No Button found with name $arg, please define/learn a new one";
  226. return "$hash->{NAME}: Unknown button name $arg";
  227. }
  228. $cmd = sprintf("Is%s", substr($ir, 1));
  229. } else {
  230. if (length ($arg) == 12) {
  231. if ($arg =~ m/^[0-9A-F]+$/) {
  232. $cmd = sprintf("Is%s", $arg);
  233. } else {
  234. Log 2, "$hash->{NAME}->irSend: Wrong IR-Code";
  235. return "$hash->{NAME}: Wrong IR-Code";
  236. }
  237. } elsif (length ($arg) == 13) {
  238. if (substr($arg, 0, 1) eq "I") {
  239. if (substr($arg, 1) =~ m/^[0-9A-F]+$/) {
  240. $cmd = sprintf("Is%s", substr($arg, 1));
  241. } else {
  242. Log 2, "$hash->{NAME}->irSend: Wrong IR-Code";
  243. return "$hash->{NAME}: Wrong IR-Code";
  244. }
  245. } else {
  246. Log 2, "$hash->{NAME}->irSend: Wrong IR-Code";
  247. return "$hash->{NAME}: Wrong IR-Code";
  248. }
  249. } else {
  250. Log 2, "$hash->{NAME}->irSend: Wrong IR-Code";
  251. return "$hash->{NAME}: Wrong IR-Code";
  252. }
  253. }
  254. Log $l4, "$hash->{NAME} SEND $cmd";
  255. IOWrite($hash, "", $cmd);
  256. }
  257. sub
  258. CUL_IR_Attr(@)
  259. {
  260. my @a = @_;
  261. if($a[2] eq "irReceive") {
  262. my $name = $a[1];
  263. my $hash = $defs{$name};
  264. my $reccommand = "";
  265. if($a[3] eq "OFF") {
  266. $reccommand = "00";
  267. } elsif ($a[3] eq "ON") {
  268. $reccommand = "01";
  269. } else {
  270. $reccommand = "02";
  271. }
  272. my $io = $hash->{IODev};
  273. Log 4, "Sending $io->{NAME}: Ir$reccommand";
  274. my $msg = CallFn($io->{NAME}, "GetFn", $io, (" ", "raw", "Ir".$reccommand));
  275. Log 4, "Answer from $io->{NAME}: $msg";
  276. if ($msg =~ m/raw => 00/) {
  277. $hash->{irReceive} = "OFF";
  278. } elsif ($msg =~ m/raw => 01/) {
  279. $hash->{irReceive} = "ON";
  280. } elsif ($msg =~ m/raw => 02/) {
  281. $hash->{irReceive} = "ON_NR";
  282. } elsif ($msg =~ m/No answer/) {
  283. $hash->{irReceive} = "NoAnswer";
  284. } else {
  285. Log 2, "CUL_IR IODev device didn't answer Ir command correctly: $msg";
  286. $hash->{irReceive} = "UNKNOWN";
  287. }
  288. Log 2, "Switched $name irReceive to $hash->{irReceive}";
  289. }
  290. return undef;
  291. }
  292. 1;
  293. =pod
  294. =begin html
  295. <a name="CUL_IR"></a>
  296. <h3>CUL_IR</h3>
  297. <ul>
  298. The CUL_IR module interprets Infrared messages received by the CUN/CUNO/CUNOv2/TuxRadio.
  299. Those devices can receive Infrared Signals from basically any Remote controller and will transform
  300. that information in a so called Button-Code <br><br>
  301. <a name="CUL_IRdefine"></a>
  302. <b>Define</b>
  303. <ul>
  304. <code>define &lt;name&gt; CUL_IR &lt;<a href="#IODev">IODev</a>&gt;</code> <br>
  305. <br>
  306. &lt;<a href="#IODev">IODev</a>&gt; is the devicename of the IR-receivung device, e.g. CUNO1.<br><br>
  307. Your definition should look like E.g.:
  308. <pre>
  309. define IR-Dev CUL_IR CUNO1</pre>
  310. </ul>
  311. <a name="CUL_IRset"></a>
  312. <b>Set</b>
  313. <ul>
  314. <a name="irLearnForSec"></a>
  315. <li>irLearnForSec<br>
  316. Sets the CUL_IR device in an IR-Code Learning mode for the given seconds. Any received IR-Code will
  317. be stored as a Button attribute for this devices. The name of these attributes is dependent on the two
  318. attributes <a href="#CUL_IRattr">learncount</a> and <a href="#CUL_IRattr">learnprefix</a>.<br>
  319. Attention: Before learning IR-Codes the CUL_IR device needs to be set in IR-Receiving mode
  320. by modifying the <a href="#irReceive">irReceive</a> attribute.
  321. </li>
  322. <a name="irSend"></a>
  323. <li>irSend<br>
  324. Sends out IR-commands via the connected IODev. The IR-command can be specified as buttonname according
  325. to <a href="#Button.*">Button.*</a> or as IR-Code directly. If a buttonname is specified, the
  326. corresponding IR-Code will be sent out.<br>
  327. Example: <br>
  328. <pre>set IR-Dev irSend ButtonA001 </pre>
  329. If defining an IR-Code directly the following Code-Syntax needs to be followed:<br>
  330. <pre>IRCode: &lt;PP&gt;&lt;AAAA&gt;&lt;CCCC&gt;&lt;FF&gt; </pre>
  331. with P = Protocol; A = Address; C = Command; F = Flags<br>
  332. With the Flags you can modify IR-Repetition. Flags between 00-0E will produce
  333. 0-15 IR-Repetitions.
  334. You can type the IR-Code as plain as above, or with a heading "I" as learnt for the buttons.<br>
  335. Example: <br>
  336. <code>set IR-Dev irSend 0A07070F0F02<br>
  337. set IR-Dev irSend I0A07070F0F00 </code>
  338. </li>
  339. </ul>
  340. <a name="CUL_IRget"></a>
  341. <b>Get</b>
  342. <ul>N/A</ul>
  343. <a name="CUL_IRattr"></a>
  344. <b>Attributes</b>
  345. <ul>
  346. <li><a href="#do_not_notify">do_not_notify</a></li><br>
  347. <li><a href="#showtime">showtime</a></li><br>
  348. <li><a href="#loglevel">loglevel</a></li><br>
  349. <li><a href="#irReceive">irReceive</a><br>
  350. Configure the IR Transceiver of the &lt;<a href="#IODev">IODev</a>&gt; (the CUNO1). Available
  351. arguments are:
  352. <ul>
  353. <li>OFF<br>
  354. Switching off the reception of IR signals. This is the default.</li>
  355. <li>ON<br>
  356. Switching on the reception of IR signals. This is WITHOUT filtering repetitions. This is
  357. not recommended as many remote controls do repeat their signals.</li>
  358. <li>ON_NR<br>
  359. Switching on the reception of IR signals with filtering of repetitions. This is
  360. the recommended modus operandi.</li>
  361. </ul>
  362. </li><br>
  363. <li><a name="Button.*"></a>Button.*<br>
  364. Button.* is the wildcard for all learnt IR-Codes. IR-Codes are learnt as Button-Attributes.
  365. The name for a learnt Button - IR-Code is compiled out of three elements:<br>
  366. <pre>
  367. Button&lt;learnprefix&gt;&lt;learncount&gt;
  368. </pre>
  369. When the CUL_IR device is set into <a href="#irLearnForSec">learning mode</a> it will generate a
  370. new button-attribute for each new IR-Code received.This is done according to the following syntax:<br>
  371. <pre>
  372. &lt;Button-Attribute-Name&gt; &lt;IR-Code&gt;</pre>
  373. Examples of learnt button-attributes with EMPTY &lt;learnprefix&gt; and &lt;learncount&gt; starting from 1:<br>
  374. <pre>
  375. Button001 I02029A000000
  376. Button002 I02029A000001</pre>
  377. To make sure that something happens when this IR-code is received later on one has to modify the attribute
  378. and to add commands as attribute values.
  379. Examples:
  380. <pre>
  381. Button001 I02029A000000 set WZ_Lamp on
  382. Button002 I02029A000001 set Switch on</pre>
  383. The syntax for this is:
  384. <pre>
  385. attr &lt;device-name&gt; &lt;attribute-name&gt; &lt;IR-Code&gt; &lt;command&gt;
  386. </pre>
  387. </li>
  388. <li><a name="Group.*"></a>Group.*<br>
  389. Group.* is the wildcard for IR-Code groups. With these attributes one can define
  390. IR-Code parts, which may match to several Button-IR-Codes.<br>
  391. This is done by defining group-attributes that contain only parts of the IR-Code.
  392. The syntax is:
  393. <pre>
  394. &lt;Group-Attribute-Name&gt; &lt;IR-Code&gt;</pre>
  395. Examples of a group-attribute is:<br>
  396. <pre>
  397. Group001 I02029A</pre>
  398. With this all IR-Codes starting with I02029A will match the Group001.
  399. </li><br>
  400. <li><a name="learncount"></a>learncount<br>
  401. learncount is used to store the next button-code-number that needs to be learned.
  402. By manually modifying this attribute new button sequences can be arranged.
  403. </li><br>
  404. <li><a name="learnprefix"></a>learnprefix<br>
  405. learnprefix is a string which will be added to the button-attribute-name. <br>
  406. A button-attribute-name is constructed by:
  407. <pre>
  408. Button&lt;learnprefix&gt;&lt;learncount&gt; </pre>
  409. If learnprefix is empty the button-attribute-name only contains the term
  410. "Button" and the actual number of <a href="#learncount">learncount</a>.
  411. </li><br>
  412. </ul>
  413. <br>
  414. </ul>
  415. =end html
  416. =cut