diff --git a/fhem/70_NEUTRINO.pm b/fhem/70_NEUTRINO.pm new file mode 100644 index 000000000..30cbeb47b --- /dev/null +++ b/fhem/70_NEUTRINO.pm @@ -0,0 +1,2022 @@ +# $Id$ +############################################################################ +# 2017-07-12, v1.0.6 +# +# v1.0.6 +# - FEATURE: CommandRef hinzugefügt (DE/EN) +# - BUFIX: Optimierung Refresh Infos Senderwechsel (EPGInfos, input, Bouquetliste) +# Optimierung Refresh EGPInfos (Wenn Sendung vorbei) +# Optimierung Neutrino Version nur auslesen wenn sich das Reading "power" ändert! +# Optimierung Reading time_now / time_raw_now (Wird vom FHEM Server verwendet/ Infos kommen nicht mehr von Neutrino) +# Probleme beim Umschalten von Kanälen mit + Zeichen +# Logeinträge überarbeitet +# div. Codeoptimierungen +# - CHANGE HTTP Standardtimout auf 2 gesetzt +# NEUTRINO_HD_HandleCmdQueue hinzugefügt +# NEUTRINO_HD_SendCommand hinzugefügt +# Nicht verwendete Attribute entfernt +# bouquet-tv +# bouquet-radio +# remotecontrol +# lightMode +# macaddr +# wakeupCmd +# http_method +# +# v1.0.5 BETA5 - 20160626 +# - BUGFIX: clear readings timerlist +# +# v1.0.4 BETA4 - 20160624 +# - BUGFIX: Not an ARRAY reference at ./FHEM/70_NEUTRINO.pm line 1237 +# +# v1.0.3 BETA3 - 20160614 +# - FEATURE: add recordchannel reading +# add recordtitel reading +# +# v1.0.2 BETA2 - 20160613 +# - FEATURE: add timer readings +# +# v1.0.0 BETA1 - 20160612 +# - FEATURE: add recordmode reading +# +# 70_NEUTRINO.pm +# An FHEM Perl module for controlling NEUTRINO based TV receivers +# via network connection. +# +# Copyright by Michael Winkler +# e-mail: michael.winkler at online.de +# +# This file is part of fhem. +# +# Fhem is free software: you can redistribute it andor 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 . +# +############################################################################## + +package main; + +use strict; +use warnings; +use HttpUtils; +use Encode; +use Time::Piece; + +no warnings "all"; + +sub NEUTRINO_Set($@); +sub NEUTRINO_Get($@); +sub NEUTRINO_GetStatus($;$); +sub NEUTRINO_Define($$); +sub NEUTRINO_Undefine($$); + +################################### +sub NEUTRINO_Initialize($) { + my ($hash) = @_; + + Log3 $hash, 5, "NEUTRINO_Initialize: Entering"; + + $hash->{GetFn} = "NEUTRINO_Get"; + $hash->{AttrFn} = "NEUTRINO_Attr"; + $hash->{SetFn} = "NEUTRINO_Set"; + $hash->{DefFn} = "NEUTRINO_Define"; + $hash->{UndefFn} = "NEUTRINO_Undefine"; + + $hash->{AttrList} = +"https:0,1 http-method:absolete http-noshutdown:1,0 disable:0,1 timeout " + . $readingFnAttributes; + + return; +} + +##################################### +# AttrFn +##################################### +sub NEUTRINO_Attr(@) { + + my ( $cmd, $name, $attrName, $attrVal ) = @_; + my $hash = $defs{$name}; + + my $orig = $attrVal; + + if( $attrName eq "bouquet-tv" || $attrName eq "bouquet-radio" || $attrName eq "remotecontrol" || $attrName eq "http-method" || $attrName eq "wakeupCmd" || $attrName eq "macaddr" || $attrName eq "lightMode" ) { + if( $cmd eq "set" ) { + Log3 $name, 3, "NEUTRINO $name [NEUTRINO_Attr] [$attrName] - !!! Attention, the attribut is absolete and will delete in the future"; + return "NEUTRINO $name [NEUTRINO_Attr] [$attrName] - !!! Attention, the attribut is absolete and will delete in the future"; + } + } +} + +##################################### +# Get Status +##################################### +sub NEUTRINO_GetStatus($;$) { + my ( $hash, $update ) = @_; + my $name = $hash->{NAME}; + my $interval = $hash->{INTERVAL}; + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_GetStatus] called function"; + if ($update ne '') {Log3 $name, 5, "NEUTRINO $name [NEUTRINO_GetStatus] Update = $update";} + + RemoveInternalTimer($hash); + InternalTimer( gettimeofday() + $interval, "NEUTRINO_GetStatus", $hash, 0 ); + + return if ( AttrVal( $name, "disable", 0 ) == 1 ); + + if ( !$update ) {NEUTRINO_SendCommand( $hash, "powerstate" );} + + return; +} + +################################### +sub NEUTRINO_SendCommand($$;$$) { + my ( $hash, $service, $cmd, $type ) = @_; + my $name = $hash->{NAME}; + my $address = $hash->{helper}{ADDRESS}; + my $port = $hash->{helper}{PORT}; + my $serviceurl; + my $channelid = ReadingsVal( $name, "channel_id", "" ); + my $param; + + # Cannelname + my $channelname = ReadingsVal( $name, "recordchannel", "" ); + $channelname =~ s/_/%20/g; + + #$cmd = ( defined($cmd) ) ? $cmd : ""; + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_SendCommand] called function CMD = $cmd "; + + my $http_proto; + if ( $port eq "443" ) { + $http_proto = "https"; + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_SendCommand] port 443 implies using HTTPS"; + } + elsif ( AttrVal( $name, "https", "0" ) eq "1" ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_SendCommand] explicit use of HTTPS"; + $http_proto = "https"; + if ( $port eq "80" ) { + $port = "443"; + Log3 $name, 5, + "NEUTRINO $name [NEUTRINO_SendCommand] implicit change of from port 80 to 443"; + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_SendCommand] using unencrypted connection via HTTP"; + $http_proto = "http"; + } + + my $http_user = ""; + my $http_passwd = ""; + if ( defined( $hash->{helper}{USER} ) + && defined( $hash->{helper}{PASSWORD} ) ) + { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_SendCommand] using BasicAuth"; + $http_user = $hash->{helper}{USER}; + $http_passwd = $hash->{helper}{PASSWORD}; + } + if ( defined( $hash->{helper}{USER} ) ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_SendCommand] using BasicAuth (username only)"; + $http_user = $hash->{helper}{USER}; + } + my $URL; + my $response; + my $return; + + if ( !defined($cmd) || $cmd eq "" ) { + Log3 $name, 4, "NEUTRINO $name [NEUTRINO_SendCommand] SERVICE = $service"; + } + else { + #2017-07-14 - http_method deaktiviert + $cmd = "?" . $cmd; + # if ( $http_method eq "GET" || $http_method eq "" ); + Log3 $name, 4, "NEUTRINO $name [NEUTRINO_SendCommand] SERVICE = $service/" . urlDecode($cmd); + } + + # Check Service and change serviceurl + if ($service eq "epginfo") { + #2017.07.12 - $channelid entfernt! '$serviceurl = "epg?xml=true&channelid=" . $channelid . "&details=true&max=6";' + $serviceurl = "epg?xml=true&details=true&max=6"; + } + + elsif ($service eq "epginforecord") { + $serviceurl = + "epg?xml=true&channelname=" + . $channelname . "&max=6"; + } + + elsif ($service eq "getrawtime") { + $serviceurl = "gettime?rawtime"; + } + + elsif ($service eq "timerlist") { + $serviceurl = "timer"; + } + + elsif ($service eq "mutestate") { + $serviceurl = "volume?status"; + } + + elsif ($service eq "mute") { + $serviceurl = "volume?mute"; + } + + elsif ($service eq "unmute") { + $serviceurl = "volume?unmute"; + } + + elsif ($service eq "recordmode") { + $serviceurl = "setmode?status"; + } + + elsif ($service eq "powerstate") { + $serviceurl = "standby"; + } + + elsif ($service eq "bouquet") { + $serviceurl = "getbouquet?actual"; + } + + elsif ($service eq "bouquet_list") { + my $bouquet = ReadingsVal( $name, "bouquetnr", "0" ); + my $bouquetset = ReadingsVal( $name, "bouquetnr_set", "73482423648726384726384" ); + my $bouquetmode = ReadingsVal( $name, "input", "tv" ); + + if (!($bouquet eq $bouquetset)) { + $serviceurl = "getbouquet?bouquet=" . $bouquet . "&mode=" . $bouquetmode; + } + else{ + return "bouguet schon vorhanden!"; + } + + } + + else{ + $serviceurl = $service; + } + + if ( $http_user ne "" && $http_passwd ne "" ) { + $URL = + $http_proto . "://" + . $http_user . ":" + . $http_passwd . "@" + . $address . ":" + . $port . "/control/" + . $serviceurl; + #2017-07-14 - http_method deaktiviert + $URL .= $cmd; #if ( $http_method eq "GET" || $http_method eq "" ); + } + + elsif ( $http_user ne "" ) { + $URL = + $http_proto . "://" + . $http_user . "@" + . $address . ":" + . $port . "/control/" + . $serviceurl; + #2017-07-14 - http_method deaktiviert + $URL .= $cmd; #if ( $http_method eq "GET" || $http_method eq "" ); + } + + else { + $URL = + $http_proto . "://" . $address . ":" . $port . "/control/" . $serviceurl; + #2017-07-14 - http_method deaktiviert + $URL .= $cmd; #if ( $http_method eq "GET" || $http_method eq "" ); + } + + #2017.07.19 - Übergabe SendCommandQuery + $param = { + url => $URL, + service => $service, + cmd => $cmd, + type => $type, + callback => \&NEUTRINO_ReceiveCommand, + }; + + NEUTRINO_HD_SendCommand($hash,$param); + + return; +} + +############################# +# pushes new command to cmd queue +sub NEUTRINO_HD_SendCommand($$) { + my ($hash, $param) = @_; + my $name = $hash->{NAME}; + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_HD_SendCommand] - append to queue " .$param->{url}; + + # In case any URL changes must be made, this part is separated in this function". + + push @{$hash->{helper}{CMD_QUEUE}}, $param; + + NEUTRINO_HD_HandleCmdQueue($hash); +} + +############################# +# starts http requests from cmd queue +sub NEUTRINO_HD_HandleCmdQueue($) { + my ($hash, $param) = @_; + my $name = $hash->{NAME}; + my $http_noshutdown = AttrVal( $name, "http-noshutdown", "0" ); + my $http_timeout = AttrVal( $name, "timeout", "2" ); + + if(not($hash->{helper}{RUNNING_REQUEST}) and @{$hash->{helper}{CMD_QUEUE}}) + { + + my $params = { + url => $param->{url}, + timeout => $http_timeout, + noshutdown => $http_noshutdown, + keepalive => 0, + hash => $hash, + callback => \&NEUTRINO_ReceiveCommand + }; + + my $request = pop @{$hash->{helper}{CMD_QUEUE}}; + + map {$hash->{helper}{HTTP_CONNECTION}{$_} = $params->{$_}} keys %{$params}; + map {$hash->{helper}{HTTP_CONNECTION}{$_} = $request->{$_}} keys %{$request}; + + $hash->{helper}{RUNNING_REQUEST} = 1; + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_HD_HandleCmdQueue] - send command " .$params->{url}; + HttpUtils_NonblockingGet($hash->{helper}{HTTP_CONNECTION}); + } +} + +################################### +sub NEUTRINO_Get($@) { + my ( $hash, @a ) = @_; + my $name = $hash->{NAME}; + my $what; + + return "argument is missing" if ( int(@a) < 2 ); + $what = $a[1]; + + #2017.07.21 - Log nur schreiben wenn get nicht initialisiert wird + if ($what ne '?') { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Get] [$what] called function"; + } + + if ( $what =~ +/^(power|input|volume|mute|channel|currentTitle|channel_url)$/ + ) + { + if ( ReadingsVal( $name, $what, "" ) ne "" ) { + return ReadingsVal( $name, $what, "" ); + } + else { + return "no such reading: $what"; + } + } + + else { + return "Unknown argument $what, choose one of power:noArg input:noArg volume:noArg mute:noArg channel:noArg currentTitle:noArg channel_url:noArg "; + } +} + +################################### +sub NEUTRINO_Set($@) { + my ( $hash, @a ) = @_; + my $name = $hash->{NAME}; + my $state = ReadingsVal( $name, "state", "absent" ); + my $presence = ReadingsVal( $name, "presence", "absent" ); + my $input = ReadingsVal( $name, "input", "" ); + my $channel = ReadingsVal( $name, "channel", "" ); + my $channels = ""; + + #2017.07.21 - Log nur schreiben wenn get nicht initialisiert wird + if ($a[1] ne '?') { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] called function"; + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] [" . $a[1] . "] set"; + } + + return "No Argument given" if ( !defined( $a[1] ) ); + + # load channel list + if ( + defined($input) + && defined($channel) + && $input ne "" + && $channel ne "" + && ( !defined( $hash->{helper}{channels}{$input} ) + || !defined( $hash->{helper}{channels}{$input} ) ) + ) + { + $channels = $channel . ","; + } + + if ( $input ne "" + && defined( $hash->{helper}{channels}{$input} ) + && ref( $hash->{helper}{channels}{$input} ) eq "ARRAY" ) + { + $channels = join( ',', @{ $hash->{helper}{channels}{$input} } ); + } + + my $usage = "Unknown argument " . $a[1] . ", choose one of toggle:noArg on:noArg off:noArg volume:slider,0,1,100 remoteControl showText showtextwithbutton channel:" . $channels; + + $usage .= " mute:-,on,off" + if ( ReadingsVal( $name, "mute", "-" ) eq "-" ); + + $usage .= " mute:on,off" + if ( ReadingsVal( $name, "mute", "-" ) ne "-" ); + + $usage .= " reboot:noArg"; + $usage .= " shutdown:noArg"; + $usage .= " statusRequest:noArg"; + + my $cmd = ''; + my $result; + + # statusRequest + if ( lc( $a[1] ) eq "statusrequest" ) { + NEUTRINO_GetStatus($hash); + } + + # toggle + elsif ( lc( $a[1] ) eq "toggle" ) { + if ( $state ne "on" ) { + return NEUTRINO_Set( $hash, $name, "on" ); + } + else { + return NEUTRINO_Set( $hash, $name, "off" ); + } + } + + # shutdown + elsif ( lc( $a[1] ) eq "shutdown" ) { + + if ( $state ne "absent" ) { + $cmd = "shutdown"; + $result = NEUTRINO_SendCommand( $hash, "shutdown"); + } + else { + return "Device needs to be ON to be set to standby mode."; + } + } + + # reboot + elsif ( lc( $a[1] ) eq "reboot" ) { + if ( $state ne "absent" ) { + $result = NEUTRINO_SendCommand( $hash, "reboot"); + } + else { + return "Device needs to be reachable to be rebooted."; + } + } + + # on + elsif ( lc( $a[1] ) eq "on" ) { + + if ( $state eq "standby" ) { + $cmd = "off"; + $result = NEUTRINO_SendCommand( $hash, "powerstate", $cmd, "off" ); + } + else { + return "Device needs to be reachable to be set to standby mode."; + } + } + + # off + elsif ( lc( $a[1] ) eq "off" ) { + if ( $state ne "absent" ) { + $cmd = "on"; + NEUTRINO_SendCommand( $hash, "powerstate", $cmd, "on" ); + } + else { + return "Device needs to be reachable to be set to standby mode."; + } + } + + # volume + elsif ( lc( $a[1] ) eq "volume" ) { + if ( !defined( $a[2] ) ) {return "No argument given";} + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] [" . $a[1] . "] " . $a[2]; + + if ( $state eq "on" ) { + my $_ = $a[2]; + if ( m/^\d+$/ && $_ >= 0 && $_ <= 100 ) { + $cmd = $a[2]; + } + else { + return "Argument does not seem to be a valid integer between 0 and 100"; + } + $result = NEUTRINO_SendCommand( $hash, "volume", $cmd ); + } + else { + return "Device needs to be ON to adjust volume."; + } + } + + # mute + elsif ( lc( $a[1] ) eq "mute" || lc( $a[1] ) eq "mutet" ) { + if ( $state eq "on" ) { + if ( defined( $a[2] ) ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] [" . $a[1] . "] " . $a[2]; + } + + if ( lc( $a[2] ) eq "off" ) { + NEUTRINO_SendCommand( $hash, "unmute", $cmd ); + } + elsif ( lc( $a[2] ) eq "on" ) { + NEUTRINO_SendCommand( $hash, "mute", $cmd ); + } + else { + return "Unknown argument " . $a[2]; + } + } + else { + return "Device needs to be ON to mute/unmute audio."; + } + } + + # remoteControl + elsif ( lc( $a[1] ) eq "remotecontrol" ) { + + if ( !defined( $a[2] ) ){return "No argument given.";} + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] [" . $a[1] . "] " . $a[2]; + + if ( defined( $a[2] )){ + $result = NEUTRINO_SendCommand( $hash, "rcem", $a[2] ); + return $result; + } + + } + + # channel + elsif ( lc( $a[1] ) eq "channel" ) { + + if ( !defined( $a[2] ) ) {return "No argument given, choose one of channel channelNumber servicereference ";} + + if ( defined( $a[2] ) + && $presence eq "present" + && $state ne "on" ) + { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] [" . $a[1] . "] indirect switching request to ON"; + NEUTRINO_Set( $hash, $name, "on" ); + } + + if ( defined( $a[3] ) ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] [" . $a[1] . "] " . $a[2] . "+" . $a[3]; + } + else{ + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Set] [" . $a[1] . "] " . $a[2]; + } + + if ( $state eq "on" ) { + my $_ = $a[2]; + my $channellistname; + + #2017.07.19 - Plus Zeichen im Name erkennen + if ( defined( $a[3] ) ) { + # + Zeichen im Name erkannt! + $channellistname = $a[2] . "%2B" . $a[3]; + } + else {$channellistname = $a[2];} + + $channellistname =~ s/_/%20/g; + NEUTRINO_SendCommand( $hash, "zapto", "name=$channellistname" ); + } + else { + return + "Device needs to be present to switch to a specific channel."; + } + } + + # showText + elsif ( lc( $a[1] ) eq "showtext" ) { + if ( $state ne "absent" ) { + + if ( !defined( $a[2] ) ) {return "No argument given, choose one of messagetext ";} + + my $i = 2; + my $text = $a[$i]; + $i++; + if ( defined( $a[$i] ) ) { + my $arr_size = @a; + while ( $i < $arr_size ) { + $text = $text . " " . $a[$i]; + $i++; + } + } + $cmd = "popup=" . urlEncode($text) ."&timeout=10"; + $result = NEUTRINO_SendCommand( $hash, "message", $cmd ); + } + else { + return "Device needs to be reachable to send a message to screen."; + } + } + + # showTextwithbutton + elsif ( lc( $a[1] ) eq "showtextwithbutton" ) { + if ( $state ne "absent" ) { + if ( !defined( $a[2] ) ) {return "No argument given, choose one of messagetext";} + + my $i = 2; + my $text = $a[$i]; + $i++; + if ( defined( $a[$i] ) ) { + my $arr_size = @a; + while ( $i < $arr_size ) { + $text = $text . " " . $a[$i]; + $i++; + } + } + $cmd = "nmsg=" . urlEncode($text); + $result = NEUTRINO_SendCommand( $hash, "message", $cmd ); + } + else { + return "Device needs to be reachable to send a message to screen."; + } + } + + # return usage hint + else { + return $usage; + } + + return; +} + +################################### +sub NEUTRINO_Define($$) { + my ( $hash, $def ) = @_; + my @a = split( "[ \t][ \t]*", $def ); + my $name = $hash->{NAME}; + + Log3 $name, 0, "NEUTRINO $name [NEUTRINO_Define] start device"; + + eval { require XML::Simple; }; + return "Please install Perl XML::Simple to use module NEUTRINO" + if ($@); + + if ( int(@a) < 3 ) { + my $msg = "Wrong syntax: define NEUTRINO [] [] []"; + Log3 $name, 4, $msg; + return $msg; + } + + $hash->{TYPE} = "NEUTRINO"; + + my $address = $a[2]; + $hash->{helper}{ADDRESS} = $address; + + # use port 80 if not defined + my $port = $a[3] || 80; + $hash->{helper}{PORT} = $port; + + # use interval of 45sec if not defined + my $interval = $a[4] || 45; + $hash->{INTERVAL} = $interval; + + # set http user if defined + my $http_user = $a[5]; + $hash->{helper}{USER} = $http_user if $http_user; + + # set http password if defined + my $http_passwd = $a[6]; + $hash->{helper}{PASSWORD} = $http_passwd if $http_passwd; + + $hash->{helper}{CMD_QUEUE} = (); + delete($hash->{helper}{HTTP_CONNECTION}) if(exists($hash->{helper}{HTTP_CONNECTION})); + + # set default settings on first define + if ($init_done) { + + # use http-method POST for FritzBox environment as GET does not seem to + # work properly. Might restrict use to newer + # NEUTRINO Webif versions or use of OWIF only. + if ( exists $ENV{CONFIG_PRODUKT_NAME} + && defined $ENV{CONFIG_PRODUKT_NAME} ) + { + #2017-07-14 - http_method deaktiviert + #$attr{$name}{"http-method"} = 'POST'; + } + + # default method is GET and should be compatible to most + # NEUTRINO Webif versions + else { + #2017-07-14 - http_method deaktiviert + #$attr{$name}{"http-method"} = 'GET'; + } + $attr{$name}{webCmd} = 'channel'; + $attr{$name}{devStateIcon} = 'on:rc_GREEN:off off:rc_RED:on standby:rc_YELLOW:on'; + $attr{$name}{icon} = 'dreambox'; + } + + # start the status update timer + RemoveInternalTimer($hash); + InternalTimer( gettimeofday() + 2, "NEUTRINO_GetStatus", $hash, 1 ); + + return; +} + +############################################################################################################ +# +# Begin of helper functions +# +############################################################################################################ + +################################### +sub NEUTRINO_ReceiveCommand($$$) { + my ( $param, $err, $data ) = @_; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + my $service = $param->{service}; + my $cmd = $param->{cmd}; + my $state = ReadingsVal( $name, "state", "off" ); + my $presence = ReadingsVal( $name, "presence", "absent" ); + my $type = ( $param->{type} ) ? $param->{type} : ""; + my $return; + my $line; + my $UnixDate = time(); + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] called function"; + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] Data = $data"; + + $hash->{helper}{RUNNING_REQUEST} = 0; + + delete($hash->{helper}{HTTP_CONNECTION}) unless($param->{keepalive}); + + readingsBeginUpdate($hash); + + # mute data = 0 then data = off + if ($service eq "mutestate" && $data == 0){ + $data = "off"; + } + + # empty timerlist + if ($service eq "timerlist" && $data == 0){ + $data = "empty"; + } + + # device not reachable + if ($err) { + + # powerstate + if ( $service eq "powerstate" ) { + $state = "absent"; + + if ( !defined($cmd) || $cmd eq "" ) { + Log3 $name, 4, "NEUTRINO $name RCV TIMEOUT $service"; + } + else { + Log3 $name, 4, + "NEUTRINO $name RCV TIMEOUT $service/" . urlDecode($cmd); + } + + $presence = "absent"; + readingsBulkUpdate( $hash, "power", "off" ); + readingsBulkUpdate( $hash, "state", "off" ); + readingsBulkUpdate( $hash, "presence", $presence ) + if ( ReadingsVal( $name, "presence", "" ) ne $presence ); + } + } + + # data received + elsif ($data) { + $presence = "present"; + $state = "on"; + readingsBulkUpdate( $hash, "presence", $presence ) + if ( ReadingsVal( $name, "presence", "" ) ne $presence ); + + #2017.07.21 - Log anzeigen wenn $cmd befüllt ist + if ($cmd ne "" ) {Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] URL = " . urlDecode($cmd);} + + # split date (non XML services) + my @ans = split (/\n/s, $data); + + ####################### + # process return data + ####################### + + # XML services + if ($service eq "epginfo" || $service eq "epginforecord") { + + $data = '' . "\n" . $data; + + if ( $data =~ /<\?xml/ && $data !~ /<\/html>/ ) { + + my $parser = XML::Simple->new( + NormaliseSpace => 2, + KeepRoot => 0, + ForceArray => 0, + SuppressEmpty => 1, + KeyAttr => {} + ); + + eval + '$return = $parser->XMLin( Encode::encode_utf8($data) ); 1'; + if ($@) { + + if ( !defined($cmd) || $cmd eq "" ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] - unable to parse malformed XML: $@\n" + . $data; + } + else { + Log3 $name, 5, + "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] " + . urlDecode($cmd) + . " - unable to parse malformed XML: $@\n" + . $data; + + } + + return undef; + } + + undef $parser; + } + else { + if ( !defined($cmd) || $cmd eq "" ) { + Log3 $name, 5, + "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] - not in XML format\n" + . $data; + } + else { + Log3 $name, 5, + "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] " + . urlDecode($cmd) + . " - not in XML format\n" + . $data; + } + + return undef; + } + + $return = Encode::encode_utf8($data) + if ( $return && ref($return) ne "HASH" ); + + } + + # powerstate + if ( $service eq "powerstate" ) { + + if (@ans[0]) { + + if (index(lc(@ans[0]), "on") != -1) { + readingsBulkUpdate( $hash, "power","off"); + readingsBulkUpdate( $hash, "state", "standby" ); + $state = "off"; + } + + elsif(index(lc(@ans[0]), "off") != -1) { + + # 2017.07.12 - Aenderungen nur durchfuehren wenn power vorher ungleich "on" war + if (ReadingsVal( $name, "power", "unbekannt" ) ne 'on' ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] detect change"; + readingsBulkUpdate( $hash, "power","on"); + readingsBulkUpdate( $hash, "state", "on" ); + NEUTRINO_SendCommand( $hash, "version" ); + } + + #2017.07.12 - time_raw_now/time_now vom FHEM-Server verwenden + readingsSingleUpdate( $hash, "time_raw_now", $UnixDate ,0); + readingsSingleUpdate( $hash, "time_now", localtime() ,0); + + #2017.07.12 - Pruefen ob die bouquet_list aktualisiert werden muss + if ($hash->{helper}{channels}{ReadingsVal( $name, "input", "-" )} eq '') { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] bouquet_list detect change!"; + NEUTRINO_SendCommand( $hash, "bouquet_list" ); + } + + #2017.07.12 - Folgendes wird alle INTERVAL abgefragt + NEUTRINO_SendCommand( $hash, "zapto" ); # aktuellen channel_id auslesen + NEUTRINO_SendCommand( $hash, "bouquet" ); # aktuelles Bouguet auslesen + NEUTRINO_SendCommand( $hash, "volume" ); # aktuelles Volumen auslesen + NEUTRINO_SendCommand( $hash, "mutestate" ); # mutestate 0 = off 1 = on + NEUTRINO_SendCommand( $hash, "signal" ); # SIG, SNR und BER + NEUTRINO_SendCommand( $hash, "recordmode" ); # 0 = off 1 = on + NEUTRINO_SendCommand( $hash, "timerlist" ); # aktuelle Timerliste + + #2017.07.12 - deaktivert bzw. verschoben + # MOVE --> NEUTRINO_SendCommand( $hash, "bouquet" ); #CHANGE bei Senderwechsel + # MOVE --> NEUTRINO_SendCommand( $hash, "version" ); #CHANGE bei Powerstat wechsel + # MOVE --> NEUTRINO_SendCommand( $hash, "build_live_url" ); #CHANGE bei Senderwechsel + # MOVE --> NEUTRINO_SendCommand( $hash, "getmode" ); #CHANGE bei Senderwechsel + # DEL --> NEUTRINO_SendCommand( $hash, "gettime" ); #FHEM Zeit verwenden + # DEL --> NEUTRINO_SendCommand( $hash, "getrawtime" ); #FHEM Zeit verwenden + } + + elsif(index(lc(@ans[0]), "ok") != -1) { + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] TYP = $type"; + + if (index($type, "off") != -1) { + Log3 $name, 5, "NEUTRINO $name TYP = OFF"; + readingsBulkUpdate( $hash, "power", "on"); + readingsBulkUpdate( $hash, "state", "on" ); + } + elsif(index($type, "on") != -1) { + Log3 $name, 5, "NEUTRINO $name TYP = ON"; + readingsBulkUpdate( $hash, "power", "off"); + readingsBulkUpdate( $hash, "state", "standby" ); + } + else { + readingsBulkUpdate( $hash, "power", "off"); + readingsBulkUpdate( $hash, "state", "standby" ); + $state = "off"; + } + NEUTRINO_SendCommand( $hash, "recordmode" ); + } + + else{ + readingsBulkUpdate( $hash, "power", "undefined" ); + readingsBulkUpdate( $hash, "state", "undefined" ); + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no powerstate could be extracted"; + } + } + + # bouquet + elsif ( $service eq "bouquet" ) { + + if (@ans[0]) { + + #2017.07.17 - Liste nur bei aenderung aktualisieren + if (ReadingsVal( $name, "bouquetnr", "99999" ) ne @ans[0] ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] detect change"; + readingsBulkUpdate( $hash, "bouquetnr", @ans[0] ); + NEUTRINO_SendCommand( $hash, "bouquet_list" ); + } + } + else { + readingsBulkUpdate( $hash, "bouquetnr", "0" ); + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no bouquetnr could be extracted"; + } + } + + # bouquet_list + elsif ( $service eq "bouquet_list" ) { + + my $channellistname; + my $i = 0; + my $input = ReadingsVal( $name, "input", "-" ); + + #2017.07.19 - Nur durchführen wenn $input <> '-' ist + if ($input ne '-') { + $hash->{helper}{channels}{$input} = (); + + foreach $line (@ans) { + if (index($line, "",6) != -1) { + $channellistname = substr($line,index($line," ", 6 )+1); + $channellistname =~ s/\s/_/g; + if (substr($channellistname, 0, 1) ne "" && substr($channellistname, 0, 1) ne "_") { + $hash->{helper}{channels}{$input}[$i] = $channellistname ; + $i++; + } + } + } + } + } + + # volume + elsif ( $service eq "volume" ) { + if (index(lc(@ans[0]), "ok") != -1) { + #2017.07.12 - Nur bei einer Aenderung schreiben + if (ReadingsVal( $name, "volume", "0" ) ne substr($cmd,1) ) {readingsBulkUpdate( $hash, "volume", substr($cmd,1) );} + } + elsif (@ans[0]) { + #2017.07.12 - Nur bei einer Aenderung schreiben + if (ReadingsVal( $name, "volume", "0" ) ne @ans[0] ) {readingsBulkUpdate( $hash, "volume", @ans[0] );} + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no volume could be extracted"; + } + } + + # mutestate + elsif ( $service eq "mutestate" ) { + + if (@ans[0]) { + if (index(lc(@ans[0]), "1") != -1) { + #2017.07.12 - Änderung schreiben + if (ReadingsVal( $name, "mute", "0" ) ne 'on' ) {readingsBulkUpdate( $hash, "mute","on");} + } + else{ + if (ReadingsVal( $name, "mute", "0" ) ne 'off' ) {readingsBulkUpdate( $hash, "mute","off");} + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no mute could be extracted"; + } + + } + + # mute + elsif ( $service eq "mute" ) { + + if (@ans[0]) { + if (index(lc(@ans[0]), "ok") != -1) { + readingsBulkUpdate( $hash, "mute","on"); + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no mute could be extracted"; + } + } + + # unmute + elsif ( $service eq "unmute" ) { + + if (@ans[0]) { + if (index(lc(@ans[0]), "ok") != -1) { + readingsBulkUpdate( $hash, "mute","off"); + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no mute could be extracted"; + } + } + + # timerlist + elsif ( $service eq "timerlist" ) { + + my $channellistname; + my $timernumber; + my $timerrepeat; + my $timertyp; + my $timerannounceTime; + my $timerstartTime; + my $timerstopTime; + my $timername; + my $i = 0; + my $c = 0; + my $d = 0; + my $timermaxcount = ReadingsVal( $name, "timer_maxcount", 1 ); + my $neutrinotime = ReadingsVal( $name, "time_raw_now", "" ); + + if ($data ne "empty") { + foreach $line (@ans) { + if (index($line, "",6) != -1) { + my @timerlist = split (/ /s, $line); + $timernumber = @timerlist[0]; + $timertyp = @timerlist[1]; + $timerrepeat = @timerlist[2]; + $timerannounceTime = @timerlist[4]; + $timerstartTime = @timerlist[5]; + $timerstopTime = @timerlist[6]; + + #2017.07.12 - Nur Änderungen schreiben + if (ReadingsVal( $name, "timer$i", "0" ) ne $line ) { + readingsBulkUpdate( $hash, "timer$i", $line ); + readingsBulkUpdate( $hash, "timer$i" . "number", $timernumber ); + + # timertyp + if ($timertyp eq "1") {$timertyp = "shutdown"} + elsif ($timertyp eq "2") {$timertyp = "nextprogram"} + elsif ($timertyp eq "3") {$timertyp = "zapto"} + elsif ($timertyp eq "4") {$timertyp = "standby"} + elsif ($timertyp eq "5") {$timertyp = "record"} + elsif ($timertyp eq "6") {$timertyp = "remind"} + elsif ($timertyp eq "7") {$timertyp = "sleeptimer"} + elsif ($timertyp eq "8") {$timertyp = "exec_plugin"} + else {$timertyp = "unknown"} + + readingsBulkUpdate( $hash, "timer$i" . "typ", $timertyp ); + + # timer repeat + if ($timerrepeat eq "0") {$timerrepeat = "once"} + elsif ($timerrepeat eq "1") {$timerrepeat = "daily"} + elsif ($timerrepeat eq "2") {$timerrepeat = "weekly"} + elsif ($timerrepeat eq "3") {$timerrepeat = "biweekly"} + elsif ($timerrepeat eq "4") {$timerrepeat = "fourweekly"} + elsif ($timerrepeat eq "5") {$timerrepeat = "monthly"} + elsif ($timerrepeat eq "6") {$timerrepeat = "beeventdescription"} + else {$timerrepeat = "weekdays"} + + readingsBulkUpdate( $hash, "timer$i" . "repeat", $timerrepeat ); + + # timer repcount + readingsBulkUpdate( $hash, "timer$i" . "repcount", @timerlist[3] ); + + # announceTime + if ($timerannounceTime eq "0") {readingsBulkUpdate( $hash, "timer$i" . "manualrecord", "" );} + else { + my $date = localtime($timerannounceTime)->strftime('%F %T'); + readingsBulkUpdate( $hash, "timer$i" . "announceTime", $date ); + } + + # startTime + my $date = localtime($timerstartTime)->strftime('%F %T'); + readingsBulkUpdate( $hash, "timer$i" . "startTime", $date ); + + # stopTime + my $date = localtime($timerstopTime)->strftime('%F %T'); + readingsBulkUpdate( $hash, "timer$i" . "stopTime", $date ); + + # timer name + $timername = ""; + $c = 0; + foreach (@timerlist) { + if ($c > 6){ + if ($timername ne "") {$timername = $timername . " " . @timerlist[$c]} else {$timername = @timerlist[$c]} + } + $c++; + } + readingsBulkUpdate( $hash, "timer$i" . "name", $timername ); + } + + # find running record + if ($neutrinotime > $timerstartTime && $neutrinotime < $timerstopTime) { + readingsBulkUpdate( $hash, "recordchannel", $timername ); + NEUTRINO_SendCommand( $hash, "epginforecord",""); + } + + $i++; + } + } + } + + # timer count + #2017.07.12 - Nur Änderungen schreiben + if (ReadingsVal( $name, "timer_count", "0" ) ne $i ) {readingsBulkUpdate( $hash, "timer_count", $i );} + + # timer maxcount + if ($timermaxcount <= $i) { + #2017.07.12 - Nur Änderungen schreiben + if (ReadingsVal( $name, "timer_maxcount", "0" ) ne $i ) {readingsBulkUpdate( $hash, "timer_maxcount", $i );} + } + else { + # detele not used timer + while ($d < $timermaxcount) { + if ($d > $i -1 ) { + foreach ( "","announceTime","name","number","repcount","repeat","startTime","stopTime","typ", ) { + if (ReadingsVal( $name, "timer" . $d . $_, "0" ) ne '-' ) {readingsBulkUpdate( $hash, "timer" . $d . $_, "-" );}; + } + } + $d++; + } + } + } + + # EPG informations (record) + elsif ( $service eq "epginforecord" ) { + my $readvalue; + my $neutrinotime = ReadingsVal( $name, "time_raw_now", "" ); + my $readnumber = 0; + my $line; + + if ( ref($return) eq "HASH" + && defined( $return->{channel_id} ) ) + { + + if (defined( $return->{prog} ) ) { + + #egp stop time serach + my $arr_size = @{ $return->{prog} }; + my $i = 0; + + while ( $i < $arr_size ) { + $readvalue = $return->{prog}[$i]{stop_sec}; + if ($readvalue > $neutrinotime){ + $readnumber = $i; + last; + } + $i++; + } + + # recordtitle + $readvalue = $return->{prog}[$readnumber]{description}; + readingsBulkUpdate( $hash, "recordtitle",$readvalue); + } + } + else { + Log3 $name, 5, + "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no record epg information could be found"; + } + } + + # time + elsif ( $service eq "gettime" ) { + if (@ans[0]) { + + readingsBulkUpdate( $hash, "time_now", @ans[0] ) + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no time could be extracted"; + } + + } + + # rawtime + elsif ( $service eq "getrawtime" ) { + if (@ans[0]) { + readingsBulkUpdate( $hash, "time_raw_now", @ans[0] ); + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no rawtime could be extracted"; + } + + } + + # channel (ID) + elsif ( $service eq "zapto" ) { + + if (@ans[0]) { + + # 2017.07.12 - EPG Info aktualisieren wenn der Kanal gewurde! + if (ReadingsVal( $name, "channel_id", "0" ) ne @ans[0] ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] detect change OLD " . ReadingsVal( $name, "channel_id", "0" ); + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] detect change NEW @ans[0]"; + #2017.07.12 - entfernt: channel_id wird mit epginfos gesetzt 'readingsBulkUpdate( $hash, "channel_id", @ans[0] );' + NEUTRINO_SendCommand( $hash, "epginfo" ); + NEUTRINO_SendCommand( $hash, "build_live_url" ); #2017.07.12 - channel_url wird nur beim Senderwechsel aktualisiert! + #NEUTRINO_SendCommand( $hash, "bouquet" ); #2017.07.12 - Bouquetliste wird nur beim Senderwechsel aktualisiert! + NEUTRINO_SendCommand( $hash, "getmode" ); #2017.07.12 - Mode wird nur beim Senderwechsel aktualisiert! + } + else { + # 2017.07.12 - EPGInfo aktualisieren wenn die aktuelle Sendeung zu ende ist + if ($UnixDate > ReadingsVal( $name, "egp_current_stop_sec", "0" ) ) { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] epginfo detect change"; + NEUTRINO_SendCommand( $hash, "epginfo" ); + } + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no ID could be extracted"; + } + + } + + # stream URL + elsif ( $service eq "build_live_url" ) { + if (@ans[0]) { + readingsBulkUpdate( $hash, "channel_url", @ans[0] ); + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no build_live_url could be extracted"; + } + } + + # Mode TV/Radio + elsif ( $service eq "getmode" ) { + + if (@ans[0]) { + if (index(lc(@ans[0]), "tv") != -1) { + readingsBulkUpdate( $hash, "input","tv"); + } + elsif(index(lc(@ans[0]), "radio") != -1) { + readingsBulkUpdate( $hash, "input","radio"); + } + else{ + readingsBulkUpdate( $hash, "input", "-" ) + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no inputmode could be extracted"; + } + + } + + # Mode TV/Radio + elsif ( $service eq "recordmode" ) { + + if (@ans[0]) { + if (index(lc(@ans[0]), "on") != -1) { + #2017.07.12 - Nur bei einer Aenderung schreiben + if (ReadingsVal( $name, "recordmode", "0" ) ne 'on' ) {readingsBulkUpdate( $hash, "recordmode","on");} + } + elsif(index(lc(@ans[0]), "off") != -1) { + #2017.07.12 - Nur bei einer Aenderung schreiben + if (ReadingsVal( $name, "recordmode", "0" ) ne 'off' ) {readingsBulkUpdate( $hash, "recordmode","off");} + } + else{ + readingsBulkUpdate( $hash, "recordmode", "-" ) + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no recordmode could be extracted"; + } + + } + + # EPG informations + elsif ( $service eq "epginfo" ) { + my $reading; + my $readingname; + my $readvalue; + my $neutrinotime = ReadingsVal( $name, "time_raw_now", "" ); + my $readnumber = 0; + if ( ref($return) eq "HASH" + && defined( $return->{channel_id} ) ) + { + + # channel_Name + $readvalue = $return->{channel_name}; + readingsBulkUpdate( $hash, "channel_name",$readvalue); + + # channel displayname + $readvalue =~ s/\s/_/g; + readingsBulkUpdate( $hash, "channel",$readvalue); + + if (defined( $return->{prog} ) ) { + + #egp stop time serach + my $arr_size = @{ $return->{prog} }; + my $i = 0; + + while ( $i < $arr_size ) { + $readvalue = $return->{prog}[$i]{stop_sec}; + if ($readvalue > $neutrinotime){ + $readnumber = $i; + readingsBulkUpdate( $hash, "egp_current_number", $readnumber); + last; + } + $i++; + } + + foreach ( "eventid", ) { + $reading = $_; + + if ( defined( $return->{prog}[$readnumber]{$reading} ) + && lc( $return->{prog}[$readnumber]{$reading} ) ne "n/a" ) + { + $readvalue = $return->{prog}[$readnumber]{$reading}; + if ($readvalue) { + readingsBulkUpdate( $hash, $reading, $readvalue ); + } + else { + readingsBulkUpdate( $hash, $reading, "0" ); + } + } + else { + readingsBulkUpdate( $hash, $reading, "0" ); + } + } + + # 2017.07.12 - current channel_ID + readingsBulkUpdate( $hash, "channel_id",$return->{prog}[$readnumber]{channel_id}); + + # currentTitel + $readvalue = $return->{prog}[$readnumber]{description}; + readingsBulkUpdate( $hash, "currentTitle",$readvalue); + + foreach ( "description","info1","info2","start_t","stop_t","duration_min","date","channel_id","stop_sec","start_sec", ) { + $reading = $_; + $readingname = "egp_current_" . $_; + + if ( defined( $return->{prog}[$readnumber]{$reading} ) + && lc( $return->{prog}[$readnumber]{$reading} ) ne "n/a" ) + { + $readvalue = $return->{prog}[$readnumber]{$reading}; + if ($readvalue) { + readingsBulkUpdate( $hash, $readingname, $readvalue ); + } + else { + readingsBulkUpdate( $hash, $readingname, "0" ); + } + } + else { + readingsBulkUpdate( $hash, $readingname, "0" ); + } + } + } + } + else { + Log3 $name, 5, + "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no epg information could be found"; + } + } + + # signal + elsif ( $service eq "signal" ) { + my $signalvalue; + if (@ans[0]) { + foreach $line (@ans) { + foreach ("sig","snr","ber",) { + if (index(lc($line), $_) != -1) { + $signalvalue = substr($line,index($line,":")+1); + #2017.07.12 - Nur bei einer Aenderung schreiben + if (ReadingsVal( $name, "$_", "0" ) ne $signalvalue ) {readingsBulkUpdate( $hash, "$_",$signalvalue);} + } + } + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no signal could be extracted"; + } + } + + # Boxinformations + elsif ( $service eq "version" ) { + my $versionvalue; + my $versionname; + if (@ans[0]) { + foreach $line (@ans) { + if (index(lc($line), "=") != -1) { + $versionvalue = substr($line,index($line,"=")+1); + $versionname = substr($line,0,index($line,"=")); + readingsBulkUpdate( $hash, "image_" . "$versionname",$versionvalue); + } + } + } + else { + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no signal could be extracted"; + } + } + + # all other command results + else { + NEUTRINO_GetStatus( $hash, 1 ); + } + + } + else{ + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] no data!"; + } + + readingsEndUpdate( $hash, 1 ); + + NEUTRINO_HD_HandleCmdQueue($hash); + + undef $return; + return; +} + +################################### +sub NEUTRINO_Undefine($$) { + my ( $hash, $arg ) = @_; + my $name = $hash->{NAME}; + + Log3 $name, 5, "NEUTRINO $name [NEUTRINO_Undefine] called function"; + + # Stop the internal GetStatus-Loop and exit + RemoveInternalTimer($hash); + + return; +} + +1; + +=pod +=item device +=item summary control for NEUTRINO based receivers via network connection +=item summary_DE Steuerung von NEUTRINO basierte Receiver über das Netzwerk +=begin html + +

