From c377a0c628f1ffae4ed82d39f85539bde7c81104 Mon Sep 17 00:00:00 2001 From: betateilchen Date: Fri, 24 Jan 2014 18:45:33 +0000 Subject: [PATCH] changed: complete redesign to use new LL V1.52 functionality git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@4727 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/71_LISTENLIVE.pm | 1039 ++++++++++++++++++------------------ 1 file changed, 515 insertions(+), 524 deletions(-) diff --git a/fhem/FHEM/71_LISTENLIVE.pm b/fhem/FHEM/71_LISTENLIVE.pm index 9f41493d2..6c4b58bb8 100644 --- a/fhem/FHEM/71_LISTENLIVE.pm +++ b/fhem/FHEM/71_LISTENLIVE.pm @@ -48,6 +48,29 @@ # Fixed: Fehlermeldungen wegen ReplaceEventMap # ############################################################################## +# +# modifications for LL firmware V1.5x +# +# 2014-01-24 +# Removed: commandGroup app +# commandGroup reset +# command cursor ok +# readings lastCmd, lastResult +# German commandref documentation +# +# Added: commandGroup message +# command audio reset (reset mute state) +# readings rawCmd, rawResult +# get commands: version volume power +# menuinfo listinfo metatinfo +# attribute llDelay (to adjust communication timimg) +# +# Changed: logging to new Log3 feature +# +# Updated: commandref documentations +# internal help texts +# +############################################################################## package main; @@ -57,11 +80,10 @@ use POSIX; use CGI qw(:standard); use IO::Socket; use IO::Socket::INET; -use MIME::Base64; -use Time::HiRes qw(gettimeofday sleep usleep nanosleep); use HttpUtils; -use feature qw/say switch/; - +use MIME::Base64; +use Time::HiRes qw(gettimeofday sleep usleep); +use feature qw(say switch); sub LISTENLIVE_Set($@); sub LISTENLIVE_Get($@); @@ -80,350 +102,83 @@ pageup => "PAGEUP", pagedn => "PAGEDOWN", ); -# %HMT350_RCtranslate = ( -# power => "POWER", -# mute => "MUTE", -# home => "HOME", -# volplus => "VOLp", -# tvout => "OK", -# up => "UP", -# rewind => "REWIND", -# left => "LEFT", -# ok => "OK", -# right => "RIGHT", -# down => "DOWN", -# "return" => "RETURN", -# volmin => "VOLm", -# stop => "STOP", -# pageup => "PAGEUP", -# pause => "PAUSE", -# itv => "ITV", -# pagedn => "PAGEDOWN", -# menu => "MENU", -# fav => "OK", -# fmradio => "FMRADIO", -# ); +my @appList = ( +'mainmenu', +'internet tv app', +'internet radio app', +'shoutcast app', +'podcast app', +'mediaplayer app', +'linein', +'fm app', +'clock app', +'settings app', +'tv out', +'audio player', +'video player', +'about screen', +'keyboard is onscreen', +'weather app', +'news app', +'twitter app', +'blubrry app', +'media player selection', +'weather location selection', +'popup', +'stocks app', +'calendar', +'soundcloud', +'n/a', +'n/a', +'usatoday', +'revision3', +'n/a', +'n/a', +'n/a', +'vodcast', +'favorites', +'night stand', +'submenu', +'n/a', +'icecast', +'tunein', +'101.ru', +'tuner app', +'rad.io', +'live365', +'chinaradio', +'homeradio', +'steamcast', +'anyradio', +'qingting', +'lautfm'); ################################### -sub -LISTENLIVE_Initialize($) -{ +sub LISTENLIVE_Initialize($) { my ($hash) = @_; - $hash->{GetFn} = "LISTENLIVE_Get"; - $hash->{SetFn} = "LISTENLIVE_Set"; $hash->{DefFn} = "LISTENLIVE_Define"; $hash->{UndefFn} = "LISTENLIVE_Undefine"; + $hash->{AttrFn} = "LISTENLIVE_Attr"; + $hash->{SetFn} = "LISTENLIVE_Set"; + $hash->{GetFn} = "LISTENLIVE_Get"; $hash->{AttrList} = "do_not_notify:0,1 ". + "llDelay ". $readingFnAttributes; $data{RC_layout}{HMT350} = "HMT350_RClayout"; $data{RC_makenotify}{LISTENLIVE}= "HMT350_RCmakenotify"; } -################################### -sub -LISTENLIVE_Set($@) -{ - my ($hash, @a) = @_; - my $name = $hash->{NAME}; - my $address = $hash->{helper}{ADDRESS}; - my $loglevel = GetLogLevel($name, 3); - my $result; - my $response; - - return "No Argument given!\n\n".LISTENLIVE_HelpSet() if(!defined($a[1])); - - my %powerGroup = (on => "POWER", off => "POWER"); - my %muteGroup = (on => "MUTE", off => "MUTE"); - my %cursorGroup = (left => "LEFT", right => "RIGHT", up => "UP", down => "DOWN", home => "HOME", enter => "OK", ok => "OK", "exit" => "RETURN"); - my %audioGroup = (mute => "MUTE", unmute => "MUTE", volp => "VOLp", volm => "VOLm"); - - my $pstat = $hash->{READINGS}{power}{VAL}; - my $mute = $hash->{READINGS}{mute}{VAL}; - -# my @b = split(/\./, $a[1]); -# my $cmdGroup = $b[0]; -# my $cmd = $b[1]; -# if(!defined($cmd) && defined($a[2])) { $cmd = $a[2]; } - - my $cmdGroup = $a[1]; - my $cmd = $a[2]; - - my $usage = "Unknown argument, choose one of help:noArg statusRequest:noArg ". - "power:on,off audio:volp,volm,mute,unmute cursor:up,down,left,right,enter,exit,home,ok ". - "reset:power,mute,menupos app:weather raw user"; - - given ($cmdGroup){ - -# -# commandGroup = rc -# verarbeitet Steuerbefehle aus 95_remotecontrol -# - - when("rc"){ - - my ($c, $g); - $g = "raw"; - # prüfen ob Befehl in Kleinbuchstaben, - # wenn ja => übersetzen! - if($cmd eq lc($cmd)){ - $c = $HMT350_RCtranslate{$cmd}; - Log $loglevel, "LISTENLIVE $name rc_translate: >$cmdGroup $cmd< translated to: >$g $c<"; - } else { - $c = $cmd; - } - fhem("set $name $g $c"); - break; - } - -# -# commandGroup = user -# ruft eine userdefinierte Funktion, z.B. aus 99_myUtils.pm auf -# - - when("user"){ - - if(defined($cmd)){ - Log $loglevel, "LISTENLIVE $name input: $cmdGroup $cmd"; - no strict 'refs'; - $result = &{$cmd}; - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd","$cmdGroup $cmd"); - readingsBulkUpdate($hash, "lastResult",$result); - readingsEndUpdate($hash, 1); - } else { - return $usage; - } - break; - } - -# -# commandGroup = raw -# sendet einfach das per http an das Gerät -# - - when("raw"){ - - if(defined($cmd)){ - Log $loglevel, "LISTENLIVE $name input: $cmdGroup $cmd"; - $result = LISTENLIVE_SendCommand($hash, $cmd); - if($result =~ m/OK/){ - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd","$cmdGroup $cmd"); - readingsBulkUpdate($hash, "lastResult",$result); - readingsEndUpdate($hash, 1); - } else { - LISTENLIVE_rbuError($hash, $cmdGroup, $cmd); - } - } else { - return $usage; - } - break; - } - -# -# commandGroup = reset | -# setzt den Status von power und mute auf unbekannt, -# der nächste Befehl setzt den Status dann neu -# - - when("reset"){ - - Log $loglevel, "LISTENLIVE $name input: $cmdGroup $cmd"; - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd","$cmdGroup $cmd"); - readingsBulkUpdate($hash, "lastResult","OK"); - readingsBulkUpdate($hash, $cmd,"???"); - readingsEndUpdate($hash, 1); - break; - } - -# -# commandGroup power | -# Es wird vor dem Senden geprüft, ob der Befehl Sinn macht -# - - when("power"){ - - my $xCmd; - Log $loglevel, "LISTENLIVE $name input: $cmdGroup $cmd"; - if($pstat ne $cmd) { - $xCmd = $powerGroup{$cmd}; - $result = LISTENLIVE_SendCommand($hash, $xCmd); - if($result =~ m/OK/){ - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd","$cmdGroup $cmd"); - readingsBulkUpdate($hash, "lastResult",$result); - readingsBulkUpdate($hash, "power",$cmd); - if($cmd eq "on"){ - readingsBulkUpdate($hash, "mute", "off"); - } - readingsEndUpdate($hash, 1); - } else { - LISTENLIVE_rbuError($hash, $cmdGroup, $cmd); - } - } else { - LISTENLIVE_rbuError($hash, $cmdGroup, $cmd, " => device already $cmd!"); - } - break; - } - -# -# commandGroup audio ||| -# - - when("audio"){ - - Log $loglevel, "LISTENLIVE $name input: $cmdGroup $cmd"; - if($mute ne $cmd) { - my $xCmd = $audioGroup{$cmd}; - $result = LISTENLIVE_SendCommand($hash, $xCmd); - if($result =~ m/OK/){ - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd","$cmdGroup $cmd"); - readingsBulkUpdate($hash, "lastResult",$result); - if($cmd eq "mute"){ - readingsBulkUpdate($hash, "mute", "on"); - } else { - readingsBulkUpdate($hash, "mute", "off"); - } - readingsEndUpdate($hash, 1); - } else { - LISTENLIVE_rbuError($hash, $cmdGroup, $cmd); - } - } else { - LISTENLIVE_rbuError($hash, $cmdGroup, $cmd, " => no action required!"); - } - break; - } - -# -# commandGroup cursor ||||home||| -# - - when("cursor"){ - - Log $loglevel, "LISTENLIVE: $name input: $cmdGroup $cmd"; - my $xCmd = $cursorGroup{$cmd}; - $result = LISTENLIVE_SendCommand($hash, $xCmd); - if($result =~ m/OK/){ - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd","$cmdGroup $cmd"); - readingsBulkUpdate($hash, "lastResult",$result); - readingsEndUpdate($hash, 1); - } else { - LISTENLIVE_rbuError($hash, $cmdGroup, $cmd); - } - break; - } - -# -# AREA app -# - - when ("app"){ - - given($cmd){ - - when("weather"){ - Log $loglevel, "LISTENLIVE $name input: $cmdGroup $cmd"; - $result = LISTENLIVE_SendCommand($hash, "POWER"); - select(undef, undef, undef, 1.0); - $result = LISTENLIVE_SendCommand($hash, "HOME"); - select(undef, undef, undef, 0.2); - $result = LISTENLIVE_SendCommand($hash, "DOWN"); - select(undef, undef, undef, 0.2); - $result = LISTENLIVE_SendCommand($hash, "DOWN"); - select(undef, undef, undef, 0.2); - $result = LISTENLIVE_SendCommand($hash, "RIGHT"); - select(undef, undef, undef, 0.2); - $result = LISTENLIVE_SendCommand($hash, "OK"); - - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd",$a[1]); - readingsBulkUpdate($hash, "lastResult","done"); - readingsEndUpdate($hash, 1); - } # end doit.weather - - default: - { return $usage; } - } - } - - when("statusRequest") { break; } # wird automatisch aufgerufen! - when("present") { break; } - when("absent") { break; } - when("online") { break; } - when("offline") { break; } - when("help") { return LISTENLIVE_HelpSet(); } - when("?") { return $usage; } - default: { return $usage; } - - } - - LISTENLIVE_GetStatus($hash, 1); - - return $response; -} - -################################### -sub -LISTENLIVE_Get($@){ - my ($hash, @a) = @_; - my $name = $hash->{NAME}; - my $address = $hash->{helper}{ADDRESS}; - my ($response, $usage); - - return "No Argument given" if(!defined($a[1])); - - my $cmdGroup = $a[1]; - my $cmd = $a[2]; - - given($cmdGroup){ - when("?") { return $usage; } - when("help") { $response = LISTENLIVE_HelpGet(); } - default: { return $usage; } - } - return $response; -} - -################################### -sub -LISTENLIVE_GetStatus($;$){ - my ($hash, $local) = @_; - my $name = $hash->{NAME}; - my $presence; - - $local = 0 unless(defined($local)); - - if($hash->{helper}{ADDRESS} ne "none") - { $presence = ReadingsVal("pres_".$name,"state","absent"); } - else - { $presence = "present"; } - - if($presence eq "absent") { $presence = "offline";} - else { $presence = "online"; } - - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "state", $presence); - readingsEndUpdate($hash, 1); - - $hash->{STATE} = $presence; - - InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "LISTENLIVE_GetStatus", $hash, 0) unless($local == 1); - return 1; -} - -############################# -sub -LISTENLIVE_Define($$){ +sub LISTENLIVE_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $name = $hash->{NAME}; my ($cmd, $presence, $ret); + $hash->{HELPER}{DELAY} = 1000; + if(! @a >= 4){ my $msg = "wrong syntax: define LISTENLIVE [:] []"; - Log 2, $msg; + Log3($name, 2, $msg); return $msg; } @@ -448,12 +203,12 @@ LISTENLIVE_Define($$){ $cmd = "pres_$name PRESENCE lan-ping $address[0]"; $ret = CommandDefine(undef, $cmd); if($ret){ - Log 2, "LISTENLIVE ERROR $ret"; + Log3($name, 2, "LISTENLIVE ERROR $ret"); } else { - Log 3, "LISTENLIVE $name PRESENCE pres_$name created."; + Log3($name, 3, "LISTENLIVE $name PRESENCE pres_$name created."); } } else { - Log 3, "LISTENLIVE $name PRESENCE pres_$name found."; + Log3($name, 3, "LISTENLIVE $name PRESENCE pres_$name found."); } $presence = "absent"; } else { @@ -461,66 +216,385 @@ LISTENLIVE_Define($$){ $presence = "present"; # dummy immer als online melden } - if($presence eq "absent") { $presence = "offline"; } else { $presence = "online"; } -# Readings anlegen und füllen - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd",""); - readingsBulkUpdate($hash, "lastResult",""); - readingsBulkUpdate($hash, "mute","???"); - readingsBulkUpdate($hash, "power","???"); - readingsBulkUpdate($hash, "state",$presence); - readingsEndUpdate($hash, 1); - - $hash->{helper}{AVAILABLE} = 1; - $hash->{STATE} = $presence; + readingsSingleUpdate($hash, "state",$presence, 1); InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "LISTENLIVE_GetStatus", $hash, 0); + $hash->{helper}{AVAILABLE} = 1; return; } -############################# -sub -LISTENLIVE_SendCommand($$;$){ - my ($hash, $command, $loglevel) = @_; +sub LISTENLIVE_Undefine($$) { + my($hash, $name) = @_; + RemoveInternalTimer($hash); + return undef; +} + +sub LISTENLIVE_Attr($@) { + my @a = @_; + my $hash = $defs{$a[1]}; + my (undef, $name, $attrName, $attrValue) = @a; + + given($attrName){ + when("llDelay"){ + if($attrValue ~~[1..50]) { + $attr{$name}{$attrName} = $attrValue; + } else { + $attr{$name}{$attrName} = 1; + } + $hash->{HELPER}{DELAY} = 1000 * $attrValue; + break; + } + default {$attr{$name}{$attrName} = $attrValue;} + } + + $hash->{HELPER}{DELAY} = 1000 if $hash->{HELPER}{DELAY} < 1000; + + return ""; + +} + +sub LISTENLIVE_Set($@) { + my ($hash, @a) = @_; + my $name = $hash->{NAME}; + my $address = $hash->{helper}{ADDRESS}; + my $result; + my $response; + + return "No Argument given!\n\n".LISTENLIVE_HelpSet() if(!defined($a[1])); + + my %powerGroup = (on => "POWER", off => "POWER"); + my %muteGroup = (on => "MUTE", off => "MUTE"); + my %cursorGroup = (left => "LEFT", right => "RIGHT", up => "UP", down => "DOWN", home => "HOME", ok => "OK", "exit" => "RETURN"); + my %audioGroup = (mute => "MUTE", unmute => "MUTE", volp => "VOLp", volm => "VOLm"); + + my $pstat = $hash->{READINGS}{power}{VAL}; + my $mute = $hash->{READINGS}{mute}{VAL}; + + my $cmdGroup = lc($a[1]); + my $cmd = $a[2]; + + my $usage = "Unknown argument, choose one of help:noArg statusRequest:noArg ". + "power:on,off audio:volp,volm,mute,unmute,reset cursor:up,down,left,right,enter,exit,home ". + "message raw user"; + + given ($cmdGroup){ + +# +# commandGroup power | +# Es wird vor dem Senden geprüft, ob der Befehl Sinn macht +# + + when("power"){ + + my $xCmd; + Log3($name, 3, "LISTENLIVE $name input: $cmdGroup $cmd"); + if($pstat ne $cmd) { + $xCmd = $powerGroup{$cmd}; + $result = LISTENLIVE_SendCommand($hash, $xCmd); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "power",$cmd); + if($cmd eq "on"){ + readingsBulkUpdate($hash, "mute", "off"); + } + readingsEndUpdate($hash, 1); + } else { + LISTENLIVE_rbuError($hash, $cmdGroup, $cmd); + } + } else { + LISTENLIVE_rbuError($hash, $cmdGroup, $cmd, " => device already $cmd!"); + } + break; + } + +# +# commandGroup cursor ||||home||| +# + + when("cursor"){ + + Log3($name, 3, "LISTENLIVE: $name input: $cmdGroup $cmd"); + my $xCmd = $cursorGroup{$cmd}; + $result = LISTENLIVE_SendCommand($hash, $xCmd); + if($result =~ m/OK/){ + usleep($hash->{HELPER}{DELAY}); + } else { + LISTENLIVE_rbuError($hash, $cmdGroup, $cmd); + } + break; + } + +# +# commandGroup audio |||| +# + + when("audio"){ + + Log3($name, 3, "LISTENLIVE $name input: $cmdGroup $cmd"); + if($mute ne $cmd) { + my $xCmd = $audioGroup{$cmd}; + $result = LISTENLIVE_SendCommand($hash, $xCmd); + if($result =~ m/OK/){ + given($cmd) { + when ('mute'){ + readingsSingleUpdate($hash, "mute", "on", 1); + } + when ('unmute'){ + readingsSingleUpdate($hash, "mute", "off", 1); + } + when ('reset'){ + readingsSingleUpdate($hash, "mute", "???", 1); + } + } + } else { + LISTENLIVE_rbuError($hash, $cmdGroup, $cmd); + } + } else { + LISTENLIVE_rbuError($hash, $cmdGroup, $cmd, " => no action required!"); + } + break; + } + +# +# commandGroup = message [] +# gibt eine Textnachricht als PopUp aus. +# wird die textMessage weggelassen, wird ein eventuell +# vorhandenes PopUp geschlossen. +# Mehrere message-Befehle nacheinander überschreiben jeweils +# den Inhalt eines noch geöffneten PopUps +# + + when("message"){ + if(defined($cmd)){ + my $as = @a; + for (my $i=3; $i<$as;$i++){ + $cmd .= " $a[$i]"; + } + Log3($name, 3, "LISTENLIVE $name input: $cmdGroup $cmd"); + $result = LISTENLIVE_SendCommand($hash, "MESSAGE ".$cmd); + } else { +# ll_menuinfo($hash); + usleep($hash->{HELPER}{DELAY}); + my $mi_state = ReadingsVal($name, "mi_state",0); + # Popup schließen, falls vorhanden + fhem("set $name cursor ok") if $mi_state == 21; + } + break; + } + +# +# commandGroup = raw +# sendet einfach das per http an das Gerät +# + + when("raw"){ + + if(defined($cmd)){ + Log3($name, 3, "LISTENLIVE $name input: $cmdGroup $cmd"); + $result = LISTENLIVE_SendCommand($hash, $cmd); + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "rawCmd","$cmdGroup $cmd"); + readingsBulkUpdate($hash, "rawResult",$result); + readingsEndUpdate($hash, 1); + } else { + return $usage; + } + break; + } + +# +# commandGroup = rc +# verarbeitet Steuerbefehle aus 95_remotecontrol +# + + when("rc"){ + + my ($c, $g); + $g = "raw"; + # prüfen ob Befehl in Kleinbuchstaben, + # wenn ja => übersetzen! + if($cmd eq lc($cmd)){ + $c = $HMT350_RCtranslate{$cmd}; + Log3($name, 3, "LISTENLIVE $name rc_translate: >$cmdGroup $cmd< translated to: >$g $c<"); + } else { + $c = $cmd; + } + fhem("set $name $g $c"); + break; + } + +# +# commandGroup = user +# ruft eine userdefinierte Funktion, z.B. aus 99_myUtils.pm auf +# + + when("user"){ + + if(defined($cmd)){ + Log3($name, 3, "LISTENLIVE $name input: $cmdGroup $cmd"); + no strict 'refs'; + $result = &{$cmd}; + } else { + return $usage; + } + break; + } + + when("statusRequest") { break; } # wird automatisch aufgerufen! + when("help") { return LISTENLIVE_HelpSet(); } + when("?") { return $usage; } + default: { return $usage; } + + } + + ll_version($hash); + ll_power($hash); + ll_volume($hash); + ll_menuinfo($hash); + ll_listinfo($hash); + ll_metainfo($hash); + + return; +} + +sub LISTENLIVE_Get($@) { + my ($hash, @a) = @_; + my $name = $hash->{NAME}; + my $address = $hash->{helper}{ADDRESS}; + my ($response, $result); + + return "No Argument given" if(!defined($a[1])); + + my $usage = "Unknown argument, choose one of help:noArg ". + "version:noArg volume:noArg menuinfo:noArg ". + "power:noArg listinfo:noArg metainfo:noArg" ; + + my $cmdGroup = lc($a[1]); +# my $cmd = $a[2]; + + given($cmdGroup) { + + when("?") { + return $usage; + } + + when("help") { + $response = LISTENLIVE_HelpGet(); + } + + when("version") { + ll_version($hash); + } + + when("volume") { + ll_volume($hash); + } + + when("menuinfo") { + ll_menuinfo($hash); + } + + when("metainfo") { + ll_metainfo($hash); + } + + when("listinfo") { + ll_listinfo($hash); + } + + when("power") { + ll_power($hash); + } + + default: { + return $usage; + } + + } + return $response; +} + +sub LISTENLIVE_GetStatus($;$) { + my ($hash, $local) = @_; + my $name = $hash->{NAME}; + my $presence; + + $local = 0 unless(defined($local)); + RemoveInternalTimer($hash); + + if($hash->{helper}{ADDRESS} ne "none") { + $presence = ReadingsVal("pres_".$name,"state","absent"); + } else { + $presence = "present"; + } + + if($presence eq "absent") { + $presence = "offline"; + } else { + $presence = "online"; + } + + readingsSingleUpdate($hash,"state",$presence,1); + + ll_version($hash); + ll_power($hash); + ll_volume($hash); + ll_menuinfo($hash); + ll_listinfo($hash); + ll_metainfo($hash); + + InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "LISTENLIVE_GetStatus", $hash, 0) unless($local == 1); + return 1; +} + +sub LISTENLIVE_SendCommand($$) { + my ($hash, $command) = @_; my $name = $hash->{NAME}; my $address = $hash->{helper}{ADDRESS}; my $port = $hash->{helper}{PORT}; my $response = ""; my $modus = "dummy"; - my ($socket,$client_socket); + my ($socket);#,$client_socket); - $loglevel = GetLogLevel($name, 3) unless(defined($loglevel)); - Log $loglevel, "LISTENLIVE $name command: $command"; + Log3($name, 3, "LISTENLIVE $name command: $command"); if (Value("$name") eq "online" && $hash->{helper}{ADDRESS} ne "none") { $modus = "online"; } if (Value("$name") eq "offline") { $modus = "offline"; } given($modus) { when("online") { + usleep($hash->{HELPER}{DELAY}); eval { $socket = new IO::Socket::INET ( PeerHost => $address, PeerPort => $port, - Proto => 'tcp', + Blocking => 0, + Timeout => 10, + Proto => 'tcp', ) or die "ERROR in Socket Creation : $!\n"; $socket->send($command); - usleep(30000); - $socket->recv($response, 2); - if($response !~ m/OK/) { Log 2, "LISTENLIVE $name error: $response"; } - else { Log $loglevel, "LISTENLIVE $name response: $response"; } + usleep($hash->{HELPER}{DELAY} * 3); + $socket->recv($response, 1024); + my $resplen = length($response); +# Debug "LISTENLIVE $name C: $command R: $response L: $resplen"; + if($response ~~ m/UNK/) { + Log3($name, 2, "LISTENLIVE $name error: $response"); + } else { + Log3($name, 3, "LISTENLIVE $name response: $response"); + } $socket->close(); }; warn $@ if $@; $hash->{helper}{AVAILABLE} = (defined($response) ? 1 : 0); } when("offline") { - Log 2, "LISTENLIVE $name error: device offline!"; + Log3($name, 2, "LISTENLIVE $name error: device offline!"); $response = "device offline!"; } @@ -530,47 +604,43 @@ LISTENLIVE_SendCommand($$;$){ return $response; } -sub -LISTENLIVE_rbuError($$;$$){ +sub LISTENLIVE_rbuError($$;$$){ my ($hash, $cmdGroup, $cmd, $parameter) = @_; - Log 2, "LISTENLIVE $hash->{NAME} error: $cmdGroup $cmd $parameter"; - - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "lastCmd","$cmdGroup $cmd $parameter"); - readingsBulkUpdate($hash, "lastResult","Error: $cmdGroup $cmd $parameter"); - readingsEndUpdate($hash, 1); + $parameter = ' ' if(!defined($parameter)); + Log3($hash, 2, "LISTENLIVE $hash->{NAME} error: $cmdGroup $cmd $parameter"); return undef; } -sub -LISTENLIVE_HelpGet(){ +sub LISTENLIVE_HelpGet() { my $helptext = 'get [] -commandGroup "help" -get llradio help (show this help page)'; +get llradio help (show this help page) + +get llradio power (read powerState) +get llradio version (read version info) +get llradio volume (read volume level) +get llradio menuinfo (read menu infos) +get llradio listinfo (read list infos) +get llradio metainfo (read meta infos from current title)'; return $helptext; } -sub -LISTENLIVE_HelpSet(){ +sub LISTENLIVE_HelpSet() { my $helptext = 'set [] - commandGroup "help" set llradio help (show this help page) - commandGroup "audio" set llradio audio mute set llradio audio unmute set llradio audio volm set llradio audio volp - commandGroup "cursor" set llradio cursor down set llradio cursor left @@ -581,56 +651,98 @@ set llradio cursor exit set llradio cursor home set llradio cursor ok - commandGroup "power" set llradio power off set llradio power on - commandGroup "raw" set llradio raw - commandGroup "reset" set llradio reset mute set llradio reset power - commandGroup "user" (experimental!) set llradio user - -commandGroup "app" (experimental!) -set llradio app weather - - commandGroup "statusRequest" set llradio statusRequest'; return $helptext; } -############################# -sub -LISTENLIVE_Undefine($$){ - my($hash, $name) = @_; - RemoveInternalTimer($hash); - return undef; +#### Funktionen zum Lesen bestimmter Gerätezustände + +sub ll_version($){ + my ($hash) = @_; + my $result = LISTENLIVE_SendCommand($hash, 'VERSION'); + (undef, $result) = split('=',$result); + readingsSingleUpdate($hash, 'version', $result, 0); + return; } -##################################### +sub ll_listinfo($){ + my ($hash) = @_; + my $result = LISTENLIVE_SendCommand($hash, 'LISTINFO'); + readingsSingleUpdate($hash, 'listinfo', $result, 1); + return; +} + +sub ll_metainfo($){ + my ($hash) = @_; + my $result = LISTENLIVE_SendCommand($hash, 'METAINFO'); + my @mi = split('=',$result); + readingsBeginUpdate($hash); + for my $i (1..5){ + $mi[$i] = substr($mi[$i],0,length($mi[$i])-2) if($i != 5 && defined($mi[$i])); + readingsBulkUpdate($hash,"metainfo".$i, $mi[$i]) if(defined($mi[$i])); + } + readingsEndUpdate($hash,1); + return; +} + +sub ll_menuinfo($){ + my ($hash) = @_; + my $result = LISTENLIVE_SendCommand($hash, 'MINFO'); + my @mi = split('=',$result); + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, 'mi_info', $result); + readingsBulkUpdate($hash, 'mi_state', substr($mi[1],0,length($mi[1])-2)) if(defined($mi[1])); + readingsBulkUpdate($hash, 'mi_app', $appList[substr($mi[1],0,length($mi[1])-2)]) if(defined($mi[1])); + readingsBulkUpdate($hash, 'mi_mp', substr($mi[2],0,length($mi[2])-2)) if(defined($mi[2])); + readingsBulkUpdate($hash, 'mi_ms', $mi[3]); + readingsEndUpdate($hash,1); + return; +} + +sub ll_volume($){ + my ($hash) = @_; + my $result = LISTENLIVE_SendCommand($hash, 'VOLUME'); + (undef, $result) = split('=',$result); + readingsSingleUpdate($hash, 'volume', $result, 1); + return; +} + +sub ll_power($){ + my ($hash) = @_; + my $result = LISTENLIVE_SendCommand($hash, 'STATE'); + (undef, $result) = split('=',$result); + readingsSingleUpdate($hash, 'power', $result, 1); + return; +} + +#### Funktionen zur Anbindung an remotecontrol + sub HMT350_RCmakenotify($$) { -# my $loglevel = GetLogLevel($name, 3) unless(defined($loglevel)); my ($nam, $ndev) = @_; my $nname="notify_$nam"; my $cmd = "$nname notify $nam set $ndev rc \$EVENT"; my $ret = CommandDefine(undef, $cmd); - if($ret) { Log 2, "remotecontrol ERROR $ret"; } - else { Log 3, "remotecontrol HMT350: $nname created as notify"; } + if($ret) { Log3(undef, 2, "remotecontrol ERROR $ret"); } + else { Log3(undef, 3, "remotecontrol HMT350: $nname created as notify"); } return "Notify created: $nname"; } -##################################### sub HMT350_RClayout() { my @row; my $rownum = 0; @@ -716,7 +828,9 @@ cursor right
cursor home
cursor exit
cursor enter
-cursor ok
+
+commandGroup message
+message [<textMessage>]
commandGroup reset
reset power
@@ -729,9 +843,6 @@ raw
commandGroup user (experimental)
user

