# $Id$
############################################################################
# 2019-01-20, v1.0.13
#
# v1.0.13
# - BUFIX: main::readingsBulkUpdateIfChanged called by ./FHEM/70_NEUTRINO.pm (1191)
#
# v1.0.12
# - BUFIX: $_ ersetzt durch $uResult
#
# v1.0.11
# - BUFIX: Code Optimierungen
#
# v1.0.10
# - BUFIX: Code Optimierungen
#
# v1.0.9
# - BUFIX: BUG EPG Info https://forum.fhem.de/index.php/topic,54481.msg665959.html#msg665959
# Change Volume
# - CHANGE Readings für EPG zurücksetzen wenn keine Infos vorhanden sind
#
# v1.0.8
# - BUFIX: Code Optimierungen
# Zeilenumbruch in EPG Informationen entfernt
# NEUTRINO BUG Umschalten wenn EGP und CHANNEL_ID nicht passen!
# BUG leeres EPG https://forum.fhem.de/index.php/topic,54481.msg665355.html#msg665355
#
# v1.0.7 erste SVN Version
# - FEATURE: Reading Model hinzugefügt
# - CHANGE CommandRef ergänzt
# - BUFIX: Optimierung Neutrino Version/Model auslesen bei
# Änderung Power
# Initialisierung Device
#
# 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 "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 "model") {
$serviceurl = "info";
}
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 $uResult = $a[2];
if ( $uResult =~ m/^\d+$/ && $uResult >= 0 && $uResult <= 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 $uResult = $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";
}
# volume data = 0 then data = off
if ($service eq "volume" && $data eq '0'){
$data = "off";
}
# 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";
readingsBulkUpdateIfChanged( $hash, "power", "off" );
readingsBulkUpdateIfChanged( $hash, "state", "off" );
readingsBulkUpdateIfChanged( $hash, "presence", $presence )
if ( ReadingsVal( $name, "presence", "" ) ne $presence );
}
}
# data received
elsif ($data) {
$presence = "present";
$state = "on";
readingsBulkUpdateIfChanged( $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) {
readingsBulkUpdateIfChanged( $hash, "power","off");
readingsBulkUpdateIfChanged( $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";
readingsBulkUpdateIfChanged( $hash, "power","on");
readingsBulkUpdateIfChanged( $hash, "state", "on" );
delete($hash->{helper}{FIRSTSTART});
}
#2017.07.25 - Erste Start: NUTRINO Version auslesen
if ($hash->{helper}{FIRSTSTART} eq '') {
NEUTRINO_SendCommand( $hash, "version" );
NEUTRINO_SendCommand( $hash, "model" );
$hash->{helper}{FIRSTSTART} = '1';
}
#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";
readingsBulkUpdateIfChanged( $hash, "power", "on");
readingsBulkUpdateIfChanged( $hash, "state", "on" );
}
elsif(index($type, "on") != -1) {
Log3 $name, 5, "NEUTRINO $name TYP = ON";
readingsBulkUpdateIfChanged( $hash, "power", "off");
readingsBulkUpdateIfChanged( $hash, "state", "standby" );
}
else {
readingsBulkUpdateIfChanged( $hash, "power", "off");
readingsBulkUpdateIfChanged( $hash, "state", "standby" );
$state = "off";
}
NEUTRINO_SendCommand( $hash, "recordmode" );
}
else{
readingsBulkUpdateIfChanged( $hash, "power", "undefined" );
readingsBulkUpdateIfChanged( $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";
readingsBulkUpdateIfChanged( $hash, "bouquetnr", @ans[0] );
NEUTRINO_SendCommand( $hash, "bouquet_list" );
}
}
else {
readingsBulkUpdateIfChanged( $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
readingsBulkUpdateIfChanged( $hash, "volume", substr($cmd,1) );
}
elsif (index(lc(@ans[0]), "off") != -1) {
#2017.07.12 - Nur bei einer Aenderung schreiben
readingsBulkUpdateIfChanged( $hash, "volume", "0" );
}
elsif (@ans[0]) {
#2017.07.12 - Nur bei einer Aenderung schreiben
readingsBulkUpdateIfChanged( $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
readingsBulkUpdateIfChanged( $hash, "mute","on");
}
else{
readingsBulkUpdateIfChanged( $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) {
readingsBulkUpdateIfChanged( $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) {
readingsBulkUpdateIfChanged( $hash, "mute","off");
}
}
else {
Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no mute could be extracted";
}
}
# model
elsif ( $service eq "model" ) {
if (@ans[0]) {
readingsBulkUpdateIfChanged( $hash, "model",@ans[0]);
}
else {
Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no model 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 ) {
readingsBulkUpdateIfChanged( $hash, "timer$i", $line );
readingsBulkUpdateIfChanged( $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"}
readingsBulkUpdateIfChanged( $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"}
readingsBulkUpdateIfChanged( $hash, "timer$i" . "repeat", $timerrepeat );
# timer repcount
readingsBulkUpdateIfChanged( $hash, "timer$i" . "repcount", @timerlist[3] );
# announceTime
if ($timerannounceTime eq "0") {readingsBulkUpdateIfChanged( $hash, "timer$i" . "manualrecord", "" );}
else {
my $date = localtime($timerannounceTime)->strftime('%F %T');
readingsBulkUpdateIfChanged( $hash, "timer$i" . "announceTime", $date );
}
# startTime
my $date = localtime($timerstartTime)->strftime('%F %T');
readingsBulkUpdateIfChanged( $hash, "timer$i" . "startTime", $date );
# stopTime
my $date = localtime($timerstopTime)->strftime('%F %T');
readingsBulkUpdateIfChanged( $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++;
}
readingsBulkUpdateIfChanged( $hash, "timer$i" . "name", $timername );
}
# find running record
if ($timername ne "") {
if ($neutrinotime > $timerstartTime && $neutrinotime < $timerstopTime) {
readingsBulkUpdateIfChanged( $hash, "recordchannel", $timername );
NEUTRINO_SendCommand( $hash, "epginforecord","");
}
}
$i++;
}
}
}
# timer count
#2017.07.12 - Nur Änderungen schreiben
readingsBulkUpdateIfChanged( $hash, "timer_count", $i );
# timer maxcount
if ($timermaxcount <= $i) {
#2017.07.12 - Nur Änderungen schreiben
readingsBulkUpdateIfChanged( $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", ) {
readingsBulkUpdateIfChanged( $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};
readingsBulkUpdateIfChanged( $hash, "recordtitle",$readvalue);
}
}
else {
Log3 $name, 5,
"NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ERROR: no record epg information could be found";
}
}
# channel (ID)
elsif ( $service eq "zapto" ) {
if (@ans[0]) {
if (@ans[0] eq 'ok') {
# Umschalten eines Sender erkannt / Aktuellen Sender abfragen!
Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] detect switch channel";
NEUTRINO_SendCommand( $hash, "zapto" );
}
else {
# Prüfen ob div. Informationen aktualisiert werden müssen
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]";
readingsBulkUpdateIfChanged( $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, "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]) {
readingsBulkUpdateIfChanged( $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) {
readingsBulkUpdateIfChanged( $hash, "input","tv");
}
elsif(index(lc(@ans[0]), "radio") != -1) {
readingsBulkUpdateIfChanged( $hash, "input","radio");
}
else{
readingsBulkUpdateIfChanged( $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
readingsBulkUpdateIfChanged( $hash, "recordmode","on");
}
elsif(index(lc(@ans[0]), "off") != -1) {
#2017.07.12 - Nur bei einer Aenderung schreiben
readingsBulkUpdateIfChanged( $hash, "recordmode","off");
}
else{
readingsBulkUpdateIfChanged( $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};
readingsBulkUpdateIfChanged( $hash, "channel_name",$readvalue);
# channel displayname
$readvalue =~ s/\s/_/g;
readingsBulkUpdateIfChanged( $hash, "channel",$readvalue);
if(ref($return->{prog}) eq 'ARRAY') {
Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ARRAY!!!" . ref($return->{prog});
}else {Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] ARRAY!!! NOT" . ref($return->{prog});}
Log3 $name, 5, "NEUTRINO $name [NEUTRINO_ReceiveCommand] [$service] Data = $data";
if (defined( $return->{prog} ) && ref($return->{prog}) eq 'ARRAY' ) {
#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;
readingsBulkUpdateIfChanged( $hash, "egp_current_number", $readnumber);
last;
}
$i++;
}
# 2017.07.27 - BUG NEUTRINO / Umschalten wenn EGP und CHANNEL_ID nicht passen!
if (ReadingsVal( $name, "channel_id", "" ) ne $return->{prog}[$readnumber]{channel_id}) {
Log3 $name, 0, "NEUTRINO [BUG NEUTRINO] EPG channel_id = " . $return->{prog}[$readnumber]{channel_id} ;
NEUTRINO_SendCommand( $hash, "zapto", $return->{prog}[$readnumber]{channel_id} );
}
# currentTitel
$readvalue = $return->{prog}[$readnumber]{description};
readingsBulkUpdateIfChanged( $hash, "currentTitle",$readvalue);
foreach ( "eventid","description","info1","info2","start_t","stop_t","duration_min","date","channel_id","stop_sec","start_sec", ) {
$reading = $_;
if ($_ eq "eventid") {$readingname = $reading ;} else {$readingname = "egp_current_" . $_;}
if ( defined( $return->{prog}[$readnumber]{$reading} )
&& lc( $return->{prog}[$readnumber]{$reading} ) ne "n/a" )
{
$readvalue = $return->{prog}[$readnumber]{$reading};
$readvalue =~ s/\n//g;
if ($readvalue) {
readingsBulkUpdateIfChanged( $hash, $readingname, $readvalue );
}
else {
readingsBulkUpdateIfChanged( $hash, $readingname, "-" );
}
}
else {
readingsBulkUpdateIfChanged( $hash, $readingname, "-" );
}
}
}else{
readingsBulkUpdateIfChanged( $hash, "eventid", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_description", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_info1", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_info2", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_start_t", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_stop_t", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_duration_min", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_date", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_channel_id", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_stop_sec", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_start_sec", "-" );
readingsBulkUpdateIfChanged( $hash, "egp_current_number", "-" );
readingsBulkUpdateIfChanged( $hash, "currentTitle", "-" );
}
}
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
readingsBulkUpdateIfChanged( $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,"="));
readingsBulkUpdateIfChanged( $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_* - 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 intervall 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_* - 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