95_WebViewControl.pm 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. ################################################################################
  2. # 95_webViewControl.pm
  3. # Modul for FHEM
  4. #
  5. # Modul for communication between WebViewControl Android App and FHEM
  6. #
  7. # contributed by Dirk Hoffmann 01/2013
  8. # $Id:
  9. #
  10. ################################################################################
  11. package main;
  12. use Data::Dumper; # for debugging only
  13. use strict;
  14. use warnings;
  15. use URI::Escape;
  16. use vars qw {%data %attr %defs %modules $FW_RET}; #supress errors in Eclipse EPIC
  17. use constant {
  18. webViewControl_Version => '0.5.1_beta',
  19. };
  20. #########################
  21. # Forward declaration
  22. sub webViewControl_Initialize($); # Initialize
  23. sub webViewControl_Define($$); # define <name> WEBVIEWCONTROL
  24. sub webViewControl_Undef($$); # delete
  25. sub webViewControl_modifyJsInclude($); # include js parts
  26. sub webViewControl_Set($@); # set
  27. sub webViewControl_Get($@); # get
  28. sub webViewControl_Cgi(); # analyze and parse URL
  29. sub webViewControl_Attr(@);
  30. #########################
  31. # Global variables
  32. my $fhemUrl = '/webviewcontrol' ;
  33. my %sets = (
  34. 'screenBrightness' => 'screenBrightness', # slider,1,1,100',
  35. 'volume' => 'volume', # slider,1,1,100',
  36. 'keepScreenOn' => 'keepScreenOn',
  37. 'toastMessage' => 'toastMessage',
  38. 'reload' => 'reload',
  39. 'audioPlay' => 'audioPlay',
  40. 'audioStop' => 'audioStop',
  41. 'ttsSay' => 'ttsSay',
  42. 'voiceRec' => 'voiceRec',
  43. 'newUrl' => 'newUrl',
  44. 'reload' => 'reload',
  45. );
  46. my %gets = (
  47. 'powerLevel' => 1,
  48. 'powerPlugged' => 1,
  49. 'voiceRecognitionLastError' => 1,
  50. 'voiceRecognitionLastResult'=> 1,
  51. );
  52. my $FW_encoding="UTF-8"; # like in FHEMWEB: encoding hardcoded
  53. ################################################################################
  54. # Implements Initialize function
  55. #
  56. # @param hash $hash hash of device addressed
  57. #
  58. ################################################################################
  59. sub webViewControl_Initialize($) {
  60. my ($hash) = @_;
  61. $hash->{DefFn} = 'webViewControl_Define';
  62. $hash->{UndefFn} = 'webViewControl_Undef';
  63. $hash->{SetFn} = 'webViewControl_Set';
  64. $hash->{GetFn} = 'webViewControl_Get';
  65. $hash->{AttrFn} = "webViewControl_Attr";
  66. $hash->{AttrList} = 'loglevel:0,1,2,3,4,5,6 model userJsFile userCssFile '
  67. . $readingFnAttributes;
  68. # CGI
  69. $data{FWEXT}{$fhemUrl}{FUNC} = 'webViewControl_Cgi';
  70. }
  71. ################################################################################
  72. # Implements DefFn function
  73. #
  74. # @param hash $hash hash of device addressed
  75. # @param string $def definition string
  76. #
  77. # @return string
  78. #
  79. ################################################################################
  80. sub webViewControl_Define($$) {
  81. my ($hash, $def) = @_;
  82. my @a = split("[ \t][ \t]*", $def);
  83. my $name = $hash->{NAME};
  84. return "wrong syntax: define <name> WEBVIEWCONTROL APP-ID" if int(@a)!=3;
  85. $hash->{appID} = $a[2];
  86. $modules{webViewControl}{defptr}{$name} = $hash;
  87. webViewControl_modifyJsInclude($hash);
  88. $hash->{VERSION} = webViewControl_Version;
  89. return undef;
  90. }
  91. #############################
  92. sub webViewControl_Undef($$) {
  93. my ($hash, $name) = @_;
  94. delete($modules{webViewControl}{defptr}{$name});
  95. webViewControl_modifyJsInclude($hash);
  96. return undef;
  97. }
  98. sub webViewControl_Attr (@) {
  99. my (undef, $name, $attr, $val) = @_;
  100. my $hash = $defs{$name};
  101. my $msg = '';
  102. if ($attr eq 'userJsFile' || $attr eq 'userCssFile') {
  103. $attr{$name}{$attr} = $val;
  104. webViewControl_modifyJsInclude($hash);
  105. }
  106. return undef;
  107. }
  108. sub webViewControl_modifyJsInclude($) {
  109. my ($hash) = @_;
  110. my $name = $hash->{NAME};
  111. my @appsArray;
  112. foreach my $appName (keys %{ $modules{webViewControl}{defptr} } ) {
  113. push(@appsArray, '\'' . $modules{webViewControl}{defptr}{$appName}->{appID} . '\': \'' . $appName . '\'');
  114. }
  115. my $vars = 'var wvcDevices = {' . join(', ', @appsArray) . '}';
  116. my $userJs = AttrVal($name, 'userJsFile', '');
  117. $userJs = $userJs ? '<script type="text/javascript" src="/fhem/pgm2/' . $userJs . '"></script>' : '';
  118. my $userCss = AttrVal($name, 'userCssFile', '');
  119. if ($userCss) {
  120. $vars.= '; var wvcUserCssFile="' . $userCss . '"';
  121. }
  122. $data{FWEXT}{$fhemUrl}{SCRIPT} = 'cordova-2.3.0.js"></script>' .
  123. '<script type="text/javascript" src="/fhem/pgm2/webviewcontrol.js"></script>' .
  124. $userJs .
  125. '<script type="text/javascript">' . $vars . '</script>' .
  126. '<script type="text/javascript" charset="UTF-8';
  127. }
  128. ###################################
  129. sub webViewControl_Set($@) {
  130. my ($hash, @a) = @_;
  131. my $setArgs = join(' ', sort values %sets);
  132. my $name = shift @a;
  133. if (int(@a) == 1 && $a[0] eq '?') {
  134. my %localSets = %sets;
  135. $localSets{screenBrightness}.=':slider,1,1,255';
  136. $localSets{volume}.=':slider,0,1,15';
  137. my $setArgs = join(' ', sort values %localSets);
  138. return $setArgs;
  139. }
  140. if ((int(@a) < 1) || (!defined $sets{$a[0]}) ) {
  141. return 'Please specify one of following set value: ' . $setArgs;
  142. }
  143. my $cmd = $a[0];
  144. if (! (($sets{$cmd} eq 'reload') || ($sets{$cmd} eq 'audioStop')) ) {
  145. if ($sets{$cmd} eq 'toastMessage' && (int(@a)) < 2) {
  146. return 'Please input a text for toastMessage';
  147. } elsif ($sets{$cmd} eq 'keepScreenOn') {
  148. if ($a[1] ne 'on' && $a[1] ne 'off') {
  149. return 'keepScreenOn needs on of off';
  150. } else {
  151. $a[1] = ($a[1] eq 'on') ? 'true' : 'false';
  152. }
  153. } elsif ($sets{$cmd} eq 'screenBrightness' && (int($a[1]) < 1 || int($a[1]) > 255)) {
  154. return 'screenBrightness needs value from 1 to 255';
  155. } elsif ($sets{$cmd} eq 'volume' && (int($a[1]) < 0 || int($a[1]) > 15)) {
  156. return 'volume needs value from 0 to 15';
  157. } elsif ($sets{$cmd} eq 'audioPlay' && (int(@a)) < 2 ) {
  158. return 'Please input a url where Audio to play.';
  159. } elsif ($sets{$cmd} eq 'ttsSay' && (int(@a)) < 2 ) {
  160. return 'Please input a text to say.';
  161. } elsif ($sets{$cmd} eq 'voiceRec' && ($a[1] ne 'start' && $a[1] ne 'stop')) {
  162. return 'voiceRec must set to start or stop';
  163. } elsif ($sets{$cmd} eq 'newUrl') {
  164. if ((int(@a)) < 2 ) {
  165. return 'Please input a url.';
  166. } else {
  167. shift(@a);
  168. my $v = uri_escape(join(' ', @a));
  169. @a = ($cmd, $v);
  170. }
  171. }
  172. }
  173. my $v = join(' ', @a);
  174. $hash->{CHANGED}[0] = $v;
  175. $hash->{STATE} = $v;
  176. $hash->{lastCmd} = $v;
  177. $hash->{READINGS}{state}{TIME} = TimeNow();
  178. $hash->{READINGS}{state}{VAL} = $v;
  179. return undef;
  180. }
  181. sub webViewControl_Get($@) {
  182. my ($hash, @a) = @_;
  183. return ('argument missing, usage is <attribute>') if(@a!=2);
  184. if(!$gets{$a[1]}) {
  185. return $a[1] . 'Not supported by get. Supported attributes: ' . join(' ', keys %gets) ;
  186. }
  187. my $retVal;
  188. if ($hash->{READINGS}{$a[1]}{VAL}) {
  189. $retVal = $hash->{READINGS}{$a[1]}{VAL};
  190. } else {
  191. $retVal = $a[1] . ' not yet set';
  192. }
  193. return $retVal;
  194. }
  195. ##################
  196. # Answer requests for webviewcontrol url for set some readings
  197. sub webViewControl_Cgi() {
  198. my ($htmlarg) = @_; #URL
  199. $htmlarg =~ s/^\///;
  200. my @htmlpart = ();
  201. @htmlpart = split("\\?", $htmlarg) if ($htmlarg); #split URL by ?
  202. if ($htmlpart[1]) {
  203. $htmlpart[1] =~ s,^[?/],,;
  204. my @states = ();
  205. my $name = undef;
  206. my %readings = ();
  207. my $timeNow = TimeNow();
  208. foreach my $pv (split("&", $htmlpart[1])) { #per each URL-section devided by &
  209. $pv =~ s/\+/ /g;
  210. $pv =~ s/%(..)/chr(hex($1))/ge;
  211. my ($p,$v) = split("=",$pv, 2); #$p = parameter, $v = value
  212. $p =~ s/[\r]\n/\\\n/g;
  213. $v =~ s/[\r]\n/\\\n/g;
  214. if ($p eq 'id') {
  215. $name = $v;
  216. } else {
  217. $readings{$p} = $v;
  218. push(@states, $p . '=' . $v);
  219. }
  220. }
  221. if ($modules{webViewControl}{defptr}{$name}) {
  222. my $state = join(', ', @states);
  223. my $hash = $modules{webViewControl}{defptr}{$name};
  224. readingsBeginUpdate($hash);
  225. readingsBulkUpdate($hash, "state", $state);
  226. foreach my $reading (keys %readings) {
  227. readingsBulkUpdate($hash, $reading, $readings{$reading});
  228. }
  229. readingsEndUpdate($hash, 1);
  230. }
  231. }
  232. return ("text/html; charset=$FW_encoding", $FW_RET); # $FW_RET composed by FW_pO, FP_pH etc
  233. }
  234. 1;
  235. =pod
  236. =begin html
  237. <a name="WebViewControl"></a>
  238. <h3>WebViewControl</h3>
  239. <ul>
  240. WebViewCountrol ist the interface for the android APP WebviewControl
  241. <br><br>
  242. </ul>
  243. =end html
  244. =cut