WebViewControl: first commit
git-svn-id: https://svn.fhem.de/fhem/trunk@8178 2b470e98-0d58-463d-a4d8-8e2adae1ed80
@ -66,7 +66,6 @@ WS300_Initialize($)
|
||||
|
||||
# Provider
|
||||
$hash->{AttrList} = "do_not_notify:0,1 showtime:0,1 model:ws300 ".
|
||||
"loglevel:0,1,2,3,4,5,6 ".
|
||||
$readingFnAttributes;
|
||||
|
||||
$hash->{DefFn} = "WS300_Define";
|
||||
@ -669,7 +668,6 @@ NEXTPOLL:
|
||||
<b>Attributes</b>
|
||||
<ul>
|
||||
<li><a href="#do_not_notify">do_not_notify</a></li>
|
||||
<li><a href="#loglevel">loglevel</a></li>
|
||||
<li><a href="#model">model</a> (ws300)</li>
|
||||
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
||||
</ul>
|
||||
|
@ -72,14 +72,14 @@ sub I2C_BMP180_Initialize($) {
|
||||
my ($hash) = @_;
|
||||
|
||||
eval "use HiPi::Device::I2C;";
|
||||
$libcheck_hasHiPi = 0 if($@);
|
||||
$libcheck_hasHiPi = 0 if($@);
|
||||
|
||||
$hash->{DefFn} = 'I2C_BMP180_Define';
|
||||
$hash->{InitFn} = 'I2C_BMP180_Init';
|
||||
$hash->{AttrFn} = 'I2C_BMP180_Attr';
|
||||
$hash->{SetFn} = 'I2C_BMP180_Set';
|
||||
$hash->{UndefFn} = 'I2C_BMP180_Undef';
|
||||
$hash->{I2CRecFn} = 'I2C_BMP180_I2CRec';
|
||||
$hash->{I2CRecFn} = 'I2C_BMP180_I2CRec';
|
||||
|
||||
$hash->{AttrList} = 'IODev do_not_notify:0,1 showtime:0,1 model:BMP180,BMP085 ' .
|
||||
'poll_interval:1,2,5,10,20,30 oversampling_settings:0,1,2,3 ' .
|
||||
@ -119,10 +119,9 @@ sub I2C_BMP180_Define($$) {
|
||||
return $msg;
|
||||
}
|
||||
if ($main::init_done || $hash->{HiPi_used}) {
|
||||
eval { I2C_BMP180_Init( $hash, [ @a[ 2 .. scalar(@a) - 1 ] ] ); };
|
||||
return I2C_BMP180_Catch($@) if $@;
|
||||
}
|
||||
|
||||
eval { I2C_BMP180_Init( $hash, [ @a[ 2 .. scalar(@a) - 1 ] ] ); };
|
||||
return I2C_BMP180_Catch($@) if $@;
|
||||
}
|
||||
}
|
||||
|
||||
sub I2C_BMP180_Init($$) {
|
||||
@ -160,12 +159,12 @@ sub I2C_BMP180_Init($$) {
|
||||
}
|
||||
|
||||
sub I2C_BMP180_Catch($) {
|
||||
my $exception = shift;
|
||||
if ($exception) {
|
||||
$exception =~ /^(.*)( at.*FHEM.*)$/;
|
||||
return $1;
|
||||
}
|
||||
return undef;
|
||||
my $exception = shift;
|
||||
if ($exception) {
|
||||
$exception =~ /^(.*)( at.*FHEM.*)$/;
|
||||
return $1;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
=head2 I2C_BMP180_Attr
|
||||
@ -260,7 +259,7 @@ sub I2C_BMP180_Undef($$) {
|
||||
|
||||
sub I2C_BMP180_I2CRec ($$) {
|
||||
my ($hash, $clientmsg) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $name = $hash->{NAME};
|
||||
my $pname = undef;
|
||||
unless ($hash->{HiPi_used}) {#nicht nutzen wenn HiPi Bibliothek in Benutzung
|
||||
my $phash = $hash->{IODev};
|
||||
@ -275,7 +274,7 @@ sub I2C_BMP180_I2CRec ($$) {
|
||||
|| $hash->{HiPi_used}) ) {
|
||||
if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received}) ) {
|
||||
Log3 $hash, 5, "$name empfangen: $clientmsg->{received}";
|
||||
I2C_BMP180_GetCal ($hash, $clientmsg->{received}) if $clientmsg->{reg} == hex("AA");
|
||||
I2C_BMP180_GetCal ($hash, $clientmsg->{received}) if $clientmsg->{reg} == hex("AA");
|
||||
I2C_BMP180_GetTemp ($hash, $clientmsg->{received}) if $clientmsg->{reg} == hex("F6") && $clientmsg->{nbyte} == 2;
|
||||
I2C_BMP180_GetPress ($hash, $clientmsg->{received}) if $clientmsg->{reg} == hex("F6") && $clientmsg->{nbyte} == 3;
|
||||
}
|
||||
@ -284,7 +283,7 @@ sub I2C_BMP180_I2CRec ($$) {
|
||||
|
||||
sub I2C_BMP180_GetCal ($$) {
|
||||
my ($hash, $rawdata) = @_;
|
||||
my @raw = split(" ",$rawdata);
|
||||
my @raw = split(" ",$rawdata);
|
||||
my $n = 0;
|
||||
Log3 $hash, 5, "in get cal: $rawdata";
|
||||
$hash->{calibrationData}{ac1} = I2C_BMP180_GetCalVar($raw[$n++], $raw[$n++]);
|
||||
@ -317,23 +316,23 @@ sub I2C_BMP180_GetCalVar ($$;$) {
|
||||
|
||||
sub I2C_BMP180_GetTemp ($$) {
|
||||
my ($hash, $rawdata) = @_;
|
||||
my @raw = split(" ",$rawdata);
|
||||
$hash->{uncompTemp} = $raw[0] << 8 | $raw[1];
|
||||
my @raw = split(" ",$rawdata);
|
||||
$hash->{uncompTemp} = $raw[0] << 8 | $raw[1];
|
||||
}
|
||||
|
||||
sub I2C_BMP180_GetPress ($$) {
|
||||
my ($hash, $rawdata) = @_;
|
||||
my @raw = split(" ",$rawdata);
|
||||
my @raw = split(" ",$rawdata);
|
||||
my $overSamplingSettings = AttrVal($hash->{NAME}, 'oversampling_settings', 3);
|
||||
|
||||
my $ut = $hash->{uncompTemp};
|
||||
my $ut = $hash->{uncompTemp};
|
||||
delete $hash->{uncompTemp};
|
||||
my $up = ( ( ($raw[0] << 16) | ($raw[1] << 8) | $raw[2] ) >> (8 - $overSamplingSettings) );
|
||||
|
||||
my $temperature = sprintf(
|
||||
'%.' . AttrVal($hash->{NAME}, 'roundTemperatureDecimal', 1) . 'f',
|
||||
I2C_BMP180_calcTrueTemperature($hash, $ut) / 10
|
||||
);
|
||||
'%.' . AttrVal($hash->{NAME}, 'roundTemperatureDecimal', 1) . 'f',
|
||||
I2C_BMP180_calcTrueTemperature($hash, $ut) / 10
|
||||
);
|
||||
|
||||
my $pressure = sprintf(
|
||||
'%.' . AttrVal($hash->{NAME}, 'roundPressureDecimal', 1) . 'f',
|
||||
@ -369,7 +368,7 @@ sub I2C_BMP180_GetPress ($$) {
|
||||
=cut
|
||||
sub I2C_BMP180_readUncompensatedTemperature($) {
|
||||
my ($hash) = @_;
|
||||
|
||||
|
||||
# Write 0x2E into Register 0xF4. This requests a temperature reading
|
||||
I2C_BMP180_i2cwrite($hash, hex("F4"), hex("2E"));
|
||||
|
||||
@ -452,8 +451,8 @@ sub I2C_BMP180_i2cwrite($$$) {
|
||||
CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
|
||||
direction => "i2cwrite",
|
||||
i2caddress => $hash->{I2C_Address},
|
||||
reg => $reg,
|
||||
data => join (' ',@data),
|
||||
reg => $reg,
|
||||
data => join (' ',@data),
|
||||
});
|
||||
} else {
|
||||
return "no IODev assigned to '$hash->{NAME}'";
|
||||
@ -531,39 +530,39 @@ sub I2C_BMP180_calcTruePressure($$$) {
|
||||
via the i2c bus on Raspberry Pi.<br><br>
|
||||
<b>There are two possibilities connecting to I2C bus:</b><br>
|
||||
<ul>
|
||||
<li><b>via RPII2C module</b><br>
|
||||
The I2C messages are send through an I2C interface module like <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
|
||||
or <a href="#NetzerI2C">NetzerI2C</a> so this device must be defined first.<br>
|
||||
<b>attribute IODev must be set</b><br><br>
|
||||
<li><b>via RPII2C module</b><br>
|
||||
The I2C messages are send through an I2C interface module like <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
|
||||
or <a href="#NetzerI2C">NetzerI2C</a> so this device must be defined first.<br>
|
||||
<b>attribute IODev must be set</b><br><br>
|
||||
</li>
|
||||
<li><b>via HiPi library</b><br>
|
||||
Add these two lines to your <b>/etc/modules</b> file to load the I2C relevant kernel modules
|
||||
automaticly during booting your Raspberry Pi.<br>
|
||||
<code><pre> i2c-bcm2708
|
||||
<li><b>via HiPi library</b><br>
|
||||
Add these two lines to your <b>/etc/modules</b> file to load the I2C relevant kernel modules
|
||||
automaticly during booting your Raspberry Pi.<br>
|
||||
<code><pre>i2c-bcm2708
|
||||
i2c-dev</pre></code>
|
||||
Install HiPi perl modules:<br>
|
||||
<code><pre> wget http://raspberry.znix.com/hipifiles/hipi-install
|
||||
Install HiPi perl modules:<br>
|
||||
<code><pre>wget http://raspberry.znix.com/hipifiles/hipi-install
|
||||
perl hipi-install</pre></code>
|
||||
To change the permissions of the I2C device create file:<br>
|
||||
<code><pre> /etc/udev/rules.d/98_i2c.rules</pre></code>
|
||||
with this content:<br>
|
||||
<code><pre> SUBSYSTEM=="i2c-dev", MODE="0666"</pre></code>
|
||||
<b>Reboot</b><br><br>
|
||||
To change the permissions of the I2C device create file:<br>
|
||||
<code><pre> /etc/udev/rules.d/98_i2c.rules</pre></code>
|
||||
with this content:<br>
|
||||
<code><pre>SUBSYSTEM=="i2c-dev", MODE="0666"</pre></code>
|
||||
<b>Reboot</b><br><br>
|
||||
|
||||
To use the sensor on the second I2C bus at P5 connector
|
||||
(only for version 2 of Raspberry Pi) you must add the bold
|
||||
line of following code to your FHEM start script:
|
||||
<code><pre> case "$1" in
|
||||
To use the sensor on the second I2C bus at P5 connector
|
||||
(only for version 2 of Raspberry Pi) you must add the bold
|
||||
line of following code to your FHEM start script:
|
||||
<code><pre> case "$1" in
|
||||
'start')
|
||||
<b>sudo hipi-i2c e 0 1</b>
|
||||
...</pre></code>
|
||||
</li></ul>
|
||||
<p>
|
||||
</li></ul>
|
||||
<p>
|
||||
|
||||
<b>Define</b>
|
||||
<ul>
|
||||
<code>define BMP180 I2C_BMP180 [<I2C device>]</code><br><br>
|
||||
<I2C device> must not be used if you connect via RPII2C module. For HiPi it's mandatory. <br>
|
||||
<I2C device> must not be used if you connect via RPII2C module. For HiPi it's mandatory. <br>
|
||||
<br>
|
||||
Examples:
|
||||
<pre>
|
||||
@ -571,7 +570,7 @@ sub I2C_BMP180_calcTruePressure($$$) {
|
||||
attr BMP180 oversampling_settings 3
|
||||
attr BMP180 poll_interval 5
|
||||
</pre>
|
||||
<pre>
|
||||
<pre>
|
||||
define BMP180 I2C_BMP180
|
||||
attr BMP180 IODev RPiI2CMod
|
||||
attr BMP180 oversampling_settings 3
|
||||
@ -640,39 +639,39 @@ sub I2C_BMP180_calcTruePressure($$$) {
|
||||
Dieses Modul ermöglicht das Auslesen der digitalen (Luft)drucksensoren
|
||||
BMP085 und BMP180 über den I2C Bus des Raspberry Pi.<br><br>
|
||||
<b>Es gibt zwei Möglichkeiten das Modul mit dem I2C Bus zu verbinden:</b><br>
|
||||
<ul>
|
||||
<li><b>Über das RPII2C Modul</b><br>
|
||||
I2C-Botschaften werden über ein I2C Interface Modul wie beispielsweise das <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
|
||||
oder <a href="#NetzerI2C">NetzerI2C</a> gesendet. Daher muss dieses vorher definiert werden.<br>
|
||||
<b>Das Attribut IODev muss definiert sein.</b><br><br>
|
||||
</li>
|
||||
<li><b>Über die HiPi Bibliothek</b><br>
|
||||
Diese beiden Zeilen müssen in die Datei <b>/etc/modules</b> angefügt werden,
|
||||
um die Kernel Module automatisch beim Booten des Raspberry Pis zu laden.<br>
|
||||
<code><pre> i2c-bcm2708
|
||||
<ul>
|
||||
<li><b>Über das RPII2C Modul</b><br>
|
||||
I2C-Botschaften werden über ein I2C Interface Modul wie beispielsweise das <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
|
||||
oder <a href="#NetzerI2C">NetzerI2C</a> gesendet. Daher muss dieses vorher definiert werden.<br>
|
||||
<b>Das Attribut IODev muss definiert sein.</b><br><br>
|
||||
</li>
|
||||
<li><b>Über die HiPi Bibliothek</b><br>
|
||||
Diese beiden Zeilen müssen in die Datei <b>/etc/modules</b> angefügt werden,
|
||||
um die Kernel Module automatisch beim Booten des Raspberry Pis zu laden.<br>
|
||||
<code><pre>i2c-bcm2708
|
||||
i2c-dev</pre></code>
|
||||
Installation des HiPi Perl Moduls:<br>
|
||||
<code><pre> wget http://raspberry.znix.com/hipifiles/hipi-install
|
||||
Installation des HiPi Perl Moduls:<br>
|
||||
<code><pre>wget http://raspberry.znix.com/hipifiles/hipi-install
|
||||
perl hipi-install</pre></code>
|
||||
Um die Rechte für die I2C Devices anzupassen, folgende Datei:<br>
|
||||
<code><pre> /etc/udev/rules.d/98_i2c.rules</pre></code>
|
||||
mit diesem Inhalt anlegen:<br>
|
||||
<code><pre> SUBSYSTEM=="i2c-dev", MODE="0666"</pre></code>
|
||||
<b>Reboot</b><br><br>
|
||||
Falls der Sensor am zweiten I2C Bus am Stecker P5 (nur in Version 2 des
|
||||
Raspberry Pi) verwendet werden soll, muss die fett gedruckte Zeile
|
||||
des folgenden Codes in das FHEM Start Skript aufgenommen werden:
|
||||
<code><pre> case "$1" in
|
||||
Um die Rechte für die I2C Devices anzupassen, folgende Datei:<br>
|
||||
<code><pre> /etc/udev/rules.d/98_i2c.rules</pre></code>
|
||||
mit diesem Inhalt anlegen:<br>
|
||||
<code><pre>SUBSYSTEM=="i2c-dev", MODE="0666"</pre></code>
|
||||
<b>Reboot</b><br><br>
|
||||
Falls der Sensor am zweiten I2C Bus am Stecker P5 (nur in Version 2 des
|
||||
Raspberry Pi) verwendet werden soll, muss die fett gedruckte Zeile
|
||||
des folgenden Codes in das FHEM Start Skript aufgenommen werden:
|
||||
<code><pre> case "$1" in
|
||||
'start')
|
||||
<b>sudo hipi-i2c e 0 1</b>
|
||||
...</pre></code>
|
||||
</li></ul>
|
||||
</li></ul>
|
||||
<p>
|
||||
|
||||
<b>Define</b>
|
||||
<ul>
|
||||
<code>define BMP180 <BMP180_name> <I2C_device></code><br><br>
|
||||
<I2C device> darf nicht verwendet werden, wenn der I2C Bus über das RPII2C Modul angesprochen wird. For HiPi ist es allerdings notwendig. <br>
|
||||
<I2C device> darf nicht verwendet werden, wenn der I2C Bus über das RPII2C Modul angesprochen wird. For HiPi ist es allerdings notwendig. <br>
|
||||
<br>
|
||||
Beispiel:
|
||||
<pre>
|
||||
@ -680,7 +679,7 @@ sub I2C_BMP180_calcTruePressure($$$) {
|
||||
attr BMP180 oversampling_settings 3
|
||||
attr BMP180 poll_interval 5
|
||||
</pre>
|
||||
<pre>
|
||||
<pre>
|
||||
define BMP180 I2C_BMP180
|
||||
attr BMP180 IODev RPiI2CMod
|
||||
attr BMP180 oversampling_settings 3
|
||||
|
@ -324,6 +324,7 @@ contrib/71_LISTENLIVE.pm betateilchen http://forum.fhem.de Multimedi
|
||||
contrib/98_geodata.pm betateilchen http://forum.fhem.de Sonstiges
|
||||
contrib/98_openweathermap.pm betateilchen http://forum.fhem.de Unterstuetzende Dienste
|
||||
contrib/98_PID.pm betateilchen http://forum.fhem.de Automatisierung
|
||||
contrib/WebViewControl/* Dirk http://forum.fhem.de Mobile Devices
|
||||
|
||||
www/codemirror/* betateilchen http://forum.fhem.de Frontends
|
||||
www/gplot/* rudolfkoenig http://forum.fhem.de Frontends
|
||||
|
311
fhem/contrib/WebViewControl/95_WebViewControl.pm
Normal file
@ -0,0 +1,311 @@
|
||||
################################################################################
|
||||
# 95_webViewControl.pm
|
||||
# Modul for FHEM
|
||||
#
|
||||
# Modul for communication between WebViewControl Android App and FHEM
|
||||
#
|
||||
# contributed by Dirk Hoffmann 01/2013
|
||||
# $Id:
|
||||
#
|
||||
################################################################################
|
||||
|
||||
package main;
|
||||
|
||||
use Data::Dumper; # for debugging only
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use URI::Escape;
|
||||
|
||||
use vars qw {%data %attr %defs %modules $FW_RET}; #supress errors in Eclipse EPIC
|
||||
|
||||
use constant {
|
||||
webViewControl_Version => '0.5.1_beta',
|
||||
};
|
||||
|
||||
#########################
|
||||
# Forward declaration
|
||||
sub webViewControl_Initialize($); # Initialize
|
||||
sub webViewControl_Define($$); # define <name> WEBVIEWCONTROL
|
||||
sub webViewControl_Undef($$); # delete
|
||||
sub webViewControl_modifyJsInclude($); # include js parts
|
||||
sub webViewControl_Set($@); # set
|
||||
sub webViewControl_Get($@); # get
|
||||
sub webViewControl_Cgi(); # analyze and parse URL
|
||||
sub webViewControl_Attr(@);
|
||||
|
||||
#########################
|
||||
# Global variables
|
||||
my $fhemUrl = '/webviewcontrol' ;
|
||||
|
||||
my %sets = (
|
||||
'screenBrightness' => 'screenBrightness', # slider,1,1,100',
|
||||
'volume' => 'volume', # slider,1,1,100',
|
||||
'keepScreenOn' => 'keepScreenOn',
|
||||
'toastMessage' => 'toastMessage',
|
||||
'reload' => 'reload',
|
||||
'audioPlay' => 'audioPlay',
|
||||
'audioStop' => 'audioStop',
|
||||
'ttsSay' => 'ttsSay',
|
||||
'voiceRec' => 'voiceRec',
|
||||
'newUrl' => 'newUrl',
|
||||
'reload' => 'reload',
|
||||
);
|
||||
|
||||
my %gets = (
|
||||
'powerLevel' => 1,
|
||||
'powerPlugged' => 1,
|
||||
'voiceRecognitionLastError' => 1,
|
||||
'voiceRecognitionLastResult'=> 1,
|
||||
);
|
||||
|
||||
my $FW_encoding="UTF-8"; # like in FHEMWEB: encoding hardcoded
|
||||
|
||||
################################################################################
|
||||
# Implements Initialize function
|
||||
#
|
||||
# @param hash $hash hash of device addressed
|
||||
#
|
||||
################################################################################
|
||||
sub webViewControl_Initialize($) {
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{DefFn} = 'webViewControl_Define';
|
||||
$hash->{UndefFn} = 'webViewControl_Undef';
|
||||
$hash->{SetFn} = 'webViewControl_Set';
|
||||
$hash->{GetFn} = 'webViewControl_Get';
|
||||
$hash->{AttrFn} = "webViewControl_Attr";
|
||||
|
||||
$hash->{AttrList} = 'loglevel:0,1,2,3,4,5,6 model userJsFile userCssFile '
|
||||
. $readingFnAttributes;
|
||||
|
||||
# CGI
|
||||
$data{FWEXT}{$fhemUrl}{FUNC} = 'webViewControl_Cgi';
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Implements DefFn function
|
||||
#
|
||||
# @param hash $hash hash of device addressed
|
||||
# @param string $def definition string
|
||||
#
|
||||
# @return string
|
||||
#
|
||||
################################################################################
|
||||
sub webViewControl_Define($$) {
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
return "wrong syntax: define <name> WEBVIEWCONTROL APP-ID" if int(@a)!=3;
|
||||
|
||||
$hash->{appID} = $a[2];
|
||||
$modules{webViewControl}{defptr}{$name} = $hash;
|
||||
|
||||
webViewControl_modifyJsInclude($hash);
|
||||
|
||||
$hash->{VERSION} = webViewControl_Version;
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#############################
|
||||
sub webViewControl_Undef($$) {
|
||||
my ($hash, $name) = @_;
|
||||
|
||||
delete($modules{webViewControl}{defptr}{$name});
|
||||
webViewControl_modifyJsInclude($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub webViewControl_Attr (@) {
|
||||
my (undef, $name, $attr, $val) = @_;
|
||||
my $hash = $defs{$name};
|
||||
my $msg = '';
|
||||
|
||||
if ($attr eq 'userJsFile' || $attr eq 'userCssFile') {
|
||||
$attr{$name}{$attr} = $val;
|
||||
webViewControl_modifyJsInclude($hash);
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub webViewControl_modifyJsInclude($) {
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my @appsArray;
|
||||
foreach my $appName (keys %{ $modules{webViewControl}{defptr} } ) {
|
||||
push(@appsArray, '\'' . $modules{webViewControl}{defptr}{$appName}->{appID} . '\': \'' . $appName . '\'');
|
||||
}
|
||||
|
||||
my $vars = 'var wvcDevices = {' . join(', ', @appsArray) . '}';
|
||||
my $userJs = AttrVal($name, 'userJsFile', '');
|
||||
$userJs = $userJs ? '<script type="text/javascript" src="/fhem/pgm2/' . $userJs . '"></script>' : '';
|
||||
|
||||
my $userCss = AttrVal($name, 'userCssFile', '');
|
||||
if ($userCss) {
|
||||
$vars.= '; var wvcUserCssFile="' . $userCss . '"';
|
||||
}
|
||||
|
||||
$data{FWEXT}{$fhemUrl}{SCRIPT} = 'cordova-2.3.0.js"></script>' .
|
||||
'<script type="text/javascript" src="/fhem/pgm2/webviewcontrol.js"></script>' .
|
||||
$userJs .
|
||||
'<script type="text/javascript">' . $vars . '</script>' .
|
||||
'<script type="text/javascript" charset="UTF-8';
|
||||
}
|
||||
|
||||
###################################
|
||||
sub webViewControl_Set($@) {
|
||||
my ($hash, @a) = @_;
|
||||
my $setArgs = join(' ', sort values %sets);
|
||||
my $name = shift @a;
|
||||
|
||||
if (int(@a) == 1 && $a[0] eq '?') {
|
||||
my %localSets = %sets;
|
||||
$localSets{screenBrightness}.=':slider,1,1,255';
|
||||
$localSets{volume}.=':slider,0,1,15';
|
||||
my $setArgs = join(' ', sort values %localSets);
|
||||
return $setArgs;
|
||||
}
|
||||
|
||||
if ((int(@a) < 1) || (!defined $sets{$a[0]}) ) {
|
||||
return 'Please specify one of following set value: ' . $setArgs;
|
||||
}
|
||||
|
||||
my $cmd = $a[0];
|
||||
|
||||
if (! (($sets{$cmd} eq 'reload') || ($sets{$cmd} eq 'audioStop')) ) {
|
||||
if ($sets{$cmd} eq 'toastMessage' && (int(@a)) < 2) {
|
||||
return 'Please input a text for toastMessage';
|
||||
|
||||
} elsif ($sets{$cmd} eq 'keepScreenOn') {
|
||||
if ($a[1] ne 'on' && $a[1] ne 'off') {
|
||||
return 'keepScreenOn needs on of off';
|
||||
} else {
|
||||
$a[1] = ($a[1] eq 'on') ? 'true' : 'false';
|
||||
}
|
||||
|
||||
} elsif ($sets{$cmd} eq 'screenBrightness' && (int($a[1]) < 1 || int($a[1]) > 255)) {
|
||||
return 'screenBrightness needs value from 1 to 255';
|
||||
|
||||
} elsif ($sets{$cmd} eq 'volume' && (int($a[1]) < 0 || int($a[1]) > 15)) {
|
||||
return 'volume needs value from 0 to 15';
|
||||
|
||||
} elsif ($sets{$cmd} eq 'audioPlay' && (int(@a)) < 2 ) {
|
||||
return 'Please input a url where Audio to play.';
|
||||
|
||||
} elsif ($sets{$cmd} eq 'ttsSay' && (int(@a)) < 2 ) {
|
||||
return 'Please input a text to say.';
|
||||
|
||||
} elsif ($sets{$cmd} eq 'voiceRec' && ($a[1] ne 'start' && $a[1] ne 'stop')) {
|
||||
return 'voiceRec must set to start or stop';
|
||||
|
||||
} elsif ($sets{$cmd} eq 'newUrl') {
|
||||
if ((int(@a)) < 2 ) {
|
||||
return 'Please input a url.';
|
||||
} else {
|
||||
shift(@a);
|
||||
my $v = uri_escape(join(' ', @a));
|
||||
@a = ($cmd, $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $v = join(' ', @a);
|
||||
$hash->{CHANGED}[0] = $v;
|
||||
$hash->{STATE} = $v;
|
||||
$hash->{lastCmd} = $v;
|
||||
$hash->{READINGS}{state}{TIME} = TimeNow();
|
||||
$hash->{READINGS}{state}{VAL} = $v;
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub webViewControl_Get($@) {
|
||||
my ($hash, @a) = @_;
|
||||
|
||||
return ('argument missing, usage is <attribute>') if(@a!=2);
|
||||
|
||||
if(!$gets{$a[1]}) {
|
||||
return $a[1] . 'Not supported by get. Supported attributes: ' . join(' ', keys %gets) ;
|
||||
}
|
||||
|
||||
my $retVal;
|
||||
if ($hash->{READINGS}{$a[1]}{VAL}) {
|
||||
$retVal = $hash->{READINGS}{$a[1]}{VAL};
|
||||
} else {
|
||||
$retVal = $a[1] . ' not yet set';
|
||||
}
|
||||
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
##################
|
||||
# Answer requests for webviewcontrol url for set some readings
|
||||
sub webViewControl_Cgi() {
|
||||
my ($htmlarg) = @_; #URL
|
||||
|
||||
$htmlarg =~ s/^\///;
|
||||
|
||||
my @htmlpart = ();
|
||||
@htmlpart = split("\\?", $htmlarg) if ($htmlarg); #split URL by ?
|
||||
|
||||
if ($htmlpart[1]) {
|
||||
$htmlpart[1] =~ s,^[?/],,;
|
||||
|
||||
my @states = ();
|
||||
my $name = undef;
|
||||
my %readings = ();
|
||||
my $timeNow = TimeNow();
|
||||
|
||||
foreach my $pv (split("&", $htmlpart[1])) { #per each URL-section devided by &
|
||||
$pv =~ s/\+/ /g;
|
||||
$pv =~ s/%(..)/chr(hex($1))/ge;
|
||||
my ($p,$v) = split("=",$pv, 2); #$p = parameter, $v = value
|
||||
$p =~ s/[\r]\n/\\\n/g;
|
||||
$v =~ s/[\r]\n/\\\n/g;
|
||||
|
||||
if ($p eq 'id') {
|
||||
$name = $v;
|
||||
} else {
|
||||
$readings{$p} = $v;
|
||||
push(@states, $p . '=' . $v);
|
||||
}
|
||||
}
|
||||
|
||||
if ($modules{webViewControl}{defptr}{$name}) {
|
||||
my $state = join(', ', @states);
|
||||
my $hash = $modules{webViewControl}{defptr}{$name};
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, "state", $state);
|
||||
|
||||
foreach my $reading (keys %readings) {
|
||||
readingsBulkUpdate($hash, $reading, $readings{$reading});
|
||||
}
|
||||
|
||||
readingsEndUpdate($hash, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return ("text/html; charset=$FW_encoding", $FW_RET); # $FW_RET composed by FW_pO, FP_pH etc
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
=begin html
|
||||
|
||||
<a name="WebViewControl"></a>
|
||||
<h3>WebViewControl</h3>
|
||||
<ul>
|
||||
WebViewCountrol ist the interface for the android APP WebviewControl
|
||||
<br><br>
|
||||
|
||||
</ul>
|
||||
|
||||
=end html
|
||||
=cut
|
BIN
fhem/contrib/WebViewControl/packages/WebViewControl-0.4a.zip
Normal file
BIN
fhem/contrib/WebViewControl/screenshots/sc1.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
fhem/contrib/WebViewControl/screenshots/sc2.jpg
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
fhem/contrib/WebViewControl/screenshots/settings.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
fhem/contrib/WebViewControl/screenshots/settings.png
Normal file
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 14 KiB |
BIN
fhem/contrib/WebViewControl/www/images/default/mic_sprite.png
Normal file
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 2.0 KiB |
6460
fhem/contrib/WebViewControl/www/pgm2/cordova-2.3.0.js
vendored
Normal file
147
fhem/contrib/WebViewControl/www/pgm2/webviewcontrol.css
Normal file
@ -0,0 +1,147 @@
|
||||
* {
|
||||
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
|
||||
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
|
||||
*-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' or 'auto' */
|
||||
}
|
||||
input, textarea {
|
||||
-webkit-user-select: auto;
|
||||
}
|
||||
|
||||
.batteryIconWrapper .batteryIcon {
|
||||
display: block;
|
||||
background: transparent url('../icons/batteryIconSprite.png') no-repeat;
|
||||
height: 32px;
|
||||
width: 18px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.batteryIconWrapper .txtPercent {
|
||||
padding-top: 32px;
|
||||
margin-left: -2px;
|
||||
font-family: sans-serif;
|
||||
color: #999999;
|
||||
width: 25px;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.batteryIconWrapper .bat10green { background-position: 0px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat20green { background-position: -20px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat30green { background-position: -40px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat40green { background-position: -60px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat50green { background-position: -80px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat60green { background-position: -100px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat70green { background-position: -120px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat80green { background-position: -139px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat90green { background-position: -159px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat100green { background-position: -179px 0; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat10yellow { background-position: 0 -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat20yellow { background-position: -20px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat30yellow { background-position: -40px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat40yellow { background-position: -60px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat50yellow { background-position: -80px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat60yellow { background-position: -100px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat70yellow { background-position: -120px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat80yellow { background-position: -139px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat90yellow { background-position: -159px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat100yellow { background-position: -179px -33px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat10red { background-position: 0 -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat20red { background-position: -20px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat30red { background-position: -40px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat40red { background-position: -60px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat50red { background-position: -80px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat60red { background-position: -100px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat70red { background-position: -120px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat80red { background-position: -139px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat90red { background-position: -159px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat100red { background-position: -179px -65px; width: 18px; height: 32px}
|
||||
.batteryIconWrapper .bat0 { background-position: 0 -98px; width: 18px; height: 32px}
|
||||
|
||||
.batteryIconWrapper .acConnected {
|
||||
background: transparent url('../icons/batteryIconSprite.png') no-repeat;
|
||||
background-position: -20px -98px;
|
||||
position: absolute;
|
||||
height: 31px;
|
||||
width: 22px;
|
||||
top: -2px;
|
||||
left: 11px;
|
||||
}
|
||||
|
||||
.onlineIconWrapper .onlineIcon {
|
||||
display: block;
|
||||
background: transparent url('../icons/onlineIconSprite.png') no-repeat;
|
||||
background-position: -19px 0;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.onlineIconWrapper .online { background-position: 0px 0; width: 18px; height: 18px}
|
||||
.onlineIconWrapper .offline { background-position: -19px 0; width: 18px; height: 18px}
|
||||
|
||||
|
||||
#voiceRecOuterWrapper, #voiceRecWrapper, #voiceRecImg, #voiceRecRing {
|
||||
display: -webkit-box;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-box-align: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#voiceRecOuterWrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#voiceRecWrapper {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
background-color: rgba(68,68,68,0.8);
|
||||
border: 2px solid #009EEE;
|
||||
-webkit-border-radius: 10px;
|
||||
}
|
||||
|
||||
#voiceRecImg {
|
||||
background: url('../icons/mic_sprite.png') no-repeat -2px -2px;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
}
|
||||
#voiceRecImg.error {
|
||||
background-position: -2px -362px;
|
||||
}
|
||||
#voiceRecImg.success {
|
||||
background-position: -2px -182px;
|
||||
}
|
||||
|
||||
#voiceRecState {
|
||||
width: 180px;
|
||||
margin-top: 130px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#voiceRecRing {
|
||||
border: 3px solid #009EEE;
|
||||
-webkit-border-radius: 110px;
|
||||
|
||||
height: 110px;
|
||||
width: 110px;
|
||||
|
||||
-webkit-animation: pulse 2s linear infinite;
|
||||
opacity: 0.0
|
||||
}
|
||||
|
||||
@-webkit-keyframes pulse {
|
||||
0% { -webkit-transform: scale(1.0); opacity: 0.0; }
|
||||
10% { opacity: 0.7; }
|
||||
50% { opacity: 1.0; }
|
||||
90% { opacity: 0.7; }
|
||||
100% { -webkit-transform: scale(1.0); opacity: 0.0; }
|
||||
}
|
876
fhem/contrib/WebViewControl/www/pgm2/webviewcontrol.js
Normal file
@ -0,0 +1,876 @@
|
||||
/***********************
|
||||
* TTS Phonegap Plugin *
|
||||
***********************/
|
||||
function TTS() {
|
||||
// var STOPPED = 0;
|
||||
// var INITIALIZING = 1;
|
||||
// var STARTED = 2;
|
||||
|
||||
/**
|
||||
* Play the passed in text as synthesized speech
|
||||
*
|
||||
* @param {String} text
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.speak = function (text, successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "speak", [text]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Interrupt any existing speech, then speak the passed in text as synthesized speech
|
||||
*
|
||||
* @param {String} text
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.interrupt = function (text, successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "interrupt", [text]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop any queued synthesized speech
|
||||
*
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.stop = function (successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "stop", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Play silence for the number of ms passed in as duration
|
||||
*
|
||||
* @param {number} duration
|
||||
* @param {object} successCallback
|
||||
* @param {object} errorCallback
|
||||
* @returns {*}
|
||||
*/
|
||||
this.silence = function(duration, successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "silence", [duration]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set speed of speech. Usable from 30 to 500. Higher values make little difference.
|
||||
*
|
||||
* @param {number} speed
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
* @returns {*}
|
||||
*/
|
||||
this.speed = function(speed, successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "speed", [speed]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set pitch of speech. Useful values are approximately 30 - 300
|
||||
*
|
||||
* @param {number} pitch
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.pitch = function(pitch, successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "pitch", [pitch]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts up the TTS Service
|
||||
*
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.startup = function(successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "startup", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shuts down the TTS Service if you no longer need it.
|
||||
*
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.shutdown = function(successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "shutdown", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds out if the language is currently supported by the TTS service.
|
||||
*
|
||||
* @param {Sting} lang
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.isLanguageAvailable = function(lang, successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "isLanguageAvailable", [lang]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds out the current language of the TTS service.
|
||||
*
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.getLanguage = function(successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "getLanguage", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the language of the TTS service.
|
||||
*
|
||||
* @param {String} lang
|
||||
* @param {Object} successCallback
|
||||
* @param {Object} errorCallback
|
||||
*/
|
||||
this.setLanguage = function(lang, successCallback, errorCallback) {
|
||||
return cordova.exec(successCallback, errorCallback, "TTS", "setLanguage", [lang]);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Load TTS
|
||||
*/
|
||||
if(!window.plugins) {
|
||||
window.plugins = {};
|
||||
}
|
||||
if (!window.plugins.tts) {
|
||||
window.plugins.tts = new TTS();
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* HeadsetListener plugin for Cordova/Phonegap *
|
||||
**********************************************/
|
||||
cordova.define("cordova/plugin/headset", function(require, exports, module) {
|
||||
/**
|
||||
* This class contains information about the current headset status.
|
||||
* @constructor
|
||||
*/
|
||||
var cordova = require('cordova'),
|
||||
exec = require('cordova/exec');
|
||||
|
||||
/**
|
||||
* @return {Number}
|
||||
*/
|
||||
function handlers() {
|
||||
return headset.channels.headsetstatus.numHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var Headset = function() {
|
||||
this._isPlugged = false;
|
||||
|
||||
// Create new event handlers on the window (returns a channel instance)
|
||||
this.channels = {
|
||||
headsetstatus:cordova.addWindowEventHandler('headsetstatus')
|
||||
};
|
||||
|
||||
for (var key in this.channels) {
|
||||
this.channels[key].onHasSubscribersChange = Headset.onHasSubscribersChange;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handlers for when callbacks get registered for the headset.
|
||||
* Keep track of how many handlers we have so we can start and stop the native headset listener.
|
||||
*/
|
||||
Headset.onHasSubscribersChange = function() {
|
||||
// If we just registered the first handler, make sure native listener is started.
|
||||
if (this.numHandlers === 1 && handlers() === 1) {
|
||||
//exec(successFunc, failureFunc, 'service', 'action', [jsonArgs]);
|
||||
exec(headset._status, headset._error, 'HeadsetListener', 'start', []);
|
||||
} else if (handlers() === 0) {
|
||||
exec(null, null, 'HeadsetListener', 'stop', []);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for headset status
|
||||
*
|
||||
* @param {Object} info keys: isPlugged
|
||||
*/
|
||||
Headset.prototype._status = function(info) {
|
||||
if (info) {
|
||||
var me = headset;
|
||||
if (me._isPlugged !== info.isPlugged) {
|
||||
// Fire headsetstatus event
|
||||
cordova.fireWindowEvent('headsetstatus', info);
|
||||
}
|
||||
me._isPlugged = info.isPlugged;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Error callback for battery start
|
||||
*/
|
||||
Headset.prototype._error = function(e) {
|
||||
console.log("Error initializing Headset listener: " + e);
|
||||
};
|
||||
|
||||
var headset = new Headset();
|
||||
|
||||
module.exports = headset;
|
||||
});
|
||||
var headset = cordova.require('cordova/plugin/headset');
|
||||
|
||||
/************************************
|
||||
* VoiceRecognition Phonegap Plugin *
|
||||
************************************/
|
||||
cordova.define("cordova/plugin/voiceRecognition", function(require, exports, module) {
|
||||
/**
|
||||
* This class contains voiceRecognition functions.
|
||||
* @constructor
|
||||
*/
|
||||
var cordova = require('cordova'),
|
||||
exec = require('cordova/exec');
|
||||
|
||||
var errorCodes = {
|
||||
1:'Network operation timed out',
|
||||
2:'Other network related errors',
|
||||
3:'Audio recording error',
|
||||
4:'Server sends error status',
|
||||
5:'Other client side errors',
|
||||
6:'No speech input',
|
||||
7:'No recognition result matched',
|
||||
8:'RecognitionService busy',
|
||||
9:'Insufficient permissions'
|
||||
};
|
||||
|
||||
var states = {
|
||||
STATE_RECOGNISE_END: 0,
|
||||
STATE_RECOGNISE_READY: 1,
|
||||
STATE_RECOGNISE_BEGIN: 2,
|
||||
STATE_RECOGNISE_RESULTS:3,
|
||||
STATE_RECOGNISE_ERROR: 9
|
||||
};
|
||||
|
||||
function handlers() {
|
||||
return voiceRecognition.channels.voicerecognition_begin.numHandlers +
|
||||
voiceRecognition.channels.voicerecognition_end.numHandlers +
|
||||
voiceRecognition.channels.voicerecognition_error.numHandlers +
|
||||
voiceRecognition.channels.voicerecognition_ready.numHandlers +
|
||||
voiceRecognition.channels.voicerecognition_result.numHandlers;
|
||||
}
|
||||
|
||||
var VoiceRecognition = function() {
|
||||
this._state = 0;
|
||||
|
||||
// Create new event handlers on the window (returns a channel instance)
|
||||
this.channels = {
|
||||
voicerecognition_begin:cordova.addWindowEventHandler('voicerecognition_begin'),
|
||||
voicerecognition_end:cordova.addWindowEventHandler('voicerecognition_end'),
|
||||
voicerecognition_error:cordova.addWindowEventHandler('voicerecognition_error'),
|
||||
voicerecognition_ready:cordova.addWindowEventHandler('voicerecognition_ready'),
|
||||
voicerecognition_result:cordova.addWindowEventHandler('voicerecognition_result')
|
||||
};
|
||||
for (var key in this.channels) {
|
||||
this.channels[key].onHasSubscribersChange = VoiceRecognition.onHasSubscribersChange;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handlers for when callbacks get registered for the voiceRecognition.
|
||||
* Keep track of how many handlers we have so we can start and stop the voiceRecognition listener
|
||||
*/
|
||||
VoiceRecognition.onHasSubscribersChange = function() {
|
||||
// If we just registered the first handler, make sure native listener is started.
|
||||
if (this.numHandlers === 1 && handlers() === 1) {
|
||||
exec(voiceRecognition._status, voiceRecognition._error, "VoiceRecognition", "start", []);
|
||||
} else if (handlers() === 0) {
|
||||
exec(null, null, "VoiceRecognition", "stop", []);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for battery status
|
||||
*
|
||||
* @param {Object} info keys: level, isPlugged
|
||||
*/
|
||||
VoiceRecognition.prototype._status = function(info) {
|
||||
if (info) {
|
||||
var me = voiceRecognition;
|
||||
var state = info.state;
|
||||
|
||||
if (me._state !== state) {
|
||||
// Fire events
|
||||
if (state == states.STATE_RECOGNISE_END) {
|
||||
cordova.fireWindowEvent('voicerecognition_end', null);
|
||||
} else if (state == states.STATE_RECOGNISE_READY) {
|
||||
cordova.fireWindowEvent('voicerecognition_ready', null);
|
||||
} else if (state == states.STATE_RECOGNISE_BEGIN) {
|
||||
cordova.fireWindowEvent('voicerecognition_begin', null);
|
||||
} else if (state == states.STATE_RECOGNISE_RESULTS) {
|
||||
cordova.fireWindowEvent('voicerecognition_result', {word: info.result});
|
||||
} else if (state == states.STATE_RECOGNISE_ERROR) {
|
||||
cordova.fireWindowEvent('voicerecognition_error', {code: info.errorCode, description: errorCodes[info.errorCode]});
|
||||
}
|
||||
}
|
||||
me._state = state;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Error callback for voice recognition start
|
||||
*/
|
||||
VoiceRecognition.prototype._error = function(e) {
|
||||
console.log("Error initializing voice recognition listener: " + e);
|
||||
};
|
||||
|
||||
var voiceRecognition = new VoiceRecognition();
|
||||
|
||||
module.exports = voiceRecognition;
|
||||
});
|
||||
var voiceRecognition = cordova.require('cordova/plugin/voiceRecognition');
|
||||
|
||||
|
||||
/******************************
|
||||
* Begin WebViewControl parts *
|
||||
******************************/
|
||||
|
||||
var deviceControl = {
|
||||
exec: function(command, params) {
|
||||
if(cordova.exec) {
|
||||
cordova.exec(
|
||||
function(winParam) {},
|
||||
function(error) {},
|
||||
'DeviceControl',
|
||||
command,
|
||||
params
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set screen brightness
|
||||
* @param level
|
||||
*/
|
||||
screenBrightness: function(level) {
|
||||
deviceControl.exec('setScreenBrightness', [level]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set volume
|
||||
* @param level
|
||||
*/
|
||||
volume: function(level) {
|
||||
deviceControl.exec('setVolume', [level]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set keep screen on / off
|
||||
* @param value
|
||||
*/
|
||||
keepScreenOn: function(value) {
|
||||
deviceControl.exec('setKeepScreenOn', [value]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set Toast Message
|
||||
* @param message
|
||||
*/
|
||||
toastMessage: function(message) {
|
||||
deviceControl.exec('showToast', [message]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform a reload
|
||||
*/
|
||||
reload: function() {
|
||||
window.location.reload();
|
||||
},
|
||||
|
||||
//"http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3"
|
||||
audioPlay: function(value) {
|
||||
audioPlayer.playAudio(value);
|
||||
},
|
||||
|
||||
audioStop: function() {
|
||||
audioPlayer.stopAudio();
|
||||
},
|
||||
|
||||
ttsSay: function(txt) {
|
||||
ttsPlayer.say(txt);
|
||||
},
|
||||
|
||||
voiceRec: function(opt) {
|
||||
fhemWVC.startVoiceRecognition();
|
||||
},
|
||||
|
||||
newUrl: function(opt) {
|
||||
location.href = decodeURIComponent(opt);
|
||||
}
|
||||
};
|
||||
|
||||
var audioPlayer = {
|
||||
media: null,
|
||||
|
||||
// Play audio
|
||||
playAudio: function(src, showToast) {
|
||||
showToast = (typeof(showToast) == 'undefined') ? true : showToast;
|
||||
if (showToast) {
|
||||
deviceControl.toastMessage('playAudio(' + src + ')');
|
||||
}
|
||||
|
||||
audioPlayer.media = new Media(
|
||||
src,
|
||||
function() {},
|
||||
function(error) {
|
||||
deviceControl.toastMessage('Error: playAudio(' + error.message + ' [' + error.code + '])');
|
||||
}
|
||||
);
|
||||
|
||||
// Play audio
|
||||
audioPlayer.media.play();
|
||||
},
|
||||
|
||||
// Stop audio
|
||||
stopAudio: function() {
|
||||
if (audioPlayer.media) {
|
||||
audioPlayer.media.stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var ttsPlayer = {
|
||||
init: function() {
|
||||
window.plugins.tts.setLanguage('de', function(){}, function(){});
|
||||
window.plugins.tts.startup(
|
||||
function() {}, // Success
|
||||
function() {deviceControl.toastMessage('TTS startup error.');}
|
||||
);
|
||||
},
|
||||
|
||||
say: function(txt) {
|
||||
if (txt) {
|
||||
deviceControl.toastMessage('TTS Say: ' + txt);
|
||||
window.plugins.tts.speak(
|
||||
txt,
|
||||
function() {}, // Success
|
||||
function() {deviceControl.toastMessage('TTS error.');}
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var wvcApp;
|
||||
wvcApp = {
|
||||
exitOnBackKey:false,
|
||||
|
||||
// Application Constructor
|
||||
initialize:function (callback) {
|
||||
document.addEventListener('deviceready', function () {
|
||||
|
||||
// console.log('cordova ready?');
|
||||
wvcApp.onDeviceReady();
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
|
||||
// deviceready Event Handler
|
||||
onDeviceReady:function () {
|
||||
if (wvcApp.exitOnBackKey) {
|
||||
document.addEventListener('backbutton', wvcApp.onBackKeyDown, false);
|
||||
}
|
||||
document.addEventListener('offline', wvcApp.onOffline, false);
|
||||
document.addEventListener('online', wvcApp.onOnline, false);
|
||||
document.addEventListener('pause', wvcApp.onPause, false);
|
||||
document.addEventListener('resume', wvcApp.onResume, false);
|
||||
window.addEventListener('batterystatus', wvcApp.onBatteryStatus, false);
|
||||
|
||||
window.addEventListener('voicerecognition_begin', wvcApp.onVoiceRecognitionBegin, false);
|
||||
window.addEventListener('voicerecognition_end', wvcApp.onVoiceRecognitionEnd, false);
|
||||
window.addEventListener('voicerecognition_error', wvcApp.onVoiceRecognitionError, false);
|
||||
window.addEventListener('voicerecognition_ready', wvcApp.onVoiceRecognitionReady, false);
|
||||
window.addEventListener('voicerecognition_result', wvcApp.onVoiceRecognitionResult, false);
|
||||
|
||||
window.addEventListener('headsetstatus', wvcApp.onHeadsetStatus, false);
|
||||
|
||||
ttsPlayer.init();
|
||||
// document.addEventListener('menubutton', wvcApp.onMenuKeyDown, false);
|
||||
},
|
||||
|
||||
removeEventListener:function () {
|
||||
document.removeEventListener('offline', wvcApp.onOffline, false);
|
||||
document.removeEventListener('online', wvcApp.onOnline, false);
|
||||
document.removeEventListener('pause', wvcApp.onPause, false);
|
||||
document.removeEventListener('resume', wvcApp.onResume, false);
|
||||
window.removeEventListener('batterystatus', wvcApp.onBatteryStatus, false);
|
||||
|
||||
window.removeEventListener('voicerecognition_begin', wvcApp.onVoiceRecognitionBegin, false);
|
||||
window.removeEventListener('voicerecognition_end', wvcApp.onVoiceRecognitionEnd, false);
|
||||
window.removeEventListener('voicerecognition_error', wvcApp.onVoiceRecognitionError, false);
|
||||
window.removeEventListener('voicerecognition_ready', wvcApp.onVoiceRecognitionReady, false);
|
||||
window.removeEventListener('voicerecognition_result', wvcApp.onVoiceRecognitionResult, false);
|
||||
|
||||
window.removeEventListener('headsetstatus', wvcApp.onHeadsetStatus, false);
|
||||
},
|
||||
|
||||
|
||||
onVoiceRecognitionBegin:function () {
|
||||
// deviceControl.toastMessage('Voice recognition Begin');
|
||||
},
|
||||
|
||||
onVoiceRecognitionEnd:function () {
|
||||
var recRing = document.getElementById('voiceRecRing');
|
||||
if (recRing) {
|
||||
document.getElementById('voiceRecImg').removeChild(recRing);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
var recDiv = document.getElementById('voiceRecOuterWrapper');
|
||||
if (recDiv) {
|
||||
document.body.removeChild(recDiv);
|
||||
}
|
||||
}, 2000);
|
||||
},
|
||||
|
||||
onVoiceRecognitionError:function (error) {
|
||||
// deviceControl.toastMessage('Voice recognition error: ' + error.description + ' (' + error.code + ')');
|
||||
audioPlayer.playAudio('/android_asset/sounds/voice_recognition_error.mp3', false);
|
||||
|
||||
var recDiv = document.createElement('div');
|
||||
recDiv.setAttribute('id','voiceRecState');
|
||||
recDiv.innerHTML = error.description;
|
||||
|
||||
var recImg = document.getElementById('voiceRecImg');
|
||||
recImg.appendChild(recDiv);
|
||||
recImg.setAttribute('class','error');
|
||||
|
||||
fhemWVC.informFhem('voiceRecognitionLastError', error.code + ':' + error.description);
|
||||
},
|
||||
|
||||
onVoiceRecognitionReady:function () {
|
||||
audioPlayer.playAudio('/android_asset/sounds/voice_recognition_start.mp3', false);
|
||||
|
||||
var recDiv = document.createElement('div');
|
||||
recDiv.setAttribute('id','voiceRecOuterWrapper');
|
||||
recDiv.innerHTML = '<div id="voiceRecWrapper"><div id="voiceRecImg"><div id="voiceRecRing"></div></div></div>';
|
||||
document.body.appendChild(recDiv);
|
||||
},
|
||||
|
||||
onVoiceRecognitionResult:function (result) {
|
||||
audioPlayer.playAudio('/android_asset/sounds/voice_recognition_ok.mp3', false);
|
||||
|
||||
var recImg = document.getElementById('voiceRecImg');
|
||||
recImg.setAttribute('class','success');
|
||||
|
||||
fhemWVC.informFhem('voiceRecognitionLastResult', result.word);
|
||||
|
||||
deviceControl.toastMessage('Voice recognition result: ' + result.word);
|
||||
// deviceControl.ttsSay(result.word);
|
||||
},
|
||||
|
||||
onHeadsetStatus:function (info) {
|
||||
if (info.isPlugged) {
|
||||
deviceControl.toastMessage('The headphones have been plugged in!');
|
||||
} else {
|
||||
deviceControl.toastMessage('The headphones have been unplugged!');
|
||||
}
|
||||
},
|
||||
|
||||
// Back key event handler
|
||||
onBackKeyDown:function () {
|
||||
overrideBackKey = false;
|
||||
if (typeof(container.wvcApp.onBackKeyDown) == 'function') {
|
||||
overrideBackKey = container.wvcApp.onBackKeyDown();
|
||||
}
|
||||
if (!overrideBackKey) {
|
||||
navigator.app.exitApp();
|
||||
}
|
||||
},
|
||||
|
||||
onOffline:function () {
|
||||
if (typeof(fhemWVC.onOffline) == 'function') {
|
||||
fhemWVC.onOffline()
|
||||
}
|
||||
},
|
||||
|
||||
onOnline:function () {
|
||||
if (typeof(fhemWVC.onOnline) == 'function') {
|
||||
fhemWVC.onOnline()
|
||||
}
|
||||
},
|
||||
|
||||
onPause:function () {
|
||||
if (typeof(fhemWVC.onPause) == 'function') {
|
||||
fhemWVC.onPause()
|
||||
}
|
||||
},
|
||||
|
||||
onResume:function () {
|
||||
if (typeof(fhemWVC.onResume) == 'function') {
|
||||
fhemWVC.onResume()
|
||||
}
|
||||
},
|
||||
|
||||
onBatteryStatus:function (info) {
|
||||
if (typeof(fhemWVC.onBatteryStatus) == 'function') {
|
||||
fhemWVC.onBatteryStatus(info);
|
||||
}
|
||||
},
|
||||
|
||||
onConnectionError:function (errorCode, description, failingUrl) {
|
||||
if (typeof(fhemWVC.onConnectionError) == 'function') {
|
||||
fhemWVC.onConnectionError(errorCode, description, failingUrl);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* ************************************************************************ */
|
||||
|
||||
var fhemWVC = {
|
||||
httpRequest: null,
|
||||
currResponseLine: 0,
|
||||
appId: 12345,
|
||||
debug: false,
|
||||
|
||||
deviceState: {
|
||||
powerLevel: null,
|
||||
powerIsPlugged: null
|
||||
},
|
||||
|
||||
reconnect: function(timeout) {
|
||||
setTimeout(function() {
|
||||
fhemWVC.connect();
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
connect: function () {
|
||||
fhemWVC.currResponseLine = 0;
|
||||
fhemWVC.httpRequest = new XMLHttpRequest();
|
||||
fhemWVC.httpRequest.open("GET", '?XHR=1&inform=type=status;filter=room=all×tamp=' + new Date().getTime(), true);
|
||||
|
||||
fhemWVC.httpRequest.onreadystatechange = fhemWVC.parse;
|
||||
fhemWVC.httpRequest.send(null);
|
||||
},
|
||||
|
||||
parse: function() {
|
||||
var httpRequest = fhemWVC.httpRequest;
|
||||
if (!fhemWVC.haveAppDevices()) {
|
||||
return;
|
||||
}
|
||||
if(httpRequest.readyState == 4) {
|
||||
fhemWVC.reconnect(100);
|
||||
return;
|
||||
}
|
||||
|
||||
if(httpRequest.readyState != 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lines = httpRequest.responseText.split("\n");
|
||||
//Pop the last (maybe empty) line after the last "\n"
|
||||
//We wait until it is complete, i.e. terminated by "\n"
|
||||
lines.pop();
|
||||
|
||||
for(var i = fhemWVC.currResponseLine; i < lines.length; i++) {
|
||||
var params = lines[i].split('<<', 3); // Complete arg, 0 -> name, 1 -> value
|
||||
if(params.length != 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wvcDevices[fhemWVC.appId] && wvcDevices[fhemWVC.appId] == params[0]) {
|
||||
var fnValue = params[1].split(' '); // fn and value
|
||||
var fn = fnValue.shift();
|
||||
var value = fnValue.join(' ');
|
||||
|
||||
fhemWVC.log(fn + " / " + value);
|
||||
if (typeof(deviceControl[fn]) != 'undefined' && typeof(deviceControl[fn]) == 'function') {
|
||||
deviceControl[fn](value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Next time, we continue at the next line
|
||||
fhemWVC.currResponseLine = lines.length;
|
||||
},
|
||||
|
||||
haveAppDevices: function() {
|
||||
var retVal = false;
|
||||
if (wvcDevices) {
|
||||
retVal = true;
|
||||
}
|
||||
return retVal;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
initialize: function() {
|
||||
var wvcDevices = {};
|
||||
|
||||
wvcApp.initialize(function(){
|
||||
fhemWVC.createIcons();
|
||||
|
||||
if (typeof(wvcUserCssFile) != 'undefined') {
|
||||
fhemWVC.injectCss(wvcUserCssFile);
|
||||
}
|
||||
|
||||
fhemWVC.reconnect(50);
|
||||
fhemWVC.setConnectionState(navigator.connection.type);
|
||||
|
||||
if (typeof(window.appInterface) != 'undefined' && typeof(window.appInterface) == 'object') {
|
||||
if (typeof(window.appInterface.getAppId) != 'undefined' && typeof(window.appInterface.getAppId) == 'function') {
|
||||
fhemWVC.appId = window.appInterface.getAppId();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.onunload=function(){
|
||||
wvcApp.removeEventListener();
|
||||
};
|
||||
},
|
||||
|
||||
createIcons: function() {
|
||||
fhemWVC.injectCss('webviewcontrol.css');
|
||||
|
||||
var iconDiv = document.createElement('div');
|
||||
iconDiv.innerHTML = '<div> <div class="onlineIconWrapper"><div id="fhemWVC_onlineIcon" class="onlineIcon"></div></div>';
|
||||
iconDiv.innerHTML+= '<div onClick="fhemWVC.startVoiceRecognition();" class="batteryIconWrapper"><div id="fhemWVC_batteryIcon" class="batteryIcon bat0"><div id="fhemWVC_acConnectedIcon" class="acConnected"></div><div id="fhemWVC_batteryPercent" class="txtPercent">?%</div></div></div> </div>';
|
||||
iconDiv.setAttribute('id','htIcons');
|
||||
iconDiv.setAttribute('style','position: fixed; right: 0px; bottom: 0px; width: 32px; height: 80px;');
|
||||
|
||||
document.body.appendChild(iconDiv);
|
||||
},
|
||||
|
||||
startVoiceRecognition: function() {
|
||||
cordova.exec(null, fhemWVC.voiceRecognitionNotPresentError, "VoiceRecognition", "init", []);
|
||||
cordova.exec(null, null, "VoiceRecognition", "startRecognition", []);
|
||||
},
|
||||
|
||||
voiceRecognitionNotPresentError: function (errTxt) {
|
||||
deviceControl.toastMessage(errTxt);
|
||||
fhemWVC.informFhem('voiceRecognitionLastError', '-1:' + errTxt);
|
||||
},
|
||||
|
||||
updateBatteryIcon: function(percent, isPlugged) {
|
||||
var txtPercent = document.getElementById('fhemWVC_batteryPercent');
|
||||
var batteryIcon = document.getElementById('fhemWVC_batteryIcon');
|
||||
var acConnectedIcon = document.getElementById('fhemWVC_acConnectedIcon');
|
||||
|
||||
if (isPlugged) {
|
||||
acConnectedIcon.className = 'acConnected';
|
||||
} else {
|
||||
acConnectedIcon.className = 'hidden';
|
||||
}
|
||||
|
||||
percent = parseInt(percent);
|
||||
percent = (percent > 0 ) ? percent : 0;
|
||||
percent = (percent < 100 ) ? percent : 100;
|
||||
|
||||
txtPercent.innerText = percent + '%';
|
||||
|
||||
var color = (percent > 25) ? 'yellow' : 'red';
|
||||
color = (percent > 50) ? 'green' : color;
|
||||
|
||||
percent = (percent > 0 && percent < 10) ? 10 : percent;
|
||||
percent = parseInt(percent/10) * 10;
|
||||
var batClass = (percent > 0) ? 'bat' + percent + color : 'bat0';
|
||||
|
||||
batteryIcon.className = 'batteryIcon ' + batClass;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inject given css file
|
||||
* @param cssFile
|
||||
*/
|
||||
injectCss: function(cssFile) {
|
||||
var css = document.createElement('link');
|
||||
css.setAttribute('href','/fhem/pgm2/' + cssFile);
|
||||
css.setAttribute('rel','stylesheet');
|
||||
document.getElementsByTagName('head')[0].appendChild(css);
|
||||
},
|
||||
|
||||
injectRemoteDebugger: function() {
|
||||
var js = document.createElement('script');
|
||||
js.setAttribute('src','http://debug.phonegap.com/target/target-script-min.js#webViewControl');
|
||||
js.setAttribute('type','text/javascript');
|
||||
document.getElementsByTagName('head')[0].appendChild(js);
|
||||
},
|
||||
|
||||
informFhem: function(command, value) {
|
||||
var webViewClientId = (typeof(wvcDevices[fhemWVC.appId]) != 'undefined') ? wvcDevices[fhemWVC.appId] : 'undefined';
|
||||
var getVars = '?id=' + webViewClientId;
|
||||
|
||||
if (command == 'powerState') {
|
||||
getVars+= '&powerLevel=' + fhemWVC.deviceState.powerLevel;
|
||||
getVars+= '&powerPlugged=' + fhemWVC.deviceState.powerIsPlugged;
|
||||
} else {
|
||||
getVars+= '&' + command + '=' + value;
|
||||
}
|
||||
|
||||
var httpRequest = new XMLHttpRequest();
|
||||
httpRequest.open("GET", '/fhem/webviewcontrol' + getVars, true);
|
||||
httpRequest.send(null);
|
||||
},
|
||||
|
||||
setConnectionState: function(networkState) {
|
||||
var onlineIcon = document.getElementById('fhemWVC_onlineIcon');
|
||||
var onlineClass = 'offline';
|
||||
|
||||
// we set the network icon on green on wifi or ethernet connection only
|
||||
if (networkState == Connection.ETHERNET || networkState == Connection.WIFI) {
|
||||
onlineClass = 'online';
|
||||
}
|
||||
|
||||
onlineIcon.className = 'onlineIcon ' + onlineClass;
|
||||
},
|
||||
|
||||
onConnectionError: function(errorCode, description, failingUrl) {
|
||||
},
|
||||
|
||||
onBatteryStatus: function(info) {
|
||||
var inform = false;
|
||||
if (fhemWVC.deviceState.powerLevel != info.level || fhemWVC.deviceState.powerIsPlugged != info.isPlugged) {
|
||||
inform = true;
|
||||
}
|
||||
|
||||
fhemWVC.updateBatteryIcon(info.level, info.isPlugged);
|
||||
fhemWVC.deviceState.powerLevel = info.level;
|
||||
fhemWVC.deviceState.powerIsPlugged = info.isPlugged;
|
||||
|
||||
if (inform) {
|
||||
fhemWVC.informFhem('powerState');
|
||||
}
|
||||
},
|
||||
|
||||
onResume: function() {
|
||||
deviceControl.toastMessage('App resumes from pause.')
|
||||
},
|
||||
|
||||
onPause: function() {
|
||||
deviceControl.toastMessage('App go to pause.')
|
||||
},
|
||||
|
||||
onOnline: function() {
|
||||
deviceControl.toastMessage('Network online')
|
||||
},
|
||||
|
||||
onOffline: function() {
|
||||
deviceControl.toastMessage('Network offline')
|
||||
},
|
||||
|
||||
log: function(dbgObj) {
|
||||
if (fhemWVC.debug) {
|
||||
console.log (dbgObj);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//fhemWVC.injectRemoteDebugger();
|
||||
fhemWVC.initialize();
|
||||
|
||||
/*
|
||||
// uncomment this for testing without the device
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
fhemWVC.appId = '00001234'; // Set alternative appId here
|
||||
fhemWVC.createIcons();
|
||||
fhemWVC.reconnect(50);
|
||||
fhemWVC.debug = true;
|
||||
fhemWVC.onBatteryStatus({level: 53, isPlugged: false});
|
||||
},false);
|
||||
*/
|