+ +

+

+ NEUTRINO +

+ +
    + Define +
      + define <name> NEUTRINO <ip-address-or-hostname> [[[[<port>] [<poll-interval>]] [<http-user>]] [<http-password>]]
      +
      + This module controls NEUTRINO based devices like Coolstream receiver via network connection.
      +
      + Defining an NEUTRINO device will schedule an internal task (interval can be set with optional parameter <poll-interval> in seconds, if not set, the value is 45 seconds), which periodically reads the status of the device and triggers notify/filelog commands.
      +
      + Example:
      +
        + define SATReceiver NEUTRINO 192.168.0.10
        +
        + # With custom port
        + define SATReceiver NEUTRINO 192.168.0.10 8080
        +
        + # With custom interval of 20 seconds
        + define SATReceiver NEUTRINO 192.168.0.10 80 20
        +
        + # With HTTP user credentials
        + define SATReceiver NEUTRINO 192.168.0.10 80 20 root secret
        +
      +
    +
    +
    + Set +
      + set <name> <command> [<parameter>]
      +
      + Currently, the following commands are defined.
      +
        +
      • + on   -   powers on the device (standby mode) +
      • +
      • + off   -   turns the device in standby mode +
      • +
      • + toggle   -   switch between on and off (standby mode) +
      • +
      • + shutdown   -   poweroff the device +
      • +
      • + reboot   -  reboots the device +
      • +
      • + channel   -   zap to specific channel +
      • +
      • + volume 0...100   -   set the volume level in percentage +
      • +
      • + mute on,off,toggle   -   controls volume to mute +
      • +
      • + statusRequest   -   requests the current status of the device +
      • +
      • + remoteControl UP,DOWN,...   -   sends remote control command
        +
      • +
      • + showText text   -   sends info messages to be displayed on screen +
      • +
      • + showtextwithbutton   -   sends info messagees to be displayed on screen with OK button +
      • +
        +
        +
        +
      +
    + Get +
      + get <name> <what>
      +
      + Currently, the following commands are defined:
      +
      +
        + channel
        + channelurl
        + currentTitle
        + input
        + mute
        + power
        + volume
        +
      +

    +
    + Attributes
    +
      +
        +
      • + disable - Disable polling (true/false) +
      • +
      • + http-noshutdown - Set FHEM-internal HttpUtils connection close behaviour (defaults=0) +
      • +
      • + https - Access box via secure HTTP (true/false) +
      • +
      • + timeout - Set different polling timeout in seconds (default=2) +
      • +
      +

    +
    +
    + Generated Readings:
    +
      +
        +
      • + ber - Shows Bit Error Rate for current channel +
      • +
      • + bouquetnr - Shows bouquet number for current channel +
      • +
      • + channel - Shows the service name of current channel +
      • +
      • + channel_id - Shows the channel id of current channel +
      • +
      • + channel_name - Shows the channel name of current channel +
      • +
      • + channel_url - Shows the channel url of current channel (use with vlc player) +
      • +
      • + currentTitle - Shows the title of the running event +
      • +
      • + epg_current_channel_id - Shows the channel id of epg information +
      • +
      • + epg_current_date - Shows the date of epg information +
      • +
      • + egp_current_description - Shows the current description of the current program +
      • +
      • + egp_current_duration_min - Shows the current duration of the current program +
      • +
      • + egp_current_info1 - Displays the current information of the current program +
      • +
      • + egp_current_info2 - Displays the current information of the current program +
      • +
      • + egp_current_number - Displays the current number(epg) of the current program +
      • +
      • + egp_current_start_sec - Shows the current start time of the current program (ticks) +
      • +
      • + egp_current_start_t - Shows the current start time of the current program +
      • +
      • + egp_current_stop_sec - Shows the current stop time of the current program (ticks) +
      • +
      • + egp_current_stop_t - Shows the current stop time of the current program +
      • +
      • + eventid - Shows the current event id of the current program +
      • +
      • + image_branch - Shows image information of NEUTRINO +
      • +
      • + image_builddate - Shows image information of NEUTRINO +
      • +
      • + image_commit - Shows image information of NEUTRINO +
      • +
      • + image_creator - Shows image information of NEUTRINO +
      • +
      • + image_describe - Shows image information of NEUTRINO +
      • +
      • + image_homepage - Shows image information of NEUTRINO +
      • +
      • + image_imagename - Shows image information of NEUTRINO +
      • +
      • + image_version - Shows image information of NEUTRINO +
      • +
      • + input - Shows currently used input +
      • +
      • + mute - Reports the mute status of the device (can be "on" or "off") +
      • +
      • + power - Reports the power status of the device (can be "on" or "off") +
      • +
      • + presence - Reports the presence status of the receiver (can be "absent" or "present"). +
      • +
      • + recordmode - Reports the record mode of the device (can be "on" or "off") +
      • +
      • + recordmodetitle - Reports the last record title +
      • +
      • + sig - Shows signal for current channel in percent +
      • +
      • + snr - Shows signal to noise for current channel in percent +
      • +
      • + state - Reports current power state and an absence of the device (can be "on", "off" or "standby") +
      • +
      • + time_now - Reports current time +
      • +
      • + time_raw_now - Reports current time (ticks) +
      • +
      • + timerX - Shows complete timer (Report from NEUTRINO) +
      • +
      • + timerXannounceTime - Shows announce time of the timer +
      • +
      • + timerXname - Shows channel name of the timer +
      • +
      • + timerXnumber - Shows timer number +
      • +
      • + timerXrepcount - Shows rep count of the timer +
      • +
      • + timerXrepeat - Shows repeat time of the timer +
      • +
      • + timerXstartTime - Shows start time of the timer +
      • +
      • + timerXstopTime - Shows stop time of the timer +
      • +
      • + timerXtyp - Shows type of the timer +
      • +
      • + timer_count - Shows the number of timers +
      • +
      • + timer_count - Shows the maximum number of timers +
      • +
      • + volume - Reports current volume level of the receiver in percentage values (between 0 and 100 %) +
      • +
      +
    +
