diff --git a/fhem/FHEM/71_LISTENLIVE.pm b/fhem/FHEM/71_LISTENLIVE.pm new file mode 100644 index 000000000..be48b4929 --- /dev/null +++ b/fhem/FHEM/71_LISTENLIVE.pm @@ -0,0 +1,1136 @@ +# $Id: $ +############################################################################## +# +# 71_LISTENLIVE.pm +# An FHEM Perl module for controlling ListenLive-enabled Mediaplayers +# via network connection. +# +# Copyright: betateilchen ® +# e-mail : fhem.development@betateilchen.de +# +# This file is part of fhem. +# +# Fhem is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# Fhem is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with fhem. If not, see . +# +############################################################################## +# Changelog: +# 2013-07-21 Logging vereinheitlich +# Meldungen komplett auf englisch umgestellt +# pod (EN) erstellt +# +############################################################################## + +package main; + +#use strict; +use warnings; +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/; + + +sub LISTENLIVE_Set($@); +sub LISTENLIVE_Get($@); +sub LISTENLIVE_Define($$); +sub LISTENLIVE_GetStatus($;$); +sub LISTENLIVE_Undefine($$); + +################################### +sub +LISTENLIVE_Initialize($) +{ + my ($hash) = @_; + + $hash->{GetFn} = "LISTENLIVE_Get"; + $hash->{SetFn} = "LISTENLIVE_Set"; + $hash->{DefFn} = "LISTENLIVE_Define"; + $hash->{UndefFn} = "LISTENLIVE_Undefine"; + + $hash->{AttrList} = "do_not_notify:0,1 loglevel:0,1,2,3,4,5 ". + $readingFnAttributes; +} + +################################### +sub +LISTENLIVE_Set($@) +{ + my ($hash, @a) = @_; + my $name = $hash->{NAME}; + my $address = $hash->{helper}{ADDRESS}; + my $loglevel = GetLogLevel($name, 3); + my $result; + my $response; + my $command; + + return "No Argument given!\n\n".LISTENLIVE_HelpSet() if(!defined($a[1])); + + my $pstat = $hash->{READINGS}{power}{VAL}; + my $mute = $hash->{READINGS}{mute}{VAL}; + +# my @b = split(/\./, $a[1]); +# my $area = $b[0]; +# my $doit = $b[1]; +# if(!defined($doit) && defined($a[2])) { $doit = $a[2]; } + + my $area = $a[1]; + my $doit = $a[2]; + + my $usage = "Unknown argument, choose one of help statusRequest 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 ($area){ + +# +# AREA = user +# ruft eine userdefinierte Funktion, z.B. aus 99_myUtils.pm auf +# + + when("user"){ + if(defined($doit)){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = &{$doit}; + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsEndUpdate($hash, 1); + } + else + { return $usage; } + break; + } # end user + +# +# AREA = raw +# sendet einfach das per http an das Gerät +# und schreibt die Rückmeldung in das Reading "rawresult" +# (hauptsächlich für Debugging vorgesehen) +# + + when("raw"){ + if(defined($doit)){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, $doit); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + } + else + { return $usage; } + break; + } # end raw + +# +# AREA = reset || +# sendet gnadenlos ein POWER oder MUTE oder setzt +# die MENUPOS auf 11 (oben links), damit man eine Chance hat, +# den Gerätestatus zu synchronisieren +# + + when("reset"){ + given($doit){ + when("power"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult","OK"); + readingsBulkUpdate($hash, "power","???"); + readingsEndUpdate($hash, 1); + break; + } # end reset.power + + when("mute"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult","OK"); + readingsBulkUpdate($hash, "mute","???"); + readingsEndUpdate($hash, 1); + break; + } # end reset.mute + + when("menupos"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "HOME"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "menuPos","11"); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end reset.menupos + + default: + { return $usage; } + + } # end doit + + } # end area.reset + +# +# AREA power | +# Es wird vor dem Senden geprüft, ob der Befehl Sinn macht, +# da der gleiche Befehl für das Ein- und Ausschalten +# verwendet wird. +# Ein "power on" wird bei einem eingeschalteten Gerät nicht gesendet +# Ein "power off" wird bei einem ausgeschalteten Gerät nicht gesendet +# Als Basis für die Entscheidung dient das Reading power +# + + when("power"){ + given ($doit){ + when("on") { + if($pstat ne "on"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "POWER"); + if($result =~ m/OK/) + { + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "power","on"); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit, " => device already on!"); + } + break; + } # end power.on + + when("off") { + if($pstat ne "off") + { + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "POWER"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "power","off"); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit, " => device already off!"); + } + break; + } # end power.off + + default: + { return $usage; } + + } # end power.doit + + } # end area.power + +# +# AREA audio ||| +# + + when("audio"){ + given($doit){ + + when("mute"){ + if($mute ne "on"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "MUTE"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "mute","on"); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit, "Already muted!"); + } + break; + } # end mute + + when("unmute"){ + if($mute ne "off"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "MUTE"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "mute","off"); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit, "Already unmuted!"); + } + break; + } # end unmute + + when("volp"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "VOLp"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end volp + + when("volm"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "VOLm"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit"); + readingsBulkUpdate($hash, "lastResult",$result); + readingsEndUpdate($hash, 1); + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end volm + + default: + { return $usage; } + + } # end audio.doit + + } # end area.audio + +# +# AREA cursor ||||home||| +# + + when("cursor"){ + given($doit){ + + when("up"){ + Log $loglevel, "LISTENLIVE $name $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "UP"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "menuPos",$hash->{READINGS}{menuPos}{VAL}-10); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end up + + when("down"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "DOWN"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "menuPos",$hash->{READINGS}{menuPos}{VAL}+10); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end down + + when("left"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "LEFT"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "menuPos",$hash->{READINGS}{menuPos}{VAL}-1); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end left + + when("right"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "RIGHT"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "menuPos",$hash->{READINGS}{menuPos}{VAL}+1); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end right + + when("home"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "HOME"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsBulkUpdate($hash, "menuPos","11"); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit) + } + break; + } # end home + + when("enter"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "OK"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end enter + + when("ok"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "OK"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + break; + } # end ok + + when("exit"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $result = LISTENLIVE_SendCommand($hash, "EXIT"); + if($result =~ m/OK/){ + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",$a[1]); + readingsBulkUpdate($hash, "lastResult",$result); + readingsEndUpdate($hash, 1); + return undef; + } + else + { + LISTENLIVE_rbuError($hash, $area, $doit); + } + } # end cursor.exit + + default: + { return $usage; } + + } # end cursor.doit + + } # end area.cursor + +# +# AREA app +# + + when ("app"){ + given($doit){ + + when("weather"){ + Log $loglevel, "LISTENLIVE $name input: $area $doit"; + $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"); + readingsBulkUpdate($hash, "menuPos", "32"); + readingsEndUpdate($hash, 1); + } # end doit.weather + + default: + { return $usage; } + + } # end doit + + } # end area.app + + when("statusRequest") { break; } # wird automatisch aufgerufen! + + when("?") { return $usage; } + + when("help") { return LISTENLIVE_HelpSet(); } + + when("present") { break; } + when("absent") { break; } + when("online") { break; } + when("offline") { break; } + + default: { return $usage; } + + } # end area + +# Call the GetStatus() Function to retrieve the new values + LISTENLIVE_GetStatus($hash, 1); + + return $response; +} + +################################### +sub +LISTENLIVE_Get($@){ + my ($hash, @a) = @_; + my $name = $hash->{NAME}; + my $address = $hash->{helper}{ADDRESS}; + my $response; + + return "No Argument given" if(!defined($a[1])); + + my @b = split(/\./, $a[1]); + my $area = $b[0]; + my $doit = $b[1]; + + my $usage = "Unknown argument $a[1], choose one of help list:commands"; + + given($area){ + + when("list"){ + + given("$doit"){ + + when("commands"){ + $response = LISTENLIVE_HelpGet(); + break; + } + + default: { return $usage; } + + } # end area.list.doit + + } # end area.list + + when("?") { return $usage; } + + when("help"){ $response = LISTENLIVE_HelpGet(); } + + default: { return $usage; } + + } # end area + +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","noPresence"); + } + else + { + $presence = "present"; + } + + $presence = ReplaceEventMap($name, $presence, 1); + + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "state", $presence); + readingsEndUpdate($hash, 1); + + InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "LISTENLIVE_GetStatus", $hash, 0) unless($local == 1); + return $hash->{STATE}; + +} + +############################# +sub +LISTENLIVE_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + my $name = $hash->{NAME}; + + if(! @a >= 4) + { + my $msg = "wrong syntax: define LISTENLIVE [:] []"; + Log 2, $msg; + return $msg; + } + +# Attribut eventMap festlegen (schönere Optik im Frontend) + $attr{$name}{"eventMap"} = "absent:offline present:online"; + +# Adresse in IP und Port zerlegen + my @address = split(":", $a[2]); + $hash->{helper}{ADDRESS} = $address[0]; + +# falls kein Port angegeben, Standardport 8080 verwenden + $address[1] = "8080" unless(defined($address[1])); + $hash->{helper}{PORT} = $address[1]; + +# falls kein Intervall angegeben, Standardintervall 60 verwenden + my $interval = $a[3]; + $interval = "60" unless(defined($interval)); + $hash->{helper}{INTERVAL} = $interval; + + if($address[0] ne "none") + { + # PRESENCE aus device pres_+NAME lesen + my $presence = ReadingsVal("pres_".$name,"state","noPresence"); + + if($presence eq "noPresence") # PRESENCE nicht vorhanden + { + $cmd = "pres_$name PRESENCE lan-ping $address[0]"; + $ret = CommandDefine(undef, $cmd); + if($ret) + { + Log 2, "LISTENLIVE ERROR $ret"; + } + else + { + Log 3, "LISTENLIVE $name PRESENCE pres_$name created."; + } + } + else + { + Log 3, "LISTENLIVE $name PRESENCE pres_$name found."; + } + } + else # Gerät ist als dummy definiert + { + $presence = "present"; # dummy immer als online melden + } + + $presence = ReplaceEventMap($name, $presence, 1); + +# Readings anlegen und füllen + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd",""); + readingsBulkUpdate($hash, "lastResult",""); + readingsBulkUpdate($hash, "menuPos","11"); + readingsBulkUpdate($hash, "mute","???")); + readingsBulkUpdate($hash, "power","???")); + readingsBulkUpdate($hash, "state",$presence); + readingsEndUpdate($hash, 1); + + $hash->{helper}{AVAILABLE} = 1; + InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "LISTENLIVE_GetStatus", $hash, 0); + +return; +} + +############################# +sub +LISTENLIVE_SendCommand($$;$) +{ + my ($hash, $command, $loglevel) = @_; + my $name = $hash->{NAME}; + my $address = $hash->{helper}{ADDRESS}; + my $port = $hash->{helper}{PORT}; + my $response = ""; + my $modus = "dummy"; + my ($socket,$client_socket); + + $loglevel = GetLogLevel($name, 3) unless(defined($loglevel)); + Log $loglevel, "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") + { + # + # Create a socket object for the communication with the radio + # + $socket = new IO::Socket::INET ( + PeerHost => $address, + PeerPort => $port, + Proto => 'tcp', + ) or die "ERROR in Socket Creation : $!\n"; + + # + # Send the given command into the socket + # + $socket->send($command); + + # + # get the radio some time to execute the command (300ms ) + # + usleep(30000); + + # + # get the answer of the radio + # + $socket->recv($response, 2); + + + if($response !~ m/OK/) + { + Log 2, "LISTENLIVE $name error: $response"; + } + else + { + Log $loglevel, "LISTENLIVE $name response: $response"; + } + + $socket->close(); + + $hash->{helper}{AVAILABLE} = (defined($response) ? 1 : 0); + } + + when("offline") + { + Log 2, "LISTENLIVE $name error: device offline!"; + $response = "device offline!"; + } + + default: + { + $response = "OK"; + } + } + + return $response; +} + +sub +LISTENLIVE_rbuError($$;$$) +{ + my ($hash, $area, $doit, $parameter) = @_; + Log 2, "LISTENLIVE $hash->{NAME} error: $area $doit $parameter"; + + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "lastCmd","$area $doit $parameter"); + readingsBulkUpdate($hash, "lastResult","Error: $area $doit $parameter"); + readingsEndUpdate($hash, 1); + return undef; +} + + +sub +LISTENLIVE_HelpGet() +{ +my $helptext = +'get [] + + +commandGroup "help" +get llradio help (show this help page)'; + +return $helptext; +} + +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 +set llradio cursor up +set llradio cursor right + +set llradio cursor enter +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 menupos +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) = @_; + + # Stop the internal GetStatus-Loop and exist + RemoveInternalTimer($hash); + return undef; +} + +1; + +=pod +=begin html +