-commandGroup app (experimental)
-app weather
-
commandGroup help
help

@@ -761,12 +872,14 @@ statusRequest

Generated Readings/Events:
    -
  • lastCmd - last command sent to device
  • -
  • lastResult - last response from device
  • -
  • menuPos - cursor position in main menu (experimental)
  • +
  • listinfo - current selection list on device and position in it
  • +
  • metainfo1-5 - metainfo for currently playing stream
  • +
  • mi_info - current menu state
  • +
  • mi_app, mi_mp, mi_ms, mi_state - readings splitted from mi_info, mi_app is derived from numerical mi_state
  • mute - current mute state ("on" => muted, "off" => unmuted)
  • power - current power state
  • state - current device state (online or offline)
  • +
  • volume - current volume level


Author's notes @@ -779,127 +892,5 @@ statusRequest =end html -=begin html_DE - - -

LISTENLIVE

-
    - - - Define -
      - define <name> LISTENLIVE <ip-address>[:<port>] [<status_interval>] -

      - - Dieses Modul steuert Internetradios, die mit der ListenLive Firmware laufen, über die Netzwerkschnittstelle. - Es bietet die Möglichkeit das Gerät an-/auszuschalten, die Lautstärke zu ändern, den Cursor zu steuern, - den Receiver "Stumm" zu schalten, sowie alle Fernbedienungskommandos an das Gerät zu senden. -

      - Die Angabe des TCP-ports ist optional. Fehlt dieser Parameter, wird der Standardwert 8080 verwendet. -

      - Bei der Definition eines LISTENLIVE-Gerätes wird eine interne Routine in Gang gesetzt, welche regelmäßig - (einstellbar durch den optionalen Parameter <status_interval>; falls nicht gesetzt ist der Standardwert 60 Sekunden) - den Status des Gerätes abfragt und entsprechende Notify-/FileLog-Geräte triggert..

      - - Beispiel: -

      -
        - define llradio LISTENLIVE 192.168.0.10

        - - define llradio LISTENLIVE 192.168.0.10:8085 120     # Mit modifiziertem Port (8085) und Status Interval (120 Sekunden) -


      -
    - - - Set-Kommandos -
      - set <Name> <Befehlsgruppe> [<Befehl>] [<Parameter>] -

      - Die Befehle zur Steuerung sind weitgehend in Befehlsgruppen eingeordnet, die sich an logischen Funktionsbereichen orientieren. - Aktuell stehen folgende Befehlsgruppen und Befehele zur Verfügung: -

      -
        -Befehlsgruppe power
        -power on
        -power off
        -
        -Befehlsgruppe audio
        -audio mute
        -audio unmute
        -audio volm
        -audio volp
        -
        -Befehlsgruppe cursor
        -cursor up
        -cursor down
        -cursor left
        -cursor right
        -cursor home
        -cursor exit
        -cursor enter
        -cursor ok
        -
        -Befehlsgruppe reset
        -reset power
        -reset mute
        -reset menupos
        -
        -Befehlsgruppe raw
        -raw
        -
        -Befehlsgruppe user (experimentell)
        -user
        -
        -Befehlsgruppe app (experimentell)
        -app weather
        -
        -Befehlsgruppe help
        -help
        -
        -Befehlsgruppe statusRequest
        -statusRequest -
      -
    -

    - - Get-Kommandos -
      - get <Name> <Parameter> -

      - Aktuell stehen folgende Parameter zur Verfügung:

      -
        -
      • help - zeigt einen Hilfetext an
      • -
      -
    -
    -

    - - Attribute - -

    - Generierte Readings/Events:
    -
      -
    • lastCmd - der letzte gesendete Befehl
    • -
    • lastResult - die letzte Antwort des Gerätes
    • -
    • menuPos - Cursorposition im Hauptmenü (experimentell)
    • -
    • mute - der aktuelle Stumm-Status("on" => Stumm, "off" => Laut)
    • -
    • power - der aktuelle Betriebsstatuse ("on" => an, "off" => aus)
    • -
    • state - der aktuelle Gerätestatus (online oder offline)
    • -
    -

    - Hinweise -
      - Dieses Modul ist nur nutzbar, wenn die Option "remote control settings" -> "network remote control [on]" in der Firmware aktiviert ist. -

      - Während der Definition wird automatisch ein passendes PRESENCE angelegt, um die Verfügbarkeit des Gerätes zu ermitteln. -
      -
    -
- -=end html_DE =cut