+ +=end html + +=begin html_DE + +

+ +

+

+ NEUTRINO +

+
    + Define +
      + define <name> NEUTRINO <ip-address-or-hostname> [[[[<port>] [<poll-interval>]] [<http-user>]] [<http-password>]]
      +
      + Dieses Modul steuert NEUTRINO basierte Geräte wie die Coolstream über eine Netzwerkverbindung.
      +
      + Für definierte NEUTRINO Geräte wird ein interner Task angelegt, welcher periodisch die Readings aktualisiert. Der Standartpollintervall ist 45 Sekunden.
      +
      + Beispiele:
      +
        + define SATReceiver NEUTRINO 192.168.0.10
        +
        + # Alternativer Port
        + define SATReceiver NEUTRINO 192.168.0.10 8080
        +
        + # Alternativer poll interval von 20 seconds
        + define SATReceiver NEUTRINO 192.168.0.10 80 20
        +
        + # Mit HTTP Benutzer Zugangsdaten
        + define SATReceiver NEUTRINO 192.168.0.10 80 20 root secret
        +
      +

    +
    + Set +
      + set <name> <command> [<parameter>]
      +
      + Aktuell gibt es folgende Befehle.
      +
        +
      • + on   -   Schaltet das Gerät aus dem Standby wieder an +
      • +
      • + off   -   Schaltet das Gerät in den Standby +
      • +
      • + toggle   -   Ein- und Ausschalten zwischen Standby +
      • +
      • + shutdown   -   Schaltet das Gerät aus +
      • +
      • + reboot   -  Neustart des Gerätes +
      • +
      • + channel   -  Schaltet auf den angegebenen Kanal +
      • +
      • + volume 0...100   -   Ändert die Lautstärke in Prozent +
      • +
      • + mute on,off,toggle   -   Steuert Lautstärke "stumm" +
      • +
      • + statusRequest   -   Fordert den aktuellen Status des Gerätes an +
      • +
      • + remoteControl UP,DOWN,...   -   Sendet Fernsteuerungsbefehle
        +
      • +
      • + showText text   -   Sendet eine Textnachricht +
      • +
      • + showtextwithbutton   -   Sendet eine Textnachricht mit OK Button +
      • +
        +
      +
    +
    +
    + Get +
      + get <name> <what>
      +
      + Aktuell gibt es folgende Befehle.
      +
      +
        + channel
        + channelurl
        + currentTitle
        + input
        + mute
        + power
        + volume
        +
      +

    +
    + Attributes
    +
      +
        +
      • + disable - Schaltet das Polling aus (true/false) +
      • +
      • + http-noshutdown - Setzt FHEM-internal HttpUtils Verbindung offen halten (defaults=0) +
      • +
      • + https - Zugriff über HTTPS aktivieren (true/false) +
      • +
      • + timeout - Setzen des Timeout der HTTP Verbindung (default=2) +
      • +
      +

    +
    +
    + Generelle Readings:
    +
      +
        +
      • + ber - Zeigt die Bit Error Rate vom aktuellen Kanal +
      • +
      • + bouquetnr - Zeigt die aktuelle Bouquet Nummer vom aktuellen Kanal +
      • +
      • + channel - Zeigt den aktuellen Servicenamen vom aktuellen Kanal +
      • +
      • + channel_id - Zeigt die aktuelle Kanal ID vom aktuellen Kanal +
      • +
      • + channel_name - Zeigt den aktuellen Kanal Namen +
      • +
      • + channel_url - Zeigt die aktuelle Kanal URL, welche im Vlc Player zum Streamen verwendet werden kann +
      • +
      • + currentTitle - Zeigt den aktuellen Titel der aktuellen Sendung an +
      • +
      • + epg_current_channel_id - Zeigt die Kanal ID von aktuellen EPG an +
      • +
      • + epg_current_date - Zeigt das Datum des aktuellen EPGs an +
      • +
      • + egp_current_description - Zeigt die aktuelle Beschreibung der aktuellen Sendung an +
      • +
      • + egp_current_duration_min - Zeigt die Dauer der aktuellen Sendung an +
      • +
      • + egp_current_info1 - Zeigt die Information Teil 1 der aktuellen Sendung an +
      • +
      • + egp_current_info2 - Zeigt die Information Teil 2 der aktuellen Sendung an +
      • +
      • + egp_current_number - Zeigt die EPG Nummer der aktuellen Sendung an +
      • +
      • + egp_current_start_sec - Zeigt die Startzeit der aktuellen Sendung an (ticks) +
      • +
      • + egp_current_start_t - Zeigt die Startzeit der aktuellen Sendung an +
      • +
      • + egp_current_stop_sec - Zeigt die Stopzeit der aktuellen Sendung an (ticks) +
      • +
      • + egp_current_stop_t - Zeigt die Stopzeit der aktuellen Sendung an +
      • +
      • + eventid - Zeigt die aktuelle Event ID von der aktuellen Sendung an +
      • +
      • + image_branch - Zeigt Image Informationen von NEUTRINO +
      • +
      • + image_builddate - Zeigt Image Informationen von NEUTRINO +
      • +
      • + image_commit - Zeigt Image Informationen von NEUTRINO +
      • +
      • + image_creator - Zeigt Image Informationen von NEUTRINO +
      • +
      • + image_describe - Zeigt Image Informationen von NEUTRINO +
      • +
      • + image_homepage - Zeigt Image Informationen von NEUTRINO +
      • +
      • + image_imagename - Zeigt Image Informationen von NEUTRINO +
      • +
      • + image_version - Zeigt Image Informationen von NEUTRINO +
      • +
      • + input - Zeigt den aktuellen Input an (TV/Radio) +
      • +
      • + mute - Zeigt aktuellen Mute Status ("on" oder "off") +
      • +
      • + power - Zeigt aktuellen Power Status ("on" oder "off") +
      • +
      • + presence - Zeigt den aktuellen presence Status an ("absent" oder "present"). +
      • +
      • + recordmode - Zeigt an ob die Box gerade eine Aufnahme macht ("on" oder "off") +
      • +
      • + recordmodetitle - Zeigt den letzten Aufnahme Titel an +
      • +
      • + sig - Zeigt Signalstärke vom aktuellen Sender an +
      • +
      • + snr - Zeigt Singal Noise vom aktuellen Sender an +
      • +
      • + state - Zeigt den aktuellen Status an ("on", "off" oder "standby") +
      • +
      • + time_now - Aktuelle Uhrzeit +
      • +
      • + time_raw_now - Aktuelle Uhrzeit (ticks) +
      • +
      • + timerX - Zeigt den kompletten Timer an (Report from NEUTRINO) +
      • +
      • + timerXannounceTime - Zeigt die Ankündigungszeit des Timers an +
      • +
      • + timerXname - Zeigt den Aufnahmekanal des Timers an +
      • +
      • + timerXnumber - Zeigt die Timernummer an +
      • +
      • + timerXrepcount - Zeigt den Rep. Counter des Timers an +
      • +
      • + timerXrepeat - Zeigt die Wiederholungszeit an +
      • +
      • + timerXstartTime - Zeigt die Startzeit des Timers an +
      • +
      • + timerXstopTime - Zeigt die Stopzeit des Timers an +
      • +
      • + timerXtyp - Zeigt den Typ des Timers an +
      • +
      • + timer_count - Zeigt die Anzahl der aktuellen Timer an +
      • +
      • + timer_count - Zeitg die max. Anzahl der Timer an (wird intern verwendet) +
      • +
      • + volume - Zeit die aktuelle Lautstärke an (zwischen 0 und 100 %) +
      • +
      +
    +
+ + +=end html_DE + +=cut \ No newline at end of file