LISTENLIVE

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

      + + This module can control all mediaplayers runnng ListenLive Firmware laufen via a network connection. + It can control power state on/off, volume up/down/mute and can send all remomte-control commands. +

      + The port value is optional. If not defined, standard port 8080 will be used. +

      + The status_interval value is optional. If not defined, standard interval 60sec will be used. +

      + Upon the definition of a new LISTENLIVE-device an internal Loop will be defined which will check and update the device readings + all seconds to trigger all notify and FileLog entities. +

      + + Example: +

      +
        + define llradio LISTENLIVE 192.168.0.10

        + + define llradio LISTENLIVE 192.168.0.10:8085 120     # with port (8085) und status interval (120 seconds) +


      +
    + + + Set-Commands +
      + set <name> <commandGroup> [<command>] [<parameter>] +

      + Commands are grouped into commandGroups depending on their functional tasks. + The following groups and commands are currently available: +

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

    + + Get-Commands +
      + get <name> <parameter> +

      + The following parameters are available:

      +
        +
      • help - show help-text
      • +
      +
    +
    +

    + + Attributes + +

    + Generated Readings/Events:
    +
      +
    • lastCmd - last command sent to device
    • +
    • lastResult - last response from device
    • +
    • menuPos - cursor position in main menu (experimental)
    • +
    • mute - current mute state ("on" => muted, "off" => unmuted)
    • +
    • power - current power state
    • +
    • state - current device state (online or offline)
    • +
    +

    + Author's notes +
      + You need to activate option "remote control settings" -> "network remote control [on]" in your device's settings. +

      + Upon the device definion a corresponding PRESENCE-entity will be created to evaluate the device availability. +
      +
    +
+=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