mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-08 07:24:21 +00:00
All my modules: refactoring code
git-svn-id: https://svn.fhem.de/fhem/trunk@14012 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
591a2717a1
commit
d2a6bcd07b
@ -1,30 +1,7 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# 59_Wunderground.pm
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# http://api.wunderground.com/weather/api
|
# http://api.wunderground.com/weather/api
|
||||||
|
#
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
@ -36,9 +13,7 @@ use Encode qw(encode_utf8 decode_utf8);
|
|||||||
use Unit;
|
use Unit;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
sub Wunderground_Hash2Readings($$;$);
|
# initialize ##################################################################
|
||||||
|
|
||||||
###################################
|
|
||||||
sub Wunderground_Initialize($) {
|
sub Wunderground_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
@ -47,15 +22,15 @@ sub Wunderground_Initialize($) {
|
|||||||
my $webhookFWinstance =
|
my $webhookFWinstance =
|
||||||
join( ",", devspec2array('TYPE=FHEMWEB:FILTER=TEMPORARY!=1') );
|
join( ",", devspec2array('TYPE=FHEMWEB:FILTER=TEMPORARY!=1') );
|
||||||
|
|
||||||
$hash->{SetFn} = "Wunderground_Set";
|
|
||||||
$hash->{DefFn} = "Wunderground_Define";
|
$hash->{DefFn} = "Wunderground_Define";
|
||||||
$hash->{AttrFn} = "Wunderground_Attr";
|
|
||||||
$hash->{UndefFn} = "Wunderground_Undefine";
|
$hash->{UndefFn} = "Wunderground_Undefine";
|
||||||
|
$hash->{SetFn} = "Wunderground_Set";
|
||||||
|
$hash->{AttrFn} = "Wunderground_Attr";
|
||||||
$hash->{DbLog_splitFn} = "Unit_DbLog_split";
|
$hash->{DbLog_splitFn} = "Unit_DbLog_split";
|
||||||
$hash->{parseParams} = 1;
|
$hash->{parseParams} = 1;
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$hash->{AttrList} =
|
||||||
"disable:0,1 timeout:1,2,3,4,5 pollInterval:300,450,600,750,900 wu_lang:en,de,at,ch,nl,fr,pl wu_pws:1,0 wu_bestfct:1,0 stateReadings stateReadingsFormat:0,1 "
|
"disable:0,1 disabledForIntervals do_not_notify:1,0 timeout:1,2,3,4,5 pollInterval:300,450,600,750,900 wu_lang:en,de,at,ch,nl,fr,pl wu_pws:1,0 wu_bestfct:1,0 stateReadings stateReadingsFormat:0,1 "
|
||||||
. "wu_features:multiple-strict,alerts,almanac,astronomy,conditions,currenthurricane,forecast,forecast10day,hourly,hourly10day "
|
. "wu_features:multiple-strict,alerts,almanac,astronomy,conditions,currenthurricane,forecast,forecast10day,hourly,hourly10day "
|
||||||
. $readingFnAttributes;
|
. $readingFnAttributes;
|
||||||
|
|
||||||
@ -228,11 +203,116 @@ sub Wunderground_Initialize($) {
|
|||||||
'wind_speed' => { rtype => 'kmph', formula_symbol => 'Ws' },
|
'wind_speed' => { rtype => 'kmph', formula_symbol => 'Ws' },
|
||||||
'wind_speed_mph' => { rtype => 'mph', formula_symbol => 'Ws' }
|
'wind_speed_mph' => { rtype => 'mph', formula_symbol => 'Ws' }
|
||||||
};
|
};
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
# regular Fn ##################################################################
|
||||||
|
sub Wunderground_Define($$$) {
|
||||||
|
my ( $hash, $a, $h ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $infix = "Wunderground";
|
||||||
|
|
||||||
|
Log3 $name, 5, "Wunderground $name: called function Wunderground_Define()";
|
||||||
|
|
||||||
|
eval {
|
||||||
|
require JSON;
|
||||||
|
import JSON qw( decode_json );
|
||||||
|
};
|
||||||
|
return "Please install Perl JSON to use module Wunderground"
|
||||||
|
if ($@);
|
||||||
|
|
||||||
|
if ( int(@$a) < 2 ) {
|
||||||
|
my $msg = "Wrong syntax: define <name> Wunderground <api-key> <pws-id>";
|
||||||
|
Log3 $name, 4, $msg;
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash->{TYPE} = "Wunderground";
|
||||||
|
|
||||||
|
$hash->{API_KEY} = @$a[2];
|
||||||
|
$hash->{QUERY} = @$a[3];
|
||||||
|
|
||||||
|
$hash->{QUERY} = "pws:" . $hash->{QUERY}
|
||||||
|
if ( $hash->{QUERY} =~ /^[A-Z]{3,}\d{1,}$/ );
|
||||||
|
|
||||||
|
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
|
||||||
|
fhem 'attr ' . $name . ' stateReadings temp_c humidity';
|
||||||
|
fhem 'attr ' . $name . ' stateReadingsFormat 1';
|
||||||
|
fhem 'attr ' . $name . ' wu_features astronomy,conditions,forecast';
|
||||||
|
}
|
||||||
|
|
||||||
|
# start the status update timer
|
||||||
|
Wunderground_GetStatus( $hash, 2 );
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Wunderground_Undefine($$$) {
|
||||||
|
my ( $hash, $a, $h ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
if ( defined( $hash->{fhem}{infix} ) ) {
|
||||||
|
Wunderground_removeExtension( $hash->{fhem}{infix} );
|
||||||
|
}
|
||||||
|
|
||||||
|
Log3 $name, 5,
|
||||||
|
"Wunderground $name: called function Wunderground_Undefine()";
|
||||||
|
|
||||||
|
# Stop the internal GetStatus-Loop and exit
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
|
# release reverse pointer
|
||||||
|
delete $modules{Wunderground}{defptr}{$name};
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Wunderground_Set($$$) {
|
||||||
|
my ( $hash, $a, $h ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
Log3 $name, 5, "Wunderground $name: called function Wunderground_Set()";
|
||||||
|
|
||||||
|
return "Argument is missing" if ( int(@$a) < 1 );
|
||||||
|
|
||||||
|
my $usage = "Unknown argument " . @$a[1] . ", choose one of update:noArg";
|
||||||
|
|
||||||
|
my $cmd = '';
|
||||||
|
my $result;
|
||||||
|
|
||||||
|
# update
|
||||||
|
if ( lc( @$a[1] ) eq "update" ) {
|
||||||
|
Log3 $name, 3, "Wunderground set $name " . @$a[1];
|
||||||
|
Wunderground_GetStatus($hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
# return usage hint
|
||||||
|
else {
|
||||||
|
return $usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Wunderground_Attr(@) {
|
||||||
|
my ( $cmd, $name, $attrName, $attrVal ) = @_;
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
|
Log3 $name, 5, "Wunderground $name: called function Wunderground_Attr()";
|
||||||
|
|
||||||
|
return
|
||||||
|
"Invalid value for attribute $attrName: minimum value is 1 second, maximum 5 seconds"
|
||||||
|
if ( $attrVal
|
||||||
|
&& $attrName eq "timeout"
|
||||||
|
&& ( $attrVal < 1 || $attrVal > 5 ) );
|
||||||
|
|
||||||
|
return
|
||||||
|
"Invalid value for attribute $attrName: minimum value is 300 seconds"
|
||||||
|
if ( $attrVal && $attrName eq "pollInterval" && $attrVal < 300 );
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
# module Fn ####################################################################
|
||||||
sub Wunderground_GetStatus($;$) {
|
sub Wunderground_GetStatus($;$) {
|
||||||
my ( $hash, $delay ) = @_;
|
my ( $hash, $delay ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -286,102 +366,6 @@ sub Wunderground_GetStatus($;$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub Wunderground_Set($$$) {
|
|
||||||
my ( $hash, $a, $h ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
|
|
||||||
Log3 $name, 5, "Wunderground $name: called function Wunderground_Set()";
|
|
||||||
|
|
||||||
return "Argument is missing" if ( int(@$a) < 1 );
|
|
||||||
|
|
||||||
my $usage = "Unknown argument " . @$a[1] . ", choose one of update:noArg";
|
|
||||||
|
|
||||||
my $cmd = '';
|
|
||||||
my $result;
|
|
||||||
|
|
||||||
# update
|
|
||||||
if ( lc( @$a[1] ) eq "update" ) {
|
|
||||||
Log3 $name, 3, "Wunderground set $name " . @$a[1];
|
|
||||||
Wunderground_GetStatus($hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
# return usage hint
|
|
||||||
else {
|
|
||||||
return $usage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub Wunderground_Define($$$) {
|
|
||||||
my ( $hash, $a, $h ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
my $infix = "Wunderground";
|
|
||||||
|
|
||||||
Log3 $name, 5, "Wunderground $name: called function Wunderground_Define()";
|
|
||||||
|
|
||||||
eval {
|
|
||||||
require JSON;
|
|
||||||
import JSON qw( decode_json );
|
|
||||||
};
|
|
||||||
return "Please install Perl JSON to use module Wunderground"
|
|
||||||
if ($@);
|
|
||||||
|
|
||||||
if ( int(@$a) < 2 ) {
|
|
||||||
my $msg = "Wrong syntax: define <name> Wunderground <api-key> <pws-id>";
|
|
||||||
Log3 $name, 4, $msg;
|
|
||||||
return $msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
$hash->{TYPE} = "Wunderground";
|
|
||||||
|
|
||||||
$hash->{API_KEY} = @$a[2];
|
|
||||||
$hash->{QUERY} = @$a[3];
|
|
||||||
|
|
||||||
$hash->{QUERY} = "pws:" . $hash->{QUERY}
|
|
||||||
if ( $hash->{QUERY} =~ /^[A-Z]{3,}\d{1,}$/ );
|
|
||||||
|
|
||||||
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
|
|
||||||
fhem 'attr ' . $name . ' stateReadings temp_c humidity';
|
|
||||||
fhem 'attr ' . $name . ' stateReadingsFormat 1';
|
|
||||||
fhem 'attr ' . $name . ' wu_features astronomy,conditions,forecast';
|
|
||||||
}
|
|
||||||
|
|
||||||
# start the status update timer
|
|
||||||
Wunderground_GetStatus( $hash, 2 );
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub Wunderground_Attr(@) {
|
|
||||||
my ( $cmd, $name, $attrName, $attrVal ) = @_;
|
|
||||||
my $hash = $defs{$name};
|
|
||||||
|
|
||||||
Log3 $name, 5, "Wunderground $name: called function Wunderground_Attr()";
|
|
||||||
|
|
||||||
return
|
|
||||||
"Invalid value for attribute $attrName: minimum value is 1 second, maximum 5 seconds"
|
|
||||||
if ( $attrVal
|
|
||||||
&& $attrName eq "timeout"
|
|
||||||
&& ( $attrVal < 1 || $attrVal > 5 ) );
|
|
||||||
|
|
||||||
return
|
|
||||||
"Invalid value for attribute $attrName: minimum value is 300 seconds"
|
|
||||||
if ( $attrVal && $attrName eq "pollInterval" && $attrVal < 300 );
|
|
||||||
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
############################################################################################################
|
|
||||||
#
|
|
||||||
# Begin of helper functions
|
|
||||||
#
|
|
||||||
############################################################################################################
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub Wunderground_SendCommand($$) {
|
sub Wunderground_SendCommand($$) {
|
||||||
my ( $hash, $features ) = @_;
|
my ( $hash, $features ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -420,7 +404,6 @@ sub Wunderground_SendCommand($$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub Wunderground_ReceiveCommand($$$) {
|
sub Wunderground_ReceiveCommand($$$) {
|
||||||
my ( $param, $err, $data ) = @_;
|
my ( $param, $err, $data ) = @_;
|
||||||
my $hash = $param->{hash};
|
my $hash = $param->{hash};
|
||||||
@ -495,7 +478,8 @@ sub Wunderground_ReceiveCommand($$$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
sub Wunderground_Hash2Readings($$;$);
|
||||||
|
|
||||||
sub Wunderground_Hash2Readings($$;$) {
|
sub Wunderground_Hash2Readings($$;$) {
|
||||||
my ( $hash, $h, $r ) = @_;
|
my ( $hash, $h, $r ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -991,27 +975,6 @@ sub Wunderground_Hash2Readings($$;$) {
|
|||||||
return "ok" if ( !$loop );
|
return "ok" if ( !$loop );
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub Wunderground_Undefine($$$) {
|
|
||||||
my ( $hash, $a, $h ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
|
|
||||||
if ( defined( $hash->{fhem}{infix} ) ) {
|
|
||||||
Wunderground_removeExtension( $hash->{fhem}{infix} );
|
|
||||||
}
|
|
||||||
|
|
||||||
Log3 $name, 5,
|
|
||||||
"Wunderground $name: called function Wunderground_Undefine()";
|
|
||||||
|
|
||||||
# Stop the internal GetStatus-Loop and exit
|
|
||||||
RemoveInternalTimer($hash);
|
|
||||||
|
|
||||||
# release reverse pointer
|
|
||||||
delete $modules{Wunderground}{defptr}{$name};
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,68 +1,29 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# 70_PHTV.pm
|
|
||||||
# An FHEM Perl module for controlling Philips Televisons
|
|
||||||
# via network connection.
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use 5.012;
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
use Time::HiRes qw(gettimeofday);
|
use Time::HiRes qw(gettimeofday);
|
||||||
use HttpUtils;
|
use HttpUtils;
|
||||||
use Color;
|
use Color;
|
||||||
use SetExtensions;
|
|
||||||
use Encode;
|
use Encode;
|
||||||
|
|
||||||
sub PHTV_Set($@);
|
# initialize ##################################################################
|
||||||
sub PHTV_Get($@);
|
|
||||||
sub PHTV_GetStatus($;$);
|
|
||||||
sub PHTV_Define($$);
|
|
||||||
sub PHTV_Notify($$);
|
|
||||||
sub PHTV_Undefine($$);
|
|
||||||
|
|
||||||
#########################
|
|
||||||
# Forward declaration for remotecontrol module
|
|
||||||
#sub PHTV_RClayout_TV();
|
|
||||||
#sub PHTV_RCmakenotify($$);
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_Initialize($) {
|
sub PHTV_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
Log3 $hash, 5, "PHTV_Initialize: Entering";
|
Log3 $hash, 5, "PHTV_Initialize: Entering";
|
||||||
|
|
||||||
$hash->{GetFn} = "PHTV_Get";
|
|
||||||
$hash->{SetFn} = "PHTV_Set";
|
|
||||||
$hash->{NotifyFn} = "PHTV_Notify";
|
|
||||||
$hash->{DefFn} = "PHTV_Define";
|
$hash->{DefFn} = "PHTV_Define";
|
||||||
$hash->{UndefFn} = "PHTV_Undefine";
|
$hash->{UndefFn} = "PHTV_Undefine";
|
||||||
|
$hash->{SetFn} = "PHTV_Set";
|
||||||
|
$hash->{GetFn} = "PHTV_Get";
|
||||||
|
$hash->{NotifyFn} = "PHTV_Notify";
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$hash->{AttrList} =
|
||||||
"disable:0,1 timeout sequentialQuery:0,1 drippyFactor:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 inputs ambiHueLeft ambiHueRight ambiHueTop ambiHueBottom ambiHueLatency:150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000 jsversion:1,5,6 macaddr:textField model wakeupCmd:textField channelsMax:slider,30,1,200 httpLoglevel:1,2,3,4,5 sslVersion device_id auth_key "
|
"disable:0,1 disabledForIntervals do_not_notify:1,0 timeout sequentialQuery:0,1 drippyFactor:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 inputs ambiHueLeft ambiHueRight ambiHueTop ambiHueBottom ambiHueLatency:150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000 jsversion:1,5,6 macaddr:textField model wakeupCmd:textField channelsMax:slider,30,1,200 httpLoglevel:1,2,3,4,5 sslVersion device_id auth_key "
|
||||||
. $readingFnAttributes;
|
. $readingFnAttributes;
|
||||||
|
|
||||||
$data{RC_layout}{PHTV_SVG} = "PHTV_RClayout_SVG";
|
$data{RC_layout}{PHTV_SVG} = "PHTV_RClayout_SVG";
|
||||||
@ -88,170 +49,73 @@ sub PHTV_Initialize($) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
FHEM_colorpickerInit();
|
FHEM_colorpickerInit();
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
# regular Fn ##################################################################
|
||||||
sub PHTV_GetStatus($;$) {
|
sub PHTV_Define($$) {
|
||||||
my ( $hash, $update ) = @_;
|
my ( $hash, $def ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my @a = split( "[ \t][ \t]*", $def );
|
||||||
my $interval = $hash->{INTERVAL};
|
|
||||||
my $presence = ReadingsVal( $name, "presence", "absent" );
|
|
||||||
my $sequential = AttrVal( $name, "sequentialQuery", 0 );
|
|
||||||
my $querySent = 0;
|
|
||||||
|
|
||||||
Log3 $name, 5, "PHTV $name: called function PHTV_GetStatus()";
|
|
||||||
|
|
||||||
$interval = $interval * 1.6
|
|
||||||
if ( ReadingsVal( $name, "ambiHue", "off" ) eq "on" );
|
|
||||||
|
|
||||||
RemoveInternalTimer($hash);
|
|
||||||
InternalTimer( gettimeofday() + $interval, "PHTV_GetStatus", $hash, 0 );
|
|
||||||
|
|
||||||
return
|
|
||||||
if ( IsDisabled($name) );
|
|
||||||
|
|
||||||
# try to fetch only some information to check device availability
|
|
||||||
if ( !$update ) {
|
|
||||||
PHTV_SendCommand( $hash, "audio/volume" ) if ( $presence eq "present" );
|
|
||||||
PHTV_SendCommand( $hash, "system" ) if ( $presence eq "absent" );
|
|
||||||
|
|
||||||
# in case we should query the device gently, mark we already sent a query
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter} = 1 if $sequential;
|
|
||||||
}
|
|
||||||
|
|
||||||
# fetch other info if device is on
|
|
||||||
if ( !$querySent
|
|
||||||
&& ( ReadingsVal( $name, "state", "off" ) eq "on" || $update ) )
|
|
||||||
{
|
|
||||||
|
|
||||||
# Read device info every 15 minutes only
|
|
||||||
if (
|
|
||||||
!$querySent
|
|
||||||
&& (
|
|
||||||
!defined( $hash->{helper}{lastFullUpdate} )
|
|
||||||
|| ( !$update
|
|
||||||
&& $hash->{helper}{lastFullUpdate} + 900 le time() )
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
PHTV_SendCommand( $hash, "system" );
|
|
||||||
PHTV_SendCommand( $hash, "ambilight/topology" );
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
|
||||||
|
|
||||||
# Update state
|
|
||||||
$hash->{helper}{lastFullUpdate} = time();
|
|
||||||
}
|
|
||||||
|
|
||||||
# read audio volume
|
|
||||||
if ( !$querySent && $update ) {
|
|
||||||
PHTV_SendCommand( $hash, "audio/volume" );
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
|
||||||
}
|
|
||||||
|
|
||||||
# read ambilight details
|
|
||||||
if ( !$querySent ) {
|
|
||||||
|
|
||||||
# read ambilight mode
|
|
||||||
PHTV_SendCommand( $hash, "ambilight/mode" );
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
|
||||||
|
|
||||||
# read ambilight RGB value
|
|
||||||
PHTV_SendCommand( $hash, "ambilight/cached" )
|
|
||||||
if ( ReadingsVal( $name, "ambiMode", "internal" ) ne "internal" );
|
|
||||||
}
|
|
||||||
|
|
||||||
# read all sources if not existing
|
|
||||||
if (
|
|
||||||
!$querySent
|
|
||||||
&& ( !defined( $hash->{helper}{device}{sourceName} )
|
|
||||||
|| !defined( $hash->{helper}{device}{sourceID} ) )
|
|
||||||
)
|
|
||||||
{
|
|
||||||
PHTV_SendCommand( $hash, "sources" );
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
|
||||||
}
|
|
||||||
|
|
||||||
# otherwise read current source
|
|
||||||
elsif ( !$querySent ) {
|
|
||||||
PHTV_SendCommand( $hash, "sources/current" );
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
|
||||||
}
|
|
||||||
|
|
||||||
# read all channels if not existing
|
|
||||||
if (
|
|
||||||
!$querySent
|
|
||||||
&& ( !defined( $hash->{helper}{device}{channelName} )
|
|
||||||
|| !defined( $hash->{helper}{device}{channelID} ) )
|
|
||||||
)
|
|
||||||
{
|
|
||||||
PHTV_SendCommand( $hash, "channels" );
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
|
||||||
}
|
|
||||||
|
|
||||||
# otherwise read current channel
|
|
||||||
elsif ( !$querySent ) {
|
|
||||||
PHTV_SendCommand( $hash, "channels/current" );
|
|
||||||
$querySent = 1 if $sequential;
|
|
||||||
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# Input alias handling
|
|
||||||
#
|
|
||||||
if ( AttrVal( $name, "inputs", "" ) ne "" ) {
|
|
||||||
my @inputs = split( ':', AttrVal( $name, "inputs", ":" ) );
|
|
||||||
|
|
||||||
if (@inputs) {
|
|
||||||
foreach (@inputs) {
|
|
||||||
if (m/[^,\s]+(,[^,\s]+)+/) {
|
|
||||||
my @input_names = split( ',', $_ );
|
|
||||||
$input_names[1] =~ s/\s/_/g;
|
|
||||||
$hash->{helper}{device}{inputAliases}{ $input_names[0] } =
|
|
||||||
$input_names[1];
|
|
||||||
$hash->{helper}{device}{inputNames}{ $input_names[1] } =
|
|
||||||
$input_names[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_Get($@) {
|
|
||||||
my ( $hash, @a ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $state = ReadingsVal( $name, "state", "Initialized" );
|
|
||||||
my $what;
|
|
||||||
|
|
||||||
Log3 $name, 5, "PHTV $name: called function PHTV_Get()";
|
Log3 $name, 5, "PHTV $name: called function PHTV_Define()";
|
||||||
|
|
||||||
return "argument is missing" if ( int(@a) < 2 );
|
eval {
|
||||||
return if ( $state =~ /^(pairing.*|initialized)$/i );
|
require JSON;
|
||||||
|
import JSON qw( decode_json encode_json );
|
||||||
|
};
|
||||||
|
return "Please install Perl JSON to use module PHTV"
|
||||||
|
if ($@);
|
||||||
|
|
||||||
$what = $a[1];
|
if ( int(@a) < 3 ) {
|
||||||
|
my $msg =
|
||||||
if ( $what =~ /^(power|input|volume|mute|rgb)$/ ) {
|
"Wrong syntax: define <name> PHTV <ip-or-hostname> [<poll-interval>]";
|
||||||
return ReadingsVal( $name, $what, "no such reading: $what" );
|
Log3 $name, 4, $msg;
|
||||||
|
return $msg;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return
|
$hash->{TYPE} = "PHTV";
|
||||||
"Unknown argument $what, choose one of power:noArg input:noArg volume:noArg mute:noArg rgb:noArg ";
|
|
||||||
|
my $address = $a[2];
|
||||||
|
$hash->{helper}{ADDRESS} = $address;
|
||||||
|
|
||||||
|
# use interval of 45sec if not defined
|
||||||
|
my $interval = $a[3] || 45;
|
||||||
|
$hash->{INTERVAL} = $interval;
|
||||||
|
|
||||||
|
readingsSingleUpdate( $hash, "ambiHue", "off", 0 )
|
||||||
|
if ( ReadingsVal( $name, "ambiHue", "" ) ne "off" );
|
||||||
|
|
||||||
|
$hash->{model} = ReadingsVal( $name, "model", undef )
|
||||||
|
if ( ReadingsVal( $name, "model", undef ) );
|
||||||
|
|
||||||
|
$hash->{swversion} = ReadingsVal( $name, "softwareversion", undef )
|
||||||
|
if ( ReadingsVal( $name, "softwareversion", undef ) );
|
||||||
|
|
||||||
|
# set default settings on first define
|
||||||
|
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
|
||||||
|
fhem 'attr ' . $name . ' webCmd volume:input:rgb';
|
||||||
|
fhem 'attr ' . $name
|
||||||
|
. ' devStateIcon on:rc_GREEN:off off:rc_YELLOW:on absent:rc_STOP:on';
|
||||||
|
fhem 'attr ' . $name . ' icon it_television';
|
||||||
|
|
||||||
|
PHTV_GetStatus($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub PHTV_Undefine($$) {
|
||||||
|
my ( $hash, $arg ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
Log3 $name, 5, "PHTV $name: called function PHTV_Undefine()";
|
||||||
|
|
||||||
|
# Stop the internal GetStatus-Loop and exit
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_Set($@) {
|
sub PHTV_Set($@) {
|
||||||
my ( $hash, @a ) = @_;
|
my ( $hash, @a ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -1396,57 +1260,26 @@ sub PHTV_Set($@) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
sub PHTV_Get($@) {
|
||||||
sub PHTV_Define($$) {
|
my ( $hash, @a ) = @_;
|
||||||
my ( $hash, $def ) = @_;
|
|
||||||
my @a = split( "[ \t][ \t]*", $def );
|
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
my $state = ReadingsVal( $name, "state", "Initialized" );
|
||||||
|
my $what;
|
||||||
|
|
||||||
Log3 $name, 5, "PHTV $name: called function PHTV_Define()";
|
Log3 $name, 5, "PHTV $name: called function PHTV_Get()";
|
||||||
|
|
||||||
eval {
|
return "argument is missing" if ( int(@a) < 2 );
|
||||||
require JSON;
|
return if ( $state =~ /^(pairing.*|initialized)$/i );
|
||||||
import JSON qw( decode_json encode_json );
|
|
||||||
};
|
|
||||||
return "Please install Perl JSON to use module PHTV"
|
|
||||||
if ($@);
|
|
||||||
|
|
||||||
if ( int(@a) < 3 ) {
|
$what = $a[1];
|
||||||
my $msg =
|
|
||||||
"Wrong syntax: define <name> PHTV <ip-or-hostname> [<poll-interval>]";
|
if ( $what =~ /^(power|input|volume|mute|rgb)$/ ) {
|
||||||
Log3 $name, 4, $msg;
|
return ReadingsVal( $name, $what, "no such reading: $what" );
|
||||||
return $msg;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
$hash->{TYPE} = "PHTV";
|
return
|
||||||
|
"Unknown argument $what, choose one of power:noArg input:noArg volume:noArg mute:noArg rgb:noArg ";
|
||||||
my $address = $a[2];
|
|
||||||
$hash->{helper}{ADDRESS} = $address;
|
|
||||||
|
|
||||||
# use interval of 45sec if not defined
|
|
||||||
my $interval = $a[3] || 45;
|
|
||||||
$hash->{INTERVAL} = $interval;
|
|
||||||
|
|
||||||
readingsSingleUpdate( $hash, "ambiHue", "off", 0 )
|
|
||||||
if ( ReadingsVal( $name, "ambiHue", "" ) ne "off" );
|
|
||||||
|
|
||||||
$hash->{model} = ReadingsVal( $name, "model", undef )
|
|
||||||
if ( ReadingsVal( $name, "model", undef ) );
|
|
||||||
|
|
||||||
$hash->{swversion} = ReadingsVal( $name, "softwareversion", undef )
|
|
||||||
if ( ReadingsVal( $name, "softwareversion", undef ) );
|
|
||||||
|
|
||||||
# set default settings on first define
|
|
||||||
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
|
|
||||||
fhem 'attr ' . $name . ' webCmd volume:input:rgb';
|
|
||||||
fhem 'attr ' . $name
|
|
||||||
. ' devStateIcon on:rc_GREEN:off off:rc_YELLOW:on absent:rc_STOP:on';
|
|
||||||
fhem 'attr ' . $name . ' icon it_television';
|
|
||||||
|
|
||||||
PHTV_GetStatus($hash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub PHTV_Notify($$) {
|
sub PHTV_Notify($$) {
|
||||||
@ -1488,13 +1321,142 @@ sub PHTV_Notify($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
############################################################################################################
|
# module Fn ####################################################################
|
||||||
#
|
sub PHTV_GetStatus($;$) {
|
||||||
# Begin of helper functions
|
my ( $hash, $update ) = @_;
|
||||||
#
|
my $name = $hash->{NAME};
|
||||||
############################################################################################################
|
my $interval = $hash->{INTERVAL};
|
||||||
|
my $presence = ReadingsVal( $name, "presence", "absent" );
|
||||||
|
my $sequential = AttrVal( $name, "sequentialQuery", 0 );
|
||||||
|
my $querySent = 0;
|
||||||
|
|
||||||
|
Log3 $name, 5, "PHTV $name: called function PHTV_GetStatus()";
|
||||||
|
|
||||||
|
$interval = $interval * 1.6
|
||||||
|
if ( ReadingsVal( $name, "ambiHue", "off" ) eq "on" );
|
||||||
|
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
InternalTimer( gettimeofday() + $interval, "PHTV_GetStatus", $hash, 0 );
|
||||||
|
|
||||||
|
return
|
||||||
|
if ( IsDisabled($name) );
|
||||||
|
|
||||||
|
# try to fetch only some information to check device availability
|
||||||
|
if ( !$update ) {
|
||||||
|
PHTV_SendCommand( $hash, "audio/volume" ) if ( $presence eq "present" );
|
||||||
|
PHTV_SendCommand( $hash, "system" ) if ( $presence eq "absent" );
|
||||||
|
|
||||||
|
# in case we should query the device gently, mark we already sent a query
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter} = 1 if $sequential;
|
||||||
|
}
|
||||||
|
|
||||||
|
# fetch other info if device is on
|
||||||
|
if ( !$querySent
|
||||||
|
&& ( ReadingsVal( $name, "state", "off" ) eq "on" || $update ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
# Read device info every 15 minutes only
|
||||||
|
if (
|
||||||
|
!$querySent
|
||||||
|
&& (
|
||||||
|
!defined( $hash->{helper}{lastFullUpdate} )
|
||||||
|
|| ( !$update
|
||||||
|
&& $hash->{helper}{lastFullUpdate} + 900 le time() )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PHTV_SendCommand( $hash, "system" );
|
||||||
|
PHTV_SendCommand( $hash, "ambilight/topology" );
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
||||||
|
|
||||||
|
# Update state
|
||||||
|
$hash->{helper}{lastFullUpdate} = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
# read audio volume
|
||||||
|
if ( !$querySent && $update ) {
|
||||||
|
PHTV_SendCommand( $hash, "audio/volume" );
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
||||||
|
}
|
||||||
|
|
||||||
|
# read ambilight details
|
||||||
|
if ( !$querySent ) {
|
||||||
|
|
||||||
|
# read ambilight mode
|
||||||
|
PHTV_SendCommand( $hash, "ambilight/mode" );
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
||||||
|
|
||||||
|
# read ambilight RGB value
|
||||||
|
PHTV_SendCommand( $hash, "ambilight/cached" )
|
||||||
|
if ( ReadingsVal( $name, "ambiMode", "internal" ) ne "internal" );
|
||||||
|
}
|
||||||
|
|
||||||
|
# read all sources if not existing
|
||||||
|
if (
|
||||||
|
!$querySent
|
||||||
|
&& ( !defined( $hash->{helper}{device}{sourceName} )
|
||||||
|
|| !defined( $hash->{helper}{device}{sourceID} ) )
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PHTV_SendCommand( $hash, "sources" );
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
||||||
|
}
|
||||||
|
|
||||||
|
# otherwise read current source
|
||||||
|
elsif ( !$querySent ) {
|
||||||
|
PHTV_SendCommand( $hash, "sources/current" );
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
||||||
|
}
|
||||||
|
|
||||||
|
# read all channels if not existing
|
||||||
|
if (
|
||||||
|
!$querySent
|
||||||
|
&& ( !defined( $hash->{helper}{device}{channelName} )
|
||||||
|
|| !defined( $hash->{helper}{device}{channelID} ) )
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PHTV_SendCommand( $hash, "channels" );
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
||||||
|
}
|
||||||
|
|
||||||
|
# otherwise read current channel
|
||||||
|
elsif ( !$querySent ) {
|
||||||
|
PHTV_SendCommand( $hash, "channels/current" );
|
||||||
|
$querySent = 1 if $sequential;
|
||||||
|
$hash->{helper}{sequentialQueryCounter}++ if $sequential;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input alias handling
|
||||||
|
#
|
||||||
|
if ( AttrVal( $name, "inputs", "" ) ne "" ) {
|
||||||
|
my @inputs = split( ':', AttrVal( $name, "inputs", ":" ) );
|
||||||
|
|
||||||
|
if (@inputs) {
|
||||||
|
foreach (@inputs) {
|
||||||
|
if (m/[^,\s]+(,[^,\s]+)+/) {
|
||||||
|
my @input_names = split( ',', $_ );
|
||||||
|
$input_names[1] =~ s/\s/_/g;
|
||||||
|
$hash->{helper}{device}{inputAliases}{ $input_names[0] } =
|
||||||
|
$input_names[1];
|
||||||
|
$hash->{helper}{device}{inputNames}{ $input_names[1] } =
|
||||||
|
$input_names[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_SendCommandDelayed($) {
|
sub PHTV_SendCommandDelayed($) {
|
||||||
my ($par) = @_;
|
my ($par) = @_;
|
||||||
|
|
||||||
@ -1507,7 +1469,6 @@ sub PHTV_SendCommandDelayed($) {
|
|||||||
$par->{type} );
|
$par->{type} );
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_SendCommand($$;$$$) {
|
sub PHTV_SendCommand($$;$$$) {
|
||||||
my ( $hash, $service, $cmd, $type, $delay ) = @_;
|
my ( $hash, $service, $cmd, $type, $delay ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -1613,7 +1574,7 @@ sub PHTV_SendCommand($$;$$$) {
|
|||||||
'Accept-Charset' => 'UTF-8',
|
'Accept-Charset' => 'UTF-8',
|
||||||
},
|
},
|
||||||
sslargs => {
|
sslargs => {
|
||||||
SSL_verify_mode => 0,
|
SSL_verify_mode => 'SSL_VERIFY_NONE',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -1621,7 +1582,6 @@ sub PHTV_SendCommand($$;$$$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_ReceiveCommand($$$) {
|
sub PHTV_ReceiveCommand($$$) {
|
||||||
my ( $param, $err, $data ) = @_;
|
my ( $param, $err, $data ) = @_;
|
||||||
my $hash = $param->{hash};
|
my $hash = $param->{hash};
|
||||||
@ -3079,20 +3039,6 @@ m/^\s*(([{\[][\s\S]+[}\]])|(<html>\s*<head>\s*<title>\s*Ok\s*<\/title>\s*<\/head
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_Undefine($$) {
|
|
||||||
my ( $hash, $arg ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
|
|
||||||
Log3 $name, 5, "PHTV $name: called function PHTV_Undefine()";
|
|
||||||
|
|
||||||
# Stop the internal GetStatus-Loop and exit
|
|
||||||
RemoveInternalTimer($hash);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_GetStateAV($) {
|
sub PHTV_GetStateAV($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -3114,7 +3060,6 @@ sub PHTV_GetStateAV($) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_wake ($) {
|
sub PHTV_wake ($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -3153,8 +3098,6 @@ sub PHTV_wake ($) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
|
||||||
# Callback from 95_remotecontrol for command makenotify.
|
|
||||||
sub PHTV_RCmakenotify($$) {
|
sub PHTV_RCmakenotify($$) {
|
||||||
my ( $nam, $ndev ) = @_;
|
my ( $nam, $ndev ) = @_;
|
||||||
my $nname = "notify_$nam";
|
my $nname = "notify_$nam";
|
||||||
@ -3164,10 +3107,6 @@ sub PHTV_RCmakenotify($$) {
|
|||||||
return "Notify created by PHTV: $nname";
|
return "Notify created by PHTV: $nname";
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
|
||||||
# RC layouts
|
|
||||||
|
|
||||||
# Philips TV with SVG
|
|
||||||
sub PHTV_RClayout_SVG() {
|
sub PHTV_RClayout_SVG() {
|
||||||
my @row;
|
my @row;
|
||||||
|
|
||||||
@ -3202,7 +3141,6 @@ sub PHTV_RClayout_SVG() {
|
|||||||
return @row;
|
return @row;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Philips TV with PNG
|
|
||||||
sub PHTV_RClayout() {
|
sub PHTV_RClayout() {
|
||||||
my @row;
|
my @row;
|
||||||
|
|
||||||
@ -3233,7 +3171,6 @@ sub PHTV_RClayout() {
|
|||||||
return @row;
|
return @row;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_GetRemotecontrolCommand($) {
|
sub PHTV_GetRemotecontrolCommand($) {
|
||||||
my ($command) = @_;
|
my ($command) = @_;
|
||||||
my $commands = {
|
my $commands = {
|
||||||
@ -3305,26 +3242,22 @@ sub PHTV_GetRemotecontrolCommand($) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_isinteger {
|
sub PHTV_isinteger {
|
||||||
defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
|
defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_bri2pct($) {
|
sub PHTV_bri2pct($) {
|
||||||
my ($bri) = @_;
|
my ($bri) = @_;
|
||||||
return 0 if ( $bri <= 0 );
|
return 0 if ( $bri <= 0 );
|
||||||
return int( $bri / 255 * 100 + 0.5 );
|
return int( $bri / 255 * 100 + 0.5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_pct2bri($) {
|
sub PHTV_pct2bri($) {
|
||||||
my ($pct) = @_;
|
my ($pct) = @_;
|
||||||
return 0 if ( $pct <= 0 );
|
return 0 if ( $pct <= 0 );
|
||||||
return int( $pct / 100 * 255 + 0.5 );
|
return int( $pct / 100 * 255 + 0.5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_hex2rgb($) {
|
sub PHTV_hex2rgb($) {
|
||||||
my ($hex) = @_;
|
my ($hex) = @_;
|
||||||
if ( uc($hex) =~ /^(..)(..)(..)$/ ) {
|
if ( uc($hex) =~ /^(..)(..)(..)$/ ) {
|
||||||
@ -3339,7 +3272,6 @@ sub PHTV_hex2rgb($) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_rgb2hex($$$) {
|
sub PHTV_rgb2hex($$$) {
|
||||||
my ( $r, $g, $b ) = @_;
|
my ( $r, $g, $b ) = @_;
|
||||||
my $return = sprintf( "%2.2X%2.2X%2.2X", $r, $g, $b );
|
my $return = sprintf( "%2.2X%2.2X%2.2X", $r, $g, $b );
|
||||||
@ -3347,7 +3279,6 @@ sub PHTV_rgb2hex($$$) {
|
|||||||
return uc($return);
|
return uc($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_hex2hsb($;$) {
|
sub PHTV_hex2hsb($;$) {
|
||||||
my ( $hex, $type ) = @_;
|
my ( $hex, $type ) = @_;
|
||||||
$type = lc($type) if ( defined( ($type) && $type ne "" ) );
|
$type = lc($type) if ( defined( ($type) && $type ne "" ) );
|
||||||
@ -3364,14 +3295,12 @@ sub PHTV_hex2hsb($;$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_hsb2hex($$$) {
|
sub PHTV_hsb2hex($$$) {
|
||||||
my ( $h, $s, $b ) = @_;
|
my ( $h, $s, $b ) = @_;
|
||||||
my $rgb = PHTV_hsb2rgb( $h, $s, $b );
|
my $rgb = PHTV_hsb2rgb( $h, $s, $b );
|
||||||
return PHTV_rgb2hex( $rgb->{r}, $rgb->{g}, $rgb->{b} );
|
return PHTV_rgb2hex( $rgb->{r}, $rgb->{g}, $rgb->{b} );
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_rgb2hsb ($$$) {
|
sub PHTV_rgb2hsb ($$$) {
|
||||||
my ( $r, $g, $b ) = @_;
|
my ( $r, $g, $b ) = @_;
|
||||||
|
|
||||||
@ -3393,7 +3322,6 @@ sub PHTV_rgb2hsb ($$$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_hsb2rgb ($$$) {
|
sub PHTV_hsb2rgb ($$$) {
|
||||||
my ( $h, $s, $bri ) = @_;
|
my ( $h, $s, $bri ) = @_;
|
||||||
|
|
||||||
@ -3415,7 +3343,6 @@ sub PHTV_hsb2rgb ($$$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_rgb2hsv($$$) {
|
sub PHTV_rgb2hsv($$$) {
|
||||||
my ( $r, $g, $b ) = @_;
|
my ( $r, $g, $b ) = @_;
|
||||||
my ( $M, $m, $c, $h, $s, $v );
|
my ( $M, $m, $c, $h, $s, $v );
|
||||||
@ -3457,7 +3384,6 @@ sub PHTV_rgb2hsv($$$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_hsv2rgb($$$) {
|
sub PHTV_hsv2rgb($$$) {
|
||||||
my ( $h, $s, $v ) = @_;
|
my ( $h, $s, $v ) = @_;
|
||||||
my $r = 0.0;
|
my $r = 0.0;
|
||||||
@ -3518,7 +3444,6 @@ sub PHTV_hsv2rgb($$$) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_max {
|
sub PHTV_max {
|
||||||
my ( $max, @vars ) = @_;
|
my ( $max, @vars ) = @_;
|
||||||
for (@vars) {
|
for (@vars) {
|
||||||
@ -3528,7 +3453,6 @@ sub PHTV_max {
|
|||||||
return $max;
|
return $max;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_min {
|
sub PHTV_min {
|
||||||
my ( $min, @vars ) = @_;
|
my ( $min, @vars ) = @_;
|
||||||
for (@vars) {
|
for (@vars) {
|
||||||
@ -3537,7 +3461,6 @@ sub PHTV_min {
|
|||||||
return $min;
|
return $min;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_createDeviceId() {
|
sub PHTV_createDeviceId() {
|
||||||
my $deviceid;
|
my $deviceid;
|
||||||
my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9 );
|
my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9 );
|
||||||
@ -3545,7 +3468,6 @@ sub PHTV_createDeviceId() {
|
|||||||
return $deviceid;
|
return $deviceid;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub PHTV_createAuthSignature($$$) {
|
sub PHTV_createAuthSignature($$$) {
|
||||||
my ( $timestamp, $pin, $secretkey ) = @_;
|
my ( $timestamp, $pin, $secretkey ) = @_;
|
||||||
my $base64 = 0;
|
my $base64 = 0;
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
# $Id$
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
# $Id$
|
||||||
# Also see API documentation:
|
|
||||||
# https://pushover.net/api
|
# https://pushover.net/api
|
||||||
|
#
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use HttpUtils;
|
use HttpUtils;
|
||||||
use utf8;
|
use utf8;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
use HttpUtils;
|
use HttpUtils;
|
||||||
use SetExtensions;
|
|
||||||
use Encode;
|
use Encode;
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
# initialize ##################################################################
|
||||||
sub Pushover_Initialize($$) {
|
sub Pushover_Initialize($$) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
$hash->{DefFn} = "Pushover_Define";
|
$hash->{DefFn} = "Pushover_Define";
|
||||||
$hash->{UndefFn} = "Pushover_Undefine";
|
$hash->{UndefFn} = "Pushover_Undefine";
|
||||||
$hash->{SetFn} = "Pushover_Set";
|
$hash->{SetFn} = "Pushover_Set";
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$hash->{AttrList} =
|
||||||
"disable:0,1 disabledForIntervals do_not_notify:0,1 timestamp:0,1 title sound:pushover,bike,bugle,cashregister,classical,cosmic,falling,gamelan,incoming,intermission,magic,mechanical,pianobar,siren,spacealarm,tugboat,alien,climb,persistent,echo,updown,none device priority:0,1,2,-1,-2 callbackUrl retry expire "
|
"disable:0,1 disabledForIntervals do_not_notify:0,1 timestamp:0,1 title sound:pushover,bike,bugle,cashregister,classical,cosmic,falling,gamelan,incoming,intermission,magic,mechanical,pianobar,siren,spacealarm,tugboat,alien,climb,persistent,echo,updown,none device priority:0,1,2,-1,-2 callbackUrl retry expire "
|
||||||
. $readingFnAttributes;
|
. $readingFnAttributes;
|
||||||
@ -27,39 +25,7 @@ sub Pushover_Initialize($$) {
|
|||||||
$hash->{'.msgParams'} = { parseParams => 1, };
|
$hash->{'.msgParams'} = { parseParams => 1, };
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
# regular Fn ##################################################################
|
||||||
sub Pushover_addExtension($$$) {
|
|
||||||
my ( $name, $func, $link ) = @_;
|
|
||||||
|
|
||||||
my $url = "/$link";
|
|
||||||
|
|
||||||
return 0
|
|
||||||
if ( defined( $data{FWEXT}{$url} )
|
|
||||||
&& $data{FWEXT}{$url}{deviceName} ne $name );
|
|
||||||
|
|
||||||
Log3 $name, 2,
|
|
||||||
"Pushover $name: Registering Pushover for webhook URI $url ...";
|
|
||||||
$data{FWEXT}{$url}{deviceName} = $name;
|
|
||||||
$data{FWEXT}{$url}{FUNC} = $func;
|
|
||||||
$data{FWEXT}{$url}{LINK} = $link;
|
|
||||||
$name->{HASH}{FHEMWEB_URI} = $url;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_removeExtension($) {
|
|
||||||
my ($link) = @_;
|
|
||||||
|
|
||||||
my $url = "/$link";
|
|
||||||
my $name = $data{FWEXT}{$url}{deviceName};
|
|
||||||
Log3 $name, 2,
|
|
||||||
"Pushover $name: Unregistering Pushover for webhook URI $url...";
|
|
||||||
delete $data{FWEXT}{$url};
|
|
||||||
delete $name->{HASH}{FHEMWEB_URI};
|
|
||||||
}
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_Define($$) {
|
sub Pushover_Define($$) {
|
||||||
my ( $hash, $def ) = @_;
|
my ( $hash, $def ) = @_;
|
||||||
|
|
||||||
@ -67,8 +33,8 @@ sub Pushover_Define($$) {
|
|||||||
my $name = shift @a;
|
my $name = shift @a;
|
||||||
my $type = shift @a;
|
my $type = shift @a;
|
||||||
|
|
||||||
return
|
return "Invalid number of arguments: "
|
||||||
"Invalid number of arguments: define <name> Pushover <token> <user> [<infix>]"
|
. "define <name> Pushover <token> <user> [<infix>]"
|
||||||
if ( int(@a) < 2 );
|
if ( int(@a) < 2 );
|
||||||
|
|
||||||
my ( $token, $user, $infix ) = @a;
|
my ( $token, $user, $infix ) = @a;
|
||||||
@ -107,9 +73,10 @@ sub Pushover_Define($$) {
|
|||||||
else {
|
else {
|
||||||
return "App or user/group token missing.";
|
return "App or user/group token missing.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_Undefine($$) {
|
sub Pushover_Undefine($$) {
|
||||||
my ( $hash, $name ) = @_;
|
my ( $hash, $name ) = @_;
|
||||||
|
|
||||||
@ -122,7 +89,6 @@ sub Pushover_Undefine($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_Set($@) {
|
sub Pushover_Set($@) {
|
||||||
my ( $hash, $name, $cmd, @args ) = @_;
|
my ( $hash, $name, $cmd, @args ) = @_;
|
||||||
my ( $a, $h ) = parseParams( join " ", @args );
|
my ( $a, $h ) = parseParams( join " ", @args );
|
||||||
@ -169,9 +135,199 @@ sub Pushover_Set($@) {
|
|||||||
|
|
||||||
return Pushover_SetMessage( $hash, @args )
|
return Pushover_SetMessage( $hash, @args )
|
||||||
if ( $cmd eq 'msg' );
|
if ( $cmd eq 'msg' );
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
# module Fn ####################################################################
|
||||||
|
sub Pushover_addExtension($$$) {
|
||||||
|
my ( $name, $func, $link ) = @_;
|
||||||
|
|
||||||
|
my $url = "/$link";
|
||||||
|
|
||||||
|
return 0
|
||||||
|
if ( defined( $data{FWEXT}{$url} )
|
||||||
|
&& $data{FWEXT}{$url}{deviceName} ne $name );
|
||||||
|
|
||||||
|
Log3 $name, 2,
|
||||||
|
"Pushover $name: Registering Pushover for webhook URI $url ...";
|
||||||
|
$data{FWEXT}{$url}{deviceName} = $name;
|
||||||
|
$data{FWEXT}{$url}{FUNC} = $func;
|
||||||
|
$data{FWEXT}{$url}{LINK} = $link;
|
||||||
|
$name->{HASH}{FHEMWEB_URI} = $url;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Pushover_removeExtension($) {
|
||||||
|
my ($link) = @_;
|
||||||
|
|
||||||
|
my $url = "/$link";
|
||||||
|
my $name = $data{FWEXT}{$url}{deviceName};
|
||||||
|
Log3 $name, 2,
|
||||||
|
"Pushover $name: Unregistering Pushover for webhook URI $url...";
|
||||||
|
delete $data{FWEXT}{$url};
|
||||||
|
delete $name->{HASH}{FHEMWEB_URI};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Pushover_CGI() {
|
||||||
|
my ($request) = @_;
|
||||||
|
|
||||||
|
my $hash;
|
||||||
|
my $name = "";
|
||||||
|
my $link = "";
|
||||||
|
my $URI = "";
|
||||||
|
|
||||||
|
# data received
|
||||||
|
if ( $request =~ m,^(/[^/]+?)(?:\&|\?)(.*)?$, ) {
|
||||||
|
$link = $1;
|
||||||
|
$URI = $2;
|
||||||
|
|
||||||
|
# get device name
|
||||||
|
$name = $data{FWEXT}{$link}{deviceName} if ( $data{FWEXT}{$link} );
|
||||||
|
$hash = $defs{$name};
|
||||||
|
|
||||||
|
# return error if no such device
|
||||||
|
return ( "text/plain; charset=utf-8",
|
||||||
|
"NOK No Pushover device for callback $link" )
|
||||||
|
unless ($name);
|
||||||
|
|
||||||
|
Log3 $name, 4, "Pushover $name callback: link='$link' URI='$URI'";
|
||||||
|
|
||||||
|
my $webArgs;
|
||||||
|
my $receipt = "";
|
||||||
|
my %revReadings;
|
||||||
|
|
||||||
|
# extract values from URI
|
||||||
|
foreach my $pv ( split( "&", $URI ) ) {
|
||||||
|
next if ( $pv eq "" );
|
||||||
|
$pv =~ s/\+/ /g;
|
||||||
|
$pv =~ s/%([\dA-F][\dA-F])/chr(hex($1))/ige;
|
||||||
|
my ( $p, $v ) = split( "=", $pv, 2 );
|
||||||
|
|
||||||
|
$webArgs->{$p} = $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined( $webArgs->{receipt} ) ) {
|
||||||
|
$receipt = $webArgs->{receipt};
|
||||||
|
}
|
||||||
|
elsif ( defined( $webArgs->{FhemCallbackId} ) ) {
|
||||||
|
$receipt = $webArgs->{FhemCallbackId};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ( "text/plain; charset=utf-8",
|
||||||
|
"NOK missing argument receipt or FhemCallbackId" );
|
||||||
|
}
|
||||||
|
|
||||||
|
# search for existing receipt
|
||||||
|
keys %{ $hash->{READINGS} };
|
||||||
|
while ( my ( $key, $value ) = each %{ $hash->{READINGS} } ) {
|
||||||
|
$revReadings{ $value->{VAL} } = $1
|
||||||
|
if ( defined( $value->{VAL} ) && $key =~ /^cb_(\d+)$/ );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined( $revReadings{$receipt} ) ) {
|
||||||
|
my $rAct = "cbAct_" . $revReadings{$receipt};
|
||||||
|
my $rAck = "cbAck_" . $revReadings{$receipt};
|
||||||
|
my $rAckAt = "cbAckAt_" . $revReadings{$receipt};
|
||||||
|
my $rAckBy = "cbAckBy_" . $revReadings{$receipt};
|
||||||
|
my $rCancelId = "cbCancelId_" . $revReadings{$receipt};
|
||||||
|
my $rDev = "cbDev_" . $revReadings{$receipt};
|
||||||
|
|
||||||
|
return ( "text/plain; charset=utf-8",
|
||||||
|
"NOK " . $receipt . ": invalid argument 'acknowledged'" )
|
||||||
|
if ( !defined( $webArgs->{acknowledged} )
|
||||||
|
|| $webArgs->{acknowledged} ne "1" );
|
||||||
|
|
||||||
|
return ( "text/plain; charset=utf-8",
|
||||||
|
"NOK " . $receipt . ": invalid argument 'acknowledged_by'" )
|
||||||
|
if ( !defined( $webArgs->{acknowledged_by} )
|
||||||
|
|| $webArgs->{acknowledged_by} ne $hash->{USER_KEY} );
|
||||||
|
|
||||||
|
if ( ReadingsVal( $name, $rAck, "1" ) eq "0"
|
||||||
|
&& $revReadings{$receipt} > int( time() ) )
|
||||||
|
{
|
||||||
|
delete $hash->{READINGS}{$rCancelId}
|
||||||
|
if ( defined( $hash->{READINGS}{$rCancelId} ) );
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
readingsBulkUpdate( $hash, $rAck, "1" );
|
||||||
|
readingsBulkUpdate( $hash, $rAckBy,
|
||||||
|
$webArgs->{acknowledged_by} );
|
||||||
|
|
||||||
|
if ( defined( $webArgs->{acknowledged_at} )
|
||||||
|
&& $webArgs->{acknowledged_at} ne "" )
|
||||||
|
{
|
||||||
|
readingsBulkUpdate( $hash, $rAckAt,
|
||||||
|
$webArgs->{acknowledged_at} );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readingsBulkUpdate( $hash, $rAckAt, int( time() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
my $redirect = "";
|
||||||
|
|
||||||
|
# run FHEM command if desired
|
||||||
|
if ( ReadingsVal( $name, $rAct, "pushover://" ) !~
|
||||||
|
/^[\w-]+:\/\/.*$/ )
|
||||||
|
{
|
||||||
|
$redirect = "pushover://";
|
||||||
|
|
||||||
|
fhem ReadingsVal( $name, $rAct, "" );
|
||||||
|
readingsBulkUpdate( $hash, $rAct,
|
||||||
|
"executed: " . ReadingsVal( $name, $rAct, "" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
# redirect to presented URL
|
||||||
|
if ( ReadingsVal( $name, $rAct, "none" ) =~ /^[\w-]+:\/\/.*$/ )
|
||||||
|
{
|
||||||
|
$redirect = ReadingsVal( $name, $rAct, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
|
return (
|
||||||
|
"text/html; charset=utf-8",
|
||||||
|
"<html><head><meta http-equiv=\"refresh\" content=\"0;url="
|
||||||
|
. $redirect
|
||||||
|
. "\"></head><body><a href=\""
|
||||||
|
. $redirect
|
||||||
|
. "\">Click here to get redirected to your destination"
|
||||||
|
. "</a></body></html>"
|
||||||
|
) if ( $redirect ne "" );
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3 $name, 4,
|
||||||
|
"Pushover $name callback: " . $receipt . " has expired";
|
||||||
|
return (
|
||||||
|
"text/plain; charset=utf-8",
|
||||||
|
"NOK " . $receipt . " has expired"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3 $name, 4,
|
||||||
|
"Pushover $name callback: unable to find existing receipt "
|
||||||
|
. $receipt;
|
||||||
|
return ( "text/plain; charset=utf-8",
|
||||||
|
"NOK unable to find existing receipt " . $receipt );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# no data received
|
||||||
|
else {
|
||||||
|
Log3 $name, 5,
|
||||||
|
"Pushover $name callback: received malformed request\n$request";
|
||||||
|
return ( "text/plain; charset=utf-8", "NOK malformed request" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( "text/plain; charset=utf-8", "OK" );
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_SendCommand($$;$\%) {
|
sub Pushover_SendCommand($$;$\%) {
|
||||||
my ( $hash, $service, $cmd, $type ) = @_;
|
my ( $hash, $service, $cmd, $type ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -267,6 +423,10 @@ sub Pushover_SendCommand($$;$\%) {
|
|||||||
Accept => 'application/json;charset=UTF-8',
|
Accept => 'application/json;charset=UTF-8',
|
||||||
'Accept-Charset' => 'UTF-8',
|
'Accept-Charset' => 'UTF-8',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
# sslargs => {
|
||||||
|
# SSL_verify_mode => 'SSL_verify_PEER',
|
||||||
|
# },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -316,7 +476,6 @@ sub Pushover_SendCommand($$;$\%) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_ReceiveCommand($$$) {
|
sub Pushover_ReceiveCommand($$$) {
|
||||||
my ( $param, $err, $data ) = @_;
|
my ( $param, $err, $data ) = @_;
|
||||||
my $hash = $param->{hash};
|
my $hash = $param->{hash};
|
||||||
@ -711,7 +870,6 @@ sub Pushover_ReceiveCommand($$$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_ValidateUser ($;$) {
|
sub Pushover_ValidateUser ($;$) {
|
||||||
my ( $hash, $update ) = @_;
|
my ( $hash, $update ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -739,7 +897,6 @@ sub Pushover_ValidateUser ($;$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_SetMessage {
|
sub Pushover_SetMessage {
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -843,7 +1000,6 @@ sub Pushover_SetMessage {
|
|||||||
return Pushover_SetMessage2( $hash, "msg", undef, \%values );
|
return Pushover_SetMessage2( $hash, "msg", undef, \%values );
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_SetMessage2 ($$$$) {
|
sub Pushover_SetMessage2 ($$$$) {
|
||||||
my ( $hash, $cmd, $a, $h ) = @_;
|
my ( $hash, $cmd, $a, $h ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -1236,165 +1392,6 @@ sub Pushover_CancelMessage ($$$$) {
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
sub Pushover_CGI() {
|
|
||||||
my ($request) = @_;
|
|
||||||
|
|
||||||
my $hash;
|
|
||||||
my $name = "";
|
|
||||||
my $link = "";
|
|
||||||
my $URI = "";
|
|
||||||
|
|
||||||
# data received
|
|
||||||
if ( $request =~ m,^(/[^/]+?)(?:\&|\?)(.*)?$, ) {
|
|
||||||
$link = $1;
|
|
||||||
$URI = $2;
|
|
||||||
|
|
||||||
# get device name
|
|
||||||
$name = $data{FWEXT}{$link}{deviceName} if ( $data{FWEXT}{$link} );
|
|
||||||
$hash = $defs{$name};
|
|
||||||
|
|
||||||
# return error if no such device
|
|
||||||
return ( "text/plain; charset=utf-8",
|
|
||||||
"NOK No Pushover device for callback $link" )
|
|
||||||
unless ($name);
|
|
||||||
|
|
||||||
Log3 $name, 4, "Pushover $name callback: link='$link' URI='$URI'";
|
|
||||||
|
|
||||||
my $webArgs;
|
|
||||||
my $receipt = "";
|
|
||||||
my %revReadings;
|
|
||||||
|
|
||||||
# extract values from URI
|
|
||||||
foreach my $pv ( split( "&", $URI ) ) {
|
|
||||||
next if ( $pv eq "" );
|
|
||||||
$pv =~ s/\+/ /g;
|
|
||||||
$pv =~ s/%([\dA-F][\dA-F])/chr(hex($1))/ige;
|
|
||||||
my ( $p, $v ) = split( "=", $pv, 2 );
|
|
||||||
|
|
||||||
$webArgs->{$p} = $v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( defined( $webArgs->{receipt} ) ) {
|
|
||||||
$receipt = $webArgs->{receipt};
|
|
||||||
}
|
|
||||||
elsif ( defined( $webArgs->{FhemCallbackId} ) ) {
|
|
||||||
$receipt = $webArgs->{FhemCallbackId};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return ( "text/plain; charset=utf-8",
|
|
||||||
"NOK missing argument receipt or FhemCallbackId" );
|
|
||||||
}
|
|
||||||
|
|
||||||
# search for existing receipt
|
|
||||||
keys %{ $hash->{READINGS} };
|
|
||||||
while ( my ( $key, $value ) = each %{ $hash->{READINGS} } ) {
|
|
||||||
$revReadings{ $value->{VAL} } = $1
|
|
||||||
if ( defined( $value->{VAL} ) && $key =~ /^cb_(\d+)$/ );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( defined( $revReadings{$receipt} ) ) {
|
|
||||||
my $rAct = "cbAct_" . $revReadings{$receipt};
|
|
||||||
my $rAck = "cbAck_" . $revReadings{$receipt};
|
|
||||||
my $rAckAt = "cbAckAt_" . $revReadings{$receipt};
|
|
||||||
my $rAckBy = "cbAckBy_" . $revReadings{$receipt};
|
|
||||||
my $rCancelId = "cbCancelId_" . $revReadings{$receipt};
|
|
||||||
my $rDev = "cbDev_" . $revReadings{$receipt};
|
|
||||||
|
|
||||||
return ( "text/plain; charset=utf-8",
|
|
||||||
"NOK " . $receipt . ": invalid argument 'acknowledged'" )
|
|
||||||
if ( !defined( $webArgs->{acknowledged} )
|
|
||||||
|| $webArgs->{acknowledged} ne "1" );
|
|
||||||
|
|
||||||
return ( "text/plain; charset=utf-8",
|
|
||||||
"NOK " . $receipt . ": invalid argument 'acknowledged_by'" )
|
|
||||||
if ( !defined( $webArgs->{acknowledged_by} )
|
|
||||||
|| $webArgs->{acknowledged_by} ne $hash->{USER_KEY} );
|
|
||||||
|
|
||||||
if ( ReadingsVal( $name, $rAck, "1" ) eq "0"
|
|
||||||
&& $revReadings{$receipt} > int( time() ) )
|
|
||||||
{
|
|
||||||
delete $hash->{READINGS}{$rCancelId}
|
|
||||||
if ( defined( $hash->{READINGS}{$rCancelId} ) );
|
|
||||||
|
|
||||||
readingsBeginUpdate($hash);
|
|
||||||
|
|
||||||
readingsBulkUpdate( $hash, $rAck, "1" );
|
|
||||||
readingsBulkUpdate( $hash, $rAckBy,
|
|
||||||
$webArgs->{acknowledged_by} );
|
|
||||||
|
|
||||||
if ( defined( $webArgs->{acknowledged_at} )
|
|
||||||
&& $webArgs->{acknowledged_at} ne "" )
|
|
||||||
{
|
|
||||||
readingsBulkUpdate( $hash, $rAckAt,
|
|
||||||
$webArgs->{acknowledged_at} );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
readingsBulkUpdate( $hash, $rAckAt, int( time() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
my $redirect = "";
|
|
||||||
|
|
||||||
# run FHEM command if desired
|
|
||||||
if ( ReadingsVal( $name, $rAct, "pushover://" ) !~
|
|
||||||
/^[\w-]+:\/\/.*$/ )
|
|
||||||
{
|
|
||||||
$redirect = "pushover://";
|
|
||||||
|
|
||||||
fhem ReadingsVal( $name, $rAct, "" );
|
|
||||||
readingsBulkUpdate( $hash, $rAct,
|
|
||||||
"executed: " . ReadingsVal( $name, $rAct, "" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
# redirect to presented URL
|
|
||||||
if ( ReadingsVal( $name, $rAct, "none" ) =~ /^[\w-]+:\/\/.*$/ )
|
|
||||||
{
|
|
||||||
$redirect = ReadingsVal( $name, $rAct, "" );
|
|
||||||
}
|
|
||||||
|
|
||||||
readingsEndUpdate( $hash, 1 );
|
|
||||||
|
|
||||||
return (
|
|
||||||
"text/html; charset=utf-8",
|
|
||||||
"<html><head><meta http-equiv=\"refresh\" content=\"0;url="
|
|
||||||
. $redirect
|
|
||||||
. "\"></head><body><a href=\""
|
|
||||||
. $redirect
|
|
||||||
. "\">Click here to get redirected to your destination"
|
|
||||||
. "</a></body></html>"
|
|
||||||
) if ( $redirect ne "" );
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log3 $name, 4,
|
|
||||||
"Pushover $name callback: " . $receipt . " has expired";
|
|
||||||
return (
|
|
||||||
"text/plain; charset=utf-8",
|
|
||||||
"NOK " . $receipt . " has expired"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log3 $name, 4,
|
|
||||||
"Pushover $name callback: unable to find existing receipt "
|
|
||||||
. $receipt;
|
|
||||||
return ( "text/plain; charset=utf-8",
|
|
||||||
"NOK unable to find existing receipt " . $receipt );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# no data received
|
|
||||||
else {
|
|
||||||
Log3 $name, 5,
|
|
||||||
"Pushover $name callback: received malformed request\n$request";
|
|
||||||
return ( "text/plain; charset=utf-8", "NOK malformed request" );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( "text/plain; charset=utf-8", "OK" );
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -1,50 +1,13 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# 70_ONKYO_AVR_ZONE.pm
|
|
||||||
# An FHEM Perl module for controlling ONKYO A/V receivers
|
|
||||||
# via network connection.
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Time::HiRes qw(usleep);
|
|
||||||
use Symbol qw<qualify_to_ref>;
|
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
use Symbol qw<qualify_to_ref>;
|
||||||
|
|
||||||
$Data::Dumper::Sortkeys = 1;
|
# initialize ##################################################################
|
||||||
|
|
||||||
sub ONKYO_AVR_ZONE_Set($$$);
|
|
||||||
sub ONKYO_AVR_ZONE_Get($$$);
|
|
||||||
sub ONKYO_AVR_ZONE_Define($$$);
|
|
||||||
sub ONKYO_AVR_ZONE_Undefine($$);
|
|
||||||
|
|
||||||
#########################
|
|
||||||
# Forward declaration for remotecontrol module
|
|
||||||
sub ONKYO_AVR_ZONE_RClayout_TV();
|
|
||||||
sub ONKYO_AVR_ZONE_RCmakenotify($$);
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub ONKYO_AVR_ZONE_Initialize($) {
|
sub ONKYO_AVR_ZONE_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
@ -52,22 +15,17 @@ sub ONKYO_AVR_ZONE_Initialize($) {
|
|||||||
|
|
||||||
require "$attr{global}{modpath}/FHEM/ONKYOdb.pm";
|
require "$attr{global}{modpath}/FHEM/ONKYOdb.pm";
|
||||||
|
|
||||||
$hash->{Match} = ".+";
|
|
||||||
|
|
||||||
$hash->{DefFn} = "ONKYO_AVR_ZONE_Define";
|
$hash->{DefFn} = "ONKYO_AVR_ZONE_Define";
|
||||||
$hash->{UndefFn} = "ONKYO_AVR_ZONE_Undefine";
|
$hash->{UndefFn} = "ONKYO_AVR_ZONE_Undefine";
|
||||||
|
$hash->{SetFn} = "ONKYO_AVR_ZONE_Set";
|
||||||
# $hash->{DeleteFn} = "ONKYO_AVR_ZONE_Delete";
|
$hash->{GetFn} = "ONKYO_AVR_ZONE_Get";
|
||||||
$hash->{SetFn} = "ONKYO_AVR_ZONE_Set";
|
|
||||||
$hash->{GetFn} = "ONKYO_AVR_ZONE_Get";
|
|
||||||
|
|
||||||
# $hash->{AttrFn} = "ONKYO_AVR_ZONE_Attr";
|
|
||||||
# $hash->{NotifyFn} = "ONKYO_AVR_ZONE_Notify";
|
|
||||||
$hash->{ParseFn} = "ONKYO_AVR_ZONE_Parse";
|
$hash->{ParseFn} = "ONKYO_AVR_ZONE_Parse";
|
||||||
|
|
||||||
|
$hash->{Match} = ".+";
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$hash->{AttrList} =
|
||||||
"IODev do_not_notify:1,0 "
|
"IODev disable:0,1 disabledForIntervals do_not_notify:1,0 "
|
||||||
. "volumeSteps:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 inputs disable:0,1 model wakeupCmd:textField "
|
. "volumeSteps:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 inputs model wakeupCmd:textField "
|
||||||
. $readingFnAttributes;
|
. $readingFnAttributes;
|
||||||
|
|
||||||
# $data{RC_layout}{ONKYO_AVR_ZONE_SVG} = "ONKYO_AVR_ZONE_RClayout_SVG";
|
# $data{RC_layout}{ONKYO_AVR_ZONE_SVG} = "ONKYO_AVR_ZONE_RClayout_SVG";
|
||||||
@ -90,7 +48,7 @@ sub ONKYO_AVR_ZONE_Initialize($) {
|
|||||||
$hash->{parseParams} = 1;
|
$hash->{parseParams} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
# regular Fn ##################################################################
|
||||||
sub ONKYO_AVR_ZONE_Define($$$) {
|
sub ONKYO_AVR_ZONE_Define($$$) {
|
||||||
my ( $hash, $a, $h ) = @_;
|
my ( $hash, $a, $h ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -125,8 +83,8 @@ sub ONKYO_AVR_ZONE_Define($$$) {
|
|||||||
. $modules{ONKYO_AVR_ZONE}{defptr}{$IOname}{$zone}{NAME};
|
. $modules{ONKYO_AVR_ZONE}{defptr}{$IOname}{$zone}{NAME};
|
||||||
}
|
}
|
||||||
elsif ( !defined($IOhash) ) {
|
elsif ( !defined($IOhash) ) {
|
||||||
return
|
return "No matching I/O device found, "
|
||||||
"No matching I/O device found, please define a ONKYO_AVR device first";
|
. "please define a ONKYO_AVR device first";
|
||||||
}
|
}
|
||||||
elsif ( !defined( $IOhash->{TYPE} ) || !defined( $IOhash->{NAME} ) ) {
|
elsif ( !defined( $IOhash->{TYPE} ) || !defined( $IOhash->{NAME} ) ) {
|
||||||
return "IODev does not seem to be existing";
|
return "IODev does not seem to be existing";
|
||||||
@ -182,10 +140,9 @@ sub ONKYO_AVR_ZONE_Define($$$) {
|
|||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "mute", "query" );
|
ONKYO_AVR_ZONE_SendCommand( $hash, "mute", "query" );
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "volume", "query" );
|
ONKYO_AVR_ZONE_SendCommand( $hash, "volume", "query" );
|
||||||
|
|
||||||
return;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub ONKYO_AVR_ZONE_Undefine($$) {
|
sub ONKYO_AVR_ZONE_Undefine($$) {
|
||||||
my ( $hash, $name ) = @_;
|
my ( $hash, $name ) = @_;
|
||||||
my $zone = $hash->{ZONE};
|
my $zone = $hash->{ZONE};
|
||||||
@ -207,300 +164,6 @@ sub ONKYO_AVR_ZONE_Undefine($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################
|
|
||||||
sub ONKYO_AVR_ZONE_Parse($$) {
|
|
||||||
my ( $IOhash, $msg ) = @_;
|
|
||||||
my @matches;
|
|
||||||
my $IOname = $IOhash->{NAME};
|
|
||||||
my $zone = $msg->{zone} || "";
|
|
||||||
|
|
||||||
delete $msg->{zone} if ( defined( $msg->{zone} ) );
|
|
||||||
|
|
||||||
Log3 $IOname, 5,
|
|
||||||
"ONKYO_AVR $IOname: called function ONKYO_AVR_ZONE_Parse()";
|
|
||||||
|
|
||||||
foreach my $d ( keys %defs ) {
|
|
||||||
my $hash = $defs{$d};
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
my $state = ReadingsVal( $name, "power", "off" );
|
|
||||||
|
|
||||||
if ( $hash->{TYPE} eq "ONKYO_AVR_ZONE"
|
|
||||||
&& $hash->{IODev} eq $IOhash
|
|
||||||
&& ( $zone eq "" || $hash->{ZONE} eq $zone ) )
|
|
||||||
{
|
|
||||||
push @matches, $d;
|
|
||||||
|
|
||||||
# Update readings
|
|
||||||
readingsBeginUpdate($hash);
|
|
||||||
|
|
||||||
foreach my $cmd ( keys %{$msg} ) {
|
|
||||||
my $value = $msg->{$cmd};
|
|
||||||
|
|
||||||
$hash->{INPUT} = $value and next if ( $cmd eq "INPUT_RAW" );
|
|
||||||
$hash->{CHANNEL} = $value and next if ( $cmd eq "CHANNEL_RAW" );
|
|
||||||
|
|
||||||
Log3 $name, 4, "ONKYO_AVR_ZONE $name: rcv $cmd = $value";
|
|
||||||
|
|
||||||
# presence
|
|
||||||
if ( $cmd eq "presence" && $value eq "present" ) {
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "power", "query" );
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "input", "query" );
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "mute", "query" );
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "volume", "query" );
|
|
||||||
}
|
|
||||||
|
|
||||||
# input
|
|
||||||
elsif ( $cmd eq "input" ) {
|
|
||||||
|
|
||||||
# Input alias handling
|
|
||||||
if (
|
|
||||||
defined(
|
|
||||||
$hash->{helper}{receiver}{input_aliases}{$value}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Log3 $name, 4,
|
|
||||||
"ONKYO_AVR_AVR $name: Input aliasing '$value' to '"
|
|
||||||
. $hash->{helper}{receiver}{input_aliases}{$value}
|
|
||||||
. "'";
|
|
||||||
$value =
|
|
||||||
$hash->{helper}{receiver}{input_aliases}{$value};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# power
|
|
||||||
elsif ( $cmd eq "power" ) {
|
|
||||||
readingsBulkUpdate( $hash, "presence", "present" )
|
|
||||||
if ( ReadingsVal( $name, "presence", "-" ) ne "present" );
|
|
||||||
}
|
|
||||||
|
|
||||||
# balance
|
|
||||||
elsif ( $cmd eq "balance" ) {
|
|
||||||
my $prefix = "";
|
|
||||||
$prefix = "-" if ( $value =~ /^\-.*/ );
|
|
||||||
$value = substr( $value, 1 ) if ( $value =~ /^[\+|\-].*/ );
|
|
||||||
|
|
||||||
$value = $prefix . ONKYO_AVR_hex2dec($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
# preset
|
|
||||||
elsif ( $cmd eq "preset" ) {
|
|
||||||
|
|
||||||
if ( defined( $IOhash->{helper}{receiver}{preset} ) ) {
|
|
||||||
|
|
||||||
foreach my $id (
|
|
||||||
sort keys %{ $IOhash->{helper}{receiver}{preset} } )
|
|
||||||
{
|
|
||||||
my $presetName =
|
|
||||||
$IOhash->{helper}{receiver}{preset}{$id};
|
|
||||||
next if ( !$presetName || $presetName eq "" );
|
|
||||||
|
|
||||||
$presetName =~ s/\s/_/g;
|
|
||||||
|
|
||||||
if ( $id eq ONKYO_AVR_dec2hex($value) ) {
|
|
||||||
$value = $presetName;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = "" if ( $value eq "0" );
|
|
||||||
}
|
|
||||||
|
|
||||||
# tone
|
|
||||||
if ( $cmd =~ /^tone/ ) {
|
|
||||||
if ( $value =~ /^B(..)T(..)$/ ) {
|
|
||||||
my $bass = $1;
|
|
||||||
my $treble = $2;
|
|
||||||
my $bassName = $cmd . "-bass";
|
|
||||||
my $trebleName = $cmd . "-treble";
|
|
||||||
my $prefixBass = "";
|
|
||||||
my $prefixTreble = "";
|
|
||||||
|
|
||||||
# tone-bass
|
|
||||||
$prefixBass = "-" if ( $bass =~ /^\-.*/ );
|
|
||||||
$bass = substr( $bass, 1 ) if ( $bass =~ /^[\+|\-].*/ );
|
|
||||||
$bass = $prefixBass . ONKYO_AVR_hex2dec($bass);
|
|
||||||
readingsBulkUpdate( $hash, $bassName, $bass )
|
|
||||||
if ( ReadingsVal( $name, $bassName, "-" ) ne $bass );
|
|
||||||
|
|
||||||
# tone-treble
|
|
||||||
$prefixTreble = "-" if ( $treble =~ /^\-.*/ );
|
|
||||||
$treble = substr( $treble, 1 )
|
|
||||||
if ( $treble =~ /^[\+|\-].*/ );
|
|
||||||
$treble = $prefixTreble . ONKYO_AVR_hex2dec($treble);
|
|
||||||
readingsBulkUpdate( $hash, $trebleName, $treble )
|
|
||||||
if (
|
|
||||||
ReadingsVal( $name, $trebleName, "-" ) ne $treble );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# all other commands
|
|
||||||
else {
|
|
||||||
readingsBulkUpdate( $hash, $cmd, $value )
|
|
||||||
if ( ReadingsVal( $name, $cmd, "-" ) ne $value
|
|
||||||
|| $cmd =~ /^currentAlbumArt.*/ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# stateAV
|
|
||||||
my $stateAV = ONKYO_AVR_ZONE_GetStateAV($hash);
|
|
||||||
readingsBulkUpdate( $hash, "stateAV", $stateAV )
|
|
||||||
if ( ReadingsVal( $name, "stateAV", "-" ) ne $stateAV );
|
|
||||||
|
|
||||||
readingsEndUpdate( $hash, 1 );
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return @matches if (@matches);
|
|
||||||
return "UNDEFINED ONKYO_AVR_ZONE";
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub ONKYO_AVR_ZONE_Get($$$) {
|
|
||||||
my ( $hash, $a, $h ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
my $zone = $hash->{ZONE};
|
|
||||||
my $IOhash = $hash->{IODev};
|
|
||||||
my $IOname = $IOhash->{NAME};
|
|
||||||
my $state = ReadingsVal( $name, "power", "off" );
|
|
||||||
my $presence = ReadingsVal( $name, "presence", "absent" );
|
|
||||||
my $commands = ONKYOdb::ONKYO_GetRemotecontrolCommand($zone);
|
|
||||||
my $commands_details = ONKYOdb::ONKYO_GetRemotecontrolCommandDetails($zone);
|
|
||||||
my $return;
|
|
||||||
|
|
||||||
Log3 $name, 5, "ONKYO_AVR_ZONE $name: called function ONKYO_AVR_ZONE_Get()";
|
|
||||||
|
|
||||||
return "Argument is missing" if ( int(@$a) < 1 );
|
|
||||||
|
|
||||||
# readings
|
|
||||||
return $hash->{READINGS}{ @$a[1] }{VAL}
|
|
||||||
if ( defined( $hash->{READINGS}{ @$a[1] } ) );
|
|
||||||
|
|
||||||
return "Device is offline and cannot be controlled at that stage."
|
|
||||||
if ( $presence eq "absent" );
|
|
||||||
|
|
||||||
# statusRequest
|
|
||||||
if ( lc( @$a[1] ) eq "statusrequest" ) {
|
|
||||||
Log3 $name, 3, "ONKYO_AVR_ZONE get $name " . @$a[1];
|
|
||||||
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "power", "query" );
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "input", "query" );
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "mute", "query" );
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, "volume", "query" );
|
|
||||||
}
|
|
||||||
|
|
||||||
# remoteControl
|
|
||||||
elsif ( lc( @$a[1] ) eq "remotecontrol" ) {
|
|
||||||
|
|
||||||
# Output help for commands
|
|
||||||
if ( !defined( @$a[2] ) || @$a[2] eq "help" || @$a[2] eq "?" ) {
|
|
||||||
|
|
||||||
my $valid_commands =
|
|
||||||
"Usage: <command> <value>\n\nValid commands in zone$zone:\n\n\n"
|
|
||||||
. "COMMAND\t\t\tDESCRIPTION\n\n";
|
|
||||||
|
|
||||||
# For each valid command
|
|
||||||
foreach my $command ( sort keys %{$commands} ) {
|
|
||||||
my $command_raw = $commands->{$command};
|
|
||||||
|
|
||||||
# add command including description if found
|
|
||||||
if ( defined( $commands_details->{$command_raw}{description} ) )
|
|
||||||
{
|
|
||||||
$valid_commands .=
|
|
||||||
$command
|
|
||||||
. "\t\t\t"
|
|
||||||
. $commands_details->{$command_raw}{description} . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# add command only
|
|
||||||
else {
|
|
||||||
$valid_commands .= $command . "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$valid_commands .=
|
|
||||||
"\nTry '<command> help' to find out well known values.\n\n\n";
|
|
||||||
|
|
||||||
$return = $valid_commands;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
# Reading values for command from HASH table
|
|
||||||
my $values =
|
|
||||||
ONKYOdb::ONKYO_GetRemotecontrolValue( $zone,
|
|
||||||
$commands->{ @$a[2] } );
|
|
||||||
|
|
||||||
@$a[3] = "query"
|
|
||||||
if ( !defined( @$a[3] ) && defined( $values->{query} ) );
|
|
||||||
|
|
||||||
# Output help for values
|
|
||||||
if ( !defined( @$a[3] ) || @$a[3] eq "help" || @$a[3] eq "?" ) {
|
|
||||||
|
|
||||||
# Get all details for command
|
|
||||||
my $command_details =
|
|
||||||
ONKYOdb::ONKYO_GetRemotecontrolCommandDetails( $zone,
|
|
||||||
$commands->{ @$a[2] } );
|
|
||||||
|
|
||||||
my $valid_values =
|
|
||||||
"Usage: "
|
|
||||||
. @$a[2]
|
|
||||||
. " <value>\n\nWell known values:\n\n\n"
|
|
||||||
. "VALUE\t\t\tDESCRIPTION\n\n";
|
|
||||||
|
|
||||||
# For each valid value
|
|
||||||
foreach my $value ( sort keys %{$values} ) {
|
|
||||||
|
|
||||||
# add value including description if found
|
|
||||||
if ( defined( $command_details->{description} ) ) {
|
|
||||||
$valid_values .=
|
|
||||||
$value
|
|
||||||
. "\t\t\t"
|
|
||||||
. $command_details->{description} . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# add value only
|
|
||||||
else {
|
|
||||||
$valid_values .= $value . "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$valid_values .= "\n\n\n";
|
|
||||||
|
|
||||||
$return = $valid_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
# normal processing
|
|
||||||
else {
|
|
||||||
Log3 $name, 3,
|
|
||||||
"ONKYO_AVR_ZONE get $name "
|
|
||||||
. @$a[1] . " "
|
|
||||||
. @$a[2] . " "
|
|
||||||
. @$a[3]
|
|
||||||
if ( !@$a[4] || @$a[4] ne "quiet" );
|
|
||||||
|
|
||||||
ONKYO_AVR_ZONE_SendCommand( $hash, @$a[2], @$a[3] );
|
|
||||||
$return = "Sent command: " . @$a[2] . " " . @$a[3]
|
|
||||||
if ( !@$a[4] || @$a[4] ne "quiet" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
$return =
|
|
||||||
"Unknown argument " . @$a[1] . ", choose one of statusRequest:noArg";
|
|
||||||
|
|
||||||
# remoteControl
|
|
||||||
$return .= " remoteControl:";
|
|
||||||
foreach my $command ( sort keys %{$commands} ) {
|
|
||||||
$return .= "," . $command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return if ($return);
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub ONKYO_AVR_ZONE_Set($$$) {
|
sub ONKYO_AVR_ZONE_Set($$$) {
|
||||||
my ( $hash, $a, $h ) = @_;
|
my ( $hash, $a, $h ) = @_;
|
||||||
my $IOhash = $hash->{IODev};
|
my $IOhash = $hash->{IODev};
|
||||||
@ -1443,13 +1106,298 @@ sub ONKYO_AVR_ZONE_Set($$$) {
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
############################################################################################################
|
sub ONKYO_AVR_ZONE_Get($$$) {
|
||||||
#
|
my ( $hash, $a, $h ) = @_;
|
||||||
# Begin of helper functions
|
my $name = $hash->{NAME};
|
||||||
#
|
my $zone = $hash->{ZONE};
|
||||||
############################################################################################################
|
my $IOhash = $hash->{IODev};
|
||||||
|
my $IOname = $IOhash->{NAME};
|
||||||
|
my $state = ReadingsVal( $name, "power", "off" );
|
||||||
|
my $presence = ReadingsVal( $name, "presence", "absent" );
|
||||||
|
my $commands = ONKYOdb::ONKYO_GetRemotecontrolCommand($zone);
|
||||||
|
my $commands_details = ONKYOdb::ONKYO_GetRemotecontrolCommandDetails($zone);
|
||||||
|
my $return;
|
||||||
|
|
||||||
###################################
|
Log3 $name, 5, "ONKYO_AVR_ZONE $name: called function ONKYO_AVR_ZONE_Get()";
|
||||||
|
|
||||||
|
return "Argument is missing" if ( int(@$a) < 1 );
|
||||||
|
|
||||||
|
# readings
|
||||||
|
return $hash->{READINGS}{ @$a[1] }{VAL}
|
||||||
|
if ( defined( $hash->{READINGS}{ @$a[1] } ) );
|
||||||
|
|
||||||
|
return "Device is offline and cannot be controlled at that stage."
|
||||||
|
if ( $presence eq "absent" );
|
||||||
|
|
||||||
|
# statusRequest
|
||||||
|
if ( lc( @$a[1] ) eq "statusrequest" ) {
|
||||||
|
Log3 $name, 3, "ONKYO_AVR_ZONE get $name " . @$a[1];
|
||||||
|
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "power", "query" );
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "input", "query" );
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "mute", "query" );
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "volume", "query" );
|
||||||
|
}
|
||||||
|
|
||||||
|
# remoteControl
|
||||||
|
elsif ( lc( @$a[1] ) eq "remotecontrol" ) {
|
||||||
|
|
||||||
|
# Output help for commands
|
||||||
|
if ( !defined( @$a[2] ) || @$a[2] eq "help" || @$a[2] eq "?" ) {
|
||||||
|
|
||||||
|
my $valid_commands =
|
||||||
|
"Usage: <command> <value>\n\nValid commands in zone$zone:\n\n\n"
|
||||||
|
. "COMMAND\t\t\tDESCRIPTION\n\n";
|
||||||
|
|
||||||
|
# For each valid command
|
||||||
|
foreach my $command ( sort keys %{$commands} ) {
|
||||||
|
my $command_raw = $commands->{$command};
|
||||||
|
|
||||||
|
# add command including description if found
|
||||||
|
if ( defined( $commands_details->{$command_raw}{description} ) )
|
||||||
|
{
|
||||||
|
$valid_commands .=
|
||||||
|
$command
|
||||||
|
. "\t\t\t"
|
||||||
|
. $commands_details->{$command_raw}{description} . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# add command only
|
||||||
|
else {
|
||||||
|
$valid_commands .= $command . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$valid_commands .=
|
||||||
|
"\nTry '<command> help' to find out well known values.\n\n\n";
|
||||||
|
|
||||||
|
$return = $valid_commands;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Reading values for command from HASH table
|
||||||
|
my $values =
|
||||||
|
ONKYOdb::ONKYO_GetRemotecontrolValue( $zone,
|
||||||
|
$commands->{ @$a[2] } );
|
||||||
|
|
||||||
|
@$a[3] = "query"
|
||||||
|
if ( !defined( @$a[3] ) && defined( $values->{query} ) );
|
||||||
|
|
||||||
|
# Output help for values
|
||||||
|
if ( !defined( @$a[3] ) || @$a[3] eq "help" || @$a[3] eq "?" ) {
|
||||||
|
|
||||||
|
# Get all details for command
|
||||||
|
my $command_details =
|
||||||
|
ONKYOdb::ONKYO_GetRemotecontrolCommandDetails( $zone,
|
||||||
|
$commands->{ @$a[2] } );
|
||||||
|
|
||||||
|
my $valid_values =
|
||||||
|
"Usage: "
|
||||||
|
. @$a[2]
|
||||||
|
. " <value>\n\nWell known values:\n\n\n"
|
||||||
|
. "VALUE\t\t\tDESCRIPTION\n\n";
|
||||||
|
|
||||||
|
# For each valid value
|
||||||
|
foreach my $value ( sort keys %{$values} ) {
|
||||||
|
|
||||||
|
# add value including description if found
|
||||||
|
if ( defined( $command_details->{description} ) ) {
|
||||||
|
$valid_values .=
|
||||||
|
$value
|
||||||
|
. "\t\t\t"
|
||||||
|
. $command_details->{description} . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# add value only
|
||||||
|
else {
|
||||||
|
$valid_values .= $value . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$valid_values .= "\n\n\n";
|
||||||
|
|
||||||
|
$return = $valid_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
# normal processing
|
||||||
|
else {
|
||||||
|
Log3 $name, 3,
|
||||||
|
"ONKYO_AVR_ZONE get $name "
|
||||||
|
. @$a[1] . " "
|
||||||
|
. @$a[2] . " "
|
||||||
|
. @$a[3]
|
||||||
|
if ( !@$a[4] || @$a[4] ne "quiet" );
|
||||||
|
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, @$a[2], @$a[3] );
|
||||||
|
$return = "Sent command: " . @$a[2] . " " . @$a[3]
|
||||||
|
if ( !@$a[4] || @$a[4] ne "quiet" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
$return =
|
||||||
|
"Unknown argument " . @$a[1] . ", choose one of statusRequest:noArg";
|
||||||
|
|
||||||
|
# remoteControl
|
||||||
|
$return .= " remoteControl:";
|
||||||
|
foreach my $command ( sort keys %{$commands} ) {
|
||||||
|
$return .= "," . $command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub ONKYO_AVR_ZONE_Parse($$) {
|
||||||
|
my ( $IOhash, $msg ) = @_;
|
||||||
|
my @matches;
|
||||||
|
my $IOname = $IOhash->{NAME};
|
||||||
|
my $zone = $msg->{zone} || "";
|
||||||
|
|
||||||
|
delete $msg->{zone} if ( defined( $msg->{zone} ) );
|
||||||
|
|
||||||
|
Log3 $IOname, 5,
|
||||||
|
"ONKYO_AVR $IOname: called function ONKYO_AVR_ZONE_Parse()";
|
||||||
|
|
||||||
|
foreach my $d ( keys %defs ) {
|
||||||
|
my $hash = $defs{$d};
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $state = ReadingsVal( $name, "power", "off" );
|
||||||
|
|
||||||
|
if ( $hash->{TYPE} eq "ONKYO_AVR_ZONE"
|
||||||
|
&& $hash->{IODev} eq $IOhash
|
||||||
|
&& ( $zone eq "" || $hash->{ZONE} eq $zone ) )
|
||||||
|
{
|
||||||
|
push @matches, $d;
|
||||||
|
|
||||||
|
# Update readings
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
foreach my $cmd ( keys %{$msg} ) {
|
||||||
|
my $value = $msg->{$cmd};
|
||||||
|
|
||||||
|
$hash->{INPUT} = $value and next if ( $cmd eq "INPUT_RAW" );
|
||||||
|
$hash->{CHANNEL} = $value and next if ( $cmd eq "CHANNEL_RAW" );
|
||||||
|
|
||||||
|
Log3 $name, 4, "ONKYO_AVR_ZONE $name: rcv $cmd = $value";
|
||||||
|
|
||||||
|
# presence
|
||||||
|
if ( $cmd eq "presence" && $value eq "present" ) {
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "power", "query" );
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "input", "query" );
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "mute", "query" );
|
||||||
|
ONKYO_AVR_ZONE_SendCommand( $hash, "volume", "query" );
|
||||||
|
}
|
||||||
|
|
||||||
|
# input
|
||||||
|
elsif ( $cmd eq "input" ) {
|
||||||
|
|
||||||
|
# Input alias handling
|
||||||
|
if (
|
||||||
|
defined(
|
||||||
|
$hash->{helper}{receiver}{input_aliases}{$value}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Log3 $name, 4,
|
||||||
|
"ONKYO_AVR_AVR $name: Input aliasing '$value' to '"
|
||||||
|
. $hash->{helper}{receiver}{input_aliases}{$value}
|
||||||
|
. "'";
|
||||||
|
$value =
|
||||||
|
$hash->{helper}{receiver}{input_aliases}{$value};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# power
|
||||||
|
elsif ( $cmd eq "power" ) {
|
||||||
|
readingsBulkUpdate( $hash, "presence", "present" )
|
||||||
|
if ( ReadingsVal( $name, "presence", "-" ) ne "present" );
|
||||||
|
}
|
||||||
|
|
||||||
|
# balance
|
||||||
|
elsif ( $cmd eq "balance" ) {
|
||||||
|
my $prefix = "";
|
||||||
|
$prefix = "-" if ( $value =~ /^\-.*/ );
|
||||||
|
$value = substr( $value, 1 ) if ( $value =~ /^[\+|\-].*/ );
|
||||||
|
|
||||||
|
$value = $prefix . ONKYO_AVR_hex2dec($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
# preset
|
||||||
|
elsif ( $cmd eq "preset" ) {
|
||||||
|
|
||||||
|
if ( defined( $IOhash->{helper}{receiver}{preset} ) ) {
|
||||||
|
|
||||||
|
foreach my $id (
|
||||||
|
sort keys %{ $IOhash->{helper}{receiver}{preset} } )
|
||||||
|
{
|
||||||
|
my $presetName =
|
||||||
|
$IOhash->{helper}{receiver}{preset}{$id};
|
||||||
|
next if ( !$presetName || $presetName eq "" );
|
||||||
|
|
||||||
|
$presetName =~ s/\s/_/g;
|
||||||
|
|
||||||
|
if ( $id eq ONKYO_AVR_dec2hex($value) ) {
|
||||||
|
$value = $presetName;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = "" if ( $value eq "0" );
|
||||||
|
}
|
||||||
|
|
||||||
|
# tone
|
||||||
|
if ( $cmd =~ /^tone/ ) {
|
||||||
|
if ( $value =~ /^B(..)T(..)$/ ) {
|
||||||
|
my $bass = $1;
|
||||||
|
my $treble = $2;
|
||||||
|
my $bassName = $cmd . "-bass";
|
||||||
|
my $trebleName = $cmd . "-treble";
|
||||||
|
my $prefixBass = "";
|
||||||
|
my $prefixTreble = "";
|
||||||
|
|
||||||
|
# tone-bass
|
||||||
|
$prefixBass = "-" if ( $bass =~ /^\-.*/ );
|
||||||
|
$bass = substr( $bass, 1 ) if ( $bass =~ /^[\+|\-].*/ );
|
||||||
|
$bass = $prefixBass . ONKYO_AVR_hex2dec($bass);
|
||||||
|
readingsBulkUpdate( $hash, $bassName, $bass )
|
||||||
|
if ( ReadingsVal( $name, $bassName, "-" ) ne $bass );
|
||||||
|
|
||||||
|
# tone-treble
|
||||||
|
$prefixTreble = "-" if ( $treble =~ /^\-.*/ );
|
||||||
|
$treble = substr( $treble, 1 )
|
||||||
|
if ( $treble =~ /^[\+|\-].*/ );
|
||||||
|
$treble = $prefixTreble . ONKYO_AVR_hex2dec($treble);
|
||||||
|
readingsBulkUpdate( $hash, $trebleName, $treble )
|
||||||
|
if (
|
||||||
|
ReadingsVal( $name, $trebleName, "-" ) ne $treble );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# all other commands
|
||||||
|
else {
|
||||||
|
readingsBulkUpdate( $hash, $cmd, $value )
|
||||||
|
if ( ReadingsVal( $name, $cmd, "-" ) ne $value
|
||||||
|
|| $cmd =~ /^currentAlbumArt.*/ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# stateAV
|
||||||
|
my $stateAV = ONKYO_AVR_ZONE_GetStateAV($hash);
|
||||||
|
readingsBulkUpdate( $hash, "stateAV", $stateAV )
|
||||||
|
if ( ReadingsVal( $name, "stateAV", "-" ) ne $stateAV );
|
||||||
|
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return @matches if (@matches);
|
||||||
|
return "UNDEFINED ONKYO_AVR_ZONE";
|
||||||
|
}
|
||||||
|
|
||||||
|
# module Fn ####################################################################
|
||||||
sub ONKYO_AVR_ZONE_SendCommand($$$) {
|
sub ONKYO_AVR_ZONE_SendCommand($$$) {
|
||||||
my ( $hash, $cmd, $value ) = @_;
|
my ( $hash, $cmd, $value ) = @_;
|
||||||
my $IOhash = $hash->{IODev};
|
my $IOhash = $hash->{IODev};
|
||||||
@ -1523,7 +1471,6 @@ sub ONKYO_AVR_ZONE_SendCommand($$$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub ONKYO_AVR_ZONE_GetStateAV($) {
|
sub ONKYO_AVR_ZONE_GetStateAV($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
@ -1,30 +1,5 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# 74_THINKINGCLEANER.pm
|
|
||||||
# An FHEM Perl module for controlling ThinkingCleaner connected
|
|
||||||
# Roomba vacuum cleaning robot.
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
@ -34,15 +9,7 @@ use HttpUtils;
|
|||||||
use Encode;
|
use Encode;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
no warnings "all";
|
# initialize ##################################################################
|
||||||
|
|
||||||
sub THINKINGCLEANER_Set($@);
|
|
||||||
sub THINKINGCLEANER_GetStatus($;$);
|
|
||||||
sub THINKINGCLEANER_Attr($@);
|
|
||||||
sub THINKINGCLEANER_Define($$);
|
|
||||||
sub THINKINGCLEANER_Undefine($$);
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_Initialize($) {
|
sub THINKINGCLEANER_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
@ -51,14 +18,14 @@ sub THINKINGCLEANER_Initialize($) {
|
|||||||
my $webhookFWinstance =
|
my $webhookFWinstance =
|
||||||
join( ",", devspec2array('TYPE=FHEMWEB:FILTER=TEMPORARY!=1') );
|
join( ",", devspec2array('TYPE=FHEMWEB:FILTER=TEMPORARY!=1') );
|
||||||
|
|
||||||
$hash->{SetFn} = "THINKINGCLEANER_Set";
|
|
||||||
$hash->{DefFn} = "THINKINGCLEANER_Define";
|
$hash->{DefFn} = "THINKINGCLEANER_Define";
|
||||||
$hash->{AttrFn} = "THINKINGCLEANER_Attr";
|
|
||||||
$hash->{UndefFn} = "THINKINGCLEANER_Undefine";
|
$hash->{UndefFn} = "THINKINGCLEANER_Undefine";
|
||||||
|
$hash->{SetFn} = "THINKINGCLEANER_Set";
|
||||||
|
$hash->{AttrFn} = "THINKINGCLEANER_Attr";
|
||||||
$hash->{parseParams} = 1;
|
$hash->{parseParams} = 1;
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$hash->{AttrList} =
|
||||||
"disable:0,1 timeout:1,2,3,4,5 pollInterval:30,45,60,75,90 pollMultiplierWebhook pollMultiplierCleaning model webhookHttpHostname webhookPort webhookFWinstance:$webhookFWinstance restart:noArg "
|
"disable:0,1 disabledForIntervals timeout:1,2,3,4,5 pollInterval:30,45,60,75,90 pollMultiplierWebhook pollMultiplierCleaning model webhookHttpHostname webhookPort webhookFWinstance:$webhookFWinstance restart:noArg "
|
||||||
. $readingFnAttributes;
|
. $readingFnAttributes;
|
||||||
|
|
||||||
# 98_powerMap.pm support
|
# 98_powerMap.pm support
|
||||||
@ -89,50 +56,82 @@ sub THINKINGCLEANER_Initialize($) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
# regular Fn ##################################################################
|
||||||
sub THINKINGCLEANER_GetStatus($;$) {
|
sub THINKINGCLEANER_Define($$$) {
|
||||||
my ( $hash, $delay ) = @_;
|
my ( $hash, $a, $h ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
$hash->{INTERVAL_MULTIPLIER} = (
|
my $infix = "THINKINGCLEANER";
|
||||||
ReadingsVal( $name, "state", "off" ) ne "off"
|
|
||||||
&& ReadingsVal( $name, "state", "absent" ) ne "absent"
|
|
||||||
&& ReadingsVal( $name, "state", "standby" ) ne "standby"
|
|
||||||
? AttrVal( $name, "pollMultiplierCleaning", "0.5" )
|
|
||||||
: (
|
|
||||||
$hash->{WEBHOOK_REGISTER} eq "success"
|
|
||||||
? AttrVal( $name, "pollMultiplierWebhook", "2" )
|
|
||||||
: "1"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$hash->{INTERVAL} =
|
|
||||||
AttrVal( $name, "pollInterval", "45" ) * $hash->{INTERVAL_MULTIPLIER};
|
|
||||||
my $interval = (
|
|
||||||
$delay
|
|
||||||
? $delay
|
|
||||||
: $hash->{INTERVAL}
|
|
||||||
);
|
|
||||||
|
|
||||||
Log3 $name, 5,
|
Log3 $name, 5,
|
||||||
"THINKINGCLEANER $name: called function THINKINGCLEANER_GetStatus()";
|
"THINKINGCLEANER $name: called function THINKINGCLEANER_Define()";
|
||||||
|
|
||||||
RemoveInternalTimer($hash);
|
eval {
|
||||||
InternalTimer( gettimeofday() + $interval,
|
require JSON;
|
||||||
"THINKINGCLEANER_GetStatus", $hash, 0 );
|
import JSON qw( decode_json );
|
||||||
|
};
|
||||||
|
return "Please install Perl JSON to use module THINKINGCLEANER"
|
||||||
|
if ($@);
|
||||||
|
|
||||||
return
|
if ( int(@$a) < 2 ) {
|
||||||
if ( $delay || AttrVal( $name, "disable", 0 ) == 1 );
|
my $msg =
|
||||||
|
"Wrong syntax: define <name> THINKINGCLEANER <ip-or-hostname>";
|
||||||
|
Log3 $name, 4, $msg;
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
THINKINGCLEANER_SendCommand( $hash, "full_status.json" );
|
$hash->{TYPE} = "THINKINGCLEANER";
|
||||||
|
|
||||||
return;
|
my $address = @$a[2];
|
||||||
|
$hash->{DeviceName} = $address;
|
||||||
|
|
||||||
|
# set reverse pointer
|
||||||
|
$modules{THINKINGCLEANER}{defptr}{$name} = \$hash;
|
||||||
|
|
||||||
|
# set default settings on first define
|
||||||
|
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
|
||||||
|
$attr{$name}{cmdIcon} =
|
||||||
|
'on-max:text_max on-spot:refresh on-delayed:time_timer dock:measure_battery_50 locate:rc_SEARCH';
|
||||||
|
$attr{$name}{devStateIcon} =
|
||||||
|
'on-delayed:rc_STOP@green:off on-max:rc_BLUE@green:off on-spot:rc_GREEN@red:off on.*:rc_GREEN@green:off dock:rc_GREEN@orange:off off:rc_STOP:on standby|remote:rc_YELLOW:on locate:rc_YELLOW .*:rc_RED';
|
||||||
|
$attr{$name}{icon} = 'scene_cleaning';
|
||||||
|
$attr{$name}{webCmd} = 'on-max:on-spot:on-delayed:dock:locate';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( THINKINGCLEANER_addExtension( $name, "THINKINGCLEANER_CGI", $infix ) )
|
||||||
|
{
|
||||||
|
$hash->{fhem}{infix} = $infix;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash->{WEBHOOK_REGISTER} = "unregistered";
|
||||||
|
|
||||||
|
# start the status update timer
|
||||||
|
THINKINGCLEANER_GetStatus( $hash, 2 );
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub THINKINGCLEANER_Undefine($$$) {
|
||||||
|
my ( $hash, $a, $h ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
if ( defined( $hash->{fhem}{infix} ) ) {
|
||||||
|
THINKINGCLEANER_removeExtension( $hash->{fhem}{infix} );
|
||||||
|
}
|
||||||
|
|
||||||
|
Log3 $name, 5,
|
||||||
|
"THINKINGCLEANER $name: called function THINKINGCLEANER_Undefine()";
|
||||||
|
|
||||||
|
# Stop the internal GetStatus-Loop and exit
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
|
# release reverse pointer
|
||||||
|
delete $modules{THINKINGCLEANER}{defptr}{$name};
|
||||||
|
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_Set($$$) {
|
sub THINKINGCLEANER_Set($$$) {
|
||||||
my ( $hash, $a, $h ) = @_;
|
my ( $hash, $a, $h ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -842,64 +841,9 @@ sub THINKINGCLEANER_Set($$$) {
|
|||||||
return $usage;
|
return $usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_Define($$$) {
|
|
||||||
my ( $hash, $a, $h ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
my $infix = "THINKINGCLEANER";
|
|
||||||
|
|
||||||
Log3 $name, 5,
|
|
||||||
"THINKINGCLEANER $name: called function THINKINGCLEANER_Define()";
|
|
||||||
|
|
||||||
eval {
|
|
||||||
require JSON;
|
|
||||||
import JSON qw( decode_json );
|
|
||||||
};
|
|
||||||
return "Please install Perl JSON to use module THINKINGCLEANER"
|
|
||||||
if ($@);
|
|
||||||
|
|
||||||
if ( int(@$a) < 2 ) {
|
|
||||||
my $msg =
|
|
||||||
"Wrong syntax: define <name> THINKINGCLEANER <ip-or-hostname>";
|
|
||||||
Log3 $name, 4, $msg;
|
|
||||||
return $msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
$hash->{TYPE} = "THINKINGCLEANER";
|
|
||||||
|
|
||||||
my $address = @$a[2];
|
|
||||||
$hash->{DeviceName} = $address;
|
|
||||||
|
|
||||||
# set reverse pointer
|
|
||||||
$modules{THINKINGCLEANER}{defptr}{$name} = \$hash;
|
|
||||||
|
|
||||||
# set default settings on first define
|
|
||||||
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
|
|
||||||
$attr{$name}{cmdIcon} =
|
|
||||||
'on-max:text_max on-spot:refresh on-delayed:time_timer dock:measure_battery_50 locate:rc_SEARCH';
|
|
||||||
$attr{$name}{devStateIcon} =
|
|
||||||
'on-delayed:rc_STOP@green:off on-max:rc_BLUE@green:off on-spot:rc_GREEN@red:off on.*:rc_GREEN@green:off dock:rc_GREEN@orange:off off:rc_STOP:on standby|remote:rc_YELLOW:on locate:rc_YELLOW .*:rc_RED';
|
|
||||||
$attr{$name}{icon} = 'scene_cleaning';
|
|
||||||
$attr{$name}{webCmd} = 'on-max:on-spot:on-delayed:dock:locate';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( THINKINGCLEANER_addExtension( $name, "THINKINGCLEANER_CGI", $infix ) )
|
|
||||||
{
|
|
||||||
$hash->{fhem}{infix} = $infix;
|
|
||||||
}
|
|
||||||
|
|
||||||
$hash->{WEBHOOK_REGISTER} = "unregistered";
|
|
||||||
|
|
||||||
# start the status update timer
|
|
||||||
THINKINGCLEANER_GetStatus( $hash, 2 );
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_Attr(@) {
|
sub THINKINGCLEANER_Attr(@) {
|
||||||
my ( $cmd, $name, $attrName, $attrVal ) = @_;
|
my ( $cmd, $name, $attrName, $attrVal ) = @_;
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
@ -1004,7 +948,7 @@ sub THINKINGCLEANER_Attr(@) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
# module Fn ####################################################################
|
||||||
sub THINKINGCLEANER_addExtension($$$) {
|
sub THINKINGCLEANER_addExtension($$$) {
|
||||||
my ( $name, $func, $link ) = @_;
|
my ( $name, $func, $link ) = @_;
|
||||||
|
|
||||||
@ -1023,7 +967,6 @@ sub THINKINGCLEANER_addExtension($$$) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_removeExtension($) {
|
sub THINKINGCLEANER_removeExtension($) {
|
||||||
my ($link) = @_;
|
my ($link) = @_;
|
||||||
|
|
||||||
@ -1034,13 +977,88 @@ sub THINKINGCLEANER_removeExtension($) {
|
|||||||
delete $data{FWEXT}{$url};
|
delete $data{FWEXT}{$url};
|
||||||
}
|
}
|
||||||
|
|
||||||
############################################################################################################
|
sub THINKINGCLEANER_CGI() {
|
||||||
#
|
my ($request) = @_;
|
||||||
# Begin of helper functions
|
|
||||||
#
|
# data received
|
||||||
############################################################################################################
|
if ( defined( $FW_httpheader{UUID} ) ) {
|
||||||
|
if ( defined( $modules{THINKINGCLEANER}{defptr} ) ) {
|
||||||
|
while ( my ( $key, $value ) =
|
||||||
|
each %{ $modules{THINKINGCLEANER}{defptr} } )
|
||||||
|
{
|
||||||
|
|
||||||
|
my $uuid = ReadingsVal( $key, "uuid", undef );
|
||||||
|
next if ( !$uuid || $uuid ne $FW_httpheader{UUID} );
|
||||||
|
|
||||||
|
$defs{$key}{WEBHOOK_COUNTER}++;
|
||||||
|
$defs{$key}{WEBHOOK_LAST} = TimeNow();
|
||||||
|
|
||||||
|
Log3 $key, 4,
|
||||||
|
"THINKINGCLEANER $key: Received webhook for matching UUID at device $key";
|
||||||
|
|
||||||
|
my $delay = undef;
|
||||||
|
|
||||||
|
# we need some delay as to the Robo seems to send webhooks but it's status does
|
||||||
|
# not really reflect the change we'd expect to get here already so give 'em some
|
||||||
|
# more time to think about it...
|
||||||
|
$delay = "2"
|
||||||
|
if ( defined( $defs{$key}{LAST_COMMAND} )
|
||||||
|
&& time() - time_str2num( $defs{$key}{LAST_COMMAND} ) < 3 );
|
||||||
|
|
||||||
|
THINKINGCLEANER_GetStatus( $defs{$key}, $delay );
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( undef, undef );
|
||||||
|
}
|
||||||
|
|
||||||
|
# no data received
|
||||||
|
else {
|
||||||
|
Log3 undef, 5, "THINKINGCLEANER: received malformed request\n$request";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( "text/plain; charset=utf-8", "Call failure: " . $request );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub THINKINGCLEANER_GetStatus($;$) {
|
||||||
|
my ( $hash, $delay ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
$hash->{INTERVAL_MULTIPLIER} = (
|
||||||
|
ReadingsVal( $name, "state", "off" ) ne "off"
|
||||||
|
&& ReadingsVal( $name, "state", "absent" ) ne "absent"
|
||||||
|
&& ReadingsVal( $name, "state", "standby" ) ne "standby"
|
||||||
|
? AttrVal( $name, "pollMultiplierCleaning", "0.5" )
|
||||||
|
: (
|
||||||
|
$hash->{WEBHOOK_REGISTER} eq "success"
|
||||||
|
? AttrVal( $name, "pollMultiplierWebhook", "2" )
|
||||||
|
: "1"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$hash->{INTERVAL} =
|
||||||
|
AttrVal( $name, "pollInterval", "45" ) * $hash->{INTERVAL_MULTIPLIER};
|
||||||
|
my $interval = (
|
||||||
|
$delay
|
||||||
|
? $delay
|
||||||
|
: $hash->{INTERVAL}
|
||||||
|
);
|
||||||
|
|
||||||
|
Log3 $name, 5,
|
||||||
|
"THINKINGCLEANER $name: called function THINKINGCLEANER_GetStatus()";
|
||||||
|
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
InternalTimer( gettimeofday() + $interval,
|
||||||
|
"THINKINGCLEANER_GetStatus", $hash, 0 );
|
||||||
|
|
||||||
|
return
|
||||||
|
if ( $delay || AttrVal( $name, "disable", 0 ) == 1 );
|
||||||
|
|
||||||
|
THINKINGCLEANER_SendCommand( $hash, "full_status.json" );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_SendCommand($$;$$) {
|
sub THINKINGCLEANER_SendCommand($$;$$) {
|
||||||
my ( $hash, $service, $cmd, $type ) = @_;
|
my ( $hash, $service, $cmd, $type ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -1166,7 +1184,6 @@ sub THINKINGCLEANER_SendCommand($$;$$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_ReceiveCommand($$$) {
|
sub THINKINGCLEANER_ReceiveCommand($$$) {
|
||||||
my ( $param, $err, $data ) = @_;
|
my ( $param, $err, $data ) = @_;
|
||||||
my $hash = $param->{hash};
|
my $hash = $param->{hash};
|
||||||
@ -1728,73 +1745,6 @@ sub THINKINGCLEANER_ReceiveCommand($$$) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_CGI() {
|
|
||||||
my ($request) = @_;
|
|
||||||
|
|
||||||
# data received
|
|
||||||
if ( defined( $FW_httpheader{UUID} ) ) {
|
|
||||||
if ( defined( $modules{THINKINGCLEANER}{defptr} ) ) {
|
|
||||||
while ( my ( $key, $value ) =
|
|
||||||
each %{ $modules{THINKINGCLEANER}{defptr} } )
|
|
||||||
{
|
|
||||||
|
|
||||||
my $uuid = ReadingsVal( $key, "uuid", undef );
|
|
||||||
next if ( !$uuid || $uuid ne $FW_httpheader{UUID} );
|
|
||||||
|
|
||||||
$defs{$key}{WEBHOOK_COUNTER}++;
|
|
||||||
$defs{$key}{WEBHOOK_LAST} = TimeNow();
|
|
||||||
|
|
||||||
Log3 $key, 4,
|
|
||||||
"THINKINGCLEANER $key: Received webhook for matching UUID at device $key";
|
|
||||||
|
|
||||||
my $delay = undef;
|
|
||||||
|
|
||||||
# we need some delay as to the Robo seems to send webhooks but it's status does
|
|
||||||
# not really reflect the change we'd expect to get here already so give 'em some
|
|
||||||
# more time to think about it...
|
|
||||||
$delay = "2"
|
|
||||||
if ( defined( $defs{$key}{LAST_COMMAND} )
|
|
||||||
&& time() - time_str2num( $defs{$key}{LAST_COMMAND} ) < 3 );
|
|
||||||
|
|
||||||
THINKINGCLEANER_GetStatus( $defs{$key}, $delay );
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( undef, undef );
|
|
||||||
}
|
|
||||||
|
|
||||||
# no data received
|
|
||||||
else {
|
|
||||||
Log3 undef, 5, "THINKINGCLEANER: received malformed request\n$request";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( "text/plain; charset=utf-8", "Call failure: " . $request );
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_Undefine($$$) {
|
|
||||||
my ( $hash, $a, $h ) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
|
|
||||||
if ( defined( $hash->{fhem}{infix} ) ) {
|
|
||||||
THINKINGCLEANER_removeExtension( $hash->{fhem}{infix} );
|
|
||||||
}
|
|
||||||
|
|
||||||
Log3 $name, 5,
|
|
||||||
"THINKINGCLEANER $name: called function THINKINGCLEANER_Undefine()";
|
|
||||||
|
|
||||||
# Stop the internal GetStatus-Loop and exit
|
|
||||||
RemoveInternalTimer($hash);
|
|
||||||
|
|
||||||
# release reverse pointer
|
|
||||||
delete $modules{THINKINGCLEANER}{defptr}{$name};
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_time2sec($) {
|
sub THINKINGCLEANER_time2sec($) {
|
||||||
my ($timeString) = @_;
|
my ($timeString) = @_;
|
||||||
my @time = split /:/, $timeString;
|
my @time = split /:/, $timeString;
|
||||||
@ -1802,7 +1752,6 @@ sub THINKINGCLEANER_time2sec($) {
|
|||||||
return $time[0] * 3600 + $time[1] * 60;
|
return $time[0] * 3600 + $time[1] * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub THINKINGCLEANER_sec2time($) {
|
sub THINKINGCLEANER_sec2time($) {
|
||||||
my ($sec) = @_;
|
my ($sec) = @_;
|
||||||
|
|
||||||
@ -1818,6 +1767,7 @@ sub THINKINGCLEANER_sec2time($) {
|
|||||||
|
|
||||||
return "$hours:$minutes:$seconds";
|
return "$hours:$minutes:$seconds";
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
@ -1,41 +1,11 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# 97_msgConfig.pm
|
|
||||||
# Global configuration settings for FHEM msg command.
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
sub msgConfig_Set($@);
|
# initialize ##################################################################
|
||||||
sub msgConfig_Get($@);
|
|
||||||
sub msgConfig_Define($$);
|
|
||||||
sub msgConfig_Undefine($$);
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub msgConfig_Initialize($) {
|
sub msgConfig_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
@ -173,7 +143,7 @@ sub msgConfig_Initialize($) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
# regular Fn ##################################################################
|
||||||
sub msgConfig_Define($$) {
|
sub msgConfig_Define($$) {
|
||||||
|
|
||||||
my ( $hash, $def ) = @_;
|
my ( $hash, $def ) = @_;
|
||||||
@ -212,7 +182,6 @@ sub msgConfig_Define($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub msgConfig_Undefine($$) {
|
sub msgConfig_Undefine($$) {
|
||||||
|
|
||||||
my ( $hash, $name ) = @_;
|
my ( $hash, $name ) = @_;
|
||||||
@ -223,7 +192,6 @@ sub msgConfig_Undefine($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub msgConfig_Set($@) {
|
sub msgConfig_Set($@) {
|
||||||
my ( $hash, @a ) = @_;
|
my ( $hash, @a ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -275,7 +243,7 @@ sub msgConfig_Set($@) {
|
|||||||
$attr{$device}{userattr} .= " msgLocationName"
|
$attr{$device}{userattr} .= " msgLocationName"
|
||||||
if ( defined( $attr{$device}{userattr} )
|
if ( defined( $attr{$device}{userattr} )
|
||||||
&& $attr{$device}{userattr} !~
|
&& $attr{$device}{userattr} !~
|
||||||
/^msgLocationName$|^msgLocationName\s|\smsgLocationName\s|\smsgLocationName$/
|
m/^msgLocationName$|^msgLocationName\s|\smsgLocationName\s|\smsgLocationName$/
|
||||||
);
|
);
|
||||||
$attr{$device}{userattr} = "msgLocationName"
|
$attr{$device}{userattr} = "msgLocationName"
|
||||||
if ( !defined( $attr{$device}{userattr} ) );
|
if ( !defined( $attr{$device}{userattr} ) );
|
||||||
@ -399,9 +367,10 @@ sub msgConfig_Set($@) {
|
|||||||
return
|
return
|
||||||
"Unknown argument $what, choose one of cleanReadings addLocation createSwitcherDev:de,en createResidentsDev:de,en";
|
"Unknown argument $what, choose one of cleanReadings addLocation createSwitcherDev:de,en createResidentsDev:de,en";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
|
||||||
sub msgConfig_Get($@) {
|
sub msgConfig_Get($@) {
|
||||||
my ( $hash, @a ) = @_;
|
my ( $hash, @a ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -578,9 +547,11 @@ sub msgConfig_Get($@) {
|
|||||||
return
|
return
|
||||||
"Unknown argument $what, choose one of routeCmd:,audio,light,mail,push,screen,queue";
|
"Unknown argument $what, choose one of routeCmd:,audio,light,mail,push,screen,queue";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
########################################
|
# module Fn ####################################################################
|
||||||
sub MSG_FindAttrVal($$$$) {
|
sub MSG_FindAttrVal($$$$) {
|
||||||
my ( $d, $n, $msgType, $default ) = @_;
|
my ( $d, $n, $msgType, $default ) = @_;
|
||||||
$msgType = "" unless ($msgType);
|
$msgType = "" unless ($msgType);
|
||||||
@ -636,7 +607,6 @@ sub MSG_FindAttrVal($$$$) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
########################################
|
|
||||||
sub msgConfig_FindReadingsVal($$$$) {
|
sub msgConfig_FindReadingsVal($$$$) {
|
||||||
my ( $d, $n, $msgType, $default ) = @_;
|
my ( $d, $n, $msgType, $default ) = @_;
|
||||||
$msgType = ucfirst($msgType) if ($msgType);
|
$msgType = ucfirst($msgType) if ($msgType);
|
||||||
@ -664,7 +634,6 @@ sub msgConfig_FindReadingsVal($$$$) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
########################################
|
|
||||||
sub msgConfig_QueueAdd(@) {
|
sub msgConfig_QueueAdd(@) {
|
||||||
my (
|
my (
|
||||||
$msgA, $params, $datetime, $msgID,
|
$msgA, $params, $datetime, $msgID,
|
||||||
@ -703,7 +672,6 @@ sub msgConfig_QueueAdd(@) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
########################################
|
|
||||||
sub msgConfig_QueueReleaseMsgId($$) {
|
sub msgConfig_QueueReleaseMsgId($$) {
|
||||||
my ( $recipient, $msgID ) = @_;
|
my ( $recipient, $msgID ) = @_;
|
||||||
|
|
||||||
|
@ -1,59 +1,18 @@
|
|||||||
################################################################################
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
|
||||||
#
|
#
|
||||||
# 98_powerMap.pm
|
|
||||||
# Original version by igami
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
# TODO
|
# TODO
|
||||||
# - document how to include powerMap for other module maintainers
|
# - document how to include powerMap for other module maintainers
|
||||||
# (see 50_HP1000)
|
# (see 50_HP1000)
|
||||||
#
|
#
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
use Unit;
|
use Unit;
|
||||||
|
|
||||||
# forward declarations #########################################################
|
# module hashes ###############################################################
|
||||||
sub powerMap_Initialize($);
|
|
||||||
|
|
||||||
sub powerMap_Define($$);
|
|
||||||
sub powerMap_Undefine($$);
|
|
||||||
sub powerMap_Set($@);
|
|
||||||
sub powerMap_Get($@);
|
|
||||||
sub powerMap_Attr(@);
|
|
||||||
sub powerMap_Notify($$);
|
|
||||||
|
|
||||||
sub powerMap_AttrVal($$$$);
|
|
||||||
sub powerMap_load($$;$$);
|
|
||||||
sub powerMap_unload($$);
|
|
||||||
sub powerMap_findPowerMaps($;$);
|
|
||||||
sub powerMap_verifyEventChain($$$);
|
|
||||||
sub powerMap_power($$$;$);
|
|
||||||
sub powerMap_energy($$;$);
|
|
||||||
sub powerMap_update($;$);
|
|
||||||
|
|
||||||
# module hashes ################################################################
|
|
||||||
my %powerMap_tmpl = (
|
my %powerMap_tmpl = (
|
||||||
|
|
||||||
# Format example for devices w/ model support:
|
# Format example for devices w/ model support:
|
||||||
@ -540,7 +499,7 @@ my %powerMap_tmpl = (
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
# initialize ###################################################################
|
# initialize ##################################################################
|
||||||
sub powerMap_Initialize($) {
|
sub powerMap_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $TYPE = "powerMap";
|
my $TYPE = "powerMap";
|
||||||
@ -553,7 +512,7 @@ sub powerMap_Initialize($) {
|
|||||||
$hash->{NotifyFn} = $TYPE . "_Notify";
|
$hash->{NotifyFn} = $TYPE . "_Notify";
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$hash->{AttrList} =
|
||||||
"disable:1,0 "
|
"disable:1,0 disabledForIntervals do_not_notify:1,0 "
|
||||||
. $TYPE
|
. $TYPE
|
||||||
. "_gridV:230,110 "
|
. "_gridV:230,110 "
|
||||||
. $TYPE
|
. $TYPE
|
||||||
@ -568,7 +527,7 @@ sub powerMap_Initialize($) {
|
|||||||
addToAttrList( $TYPE . ":textField-long" );
|
addToAttrList( $TYPE . ":textField-long" );
|
||||||
}
|
}
|
||||||
|
|
||||||
# regular Fn ###################################################################
|
# regular Fn ##################################################################
|
||||||
sub powerMap_Define($$) {
|
sub powerMap_Define($$) {
|
||||||
my ( $hash, $def ) = @_;
|
my ( $hash, $def ) = @_;
|
||||||
my ( $name, $type, $rest ) = split( /[\s]+/, $def, 3 );
|
my ( $name, $type, $rest ) = split( /[\s]+/, $def, 3 );
|
||||||
@ -747,7 +706,7 @@ sub powerMap_Notify($$) {
|
|||||||
next unless ( defined($event) );
|
next unless ( defined($event) );
|
||||||
|
|
||||||
# initialize or terminate powerMap for each device
|
# initialize or terminate powerMap for each device
|
||||||
if ( $event =~ /^(INITIALIZED|SHUTDOWN)$/ ) {
|
if ( $event =~ /^(INITIALIZED|REREADCFG|SHUTDOWN)$/ ) {
|
||||||
foreach ( keys %{ powerMap_findPowerMaps( $name, ":PM_$1" ) } )
|
foreach ( keys %{ powerMap_findPowerMaps( $name, ":PM_$1" ) } )
|
||||||
{
|
{
|
||||||
next
|
next
|
||||||
@ -1337,6 +1296,8 @@ sub powerMap_verifyEventChain($$$) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub powerMap_power($$$;$);
|
||||||
|
|
||||||
sub powerMap_power($$$;$) {
|
sub powerMap_power($$$;$) {
|
||||||
my ( $name, $dev, $event, $loop ) = @_;
|
my ( $name, $dev, $event, $loop ) = @_;
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
@ -1579,7 +1540,7 @@ sub powerMap_update($;$) {
|
|||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
# commandref ###################################################################
|
# commandref ##################################################################
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
=item helper
|
=item helper
|
||||||
|
@ -1,34 +1,9 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
package main;
|
||||||
#
|
sub ONKYOdb_Initialize() { }
|
||||||
# ONKYOdb.pm
|
|
||||||
# ONKYO command database for ONKYO AVR module to split DB from code
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
sub ONKYOdb_Initialize() {
|
|
||||||
}
|
|
||||||
|
|
||||||
package ONKYOdb;
|
package ONKYOdb;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
@ -541,10 +541,10 @@ return;;\
|
|||||||
Log3 $NAME, 3,
|
Log3 $NAME, 3,
|
||||||
"RESIDENTStk $NAME: "
|
"RESIDENTStk $NAME: "
|
||||||
. "new notify macro device $macroRNameGotosleep created";
|
. "new notify macro device $macroRNameGotosleep created";
|
||||||
fhem
|
fhem "define $macroRNameGotosleep "
|
||||||
"define $macroRNameGotosleep notify $macroRNameGotosleep $templateGotosleep";
|
. "notify $macroRNameGotosleep $templateGotosleep";
|
||||||
fhem
|
fhem "attr $macroRNameGotosleep "
|
||||||
"attr $macroRNameGotosleep comment Auto-created by RESIDENTS Toolkit: FHEM commands to run when all residents are gettin' ready for bed";
|
. "comment Auto-created by RESIDENTS Toolkit: FHEM commands to run when all residents are gettin' ready for bed";
|
||||||
fhem "attr $macroRNameGotosleep room $room"
|
fhem "attr $macroRNameGotosleep room $room"
|
||||||
if ($room);
|
if ($room);
|
||||||
}
|
}
|
||||||
@ -2061,15 +2061,19 @@ sub RESIDENTStk_RG_Attr(@) {
|
|||||||
|
|
||||||
if ( $lang eq "DE" ) {
|
if ( $lang eq "DE" ) {
|
||||||
$attr{$name}{devStateIcon} =
|
$attr{$name}{devStateIcon} =
|
||||||
'.*zuhause:user_available:absent .*anwesend:user_available:absent .*abwesend:user_away:home .*verreist:user_ext_away:home .*bettfertig:scene_toilet:asleep .*schlaeft:scene_sleeping:awoken .*schläft:scene_sleeping:awoken .*aufgestanden:scene_sleeping_alternat:home .*:user_unknown:home';
|
'.*zuhause:user_available:absent '
|
||||||
|
. '.*anwesend:user_available:absent .*abwesend:user_away:home .*verreist:user_ext_away:home .*bettfertig:scene_toilet:asleep .*schlaeft:scene_sleeping:awoken .*schläft:scene_sleeping:awoken .*aufgestanden:scene_sleeping_alternat:home .*:user_unknown:home';
|
||||||
$attr{$name}{eventMap} =
|
$attr{$name}{eventMap} =
|
||||||
"home:zuhause absent:abwesend gone:verreist gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
|
"home:zuhause absent:abwesend gone:verreist "
|
||||||
|
. "gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
|
||||||
$attr{$name}{widgetOverride} =
|
$attr{$name}{widgetOverride} =
|
||||||
"state:zuhause,bettfertig,schläft,aufgestanden,abwesend,verreist";
|
"state:zuhause,bettfertig,schläft,"
|
||||||
|
. "aufgestanden,abwesend,verreist";
|
||||||
}
|
}
|
||||||
elsif ( $lang eq "EN" ) {
|
elsif ( $lang eq "EN" ) {
|
||||||
$attr{$name}{devStateIcon} =
|
$attr{$name}{devStateIcon} =
|
||||||
'.*home:user_available:absent .*absent:user_away:home .*gone:user_ext_away:home .*gotosleep:scene_toilet:asleep .*asleep:scene_sleeping:awoken .*awoken:scene_sleeping_alternat:home .*:user_unknown:home';
|
'.*home:user_available:absent .*absent:user_away:home '
|
||||||
|
. '.*gone:user_ext_away:home .*gotosleep:scene_toilet:asleep .*asleep:scene_sleeping:awoken .*awoken:scene_sleeping_alternat:home .*:user_unknown:home';
|
||||||
delete $attr{$name}{eventMap}
|
delete $attr{$name}{eventMap}
|
||||||
if ( defined( $attr{$name}{eventMap} ) );
|
if ( defined( $attr{$name}{eventMap} ) );
|
||||||
delete $attr{$name}{widgetOverride}
|
delete $attr{$name}{widgetOverride}
|
||||||
|
@ -1,38 +1,9 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
package main;
|
||||||
#
|
sub msgSchema_Initialize() { }
|
||||||
# msgSchema.pm
|
|
||||||
# Schema database for FHEM modules and their messaging options.
|
|
||||||
# These commands are being used as default setting for FHEM command 'msg'
|
|
||||||
# unless there is an explicit msgCmd* attribute.
|
|
||||||
#
|
|
||||||
# FHEM module authors may request to extend this file
|
|
||||||
#
|
|
||||||
# Copyright by Julian Pawlowski
|
|
||||||
# e-mail: julian.pawlowski at gmail.com
|
|
||||||
#
|
|
||||||
# This file is part of fhem.
|
|
||||||
#
|
|
||||||
# Fhem is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fhem is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
sub msgSchema_Initialize() {
|
|
||||||
}
|
|
||||||
|
|
||||||
package msgSchema;
|
package msgSchema;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user