82_LGTV.pm 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. # 82_LGTV.pm; an FHEM high level module for interfacing
  2. # with LG's Scarlet Series of LCDs (e. g. LG 47LG7000)
  3. # Trying to implement a generic command set so that is
  4. # is re-usable with other low-level drivers besides my
  5. # 80_xxLG7000.pm for a serial connection.
  6. #
  7. # Written by Kai 'wusel' Siering <wusel+fhem@uu.org> around 2010-01-20
  8. # $Id: 82_LGTV.pm 2076 2012-11-04 13:49:43Z rudolfkoenig $
  9. #
  10. # re-using code of 82_M232Voltage.pm
  11. # written by Dr. Boris Neubert 2007-12-24
  12. # e-mail: omega at online dot de
  13. #
  14. ##############################################
  15. package main;
  16. use strict;
  17. use warnings;
  18. use Time::HiRes qw(gettimeofday);
  19. sub LGTV_Get($@);
  20. sub LGTV_Define($$);
  21. sub LGTV_GetStatus($);
  22. my @commandlist = (
  23. "power state",
  24. "power on",
  25. "power off",
  26. "input AV1",
  27. "input AV2",
  28. "input AV3",
  29. "input AV3",
  30. "input Component",
  31. "input RGB",
  32. "input HDMI1",
  33. "input HDMI2",
  34. "input HDMI3",
  35. "input HDMI4",
  36. "input DVB-T",
  37. "input PAL",
  38. "audio mute",
  39. "audio normal",
  40. "selected input",
  41. "audio state"
  42. );
  43. ###################################
  44. sub
  45. LGTV_Initialize($)
  46. {
  47. my ($hash) = @_;
  48. $hash->{GetFn} = "LGTV_Get";
  49. $hash->{SetFn} = "LGTV_Set";
  50. $hash->{DefFn} = "LGTV_Define";
  51. $hash->{AttrList} = "dummy:1,0 model:LGTV loglevel:0,1,2,3,4,5 TIMER:30";
  52. }
  53. ###################################
  54. sub
  55. LGTV_GetStatus($)
  56. {
  57. my ($hash) = @_;
  58. my $numchanged=0;
  59. my $name = $hash->{NAME};
  60. my @cmdlist;
  61. my $retval;
  62. @cmdlist=("get", "power", "state");
  63. $retval=LGTV_Set($hash, @cmdlist);
  64. my ($value, $state)=split(" ", $retval);
  65. if($value eq "power" && $state eq "on") {
  66. @cmdlist=("get", "selected", "input");
  67. $retval=LGTV_Set($hash, @cmdlist);
  68. }
  69. InternalTimer(gettimeofday()+$attr{$name}{TIMER}, "LGTV_GetStatus", $hash, 1);
  70. return;
  71. my $d = IOWrite($hash, "power state");
  72. if(!defined($d)) {
  73. my $msg = "LGTV $name read error";
  74. Log GetLogLevel($name,2), $msg;
  75. return $msg;
  76. }
  77. my $tn = TimeNow();
  78. # my ($value, $state)=split(" ", $d);
  79. if($value eq "power") {
  80. if($hash->{READINGS}{$value}{VAL} ne $state) {
  81. $hash->{READINGS}{$value}{TIME} = $tn;
  82. $hash->{READINGS}{$value}{VAL} = $state;
  83. $hash->{CHANGED}[$numchanged++]= "$value: $state";
  84. $hash->{STATE} = $hash->{READINGS}{$value}{VAL};
  85. }
  86. $hash->{STATE} = $hash->{READINGS}{$value}{VAL};
  87. }
  88. if($state eq "on") {
  89. $d = IOWrite($hash, "selected input");
  90. if(!defined($d)) {
  91. my $msg = "LGTV $name read error";
  92. Log GetLogLevel($name,2), $msg;
  93. return $msg;
  94. }
  95. if($value eq "input") { # ... and not e. g. "error" ;)
  96. if($hash->{READINGS}{$value}{VAL} ne $state) {
  97. $tn = TimeNow();
  98. ($value, $state)=split(" ", $d);
  99. $hash->{READINGS}{$value}{TIME} = $tn;
  100. $hash->{READINGS}{$value}{VAL} = $state;
  101. $hash->{CHANGED}[$numchanged++]= "$value: $state";
  102. }
  103. $hash->{STATE} = $hash->{STATE} . ", " . $state;
  104. }
  105. }
  106. DoTrigger($name, undef);
  107. Log GetLogLevel($name,4), "LGTV $name: $hash->{STATE}";
  108. return $hash->{STATE};
  109. }
  110. ###################################
  111. sub
  112. LGTV_Get($@)
  113. {
  114. my ($hash, @a) = @_;
  115. my $msg;
  116. return "argument is missing" if(int(@a) != 2);
  117. if($a[1] eq "power") {
  118. $msg="get power state";
  119. } elsif($a[1] eq "input") {
  120. $msg="get selected input";
  121. } elsif($a[1] eq "audio") {
  122. $msg="get audio state";
  123. } else {
  124. return "unknown get value, valid is power, input, audio";
  125. }
  126. my @msgarray=split(" ", $msg);
  127. my $v = LGTV_Set($hash, @msgarray);
  128. return "$a[0] $v";
  129. }
  130. ###################################
  131. sub
  132. LGTV_Set($@)
  133. {
  134. my ($hash, @a) = @_;
  135. my $ret = undef;
  136. my $na = int(@a);
  137. my $ncmds=int(@commandlist);
  138. my $i;
  139. my $known_cmd=0;
  140. my $what = "";
  141. my $name = $hash->{NAME};
  142. $what=$a[1];
  143. if($na>1) {
  144. for($i=2; $i<$na; $i++) {
  145. $what=$what . " " . lc($a[$i]);
  146. }
  147. }
  148. for($i=0; $i<$ncmds; $i++) {
  149. if(lc($commandlist[$i]) eq $what) {
  150. $what=$commandlist[$i];
  151. $known_cmd+=1;
  152. }
  153. }
  154. if($known_cmd==0) {
  155. return "Unknown argument $what, choose one of power input audio";
  156. }
  157. $ret=IOWrite($hash, $what, "");
  158. if(!defined($ret)) {
  159. my $msg = "LGTV $name read error";
  160. Log GetLogLevel($name,2), $msg;
  161. } else {
  162. my $tn = TimeNow();
  163. my ($value, $state)=split(" ", $ret);
  164. # Logic of the following: if no error:
  165. # if unset READINGS or difference:
  166. # store READINGS
  167. # if power-status: update STATE
  168. # if input-status: update STATE
  169. if($value ne "error") {
  170. if(!defined($hash->{READINGS}{$value}{VAL}) || $state ne $hash->{READINGS}{$value}{VAL}) {
  171. $hash->{READINGS}{$value}{TIME} = $tn;
  172. $hash->{READINGS}{$value}{VAL} = $state;
  173. $hash->{CHANGED}[0]= "$value: $state";
  174. }
  175. if($value eq "power") {
  176. $hash->{STATE}=$state;
  177. }
  178. if($value eq "input") { # implies power being on, usually ...
  179. $hash->{STATE}=$hash->{READINGS}{"power"}{VAL} . ", " . $state;
  180. }
  181. }
  182. }
  183. DoTrigger($name, undef);
  184. return $ret;
  185. }
  186. #############################
  187. sub
  188. LGTV_Define($$)
  189. {
  190. my ($hash, $def) = @_;
  191. my @a = split("[ \t][ \t]*", $def);
  192. my $name = $hash->{NAME};
  193. AssignIoPort($hash);
  194. $attr{$name}{TIMER}=30;
  195. InternalTimer(gettimeofday()+$attr{$name}{TIMER}, "LGTV_GetStatus", $hash, 0);
  196. # Preset if undefined
  197. if(!defined($hash->{READINGS}{"power"}{VAL})) {
  198. my $tn = TimeNow();
  199. $hash->{READINGS}{"power"}{VAL}="unknown";
  200. $hash->{READINGS}{"power"}{TIME}=$tn;
  201. }
  202. return undef;
  203. }
  204. 1;
  205. =pod
  206. =begin html
  207. <a name="LGTV"></a>
  208. <h3>LGTV</h3>
  209. <ul>
  210. <a name="LGTVdefine"></a>
  211. <b>Define</b>
  212. <ul>
  213. <code>define &lt;name&gt; LGTV</code>
  214. <br><br>
  215. This module is expected to work with <a href="#xxLG7000">xxLG7000</a> as it's
  216. IODev. With LGTV and a compatible hardware module (currently, there's only
  217. xxLG7000), you are able to power your TV set on and off, query it's power state,
  218. select the input (AV, RGB, Composites, analogue TV, DVB-T, HDMI) or mute/unmute
  219. the volume.<br>
  220. Defining a LGTV device will schedule an internal task, which periodically reads
  221. the status of the TV set (power state; if power is on, query the selected input)
  222. and triggers notify/filelog commands.<br><br>
  223. Example:
  224. <ul>
  225. <code>define 47LG7000 LGTV</code><br>
  226. <code>attr 47LG7000 IODev <a href="#xxLG7000">myLG7k</a></code>
  227. </ul>
  228. <br>
  229. </ul>
  230. <a name="LGTVset"></a>
  231. <b>Set </b>
  232. <ul>
  233. <code>set &lt;name&gt; &lt;what&gt; &lt;value&gt;</code>
  234. <br><br>
  235. Currently, the following commands are defined; not all may be available on a
  236. given TV set. An error messages should be recorded if e. g. the input in question
  237. is not usable.
  238. <pre>power on
  239. power off
  240. input AV1
  241. input AV2
  242. input AV3
  243. input AV3
  244. input Component
  245. input RGB
  246. input HDMI1
  247. input HDMI2
  248. input HDMI3
  249. input HDMI4
  250. input DVBT
  251. input PAL
  252. audio mute
  253. audio normal</pre>
  254. </ul>
  255. <a name="LGTVget"></a>
  256. <b>Get</b>
  257. <ul>
  258. <code>get &lt;name&gt; &lt;what&gt;</code>
  259. <br><br>
  260. Currently, the following commands are defined; not all may be available on a
  261. given TV set. An error messages should be recorded if e. g. the input in question
  262. is not usable.
  263. <pre>power
  264. input
  265. audio</pre>
  266. </ul>
  267. <a name="LGTVattr"></a>
  268. <b>Attributes</b>
  269. <ul>
  270. <li><a href="#attrdummy">dummy</a></li><br>
  271. <li><a href="#loglevel">loglevel</a></li>
  272. <!-- <li><a href="#model">model</a> (M232Counter)</li> -->
  273. </ul>
  274. <br>
  275. <b>Implementator's note</b>
  276. <ul>
  277. The commands listed above are send 1:1 to the underlying IODev (e. g. xxLG7000); that IODev
  278. is responsible for translation into <i>whatever means</i> to invoke the function on the TV.
  279. It is my hope that other's will adopt this idea and write compatible low level drivers for other
  280. TV sets, to make this module (even ;)) more useful.
  281. </ul>
  282. <br>
  283. </ul>
  284. =end html
  285. =cut