2017-02-07 22:23:48 +00:00
###############################################################################
2019-06-20 18:35:49 +00:00
#
2021-12-31 18:30:09 +00:00
# Developed with VSCodium and richterger perl plugin.
2017-02-07 22:23:48 +00:00
#
2021-12-31 18:30:09 +00:00
# (c) 2017-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
2017-02-07 22:23:48 +00:00
# All rights reserved
#
2017-02-28 09:56:14 +00:00
# Special thanks goes to comitters:
2017-04-18 09:27:57 +00:00
# - Vitolinker / Commandref
2017-02-28 09:56:14 +00:00
#
#
2017-02-07 22:23:48 +00:00
# This script 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
# any later version.
#
# The GNU General Public License can be found at
# http://www.gnu.org/copyleft/gpl.html.
# A copy is found in the textfile GPL.txt and important notices to the license
# from the author is found in LICENSE.txt distributed with these scripts.
#
# This script 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.
#
#
2022-01-04 10:09:16 +00:00
# $Id: 82_LGTV_WebOS.pm 25389 2021-12-30 15:48:41Z CoolTux $
2017-02-07 22:23:48 +00:00
#
###############################################################################
#################################
######### Wichtige Hinweise und Links #################
2017-09-17 18:48:48 +00:00
#
## Das JSON Modul immer in einem eval aufrufen
# $data = eval{decode_json($data)};
#
# if($@){
# Log3($SELF, 2, "$TYPE ($SELF) - error while request: $@");
2019-06-20 18:35:49 +00:00
#
2017-09-17 18:48:48 +00:00
# readingsSingleUpdate($hash, "state", "error", 1);
#
# return;
# }
##
##
2017-02-07 22:23:48 +00:00
##
#
################################
package main ;
2019-01-18 09:22:45 +00:00
use strict ;
use warnings ;
2022-01-04 20:44:00 +00:00
use experimental qw( switch ) ;
2019-07-02 10:14:41 +00:00
use FHEM::Meta ;
2017-02-07 22:23:48 +00:00
2022-01-04 20:44:00 +00:00
my $ missingModul = "" ;
eval { require MIME::Base64 ; 1 } or $ missingModul . = "MIME::Base64 " ;
eval { require IO::Socket::INET ; 1 } or $ missingModul . = "IO::Socket::INET " ;
eval { use Digest::SHA qw /sha1_hex/; 1 } or $ missingModul . = "Digest::SHA " ;
eval { use Encode qw /encode_utf8 decode_utf8 / ; 1 }
2022-01-04 10:09:16 +00:00
or $ missingModul . = "Encode " ;
2022-01-04 20:44:00 +00:00
eval { require Blocking ; 1 } or $ missingModul . = "Blocking " ;
2019-01-18 09:22:45 +00:00
2019-07-02 10:14:41 +00:00
# try to use JSON::MaybeXS wrapper
# for chance of better performance + open code
eval {
require JSON::MaybeXS ;
import JSON:: MaybeXS qw( decode_json encode_json ) ;
1 ;
2022-01-04 10:09:16 +00:00
} or do {
2019-07-02 10:14:41 +00:00
# try to use JSON wrapper
# for chance of better performance
eval {
# JSON preference order
local $ ENV { PERL_JSON_BACKEND } =
'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP'
unless ( defined ( $ ENV { PERL_JSON_BACKEND } ) ) ;
require JSON ;
import JSON qw( decode_json encode_json ) ;
1 ;
2022-01-04 10:09:16 +00:00
} or do {
2019-07-02 10:14:41 +00:00
# In rare cases, Cpanel::JSON::XS may
# be installed but JSON|JSON::MaybeXS not ...
eval {
require Cpanel::JSON::XS ;
import Cpanel::JSON:: XS qw( decode_json encode_json ) ;
1 ;
2022-01-04 10:09:16 +00:00
} or do {
2019-07-02 10:14:41 +00:00
# In rare cases, JSON::XS may
# be installed but JSON not ...
eval {
require JSON::XS ;
import JSON:: XS qw( decode_json encode_json ) ;
1 ;
2022-01-04 10:09:16 +00:00
} or do {
2019-07-02 10:14:41 +00:00
# Fallback to built-in JSON which SHOULD
# be available since 5.014 ...
eval {
require JSON::PP ;
import JSON:: PP qw( decode_json encode_json ) ;
1 ;
2022-01-04 10:09:16 +00:00
} or do {
2019-07-02 10:14:41 +00:00
# Fallback to JSON::backportPP in really rare cases
require JSON::backportPP ;
import JSON:: backportPP qw( decode_json encode_json ) ;
1 ;
2022-01-04 10:09:16 +00:00
} ;
} ;
} ;
} ;
} ;
2017-02-07 22:23:48 +00:00
my % lgCommands = (
2019-06-20 18:35:49 +00:00
"getServiceList" = > [ "ssap://api/getServiceList" ] ,
"getChannelList" = > [ "ssap://tv/getChannelList" ] ,
"getVolume" = > [ "ssap://audio/getVolume" ] ,
"getAudioStatus" = > [ "ssap://audio/getStatus" ] ,
"getCurrentChannel" = > [ "ssap://tv/getCurrentChannel" ] ,
"getChannelProgramInfo" = > [ "ssap://tv/getChannelProgramInfo" ] ,
"getForegroundAppInfo" = >
[ "ssap://com.webos.applicationManager/getForegroundAppInfo" ] ,
"getAppList" = > [ "ssap://com.webos.applicationManager/listApps" ] ,
"getAppStatus" = > [ "ssap://com.webos.service.appstatus/getAppStatus" ] ,
"getExternalInputList" = > [ "ssap://tv/getExternalInputList" ] ,
"get3DStatus" = > [ "ssap://com.webos.service.tv.display/get3DStatus" ] ,
"powerOff" = > [ "ssap://system/turnOff" ] ,
"powerOn" = > [ "ssap://system/turnOn" ] ,
"3DOn" = > [ "ssap://com.webos.service.tv.display/set3DOn" ] ,
"3DOff" = > [ "ssap://com.webos.service.tv.display/set3DOff" ] ,
"volumeUp" = > [ "ssap://audio/volumeUp" ] ,
"volumeDown" = > [ "ssap://audio/volumeDown" ] ,
"channelDown" = > [ "ssap://tv/channelDown" ] ,
"channelUp" = > [ "ssap://tv/channelUp" ] ,
"play" = > [ "ssap://media.controls/play" ] ,
"stop" = > [ "ssap://media.controls/stop" ] ,
"pause" = > [ "ssap://media.controls/pause" ] ,
"rewind" = > [ "ssap://media.controls/rewind" ] ,
"fastForward" = > [ "ssap://media.controls/fastForward" ] ,
"closeViewer" = > [ "ssap://media.viewer/close" ] ,
"closeApp" = > [ "ssap://system.launcher/close" ] ,
"openApp" = > [ "ssap://system.launcher/open" ] ,
"closeWebApp" = > [ "ssap://webapp/closeWebApp" ] ,
"openChannel" = > [ "ssap://tv/openChannel" , "channelNumber" ] ,
"launchApp" = > [ "ssap://system.launcher/launch" , "id" ] ,
"screenMsg" = > [ "ssap://system.notifications/createToast" , "message" ] ,
"mute" = > [ "ssap://audio/setMute" , "mute" ] ,
"volume" = > [ "ssap://audio/setVolume" , "volume" ] ,
"switchInput" = > [ "ssap://tv/switchInput" , "input" ] ,
2017-02-09 21:02:58 +00:00
) ;
my % openApps = (
2019-06-20 18:35:49 +00:00
'Maxdome' = > 'maxdome' ,
'AmazonLovefilm' = > 'lovefilm.de' ,
'AmazonVideo' = > 'amazon' ,
'YouTube' = > 'youtube.leanback.v4' ,
'Netflix' = > 'netflix' ,
'TV' = > 'com.webos.app.livetv' ,
'GooglePlay' = > 'googleplaymovieswebos' ,
'Browser' = > 'com.webos.app.browser' ,
'Chili.tv' = > 'Chilieu' ,
'TVCast' = > 'de.2kit.castbrowsing' ,
'Smartshare' = > 'com.webos.app.smartshare' ,
'Scheduler' = > 'com.webos.app.scheduler' ,
'Miracast' = > 'com.webos.app.miracast' ,
'TVGuide' = > 'com.webos.app.tvguide' ,
'Timemachine' = > 'com.webos.app.timemachine' ,
'ARDMediathek' = > 'ard.mediathek' ,
'Arte' = > 'com.3827031.168353' ,
'WetterMeteo' = > 'meteonews' ,
'Notificationcenter' = > 'com.webos.app.notificationcenter' ,
'Plex' = > 'cdp-30' ,
'SkyOnline' = > 'de.sky.skyonline' ,
2020-05-16 12:31:05 +00:00
'Smart-IPTV' = > 'com.1827622.109556' ,
'Spotify' = > 'spotify-beehive' ,
2020-05-18 09:19:59 +00:00
'DuplexIPTV' = > 'com.duplexiptv.app' ,
2020-05-22 19:43:54 +00:00
'Disney+' = > 'com.disney.disneyplus-prod' ,
2021-12-31 18:30:09 +00:00
'Smart-IPTV' = > 'siptv' ,
'AppleTV' = > 'com.apple.appletv' ,
'Joyn' = > 'joyn' ,
'YouTube-Kids' = > 'youtube.leanback.kids.v4' ,
'DAZN' = > 'dazn' ,
'SkyQ' = > 'com.skygo.app.de.q' ,
'WaipuTv' = > 'tv.waipu.app.waipu-lg' ,
2017-02-09 21:02:58 +00:00
) ;
2019-01-13 07:56:53 +00:00
my % openAppsPackageName = reverse % openApps ;
2017-02-07 22:23:48 +00:00
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Initialize {
2017-02-07 22:23:48 +00:00
my ( $ hash ) = @ _ ;
2019-06-20 17:51:26 +00:00
2019-06-20 18:35:49 +00:00
# Provider
$ hash - > { ReadFn } = "LGTV_WebOS_Read" ;
$ hash - > { WriteFn } = "LGTV_WebOS_Write" ;
2017-02-07 22:23:48 +00:00
# Consumer
2019-06-20 18:35:49 +00:00
$ hash - > { SetFn } = "LGTV_WebOS_Set" ;
$ hash - > { DefFn } = "LGTV_WebOS_Define" ;
$ hash - > { UndefFn } = "LGTV_WebOS_Undef" ;
$ hash - > { AttrFn } = "LGTV_WebOS_Attr" ;
$ hash - > { AttrList } =
"disable:1 "
. "channelGuide:1 "
. "pingPresence:1 "
. "wakeOnLanMAC "
. "wakeOnLanBroadcast "
2019-07-02 10:14:41 +00:00
. "wakeupCmd "
2019-06-20 18:35:49 +00:00
. $ readingFnAttributes ;
2019-07-02 10:14:41 +00:00
return FHEM::Meta:: InitMod ( __FILE__ , $ hash ) ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Define {
2017-02-07 22:23:48 +00:00
my ( $ hash , $ def ) = @ _ ;
2022-01-04 20:44:00 +00:00
my $ version ;
2017-02-07 22:23:48 +00:00
2019-07-02 10:14:41 +00:00
return $@ unless ( FHEM::Meta:: SetInternals ( $ hash ) ) ;
2022-01-04 20:44:00 +00:00
$ version = FHEM::Meta:: Get ( $ hash , 'version' ) ;
our $ VERSION = $ version ;
my @ a = split ( "[ \t][ \t]*" , $ def ) ;
2019-07-02 10:14:41 +00:00
2019-06-20 18:35:49 +00:00
return "too few parameters: define <name> LGTV_WebOS <HOST>" if ( @ a != 3 ) ;
return
"Cannot define LGTV_WebOS device. Perl modul ${missingModul} is missing."
if ( $ missingModul ) ;
2017-02-07 22:23:48 +00:00
2019-06-20 18:35:49 +00:00
my $ name = $ a [ 0 ] ;
my $ host = $ a [ 2 ] ;
2017-02-07 22:23:48 +00:00
2019-07-02 10:14:41 +00:00
$ hash - > { HOST } = $ host ;
$ hash - > { VERSION } = version - > parse ( $ VERSION ) - > normal ;
$ hash - > { PARTIAL } = '' ;
2019-06-20 18:35:49 +00:00
$ hash - > { helper } { device } { channelguide } { counter } = 0 ;
$ hash - > { helper } { device } { registered } = 0 ;
$ hash - > { helper } { device } { runsetcmd } = 0 ;
2017-02-07 22:23:48 +00:00
2019-06-20 18:35:49 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - defined with host $host" ;
2017-02-07 22:23:48 +00:00
2019-06-20 18:35:49 +00:00
$ attr { $ name } { devStateIcon } = 'on:10px-kreis-gruen:off off:10px-kreis-rot:on'
if ( ! defined ( $ attr { $ name } { devStateIcon } ) ) ;
$ attr { $ name } { room } = 'LGTV' if ( ! defined ( $ attr { $ name } { room } ) ) ;
CommandDeleteReading ( undef , $ name . ' presence' )
if ( AttrVal ( $ name , 'pingPresence' , 0 ) == 0 ) ;
2017-02-07 22:23:48 +00:00
2019-06-20 18:35:49 +00:00
$ modules { LGTV_WebOS } { defptr } { $ hash - > { HOST } } = $ hash ;
2017-02-07 22:23:48 +00:00
2019-06-20 18:35:49 +00:00
if ( $ init_done ) {
2017-04-18 16:58:13 +00:00
LGTV_WebOS_TimerStatusRequest ( $ hash ) ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
else {
InternalTimer ( gettimeofday ( ) + 15 ,
"LGTV_WebOS_TimerStatusRequest" , $ hash ) ;
}
2022-01-04 10:09:16 +00:00
$ hash - > { helper } - > { lastResponse } =
int ( gettimeofday ( ) ) ; # Check Socket KeepAlive
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Undef {
2017-02-07 22:23:48 +00:00
my ( $ hash , $ arg ) = @ _ ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
my $ host = $ hash - > { HOST } ;
my $ name = $ hash - > { NAME } ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
RemoveInternalTimer ( $ hash ) ;
2019-06-20 18:35:49 +00:00
delete $ modules { LGTV_WebOS } { defptr } { $ hash - > { HOST } } ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - device $name deleted" ;
2019-06-20 18:35:49 +00:00
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Attr {
2017-02-07 22:23:48 +00:00
my ( $ cmd , $ name , $ attrName , $ attrVal ) = @ _ ;
my $ hash = $ defs { $ name } ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
my $ orig = $ attrVal ;
2019-06-20 18:35:49 +00:00
if ( $ attrName eq "disable" ) {
2022-01-04 10:09:16 +00:00
if ( $ cmd eq "set" && $ attrVal eq "1" ) {
2018-01-11 10:25:50 +00:00
RemoveInternalTimer ( $ hash ) ;
2019-06-20 18:35:49 +00:00
readingsSingleUpdate ( $ hash , "state" , "disabled" , 1 ) ;
2017-02-14 06:34:29 +00:00
$ hash - > { PARTIAL } = '' ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - disabled" ;
}
2019-06-20 18:35:49 +00:00
elsif ( $ cmd eq "del" ) {
readingsSingleUpdate ( $ hash , "state" , "active" , 1 ) ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - enabled" ;
2018-01-11 10:25:50 +00:00
LGTV_WebOS_TimerStatusRequest ( $ hash ) ;
2017-02-07 22:23:48 +00:00
}
}
2019-06-20 18:35:49 +00:00
if ( $ attrName eq "disabledForIntervals" ) {
if ( $ cmd eq "set" ) {
2017-02-07 22:23:48 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - enable disabledForIntervals" ;
2019-06-20 18:35:49 +00:00
readingsSingleUpdate ( $ hash , "state" , "Unknown" , 1 ) ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
elsif ( $ cmd eq "del" ) {
readingsSingleUpdate ( $ hash , "state" , "active" , 1 ) ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - delete disabledForIntervals" ;
}
}
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_TimerStatusRequest {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
RemoveInternalTimer ( $ hash , 'LGTV_WebOS_TimerStatusRequest' ) ;
2017-02-14 15:27:55 +00:00
readingsBeginUpdate ( $ hash ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 10:09:16 +00:00
if ( ! IsDisabled ( $ name )
&& $ hash - > { CD }
&& $ hash - > { helper } { device } { registered } == 1 )
2019-06-20 18:35:49 +00:00
{
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - run get functions" ;
2017-02-14 11:28:18 +00:00
2019-06-20 18:35:49 +00:00
LGTV_WebOS_Presence ( $ hash )
if ( AttrVal ( $ name , 'pingPresence' , 0 ) == 1 ) ;
2022-01-04 10:09:16 +00:00
if ( $ hash - > { helper } { device } { channelguide } { counter } > 2
&& AttrVal ( $ name , 'channelGuide' , 0 ) == 1
&& ReadingsVal ( $ name , 'launchApp' , 'TV' ) eq 'TV' )
2019-06-20 18:35:49 +00:00
{
2017-02-15 11:57:15 +00:00
LGTV_WebOS_GetChannelProgramInfo ( $ hash ) ;
2019-06-20 18:35:49 +00:00
$ hash - > { helper } { device } { channelguide } { counter } = 0 ;
}
else {
2019-01-18 09:22:45 +00:00
2017-02-15 07:52:06 +00:00
LGTV_WebOS_GetAudioStatus ( $ hash ) ;
2019-06-20 18:35:49 +00:00
InternalTimer ( gettimeofday ( ) + 2 ,
'LGTV_WebOS_GetCurrentChannel' , $ hash )
if ( ReadingsVal ( $ name , 'launchApp' , 'TV' ) eq 'TV' ) ;
InternalTimer ( gettimeofday ( ) + 4 ,
'LGTV_WebOS_GetForgroundAppInfo' , $ hash ) ;
InternalTimer ( gettimeofday ( ) + 6 , 'LGTV_WebOS_Get3DStatus' ,
$ hash ) ;
InternalTimer ( gettimeofday ( ) + 8 ,
'LGTV_WebOS_GetExternalInputList' , $ hash ) ;
2017-02-15 07:52:06 +00:00
}
2019-06-20 18:35:49 +00:00
}
elsif ( IsDisabled ( $ name ) ) {
2017-04-20 06:38:59 +00:00
LGTV_WebOS_Close ( $ hash ) ;
2019-06-20 18:35:49 +00:00
LGTV_WebOS_Presence ( $ hash )
if ( AttrVal ( $ name , 'pingPresence' , 0 ) == 1 ) ;
$ hash - > { helper } { device } { runsetcmd } = 0 ;
readingsBulkUpdateIfChanged ( $ hash , 'state' , 'disabled' ) ;
2019-01-18 09:22:45 +00:00
}
2019-06-20 18:35:49 +00:00
else {
LGTV_WebOS_Presence ( $ hash )
if ( AttrVal ( $ name , 'pingPresence' , 0 ) == 1 ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channel' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelName' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelMedia' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelCurrentTitle' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelCurrentStartTime' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelCurrentEndTime' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelNextTitle' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelNextStartTime' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelNextEndTime' , '-' ) ;
$ hash - > { helper } { device } { runsetcmd } = 0 ;
}
readingsEndUpdate ( $ hash , 1 ) ;
2022-01-04 10:09:16 +00:00
LGTV_WebOS_Open ( $ hash ) if ( ! IsDisabled ( $ name ) && ! $ hash - > { CD } ) ;
2019-06-20 18:35:49 +00:00
$ hash - > { helper } { device } { channelguide } { counter } =
$ hash - > { helper } { device } { channelguide } { counter } + 1 ;
InternalTimer ( gettimeofday ( ) + 10 , "LGTV_WebOS_TimerStatusRequest" ,
$ hash ) ;
2021-12-31 18:30:09 +00:00
2022-01-04 10:09:16 +00:00
LGTV_WebOS_SocketKeepAlive ( $ hash ) ; # Check Socket KeepAlive
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Set {
2019-06-20 18:35:49 +00:00
my ( $ hash , $ name , $ cmd , @ args ) = @ _ ;
my ( $ arg , @ params ) = @ args ;
2017-02-07 22:23:48 +00:00
my $ uri ;
my % payload ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
given ( $ cmd ) {
when ( 'connect' ) {
return "usage: connect" if ( @ args != 0 ) ;
2019-01-18 07:50:58 +00:00
2022-01-04 21:01:26 +00:00
LGTV_WebOS_Open ( $ hash ) ;
2017-02-07 22:23:48 +00:00
2022-01-04 21:01:26 +00:00
return ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'clearInputList' ) {
return "usage: clearInputList" if ( @ args != 0 ) ;
2017-02-14 15:27:55 +00:00
2022-01-04 21:01:26 +00:00
delete $ hash - > { helper } { device } { inputs } ;
delete $ hash - > { helper } { device } { inputapps } ;
2017-02-14 15:27:55 +00:00
2022-01-04 21:01:26 +00:00
return ;
2017-02-07 22:23:48 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'pairing' ) {
return "usage: pairing" if ( @ args != 0 ) ;
2017-02-07 22:23:48 +00:00
2022-01-04 21:01:26 +00:00
LGTV_WebOS_Pairing ( $ hash ) ;
2017-02-07 22:23:48 +00:00
2022-01-04 21:01:26 +00:00
return ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'screenMsg' ) {
return "usage: screenMsg <message>" if ( @ args < 1 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
my $ msg = join ( " " , @ args ) ;
$ payload { $ lgCommands { $ cmd } - > [ 1 ] } = decode_utf8 ( $ msg ) ;
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'off' ) {
return "usage: on/off" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
$ uri = $ lgCommands { powerOff } ;
}
2022-01-04 21:01:26 +00:00
when ( 'on' ) {
2019-06-20 18:35:49 +00:00
if ( AttrVal ( $ name , 'wakeOnLanMAC' , 'none' ) ne 'none' ) {
LGTV_WebOS_WakeUp_Udp (
$ hash ,
AttrVal ( $ name , 'wakeOnLanMAC' , 0 ) ,
AttrVal ( $ name , 'wakeOnLanBroadcast' , '255.255.255.255' )
) ;
2017-09-18 10:27:35 +00:00
return ;
2019-07-02 10:14:41 +00:00
}
elsif ( AttrVal ( $ name , 'wakeupCmd' , 'none' ) ne 'none' ) {
my $ wakeupCmd = AttrVal ( $ name , 'wakeupCmd' , 'none' ) ;
2022-01-04 20:44:00 +00:00
if ( $ wakeupCmd =~ s/^[ \t]*\{|\}[ \t]*$//xg ) {
2019-07-02 10:14:41 +00:00
Log3 $ name , 4 ,
"LGTV_WebOS executing wake-up command (Perl): $wakeupCmd" ;
2022-01-04 20:44:00 +00:00
eval { $ wakeupCmd } or do {
Log3 $ name , 2 ,
"LGTV_WebOS executing wake-up command (Perl): $wakeupCmd failed" ;
return ;
} ;
2019-07-02 10:14:41 +00:00
return ;
}
else {
Log3 $ name , 4 ,
"LGTV_WebOS executing wake-up command (fhem): $wakeupCmd" ;
fhem $ wakeupCmd ;
return ;
}
}
else {
2019-06-20 18:35:49 +00:00
$ uri = $ lgCommands { powerOn } ;
2019-01-18 09:22:45 +00:00
}
}
2022-01-04 21:01:26 +00:00
when ( '3D' ) {
return "usage: 3D on/off" if ( @ args != 1 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
if ( $ args [ 0 ] eq 'off' ) {
$ uri = $ lgCommands { '3DOff' } ;
}
elsif ( $ args [ 0 ] eq 'on' ) {
$ uri = $ lgCommands { '3DOn' } ;
}
2019-06-20 18:35:49 +00:00
}
2022-01-04 21:01:26 +00:00
when ( 'mute' ) {
return "usage: mute" if ( @ args != 1 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
if ( $ args [ 0 ] eq 'off' ) {
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { volumeDown } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
elsif ( $ args [ 0 ] eq 'on' ) {
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ payload { $ lgCommands { $ cmd } - > [ 1 ] } = 'true' ;
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
}
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
}
2022-01-04 21:01:26 +00:00
when ( 'volume' ) {
return "usage: volume" if ( @ args != 1 ) ;
2017-02-07 22:23:48 +00:00
2022-01-04 21:01:26 +00:00
$ payload { $ lgCommands { $ cmd } - > [ 1 ] } = int ( join ( " " , @ args ) ) ;
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'launchApp' ) {
return "usage: launchApp" if ( @ args != 1 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ payload { $ lgCommands { $ cmd } - > [ 1 ] } =
$ openApps { join ( " " , @ args ) } ;
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'input' ) {
return "usage: input" if ( @ args != 1 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
my $ inputLabel = join ( " " , @ args ) ;
$ payload { $ lgCommands { launchApp } - > [ 1 ] } =
$ hash - > { helper } { device } { inputs } { $ inputLabel } ;
$ uri = $ lgCommands { launchApp } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'volumeUp' ) {
return "usage: volumeUp" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'volumeDown' ) {
return "usage: volumeDown" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'channelDown' ) {
return "usage: channelDown" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'channelUp' ) {
return "usage: channelUp" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'channel' ) {
return "usage: channel" if ( @ args != 1 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ payload { $ lgCommands { openChannel } - > [ 1 ] } = join ( " " , @ args ) ;
$ uri = $ lgCommands { openChannel } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'getServiceList' ) {
return "usage: getServiceList" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'getChannelList' ) {
return "usage: getChannelList" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'getAppList' ) {
return "usage: getAppList" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'getExternalInputList' ) {
return "usage: getExternalInputList" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'play' ) {
return "usage: play" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'stop' ) {
return "usage: stop" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'fastForward' ) {
return "usage: fastForward" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'rewind' ) {
return "usage: rewind" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
when ( 'pause' ) {
return "usage: pause" if ( @ args != 0 ) ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
$ uri = $ lgCommands { $ cmd } - > [ 0 ] ;
2019-06-20 18:35:49 +00:00
2022-01-04 21:01:26 +00:00
}
default {
my $ list = "" ;
$ list . =
2019-06-20 18:35:49 +00:00
'connect:noArg pairing:noArg screenMsg mute:on,off volume:slider,0,1,100 volumeUp:noArg volumeDown:noArg channelDown:noArg channelUp:noArg getServiceList:noArg on:noArg off:noArg' ;
2022-01-04 21:01:26 +00:00
$ list . =
2019-06-20 18:35:49 +00:00
' 3D:on,off stop:noArg play:noArg pause:noArg rewind:noArg fastForward:noArg clearInputList:noArg channel' ;
2022-01-04 21:01:26 +00:00
$ list . =
' launchApp:' . join ( ',' , = > map qq{ $_ } = > keys % openApps ) ;
$ list . = ' input:'
. join ( ',' ,
= > map qq{ $_ } = > keys % { $ hash - > { helper } { device } { inputs } } )
if ( defined ( $ hash - > { helper } { device } { inputs } )
&& ref ( $ hash - > { helper } { device } { inputs } ) eq "HASH" ) ;
return "Unknown argument $cmd, choose one of $list" ;
}
2017-02-07 22:23:48 +00:00
}
2018-07-30 18:16:21 +00:00
2019-06-20 18:35:49 +00:00
$ hash - > { helper } { device } { runsetcmd } = $ hash - > { helper } { device } { runsetcmd } + 1 ;
2022-01-04 10:09:16 +00:00
return LGTV_WebOS_CreateSendCommand ( $ hash , $ uri , \ % payload ) ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Open {
2017-02-07 22:23:48 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
my $ host = $ hash - > { HOST } ;
my $ port = 3000 ;
2017-02-09 21:02:58 +00:00
my $ timeout = 0.1 ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - Baue Socket Verbindung auf" ;
2019-01-18 09:22:45 +00:00
2022-01-04 20:44:00 +00:00
my $ socket = IO::Socket::INET - > new (
2022-01-04 10:09:16 +00:00
PeerHost = > $ host ,
PeerPort = > $ port ,
Proto = > 'tcp' ,
KeepAlive = > 1 ,
Timeout = > $ timeout
2019-06-20 18:35:49 +00:00
)
or return Log3 $ name , 4 ,
"LGTV_WebOS ($name) Couldn't connect to $host:$port" ; # open Socket
$ hash - > { FD } = $ socket - > fileno ( ) ;
$ hash - > { CD } = $ socket ; # sysread / close won't work on fileno
2017-02-07 22:23:48 +00:00
$ selectlist { $ name } = $ hash ;
2019-06-20 18:35:49 +00:00
2022-01-04 10:09:16 +00:00
$ hash - > { helper } - > { lastResponse } =
int ( gettimeofday ( ) ) ; # Check Socket KeepAlive
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - Socket Connected" ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
LGTV_WebOS_Handshake ( $ hash ) ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - start Handshake" ;
2019-06-20 18:35:49 +00:00
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Close {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
return if ( ! $ hash - > { CD } ) ;
2022-01-04 10:09:16 +00:00
delete ( $ hash - > { PARTIAL } ) ;
2019-06-20 18:35:49 +00:00
close ( $ hash - > { CD } ) if ( $ hash - > { CD } ) ;
delete ( $ hash - > { CD } ) ;
2022-01-04 10:09:16 +00:00
2019-06-20 18:35:49 +00:00
delete ( $ selectlist { $ name } ) ;
2022-01-04 10:09:16 +00:00
delete ( $ hash - > { FD } ) ;
2019-06-20 18:35:49 +00:00
readingsSingleUpdate ( $ hash , 'state' , 'off' , 1 ) ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - Socket Disconnected" ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Write {
2019-01-18 09:22:45 +00:00
2019-06-20 18:35:49 +00:00
my ( $ hash , $ string ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - WriteFn called" ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
return Log3 $ name , 4 , "LGTV_WebOS ($name) - socket not connected"
2019-06-20 18:35:49 +00:00
unless ( $ hash - > { CD } ) ;
2017-02-07 22:23:48 +00:00
2017-02-11 12:12:20 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - $string" ;
2019-06-20 18:35:49 +00:00
syswrite ( $ hash - > { CD } , $ string ) ;
2022-01-04 10:09:16 +00:00
return ;
}
sub LGTV_WebOS_SocketKeepAlive {
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
if ( int ( gettimeofday ( ) ) - int ( $ hash - > { helper } - > { lastResponse } ) > 2 ) {
LGTV_WebOS_SocketClosePresenceAbsent ( $ hash , 'absent' ) ;
Log3 $ name , 3 ,
"LGTV_WebOS ($name) - KeepAlive It looks like there no Data more response" ;
}
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Read {
2017-02-07 22:23:48 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
my $ len ;
my $ buf ;
2019-06-20 18:35:49 +00:00
2017-09-17 18:48:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - ReadFn started" ;
2017-02-07 22:23:48 +00:00
2022-01-04 10:09:16 +00:00
$ hash - > { helper } - > { lastResponse } =
int ( gettimeofday ( ) ) ; # Check Socket KeepAlive
2019-06-20 18:35:49 +00:00
$ len = sysread ( $ hash - > { CD } , $ buf , 10240 ) ;
2022-01-04 10:09:16 +00:00
if ( ! defined ( $ len ) || ! $ len ) {
2019-01-18 09:22:45 +00:00
2017-04-23 10:46:46 +00:00
LGTV_WebOS_Close ( $ hash ) ;
2017-04-20 06:38:59 +00:00
2017-02-07 22:23:48 +00:00
return ;
}
2019-06-20 18:35:49 +00:00
unless ( defined $ buf ) {
2017-09-17 18:48:48 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - no data received" ;
2019-06-20 18:35:49 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
if ( $ buf =~ /(\{"type":".+}}$)/x ) {
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
$ buf =~ /(\{"type":".+}}$)/x ;
2017-02-14 06:34:29 +00:00
$ buf = $ 1 ;
2019-06-20 18:35:49 +00:00
Log3 $ name , 4 ,
"LGTV_WebOS ($name) - received correct JSON string, start response processing: $buf" ;
LGTV_WebOS_ResponseProcessing ( $ hash , $ buf ) ;
}
2022-01-04 20:44:00 +00:00
elsif ( $ buf =~ /HTTP\/1.1 101 Switching Protocols/x ) {
2019-06-20 18:35:49 +00:00
Log3 $ name , 4 ,
"LGTV_WebOS ($name) - received HTTP data string, start response processing: $buf" ;
LGTV_WebOS_ResponseProcessing ( $ hash , $ buf ) ;
}
else {
Log3 $ name , 4 ,
"LGTV_WebOS ($name) - coruppted data found, run LGTV_WebOS_ProcessRead: $buf" ;
LGTV_WebOS_ProcessRead ( $ hash , $ buf ) ;
2017-02-15 23:35:35 +00:00
}
2021-12-31 18:30:09 +00:00
return ;
2017-02-11 00:30:12 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_ProcessRead {
2019-06-20 18:35:49 +00:00
my ( $ hash , $ data ) = @ _ ;
2017-02-11 00:30:12 +00:00
my $ name = $ hash - > { NAME } ;
2019-06-20 18:35:49 +00:00
2017-02-11 00:30:12 +00:00
my $ buffer = '' ;
2019-06-20 18:35:49 +00:00
2017-02-11 00:30:12 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - process read" ;
2022-01-04 10:09:16 +00:00
if ( defined ( $ hash - > { PARTIAL } ) && $ hash - > { PARTIAL } ) {
2019-06-20 18:35:49 +00:00
2017-02-11 00:30:12 +00:00
Log3 $ name , 5 , "LGTV_WebOS ($name) - PARTIAL: " . $ hash - > { PARTIAL } ;
$ buffer = $ hash - > { PARTIAL } ;
2019-06-20 18:35:49 +00:00
}
else {
2017-02-11 00:30:12 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - No PARTIAL buffer" ;
}
2017-02-23 11:53:19 +00:00
2017-02-11 00:30:12 +00:00
Log3 $ name , 5 , "LGTV_WebOS ($name) - Incoming data: " . $ data ;
2017-02-23 11:53:19 +00:00
2019-06-20 18:35:49 +00:00
$ buffer = $ buffer . $ data ;
Log3 $ name , 5 ,
"LGTV_WebOS ($name) - Current processing buffer (PARTIAL + incoming data): "
. $ buffer ;
2017-02-09 21:02:58 +00:00
2019-06-20 18:35:49 +00:00
my ( $ json , $ tail ) = LGTV_WebOS_ParseMsg ( $ hash , $ buffer ) ;
2017-02-23 11:53:19 +00:00
2019-06-20 18:35:49 +00:00
while ( $ json ) {
2017-02-11 17:40:50 +00:00
2017-02-11 00:30:12 +00:00
$ hash - > { LAST_RECV } = time ( ) ;
2017-02-23 11:53:19 +00:00
2019-06-20 18:35:49 +00:00
Log3 $ name , 5 ,
"LGTV_WebOS ($name) - Decoding JSON message. Length: "
. length ( $ json )
. " Content: "
. $ json ;
Log3 $ name , 5 ,
"LGTV_WebOS ($name) - Vor Sub: Laenge JSON: "
. length ( $ json )
. " Content: "
. $ json
. " Tail: "
. $ tail ;
LGTV_WebOS_ResponseProcessing ( $ hash , $ json )
2022-01-04 20:44:00 +00:00
if ( defined ( $ tail ) && ( $ tail ) ) ;
2019-06-20 18:35:49 +00:00
( $ json , $ tail ) = LGTV_WebOS_ParseMsg ( $ hash , $ tail ) ;
Log3 $ name , 5 ,
"LGTV_WebOS ($name) - Nach Sub: Laenge JSON: "
. length ( $ json )
. " Content: "
. $ json
. " Tail: "
. $ tail ;
}
2019-06-20 17:51:26 +00:00
2017-02-17 07:38:29 +00:00
$ tail = ''
2019-06-20 18:35:49 +00:00
if ( length ( $ tail ) > 30000 ) ;
2017-02-11 00:30:12 +00:00
$ hash - > { PARTIAL } = $ tail ;
2017-02-16 22:45:40 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - PARTIAL lenght: " . length ( $ tail ) ;
2019-06-20 18:35:49 +00:00
2017-02-11 00:30:12 +00:00
Log3 $ name , 5 , "LGTV_WebOS ($name) - Tail: " . $ tail ;
Log3 $ name , 5 , "LGTV_WebOS ($name) - PARTIAL: " . $ hash - > { PARTIAL } ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Handshake {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
my $ host = $ hash - > { HOST } ;
my $ wsKey = encode_base64 ( gettimeofday ( ) ) ;
my $ wsHandshakeCmd = "" ;
$ wsHandshakeCmd . = "GET / HTTP/1.1\r\n" ;
$ wsHandshakeCmd . = "Host: $host\r\n" ;
$ wsHandshakeCmd . = "User-Agent: FHEM\r\n" ;
$ wsHandshakeCmd . = "Upgrade: websocket\r\n" ;
$ wsHandshakeCmd . = "Connection: Upgrade\r\n" ;
$ wsHandshakeCmd . = "Sec-WebSocket-Version: 13\r\n" ;
$ wsHandshakeCmd . = "Sec-WebSocket-Key: " . $ wsKey . "\r\n" ;
LGTV_WebOS_Write ( $ hash , $ wsHandshakeCmd ) ;
$ hash - > { helper } { wsKey } = $ wsKey ;
2017-02-11 12:12:20 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - send Handshake to WriteFn" ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
LGTV_WebOS_TimerStatusRequest ( $ hash ) ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - start timer status request" ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
LGTV_WebOS_Pairing ( $ hash ) ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - start pairing routine" ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_ResponseProcessing {
2019-06-20 18:35:49 +00:00
my ( $ hash , $ response ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2017-02-07 22:23:48 +00:00
########################
### Response has HTML Header
2022-01-04 20:44:00 +00:00
if ( $ response =~ /HTTP\/1.1 101 Switching Protocols/x ) {
2019-06-20 18:35:49 +00:00
my $ data = $ response ;
my $ header = LGTV_WebOS_Header2Hash ( $ data ) ;
2017-02-07 22:23:48 +00:00
################################
### Handshake for first Connect
2019-06-20 18:35:49 +00:00
if ( defined ( $ header - > { 'Sec-WebSocket-Accept' } ) ) {
my $ keyAccept = $ header - > { 'Sec-WebSocket-Accept' } ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 5 , "LGTV_WebOS ($name) - keyAccept: $keyAccept" ;
2019-06-20 18:35:49 +00:00
my $ wsKey = $ hash - > { helper } { wsKey } ;
my $ expectedResponse = trim (
encode_base64 (
pack (
'H*' ,
sha1_hex (
trim ( $ wsKey )
. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
)
)
)
) ;
if ( $ keyAccept eq $ expectedResponse ) {
Log3 $ name , 3 ,
"LGTV_WebOS ($name) - Sucessfull WS connection to $hash->{HOST}" ;
readingsSingleUpdate ( $ hash , 'state' , 'on' , 1 ) ;
}
else {
2017-02-07 22:23:48 +00:00
LGTV_WebOS_Close ( $ hash ) ;
2019-06-20 18:35:49 +00:00
Log3 $ name , 3 ,
"LGTV_WebOS ($name) - ERROR: Unsucessfull WS connection to $hash->{HOST}" ;
2017-02-07 22:23:48 +00:00
}
}
2019-06-20 18:35:49 +00:00
2022-01-04 10:09:16 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
elsif ( $ response =~ m/^{"type":".+}}$/x ) {
2019-06-20 18:35:49 +00:00
2017-02-16 13:35:19 +00:00
return Log3 $ name , 4 , "LGTV_WebOS ($name) - garbage after JSON object"
2022-01-04 20:44:00 +00:00
if ( $ response =~ m/^{"type":".+}}.+{"type":".+/x ) ;
2019-06-20 18:35:49 +00:00
Log3 $ name , 4 ,
"LGTV_WebOS ($name) - JSON detected, run LGTV_WebOS_WriteReadings" ;
my $ json = $ response ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - Corrected JSON String: $json"
if ( $ json ) ;
2022-01-04 20:44:00 +00:00
if ( ! defined ( $ json ) || ! ( $ json ) ) {
2019-06-20 18:35:49 +00:00
2017-02-11 12:12:20 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - Corrected JSON String empty" ;
2017-02-11 00:30:12 +00:00
return ;
}
2019-06-20 18:35:49 +00:00
my $ decode_json = eval { decode_json ( encode_utf8 ( $ json ) ) } ;
if ( $@ ) {
2017-09-17 18:48:48 +00:00
Log3 $ name , 3 , "LGTV_WebOS ($name) - JSON error while request: $@" ;
return ;
}
2017-02-14 06:34:29 +00:00
2019-06-20 18:35:49 +00:00
LGTV_WebOS_WriteReadings ( $ hash , $ decode_json ) ;
2022-01-04 10:09:16 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - no Match found" ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_WriteReadings {
2019-06-20 18:35:49 +00:00
my ( $ hash , $ decode_json ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2017-02-07 22:23:48 +00:00
my $ response ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - Beginn Readings writing" ;
readingsBeginUpdate ( $ hash ) ;
2019-06-20 18:35:49 +00:00
if ( ref ( $ decode_json - > { payload } { services } ) eq "ARRAY"
2022-01-04 10:09:16 +00:00
&& scalar ( @ { $ decode_json - > { payload } { services } } ) > 0 )
2019-06-20 18:35:49 +00:00
{
2022-01-04 10:09:16 +00:00
for my $ services ( @ { $ decode_json - > { payload } { services } } ) {
2019-06-20 18:35:49 +00:00
readingsBulkUpdateIfChanged (
$ hash ,
'service_' . $ services - > { name } ,
'v.' . $ services - > { version }
) ;
2017-02-07 22:23:48 +00:00
}
}
2019-06-20 18:35:49 +00:00
elsif ( ref ( $ decode_json - > { payload } { devices } ) eq "ARRAY"
2022-01-04 10:09:16 +00:00
&& scalar ( @ { $ decode_json - > { payload } { devices } } ) > 0 )
2019-06-20 18:35:49 +00:00
{
2022-01-04 10:09:16 +00:00
for my $ devices ( @ { $ decode_json - > { payload } { devices } } ) {
2019-06-20 18:35:49 +00:00
if (
2022-01-04 20:44:00 +00:00
! defined (
$ hash - > { helper } { device } { inputs } { $ devices - > { label } }
)
2022-01-04 10:09:16 +00:00
|| ! defined (
2019-06-20 18:35:49 +00:00
$ hash - > { helper } { device } { inputapps } { $ devices - > { appId } }
)
)
{
2022-01-04 20:44:00 +00:00
$ hash - > { helper } { device } { inputs }
{ makeDeviceName ( $ devices - > { label } ) } = $ devices - > { appId } ;
2019-06-20 18:35:49 +00:00
$ hash - > { helper } { device } { inputapps } { $ devices - > { appId } } =
2022-01-04 20:44:00 +00:00
makeDeviceName ( $ devices - > { label } ) ;
2017-02-14 22:39:23 +00:00
}
2019-06-20 18:35:49 +00:00
readingsBulkUpdateIfChanged (
$ hash ,
2022-01-04 20:44:00 +00:00
'extInput_' . makeDeviceName ( $ devices - > { label } ) ,
2019-06-20 18:35:49 +00:00
'connect_' . $ devices - > { connected }
) ;
2017-02-09 21:02:58 +00:00
}
}
2019-06-20 18:35:49 +00:00
elsif ( ref ( $ decode_json - > { payload } { programList } ) eq "ARRAY"
2022-01-04 10:09:16 +00:00
&& scalar ( @ { $ decode_json - > { payload } { programList } } ) > 0 )
2019-06-20 18:35:49 +00:00
{
2022-01-04 20:44:00 +00:00
require Date::Parse ;
2017-02-14 15:27:55 +00:00
my $ count = 0 ;
2022-01-04 10:09:16 +00:00
for my $ programList ( @ { $ decode_json - > { payload } { programList } } ) {
2019-06-20 18:35:49 +00:00
if (
str2time (
LGTV_WebOS_FormartStartEndTime (
$ programList - > { localEndTime }
)
) > time ( )
)
{
if ( $ count < 1 ) {
readingsBulkUpdateIfChanged ( $ hash , 'channelCurrentTitle' ,
$ programList - > { programName } ) ;
readingsBulkUpdateIfChanged (
$ hash ,
'channelCurrentStartTime' ,
LGTV_WebOS_FormartStartEndTime (
$ programList - > { localStartTime }
)
) ;
readingsBulkUpdateIfChanged (
$ hash ,
'channelCurrentEndTime' ,
LGTV_WebOS_FormartStartEndTime (
$ programList - > { localEndTime }
)
) ;
}
elsif ( $ count < 2 ) {
readingsBulkUpdateIfChanged ( $ hash , 'channelNextTitle' ,
$ programList - > { programName } ) ;
readingsBulkUpdateIfChanged (
$ hash ,
'channelNextStartTime' ,
LGTV_WebOS_FormartStartEndTime (
$ programList - > { localStartTime }
)
) ;
readingsBulkUpdateIfChanged (
$ hash ,
'channelNextEndTime' ,
LGTV_WebOS_FormartStartEndTime (
$ programList - > { localEndTime }
)
) ;
2019-01-18 09:22:45 +00:00
}
2019-06-20 18:35:49 +00:00
2018-07-22 18:38:30 +00:00
$ count + + ;
2019-06-20 18:35:49 +00:00
return if ( $ count > 1 ) ;
2017-02-15 08:53:26 +00:00
}
2017-02-14 06:34:29 +00:00
}
}
2019-06-20 18:35:49 +00:00
elsif ( defined ( $ decode_json - > { payload } { 'mute' } )
2022-01-04 10:09:16 +00:00
|| defined ( $ decode_json - > { payload } { 'muted' } ) )
2019-06-20 18:35:49 +00:00
{
if (
defined ( $ decode_json - > { payload } { 'mute' } )
2022-01-04 10:09:16 +00:00
&& ( $ decode_json - > { payload } { 'mute' } eq 'true'
|| $ decode_json - > { payload } { 'mute' } == 1 )
2019-06-20 18:35:49 +00:00
)
{
readingsBulkUpdateIfChanged ( $ hash , 'mute' , 'on' ) ;
}
elsif ( defined ( $ decode_json - > { payload } { 'mute' } ) ) {
if ( $ decode_json - > { payload } { 'mute' } eq 'false'
2022-01-04 10:09:16 +00:00
|| $ decode_json - > { payload } { 'mute' } == 0 )
2019-06-20 18:35:49 +00:00
{
readingsBulkUpdateIfChanged ( $ hash , 'mute' , 'off' ) ;
2017-02-11 00:30:12 +00:00
}
}
2019-06-20 18:35:49 +00:00
if (
defined ( $ decode_json - > { payload } { 'muted' } )
2022-01-04 10:09:16 +00:00
&& ( $ decode_json - > { payload } { 'muted' } eq 'true'
|| $ decode_json - > { payload } { 'muted' } == 1 )
2019-06-20 18:35:49 +00:00
)
{
readingsBulkUpdateIfChanged ( $ hash , 'mute' , 'on' ) ;
}
elsif (
defined ( $ decode_json - > { payload } { 'muted' } )
2022-01-04 10:09:16 +00:00
&& ( $ decode_json - > { payload } { 'muted' } eq 'false'
|| $ decode_json - > { payload } { 'muted' } == 0 )
2019-06-20 18:35:49 +00:00
)
{
readingsBulkUpdateIfChanged ( $ hash , 'mute' , 'off' ) ;
2017-02-07 22:23:48 +00:00
}
}
2019-06-20 18:35:49 +00:00
elsif ( defined ( $ decode_json - > { payload } { status3D } { status } ) ) {
if ( $ decode_json - > { payload } { status3D } { status } eq 'false'
2022-01-04 10:09:16 +00:00
|| $ decode_json - > { payload } { status3D } { status } == 0 )
2019-06-20 18:35:49 +00:00
{
readingsBulkUpdateIfChanged ( $ hash , '3D' , 'off' ) ;
}
elsif ( $ decode_json - > { payload } { status3D } { status } eq 'true'
2022-01-04 10:09:16 +00:00
|| $ decode_json - > { payload } { status3D } { status } == 1 )
2019-06-20 18:35:49 +00:00
{
readingsBulkUpdateIfChanged ( $ hash , '3D' , 'on' ) ;
2017-02-14 22:39:23 +00:00
}
2019-06-20 18:35:49 +00:00
readingsBulkUpdateIfChanged ( $ hash , '3DMode' ,
$ decode_json - > { payload } { status3D } { pattern } ) ;
2017-02-14 22:39:23 +00:00
}
2019-06-20 18:35:49 +00:00
elsif ( defined ( $ decode_json - > { payload } { appId } ) ) {
2021-12-31 18:30:09 +00:00
if (
(
2022-01-04 20:44:00 +00:00
$ decode_json - > { payload } { appId } =~ /com.webos.app.externalinput/x
|| $ decode_json - > { payload } { appId } =~ /com.webos.app.hdmi/x
2021-12-31 18:30:09 +00:00
)
2022-01-04 10:09:16 +00:00
&& defined (
2021-12-31 18:30:09 +00:00
$ hash - > { helper } { device } { inputapps }
{ $ decode_json - > { payload } { appId } }
)
2022-01-04 10:09:16 +00:00
&& $ hash - > { helper } { device } { inputapps }
{ $ decode_json - > { payload } { appId } }
2019-08-12 15:41:18 +00:00
)
2019-06-20 18:35:49 +00:00
{
2019-01-18 09:22:45 +00:00
2019-06-20 18:35:49 +00:00
readingsBulkUpdateIfChanged ( $ hash , 'input' ,
$ hash - > { helper } { device } { inputapps }
{ $ decode_json - > { payload } { appId } } ) ;
readingsBulkUpdateIfChanged ( $ hash , 'launchApp' , '-' ) ;
2019-01-18 09:22:45 +00:00
2019-06-20 18:35:49 +00:00
}
2021-12-31 18:30:09 +00:00
elsif (
defined ( $ openAppsPackageName { $ decode_json - > { payload } { appId } } )
2022-01-04 10:09:16 +00:00
&& $ openAppsPackageName { $ decode_json - > { payload } { appId } } )
2019-08-12 15:41:18 +00:00
{
2019-06-20 18:35:49 +00:00
readingsBulkUpdateIfChanged ( $ hash , 'launchApp' ,
$ openAppsPackageName { $ decode_json - > { payload } { appId } } ) ;
readingsBulkUpdateIfChanged ( $ hash , 'input' , '-' ) ;
2017-02-14 22:39:23 +00:00
}
2021-12-31 18:30:09 +00:00
2017-02-14 22:39:23 +00:00
}
2019-06-20 18:35:49 +00:00
if ( defined ( $ decode_json - > { type } ) ) {
if ( $ decode_json - > { type } eq 'registered'
2022-01-04 10:09:16 +00:00
&& defined ( $ decode_json - > { payload } { 'client-key' } ) )
2019-06-20 18:35:49 +00:00
{
$ hash - > { helper } { device } { registered } = 1 ;
}
elsif (
(
$ decode_json - > { type } eq 'response'
2022-01-04 10:09:16 +00:00
&& ( $ decode_json - > { payload } { returnValue } eq 'true'
|| $ decode_json - > { payload } { returnValue } == 1 )
2019-06-20 18:35:49 +00:00
)
2022-01-04 10:09:16 +00:00
|| ( $ decode_json - > { type } eq 'registered' )
&& defined ( $ decode_json - > { payload } { 'client-key' } )
2019-06-20 18:35:49 +00:00
)
{
2017-02-11 00:30:12 +00:00
$ response = 'ok' ;
2019-06-20 18:35:49 +00:00
readingsBulkUpdateIfChanged ( $ hash , 'pairing' , 'paired' ) ;
$ hash - > { helper } { device } { runsetcmd } =
$ hash - > { helper } { device } { runsetcmd } - 1
if ( $ hash - > { helper } { device } { runsetcmd } > 0 ) ;
}
elsif ( $ decode_json - > { type } eq 'error' ) {
2021-12-31 18:45:40 +00:00
$ response = "error - $decode_json->{error}"
if ( $ decode_json - > { error } ne '404 no such service or method' ) ;
2019-06-20 18:35:49 +00:00
if ( $ decode_json - > { error } eq '401 insufficient permissions'
2022-01-04 10:09:16 +00:00
|| $ decode_json - > { error } eq
2019-06-20 18:35:49 +00:00
'401 insufficient permissions (not registered)' )
{
readingsBulkUpdateIfChanged ( $ hash , 'pairing' , 'unpaired' ) ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
$ hash - > { helper } { device } { runsetcmd } =
$ hash - > { helper } { device } { runsetcmd } - 1
if ( $ hash - > { helper } { device } { runsetcmd } > 0 ) ;
2017-02-07 22:23:48 +00:00
}
}
2019-06-20 18:35:49 +00:00
readingsBulkUpdateIfChanged ( $ hash , 'lgKey' ,
$ decode_json - > { payload } { 'client-key' } )
if ( defined ( $ decode_json - > { payload } { 'client-key' } ) ) ;
readingsBulkUpdateIfChanged ( $ hash , 'volume' ,
$ decode_json - > { payload } { 'volume' } )
if ( defined ( $ decode_json - > { payload } { 'volume' } ) ) ;
readingsBulkUpdateIfChanged ( $ hash , 'lastResponse' , $ response )
if ( defined ( $ response ) ) ;
if ( ReadingsVal ( $ name , 'launchApp' , 'none' ) eq 'TV' ) {
readingsBulkUpdateIfChanged ( $ hash , 'channel' ,
$ decode_json - > { payload } { 'channelNumber' } )
if ( defined ( $ decode_json - > { payload } { 'channelNumber' } ) ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelName' ,
$ decode_json - > { payload } { 'channelName' } )
if ( defined ( $ decode_json - > { payload } { 'channelName' } ) ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelMedia' ,
$ decode_json - > { payload } { 'channelTypeName' } )
if ( defined ( $ decode_json - > { payload } { 'channelTypeName' } ) ) ;
2019-01-18 09:22:45 +00:00
}
2019-06-20 18:35:49 +00:00
else {
readingsBulkUpdateIfChanged ( $ hash , 'channelName' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channel' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelMedia' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelCurrentTitle' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelCurrentStartTime' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelCurrentEndTime' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelNextTitle' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelNextStartTime' , '-' ) ;
readingsBulkUpdateIfChanged ( $ hash , 'channelNextEndTime' , '-' ) ;
}
readingsBulkUpdateIfChanged ( $ hash , 'state' , 'on' ) ;
2019-01-18 09:22:45 +00:00
2019-06-20 18:35:49 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Pairing {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - HASH handshakePayload" ;
2019-06-20 18:35:49 +00:00
my % handshakePayload = (
"pairingType" = > "PROMPT" ,
"manifest" = > {
"manifestVersion" = > 1 ,
"appVersion" = > "1.1" ,
"signed" = > {
"created" = > "20161123" ,
"appId" = > "com.lge.test" ,
"vendorId" = > "com.lge" ,
"localizedAppNames" = > {
"" = > "FHEM LG Remote" ,
"de-DE" = > "FHEM LG Fernbedienung"
} ,
"localizedVendorNames" = > {
"" = > "LG Electronics"
} ,
"permissions" = > [
"TEST_SECURE" , "CONTROL_INPUT_TEXT" ,
"CONTROL_MOUSE_AND_KEYBOARD" , "READ_INSTALLED_APPS" ,
"READ_LGE_SDX" , "READ_NOTIFICATIONS" ,
"SEARCH" , "WRITE_SETTINGS" ,
"WRITE_NOTIFICATION_ALERT" , "CONTROL_POWER" ,
"READ_CURRENT_CHANNEL" , "READ_RUNNING_APPS" ,
"READ_UPDATE_INFO" , "UPDATE_FROM_REMOTE_APP" ,
"READ_LGE_TV_INPUT_EVENTS" , "READ_TV_CURRENT_TIME"
] ,
"serial" = > "2f930e2d2cfe083771f68e4fe7bb07"
} ,
"permissions" = > [
"LAUNCH" ,
"LAUNCH_WEBAPP" ,
"APP_TO_APP" ,
"CLOSE" ,
"TEST_OPEN" ,
"TEST_PROTECTED" ,
"CONTROL_AUDIO" ,
"CONTROL_DISPLAY" ,
"CONTROL_INPUT_JOYSTICK" ,
"CONTROL_INPUT_MEDIA_RECORDING" ,
"CONTROL_INPUT_MEDIA_PLAYBACK" ,
"CONTROL_INPUT_TV" ,
"CONTROL_POWER" ,
"READ_APP_STATUS" ,
"READ_CURRENT_CHANNEL" ,
"READ_INPUT_DEVICE_LIST" ,
"READ_NETWORK_STATE" ,
"READ_RUNNING_APPS" ,
"READ_TV_CHANNEL_LIST" ,
"WRITE_NOTIFICATION_TOAST" ,
"READ_POWER_STATE" ,
"READ_COUNTRY_INFO"
] ,
"signatures" = > [
{
"signatureVersion" = > 1 ,
"signature" = >
"eyJhbGdvcml0aG0iOiJSU0EtU0hBMjU2Iiwia2V5SWQiOiJ0ZXN0LXNpZ25pbmctY2VydCIsInNpZ25hdHVyZVZlcnNpb24iOjF9.hrVRgjCwXVvE2OOSpDZ58hR+59aFNwYDyjQgKk3auukd7pcegmE2CzPCa0bJ0ZsRAcKkCTJrWo5iDzNhMBWRyaMOv5zWSrthlf7G128qvIlpMT0YNY+n/FaOHE73uLrS/g7swl3/qH/BGFG2Hu4RlL48eb3lLKqTt2xKHdCs6Cd4RMfJPYnzgvI4BNrFUKsjkcu+WD4OO2A27Pq1n50cMchmcaXadJhGrOqH5YmHdOCj5NSHzJYrsW0HPlpuAx/ECMeIZYDh6RMqaFM2DXzdKX9NmmyqzJ3o/0lkk/N97gfVRLW5hA29yeAwaCViZNCP8iC9aO0q9fQojoa7NQnAtw=="
}
]
}
) ;
2017-02-07 22:23:48 +00:00
my $ usedHandshake = \ % handshakePayload ;
2019-06-20 18:35:49 +00:00
my $ key = ReadingsVal ( $ name , 'lgKey' , '' ) ;
$ usedHandshake - > { 'client-key' } = $ key if ( defined ( $ key ) ) ;
LGTV_WebOS_CreateSendCommand ( $ hash , undef , $ usedHandshake , 'register' ) ;
2017-02-07 22:23:48 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - Send pairing informations" ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_CreateSendCommand {
2019-06-20 18:35:49 +00:00
my ( $ hash , $ uri , $ payload , $ type ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2022-01-04 10:09:16 +00:00
$ type = 'request' if ( ! defined ( $ type ) ) ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
my $ command = { } ;
2019-06-20 18:35:49 +00:00
$ command - > { 'client-key' } = ReadingsVal ( $ name , 'lgKey' , '' )
if ( $ type ne 'register' ) ;
$ command - > { id } = $ type . "_" . gettimeofday ( ) ;
$ command - > { type } = $ type ;
$ command - > { uri } = $ uri if ( $ uri ) ;
$ command - > { payload } = $ payload if ( defined ( $ payload ) ) ;
#Log3 $name, 5, "LGTV_WebOS ($name) - Payload Message: $command->{payload}{message}";
2017-02-07 22:23:48 +00:00
my $ cmd = encode_json ( $ command ) ;
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
Log3 $ name , 5 , "LGTV_WebOS ($name) - Sending command: $cmd" ;
2019-06-20 18:35:49 +00:00
LGTV_WebOS_Write ( $ hash , LGTV_WebOS_Hybi10Encode ( $ cmd , "text" , 1 ) ) ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Hybi10Encode {
2022-01-04 10:09:16 +00:00
my $ payload = shift ;
my $ type = shift // 'text' ;
my $ masked = shift // 1 ;
2017-02-07 22:23:48 +00:00
my @ frameHead ;
2019-06-20 18:35:49 +00:00
my $ frame = "" ;
2017-02-07 22:23:48 +00:00
my $ payloadLength = length ( $ payload ) ;
2022-01-04 20:44:00 +00:00
given ( $ type ) {
when ( 'text' ) {
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
# first byte indicates FIN, Text-Frame (10000001):
$ frameHead [ 0 ] = 129 ;
}
when ( 'close' ) {
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
# first byte indicates FIN, Close Frame(10001000):
$ frameHead [ 0 ] = 136 ;
}
when ( 'ping' ) {
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
# first byte indicates FIN, Ping frame (10001001):
$ frameHead [ 0 ] = 137 ;
}
when ( 'pong' ) {
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
# first byte indicates FIN, Pong frame (10001010):
$ frameHead [ 0 ] = 138 ;
}
2017-02-07 22:23:48 +00:00
}
# set mask and payload length (using 1, 3 or 9 bytes)
2019-06-20 18:35:49 +00:00
if ( $ payloadLength > 65535 ) {
2017-02-07 22:23:48 +00:00
# TODO
2019-06-20 18:35:49 +00:00
my $ payloadLengthBin = sprintf ( '%064b' , $ payloadLength ) ;
2017-02-07 22:23:48 +00:00
$ frameHead [ 1 ] = ( $ masked ) ? 255 : 127 ;
2019-06-20 18:35:49 +00:00
for ( my $ i = 0 ; $ i < 8 ; $ i + + ) {
$ frameHead [ $ i + 2 ] =
oct ( "0b" . substr ( $ payloadLengthBin , $ i * 8 , $ i * 8 + 8 ) ) ;
2017-02-07 22:23:48 +00:00
}
# most significant bit MUST be 0 (close connection if frame too big)
2019-06-20 18:35:49 +00:00
if ( $ frameHead [ 2 ] > 127 ) {
2017-02-07 22:23:48 +00:00
#$this->close(1004);
2022-01-04 10:09:16 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
}
elsif ( $ payloadLength > 125 ) {
my $ payloadLengthBin = sprintf ( '%016b' , $ payloadLength ) ;
2017-02-07 22:23:48 +00:00
$ frameHead [ 1 ] = ( $ masked ) ? 254 : 126 ;
2019-06-20 18:35:49 +00:00
$ frameHead [ 2 ] = oct ( "0b" . substr ( $ payloadLengthBin , 0 , 8 ) ) ;
$ frameHead [ 3 ] = oct ( "0b" . substr ( $ payloadLengthBin , 8 , 16 ) ) ;
}
else {
2017-02-07 22:23:48 +00:00
$ frameHead [ 1 ] = ( $ masked ) ? $ payloadLength + 128 : $ payloadLength ;
}
# convert frame-head to string:
2019-06-20 18:35:49 +00:00
for ( my $ i = 0 ; $ i < scalar ( @ frameHead ) ; $ i + + ) {
$ frameHead [ $ i ] = chr ( $ frameHead [ $ i ] ) ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
my @ mask ;
if ( $ masked ) {
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
# generate a random mask:
2019-06-20 18:35:49 +00:00
for ( my $ i = 0 ; $ i < 4 ; $ i + + ) {
2017-02-07 22:23:48 +00:00
#$mask[$i] = chr(int(rand(255)));
2019-06-20 18:35:49 +00:00
$ mask [ $ i ] = chr ( int ( 25 * $ i ) ) ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
@ frameHead = ( @ frameHead , @ mask ) ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
$ frame = join ( "" , @ frameHead ) ;
2017-02-07 22:23:48 +00:00
# append payload to frame:
my $ char ;
2019-06-20 18:35:49 +00:00
for ( my $ i = 0 ; $ i < $ payloadLength ; $ i + + ) {
$ char = substr ( $ payload , $ i , 1 ) ;
$ frame . = ( $ masked ) ? $ char ^ $ mask [ $ i % 4 ] : $ char ;
2017-02-07 22:23:48 +00:00
}
2019-06-20 18:35:49 +00:00
2017-02-07 22:23:48 +00:00
return $ frame ;
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_GetAudioStatus {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
2018-01-11 12:10:42 +00:00
2019-06-20 18:35:49 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - LGTV_WebOS_GetAudioStatus: "
. $ hash - > { helper } { device } { runsetcmd } ;
LGTV_WebOS_CreateSendCommand ( $ hash , $ lgCommands { getAudioStatus } , undef )
if ( $ hash - > { helper } { device } { runsetcmd } == 0 ) ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_GetCurrentChannel {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
RemoveInternalTimer ( $ hash , 'LGTV_WebOS_GetCurrentChannel' ) ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - LGTV_WebOS_GetCurrentChannel: "
. $ hash - > { helper } { device } { runsetcmd } ;
LGTV_WebOS_CreateSendCommand ( $ hash , $ lgCommands { getCurrentChannel } , undef )
if ( $ hash - > { helper } { device } { runsetcmd } == 0 ) ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-07 22:23:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_GetForgroundAppInfo {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
RemoveInternalTimer ( $ hash , 'LGTV_WebOS_GetForgroundAppInfo' ) ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - LGTV_WebOS_GetForgroundAppInfo: "
. $ hash - > { helper } { device } { runsetcmd } ;
LGTV_WebOS_CreateSendCommand ( $ hash , $ lgCommands { getForegroundAppInfo } ,
undef )
if ( $ hash - > { helper } { device } { runsetcmd } == 0 ) ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-09 21:02:58 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_GetExternalInputList {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
RemoveInternalTimer ( $ hash , 'LGTV_WebOS_GetExternalInputList' ) ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - LGTV_WebOS_GetExternalInputList: "
. $ hash - > { helper } { device } { runsetcmd } ;
LGTV_WebOS_CreateSendCommand ( $ hash , $ lgCommands { getExternalInputList } ,
undef )
if ( $ hash - > { helper } { device } { runsetcmd } == 0 ) ;
2021-12-31 18:30:09 +00:00
return ;
2017-02-11 00:30:12 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Get3DStatus {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
2017-02-07 22:23:48 +00:00
2019-06-20 18:35:49 +00:00
RemoveInternalTimer ( $ hash , 'LGTV_WebOS_Get3DStatus' ) ;
Log3 $ name , 4 , "LGTV_WebOS ($name) - LGTV_WebOS_Get3DStatus: "
. $ hash - > { helper } { device } { runsetcmd } ;
LGTV_WebOS_CreateSendCommand ( $ hash , $ lgCommands { get3DStatus } , undef )
if ( $ hash - > { helper } { device } { runsetcmd } == 0 ) ;
2021-12-31 18:30:09 +00:00
return ;
2019-01-18 09:22:45 +00:00
}
2017-02-07 22:23:48 +00:00
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_GetChannelProgramInfo {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
2019-06-20 17:51:26 +00:00
2019-06-20 18:35:49 +00:00
Log3 $ name , 4 , "LGTV_WebOS ($name) - LGTV_WebOS_GetChannelProgramInfo: "
. $ hash - > { helper } { device } { runsetcmd } ;
LGTV_WebOS_CreateSendCommand ( $ hash , $ lgCommands { getChannelProgramInfo } ,
undef )
if ( $ hash - > { helper } { device } { runsetcmd } == 0 ) ;
2021-12-31 18:30:09 +00:00
return ;
2019-06-20 18:35:49 +00:00
}
2019-06-20 17:51:26 +00:00
2017-02-07 22:23:48 +00:00
#############################################
### my little Helper
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_ParseMsg {
2022-01-04 10:09:16 +00:00
my $ hash = shift ;
my $ buffer = shift ;
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
my $ name = $ hash - > { NAME } ;
my $ jsonopen = 0 ;
my $ jsonclose = 0 ;
my $ msg = '' ;
my $ tail = '' ;
2019-06-20 18:35:49 +00:00
if ( $ buffer ) {
2022-01-04 10:09:16 +00:00
for my $ c ( split // , $ buffer ) {
2022-01-04 20:44:00 +00:00
if ( $ jsonopen == $ jsonclose && $ jsonopen > 0 ) {
2017-02-11 00:30:12 +00:00
$ tail . = $ c ;
2019-06-20 18:35:49 +00:00
Log3 $ name , 5 ,
2022-01-04 20:44:00 +00:00
"LGTV_WebOS ($name) - $jsonopen == $jsonclose && $jsonopen > 0" ;
2019-06-20 18:35:49 +00:00
}
2022-01-04 20:44:00 +00:00
elsif ( ( $ jsonopen == $ jsonclose ) && ( $ c ne '{' ) ) {
2019-06-20 18:35:49 +00:00
Log3 $ name , 5 ,
"LGTV_WebOS ($name) - Garbage character before message: "
. $ c ;
}
else {
if ( $ c eq '{' ) {
2017-02-11 00:30:12 +00:00
2022-01-04 20:44:00 +00:00
$ jsonopen + + ;
2019-06-20 18:35:49 +00:00
}
elsif ( $ c eq '}' ) {
2022-01-04 20:44:00 +00:00
$ jsonclose + + ;
2017-02-11 00:30:12 +00:00
}
2019-06-20 18:35:49 +00:00
2017-02-11 00:30:12 +00:00
$ msg . = $ c ;
}
}
2019-06-20 18:35:49 +00:00
2022-01-04 20:44:00 +00:00
if ( $ jsonopen != $ jsonclose ) {
2019-06-20 18:35:49 +00:00
2017-02-11 00:30:12 +00:00
$ tail = $ msg ;
2019-06-20 18:35:49 +00:00
$ msg = '' ;
2017-02-11 00:30:12 +00:00
}
}
2019-06-20 18:35:49 +00:00
2017-02-11 00:30:12 +00:00
Log3 $ name , 5 , "LGTV_WebOS ($name) - return msg: $msg and tail: $tail" ;
2019-06-20 18:35:49 +00:00
return ( $ msg , $ tail ) ;
2017-02-11 00:30:12 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Header2Hash {
2019-06-20 18:35:49 +00:00
my $ string = shift ;
my % hash = ( ) ;
2017-02-07 22:23:48 +00:00
2022-01-04 10:09:16 +00:00
for my $ line ( split ( "\r\n" , $ string ) ) {
2019-06-20 18:35:49 +00:00
my ( $ key , $ value ) = split ( ": " , $ line ) ;
next if ( ! $ value ) ;
2017-02-07 22:23:48 +00:00
2022-01-04 20:44:00 +00:00
$ value =~ s/^ //x ;
2017-02-07 22:23:48 +00:00
$ hash { $ key } = $ value ;
2019-06-20 18:35:49 +00:00
}
2017-02-07 22:23:48 +00:00
return \ % hash ;
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_FormartStartEndTime {
2019-06-20 18:35:49 +00:00
my $ string = shift ;
my @ timeArray = split ( ',' , $ string ) ;
return
"$timeArray[0]-$timeArray[1]-$timeArray[2] $timeArray[3]:$timeArray[4]:$timeArray[5]" ;
2017-02-07 22:23:48 +00:00
}
2017-04-18 13:20:47 +00:00
############ Presence Erkennung Begin #################
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_Presence {
2019-06-20 18:35:49 +00:00
my $ hash = shift ;
my $ name = $ hash - > { NAME } ;
$ hash - > { helper } { RUNNING_PID } =
BlockingCall ( "LGTV_WebOS_PresenceRun" , $ name . '|' . $ hash - > { HOST } ,
"LGTV_WebOS_PresenceDone" , 5 , "LGTV_WebOS_PresenceAborted" , $ hash )
unless ( exists ( $ hash - > { helper } { RUNNING_PID } ) ) ;
2021-12-31 18:30:09 +00:00
return ;
2017-04-18 13:20:47 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_PresenceRun {
2019-06-20 18:35:49 +00:00
my $ string = shift ;
my ( $ name , $ host ) = split ( "\\|" , $ string ) ;
2017-04-18 13:20:47 +00:00
my $ tmp ;
my $ response ;
2017-04-18 09:27:57 +00:00
2017-04-18 16:58:13 +00:00
$ tmp = qx( ping -c 3 -w 2 $host 2>&1 ) ;
2017-04-18 09:27:57 +00:00
2022-01-04 10:09:16 +00:00
if ( defined ( $ tmp ) && $ tmp ne "" ) {
2019-06-20 18:35:49 +00:00
2017-04-18 13:20:47 +00:00
chomp $ tmp ;
2019-06-20 18:35:49 +00:00
Log3 $ name , 5 ,
"LGTV_WebOS ($name) - ping command returned with output:\n$tmp" ;
$ response = "$name|"
. (
2022-01-04 20:44:00 +00:00
(
$ tmp =~ /\d+ [Bb]ytes (from|von)/x
&& ! $ tmp =~ /[Uu]nreachable/x
)
2022-01-04 10:09:16 +00:00
? "present"
: "absent"
2019-06-20 18:35:49 +00:00
) ;
}
else {
2017-04-18 13:20:47 +00:00
$ response = "$name|Could not execute ping command" ;
2017-04-18 09:27:57 +00:00
}
2019-06-20 18:35:49 +00:00
Log3 $ name , 4 ,
"Sub LGTV_WebOS_PresenceRun ($name) - Sub finish, Call LGTV_WebOS_PresenceDone" ;
2022-01-04 10:09:16 +00:00
2019-01-18 09:22:45 +00:00
return $ response ;
2017-04-18 13:20:47 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_PresenceDone {
2022-01-04 10:09:16 +00:00
my $ string = shift ;
2019-06-20 18:35:49 +00:00
my ( $ name , $ response ) = split ( "\\|" , $ string ) ;
my $ hash = $ defs { $ name } ;
delete ( $ hash - > { helper } { RUNNING_PID } ) ;
Log3 $ name , 4 ,
"Sub LGTV_WebOS_PresenceDone ($name) - Helper is disabled. Stop processing"
if ( $ hash - > { helper } { DISABLED } ) ;
return if ( $ hash - > { helper } { DISABLED } ) ;
readingsSingleUpdate ( $ hash , 'presence' , $ response , 1 ) ;
LGTV_WebOS_SocketClosePresenceAbsent ( $ hash , $ response ) ;
2017-10-06 20:40:54 +00:00
Log3 $ name , 4 , "Sub LGTV_WebOS_PresenceDone ($name) - presence done" ;
2021-12-31 18:30:09 +00:00
return ;
2019-01-18 09:22:45 +00:00
}
2017-09-18 11:59:10 +00:00
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_PresenceAborted {
2022-01-04 10:09:16 +00:00
my $ hash = shift ;
2019-06-20 18:35:49 +00:00
my $ name = $ hash - > { NAME } ;
2017-09-17 18:48:48 +00:00
2019-06-20 18:35:49 +00:00
delete ( $ hash - > { helper } { RUNNING_PID } ) ;
readingsSingleUpdate ( $ hash , 'presence' , 'pingPresence timedout' , 1 ) ;
Log3 $ name , 4 ,
"Sub LGTV_WebOS_PresenceAborted ($name) - The BlockingCall Process terminated unexpectedly. Timedout!" ;
2021-12-31 18:30:09 +00:00
return ;
2017-09-17 18:48:48 +00:00
}
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_SocketClosePresenceAbsent {
2019-01-18 09:22:45 +00:00
2022-01-04 10:09:16 +00:00
my $ hash = shift ;
my $ presence = shift ;
2019-06-20 18:35:49 +00:00
my $ name = $ hash - > { NAME } ;
2017-10-09 07:09:08 +00:00
LGTV_WebOS_Close ( $ hash )
2022-01-04 10:09:16 +00:00
if ( $ presence eq 'absent' && ! IsDisabled ( $ name ) && $ hash - > { CD } )
2019-06-20 18:35:49 +00:00
; # https://forum.fhem.de/index.php/topic,66671.msg694578.html#msg694578
# Sobald pingPresence absent meldet und der Socket noch steht soll er geschlossen werden, da sonst FHEM nach 4-6 min für 10 min blockiert
2021-12-31 18:30:09 +00:00
return ;
2019-01-18 09:22:45 +00:00
}
2017-02-07 22:23:48 +00:00
2021-12-31 18:30:09 +00:00
sub LGTV_WebOS_WakeUp_Udp {
2019-06-20 18:35:49 +00:00
my ( $ hash , $ mac_addr , $ host , $ port ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2017-02-07 22:23:48 +00:00
2022-01-04 20:44:00 +00:00
$ port = 9 if ( ! defined $ port || $ port !~ /^\d+$/x ) ;
2017-02-07 22:23:48 +00:00
2022-01-04 20:44:00 +00:00
my $ sock = IO::Socket::INET - > new ( Proto = > 'udp' ) or warn "socket : $!\n" ;
2019-06-20 18:35:49 +00:00
if ( ! $ sock ) {
Log3 $ name , 3 ,
"Sub LGTV_WebOS_WakeUp_Udp ($name) - Can't create WOL socket" ;
2019-01-18 09:22:45 +00:00
return 1 ;
}
2017-02-07 22:23:48 +00:00
2021-12-31 18:30:09 +00:00
my $ ip_addr = inet_aton ( $ host ) ;
2019-06-20 18:35:49 +00:00
my $ sock_addr = sockaddr_in ( $ port , $ ip_addr ) ;
2022-01-04 20:44:00 +00:00
$ mac_addr =~ s/://xg ;
2019-06-20 18:35:49 +00:00
my $ packet =
pack ( 'C6H*' , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , $ mac_addr x 16 ) ;
2022-01-04 20:44:00 +00:00
setsockopt ( $ sock , SOL_SOCKET , SO_BROADCAST , 1 )
or warn "setsockopt : $!\n" ;
send ( $ sock , $ packet , 0 , $ sock_addr ) or warn "send : $!\n" ;
2019-06-20 18:35:49 +00:00
close ( $ sock ) ;
2017-02-07 22:23:48 +00:00
2019-01-18 09:22:45 +00:00
return 1 ;
}
2017-02-07 22:23:48 +00:00
2019-01-18 09:22:45 +00:00
####### Presence Erkennung Ende ############
2017-02-07 22:23:48 +00:00
1 ;
2017-02-23 11:53:19 +00:00
= pod
= item device
2019-07-02 10:14:41 +00:00
= item summary Controls LG SmartTVs run with WebOS Operating System
= item summary_DE Steuert LG SmartTVs mit WebOS Betriebssystem
2017-02-23 11:53:19 +00:00
= begin html
< a name = "LGTV_WebOS" > </a>
<h3> LGTV_WebOS </h3>
2017-02-28 09:22:17 +00:00
<ul>
This module controls SmartTVs from LG based on WebOS as operation system via network . It offers to swtich the TV channel , start and switch applications , send remote control commands , as well as to query the actual status . <p> < br /><br / >
<strong> Definition </strong> <code> define & lt ; name & gt ; LGTV_WebOS & lt ; IP - Address & gt ; </code>
</p>
<ul>
<ul>
When an LGTV_WebOS - Module is defined , an internal routine is triggered which queries the TV ' s status every 15 s and triggers respective Notify / FileLog Event definitions .
</ul>
</ul>
</p>
<ul>
<ul>
Example:
</ul>
<ul>
<code> define TV LGTV_WebOS 192.168 .0 .10 < br /></co de > < br /><br / > </p>
</ul>
</ul>
<p> <code> <strong> Set - Commands </strong> <code> set & lt ; Name & gt ; & lt ; Command & gt ; [ & lt ; Parameter & gt ; ] </code> </code> </p>
<ul>
<ul>
The following commands are supported in the actual version:
</ul>
</ul>
<ul>
<ul>
<ul>
<li> <strong> connect & nbsp ; </strong> - & nbsp ; Connects to the TV at the defined address . When triggered the first time , a pairing is conducted </li>
<li> <strong> pairing & nbsp ; </strong> - & nbsp ; & nbsp ; Sends a pairing request to the TV which needs to be confirmed by the user with remote control </li>
<li> <strong> screenMsg </strong> & lt ; Text & gt ; & nbsp ; & nbsp ; - & nbsp ; & nbsp ; Displays a message for 3 - 5 s on the TV in the top right corner of the screen </li>
<li> <strong> mute </strong> on , off & nbsp ; - & nbsp ; Turns volume to mute . Depending on the audio connection , this needs to be set on the AV Receiver ( see volume ) </li>
<li> <strong> volume </strong> 0 - 100 , Slider - & nbsp ; & nbsp ; Sets the volume . Depending on the audio connection , this needs to be set on the AV Receiver ( see mute ) </li>
<li> <strong> volumeUp </strong> & nbsp ; - & nbsp ; & nbsp ; Increases the volume by 1 </li>
<li> <strong> volumeDown </strong> & nbsp ; - & nbsp ; & nbsp ; Decreases the volume by 1 </li>
<li> <strong> channelUp </strong> & nbsp ; & nbsp ; - & nbsp ; & nbsp ; Switches the channel to the next one </li>
<li> <strong> channelDown </strong> & nbsp ; & nbsp ; - & nbsp ; & nbsp ; Switches the channel to the previous one </li>
<li> <strong> getServiceList & nbsp ; </strong> - & nbsp ; Queries the running services on WebOS ( in beta phase ) </li>
<li> <strong> on </strong> - Turns the TV on , depending on type of device . Only working when LAN or Wifi connection remains active during off state . </li>
<li> <strong> off </strong> - Turns the TV off , when an active connection is established </li>
<li> <strong> launchApp </strong> & lt ; Application & gt ; & nbsp ; & nbsp ; - & nbsp ; & nbsp ; Activates an application out of the following list ( Maxdome , AmazonVideo , YouTube , Netflix , TV , GooglePlay , Browser , Chili , TVCast , Smartshare , Scheduler , Miracast , TV ) & nbsp ; < br />Note: TV is an application in LG's terms and not an input connection</ li >
<li> <strong> 3 D </strong> on , off & nbsp ; - & nbsp ; 3 D Mode is turned on and off . Depending on type of TV there might be different modes ( e . g . Side - by - Side , Top - Bottom ) </li>
<li> <strong> stop </strong> & nbsp ; - & nbsp ; & nbsp ; Stop command ( depending on application ) </li>
<li> <strong> play & nbsp ; </strong> - & nbsp ; & nbsp ; Play command ( depending on application ) </li>
<li> <strong> pause & nbsp ; </strong> - & nbsp ; & nbsp ; Pause command ( depending on application ) </li>
<li> <strong> rewind & nbsp ; </strong> - & nbsp ; & nbsp ; Rewind command ( depending on application ) </li>
<li> <strong> fastForward & nbsp ; </strong> - & nbsp ; & nbsp ; Fast Forward command ( depending on application ) </li>
<li> <strong> clearInputList & nbsp ; </strong> - & nbsp ; & nbsp ; Clears list of Inputs </li>
<li> <strong> input & nbsp ; </strong> - Selects the input connection ( depending on the actual TV type and connected devices ) < br />e.g.: extInput_AV-1, extInput_HDMI-1, extInput_HDMI-2, extInput_HDMI-3)</ li >
</ul>
</ul>
</ul> < br /><br / > </p>
<p> <strong> Get - Command </strong> <code> get & lt ; Name & gt ; & lt ; Readingname & gt ; </code> < br /></ p >
<ul>
<ul>
Currently , GET reads back the values of the current readings . Please see below for a list of Readings / Generated Events .
</ul>
</ul>
<p> < br /><strong>Attributes</s trong > </p>
<ul>
<ul>
<li> disable </li>
Optional attribute to deactivate the recurring status updates . Manual trigger of update is alsways possible . </br>
Valid Values: 0 = & gt ; recurring status updates , 1 = & gt ; no recurring status updates . </p>
</ul>
</ul>
<ul>
<ul>
<li> channelGuide </li>
Optional attribute to deactivate the recurring TV Guide update . Depending on TV and FHEM host , this causes significant network traffic and / or CPU load</ br >
Valid Values: 0 = & gt ; no recurring TV Guide updates , 1 = & gt ; recurring TV Guide updates .
</ul>
</ul>
2017-04-23 10:46:46 +00:00
<ul>
<ul>
<li> pingPresence </li>
current state of ping presence from TV . create a reading presence with values absent or present .
</ul>
</ul>
2017-09-18 12:46:57 +00:00
<ul>
<ul>
<li> wakeOnLanMAC </li>
Network MAC Address of the LG TV Networkdevice .
</ul>
</ul>
<ul>
<ul>
<li> wakeOnLanBroadcast </li>
Broadcast Address of the Network - wakeOnLanBroadcast & lt ; network & gt ; .255
</ul>
</ul>
2022-01-04 10:09:16 +00:00
<ul>
2019-06-20 17:51:26 +00:00
<ul>
<li> wakeupCmd </li>
Set a command to be executed when turning on an absent device . Can be an FHEM command or Perl command in { } .
</ul>
2019-06-20 18:35:49 +00:00
</ul>
2017-02-28 09:22:17 +00:00
</ul>
2017-02-23 11:53:19 +00:00
= end html
= begin html_DE
< a name = "LGTV_WebOS" > </a>
<h3> LGTV_WebOS </h3>
<ul>
<ul>
Dieses Modul steuert SmartTV ' s des Herstellers LG mit dem Betriebssystem WebOS & uuml ; ber die Netzwerkschnittstelle . Es bietet die M & ouml ; glichkeit den aktuellen TV Kanal zu steuern , sowie Apps zu starten , Fernbedienungsbefehle zu senden , sowie den aktuellen Status abzufragen .
</ul>
2017-02-28 09:22:17 +00:00
<p> < br /><br / > <strong> Definition </strong> <code> define & lt ; name & gt ; LGTV_WebOS & lt ; IP - Addresse & gt ; </code> < br /><br / > </p>
2017-02-23 11:53:19 +00:00
<ul>
<ul>
<ul> Bei der Definition eines LGTV_WebOS - Moduls wird eine interne Routine in Gang gesetzt , welche regelm & auml ; & szlig ; ig alle 15 s den Status des TV abfragt und entsprechende Notify - /FileLog-Definitionen triggert.</ ul >
</ul>
</ul>
<ul>
<ul>
<ul> Beispiel: <code> define TV LGTV_WebOS 192.168 .0 .10 < br /></co de > < br /><br / > </ul>
</ul>
</ul>
<strong> Set - Kommandos </strong> <code> set & lt ; Name & gt ; & lt ; Kommando & gt ; [ & lt ; Parameter & gt ; ] </code>
<ul>
<ul>
<ul> Aktuell werden folgende Kommandos unterst & uuml ; tzt . </ul>
</ul>
</ul>
<ul>
<ul>
<ul>
<ul>
<li> <strong> connect & nbsp ; </strong> - & nbsp ; Verbindet sich zum Fernseher unter der IP wie definiert , f & uuml ; hrt beim ersten mal automatisch ein pairing durch </li>
<li> <strong> pairing & nbsp ; </strong> - & nbsp ; & nbsp ; Berechtigungsanfrage an den Fernseher , hier muss die Anfrage mit der Fernbedienung best & auml ; tigt werden </li>
<li> <strong> screenMsg </strong> & lt ; Text & gt ; & nbsp ; & nbsp ; - & nbsp ; & nbsp ; zeigt f & uuml ; r ca 3 - 5 s eine Nachricht auf dem Fernseher oben rechts an </li>
<li> <strong> mute </strong> on , off & nbsp ; - & nbsp ; Schaltet den Fernseher Stumm , je nach Anschluss des Audiosignals , muss dieses am Verst & auml ; rker ( AV Receiver ) geschehen ( siehe Volume ) </li>
<li> <strong> volume </strong> 0 - 100 , Schieberegler & nbsp ; - & nbsp ; & nbsp ; Setzt die Lautst & auml ; rke des Fernsehers , je nach Anschluss des Audiosignals , muss dieses am Verst & auml ; rker ( AV Receiver ) geschehen ( siehe mute ) </li>
<li> <strong> volumeUp </strong> & nbsp ; - & nbsp ; & nbsp ; Erh & ouml ; ht die Lautst & auml ; rke um den Wert 1 </li>
<li> <strong> volumeDown </strong> & nbsp ; - & nbsp ; & nbsp ; Verringert die Lautst & auml ; rke um den Wert 1 </li>
<li> <strong> channelUp </strong> & nbsp ; & nbsp ; - & nbsp ; & nbsp ; Schaltet auf den n & auml ; chsten Kanal um </li>
<li> <strong> channelDown </strong> & nbsp ; & nbsp ; - & nbsp ; & nbsp ; Schaltet auf den vorherigen Kanal um </li>
<li> <strong> getServiceList & nbsp ; </strong> - & nbsp ; Fragrt die Laufenden Dienste des Fernsehers an ( derzeit noch in Beta - Phase ) </li>
<li> <strong> on </strong> & nbsp ; - & nbsp ; & nbsp ; Schaltet den Fernseher ein , wenn WLAN oder LAN ebenfalls im Aus - Zustand aktiv ist ( siehe Bedienungsanleitung da Typabh & auml ; ngig ) </li>
<li> <strong> off </strong> - Schaltet den Fernseher aus , wenn eine Connection aktiv ist </li>
<li> <strong> launchApp </strong> & lt ; Anwendung & gt ; & nbsp ; & nbsp ; - & nbsp ; & nbsp ; Aktiviert eine Anwendung aus der Liste ( Maxdome , AmazonVideo , YouTube , Netflix , TV , GooglePlay , Browser , Chili , TVCast , Smartshare , Scheduler , Miracast , TV ) & nbsp ; < br />Achtung: TV ist hier eine Anwendung, und kein Geräteeingang</ li >
<li> <strong> 3 D </strong> on , off & nbsp ; - & nbsp ; 3 D Modus kann hier ein - und ausgeschaltet werden , je nach Fernseher k & ouml ; nnen mehrere 3 D Modi unterst & uuml ; tzt werden ( z . B . Side - by - Side , Top - Bottom ) </li>
<li> <strong> stop </strong> & nbsp ; - & nbsp ; & nbsp ; Stop - Befehl ( anwendungsabh & auml ; ngig ) </li>
<li> <strong> play & nbsp ; </strong> - & nbsp ; & nbsp ; Play - Befehl ( anwendungsabh & auml ; ngig ) </li>
<li> <strong> pause & nbsp ; </strong> - & nbsp ; & nbsp ; Pause - Befehl ( anwendungsabh & auml ; ngig ) </li>
<li> <strong> rewind & nbsp ; </strong> - & nbsp ; & nbsp ; Zur & uuml ; ckspulen - Befehl ( anwendungsabh & auml ; ngig ) </li>
<li> <strong> fastForward & nbsp ; </strong> - & nbsp ; & nbsp ; Schneller - Vorlauf - Befehl ( anwendungsabh & auml ; ngig ) </li>
<li> <strong> clearInputList & nbsp ; </strong> - & nbsp ; & nbsp ; L & ouml ; scht die Liste der Ger & auml ; teeing & auml ; nge </li>
<li> <strong> input & nbsp ; </strong> - W & auml ; hlt den Ger & auml ; teeingang aus ( Abh & auml ; ngig von Typ und angeschossenen Ger & auml ; ten ) < br />Beispiele: extInput_AV-1, extInput_HDMI-1, extInput_HDMI-2, extInput_HDMI-3)</ li >
</ul>
</ul>
</ul>
</ul>
<p> <strong> Get - Kommandos </strong> <code> get & lt ; Name & gt ; & lt ; Readingname & gt ; </code> < br /><br / > </p>
<ul>
<ul>
<ul> Aktuell stehen via GET lediglich die Werte der Readings zur Verf & uuml ; gung . Eine genaue Auflistung aller m & ouml ; glichen Readings folgen unter "Generierte Readings/Events" . </ul>
</ul>
</ul>
<p> < br /><br / > <strong> Attribute </strong> </p>
<ul>
<ul>
<ul>
<li> disable </li>
Optionales Attribut zur Deaktivierung des zyklischen Status - Updates . Ein manuelles Update via statusRequest - Befehl ist dennoch m & ouml ; glich .
</ul>
</ul>
</ul>
<ul>
<ul>
<ul> M & ouml ; gliche Werte: 0 = & gt ; zyklische Status - Updates , 1 = & gt ; keine zyklischen Status - Updates . </ul>
</ul>
</ul>
<ul>
<ul>
<ul>
<li> channelGuide </li>
Optionales Attribut zur Deaktivierung der zyklischen Updates des TV - Guides , dieses beansprucht je nach Hardware einigen Netzwerkverkehr und Prozessorlast
</ul>
</ul>
</ul>
<ul>
2017-04-18 09:27:57 +00:00
<ul>
<ul> M & ouml ; gliche Werte: 0 = & gt ; keine zyklischen TV - Guide - Updates , 1 = & gt ; zyklische TV - Guide - Updates </ul>
</ul>
2017-02-23 11:53:19 +00:00
</ul>
2017-09-18 12:46:57 +00:00
<ul>
<ul>
<ul>
<li> wakeOnLanMAC </li>
MAC Addresse der Netzwerkkarte vom LG TV
</ul>
</ul>
</ul>
<ul>
<ul>
<ul>
<li> wakeOnLanBroadcast </li>
Broadcast Netzwerkadresse - wakeOnLanBroadcast & lt ; netzwerk & gt ; .255
</ul>
</ul>
</ul>
2022-01-04 20:44:00 +00:00
<ul>
<ul>
<ul>
<li> pingPresence </li>
M & ouml ; gliche Werte: 0 = & gt ; presence via ping deaktivert , 1 = & gt ; presence via ping aktiviert
</ul>
</ul>
</ul>
2022-01-04 10:09:16 +00:00
<ul>
2019-06-20 17:51:26 +00:00
<ul>
<ul>
<li> wakeupCmd </li>
Befehl zum Einschalten des LG TV . M & ouml ; glich ist ein FHEM Befehl oder Perl in { } .
</ul>
</ul>
2022-01-04 10:09:16 +00:00
</ul>
2017-02-23 11:53:19 +00:00
<p> < br /><br / > <strong> Generierte Readings /Events:</s trong > </p>
<ul>
<ul>
<li> <strong> 3 D </strong> - Status des 3 D - Wiedergabemodus ( "on" = & gt ; 3 D Wiedergabemodus aktiv , "off" = & gt ; 3 D Wiedergabemodus nicht aktiv ) </li>
<li> <strong> 3 DMode </strong> - Anzeigemodus ( 2 d , 2 dto3d , side_side_half , line_interleave_half , column_interleave , check_board ) </li>
<li> <strong> channel </strong> - Die Nummer des aktuellen TV - Kanals </li>
<li> <strong> channelName </strong> - Der Name des aktuellen TV - Kanals </li>
<li> <strong> channelMedia </strong> - Senderinformation </li>
<li> <strong> channelCurrentEndTime </strong> - Ende der laufenden Sendung ( Beta ) </li>
<li> <strong> channelCurrentStartTime </strong> - Start der laufenden Sendung ( Beta ) </li>
<li> <strong> channelCurrentTitle </strong> - Der Name der laufenden Sendung ( Beta ) </li>
<li> <strong> channelNextEndTime </strong> - Ende der n & auml ; chsten Sendung ( Beta ) </li>
<li> <strong> channelNextStartTime </strong> - Start der n & auml ; chsten Sendung ( Beta ) </li>
<li> <strong> channelNextTitle </strong> - Der Name der n & auml ; chsten Sendung ( Beta ) </li>
<li> <strong> extInput_ & lt ; Ger & auml ; teeingang </strong> & gt ; - Status der Eingangsquelle ( connect_true , connect_false ) </li>
<li> <strong> input </strong> - Derzeit aktiver Ger & auml ; teeingang </li>
<li> <strong> lastResponse </strong> - Status der letzten Anfrage ( ok , error & lt ; Fehlertext & gt ; ) </li>
<li> <strong> launchApp </strong> & lt ; Anwendung & gt ; - Gegenw & auml ; rtige aktive Anwendung </li>
<li> <strong> lgKey </strong> - Der Client - Key , der f & uuml ; r die Verbindung verwendet wird </li>
<li> <strong> mute </strong> on , off - Der aktuelle Stumm - Status ( "on" = & gt ; Stumm , "off" = & gt ; Laut ) </li>
<li> <strong> pairing </strong> paired , unpaired - Der Status des Pairing </li>
<li> <strong> presence </strong> absent , present - Der aktuelle Power - Status ( "present" = & gt ; eingeschaltet , "absent" = & gt ; ausgeschaltet ) </li>
<li> <strong> state </strong> on , off - Status des Fernsehers ( & auml ; hnlich presence ) </li>
<li> <strong> volume </strong> - Der aktuelle Lautst & auml ; rkepegel - 1 , 0 - 100 ( - 1 invalider Wert ) </li>
</ul>
</ul>
</ul>
= end html_DE
2019-07-02 11:00:47 +00:00
= for : application / json ; q = META . json 82 _LGTV_WebOS . pm
2019-07-02 10:14:41 +00:00
{
"abstract" : "Module for Controls LG SmartTVs run with WebOS Operating System" ,
"x_lang" : {
"de" : {
"abstract" : "Modul zur Steuerung von LG SmartTVs mit WebOS Betriebssystem"
}
} ,
"keywords" : [
"fhem-mod-device" ,
"fhem-core" ,
"Multimedia" ,
"TV" ,
"LG"
] ,
2019-07-02 11:00:47 +00:00
"release_status" : "stable" ,
2019-07-02 10:14:41 +00:00
"license" : "GPL_2" ,
2022-01-04 21:01:26 +00:00
"version" : "v3.4.0" ,
2019-07-02 10:14:41 +00:00
"author" : [
2021-12-31 18:30:09 +00:00
"Marko Oldenburg <fhemdevelopment@cooltux.net>"
2019-07-02 10:14:41 +00:00
] ,
"x_fhem_maintainer" : [
"CoolTux"
] ,
"x_fhem_maintainer_github" : [
"LeonGaultier"
] ,
"prereqs" : {
"runtime" : {
"requires" : {
"FHEM" : 5.00918799 ,
"perl" : 5.016 ,
"Meta" : 1 ,
"JSON" : 1 ,
"Date::Parse" : 0
} ,
"recommends" : {
"JSON" : 0
} ,
"suggests" : {
"Cpanel::JSON::XS" : 0 ,
"JSON::XS" : 0
}
}
}
}
= end : application / json ; q = META . json
2017-02-23 11:53:19 +00:00
= cut