[Q] Hilfe gesucht: Loewe Connect ID DR+ Smart-TV mit FHEM steuern

Begonnen von der.einstein, 08 April 2017, 15:40:50

Vorheriges Thema - Nächstes Thema

CoolTux

Lese Dir mal das Developer Wiki durch da steht alles drin was Du wissen musst.

in der Set Funktion arbeitest Du mit Abfragen

if() {

} elsif() {

} elsif() {

} else {

}


Wichtig ist auch das Du Dich daran hälst


_Set($$@) {

    my ($hash, $name, @aa)  = @_;
    my ($cmd, @args)        = @aa;
}
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

der.einstein

Danke CoolTux für den Hinweis! Hat mir weitergeholfen.

Mit ein paar Änderungen hab ich es jetzt soweit, dass ich über "get MyLoewe ..." alle Befehle absetzen kann, wie mit dem Skript.
Darunter auch alle Fernbedienungstasten (wobei das bei get natürlich quatsch ist).

package main;

use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;
use XML::Twig;
#use Net::Address::Ethernet;
#require Net::Address::Ethernet;
#Net::Address::Ethernet->import(get_address);
use Net::Ping::External qw(ping);
use Net::Wake;
use Data::Dumper::Simple;

# Declare functions
sub LoeweTV_Define($$);
sub LoeweTV_Initialize($);
sub LoeweTV_Get($$@);
sub LoeweTV_Set($$@);
sub LoeweTV_hostUp;
sub LoeweTV_checkAccess;
sub LoeweTV_sendRequest;

sub LoeweTV_Initialize($) {
    my ($hash) = @_;
    Log3 $hash, 5, "LoeweTV_Initialize: Entering";
    $hash->{GetFn}      = "LoeweTV_Get";
    $hash->{SetFn}      = "LoeweTV_Set";
    $hash->{DefFn}      = "LoeweTV_Define";

    $hash->{AttrList} =
    "ip " .
    "tvmac " .
    "action " .
    "RCkey " .
    "clientid " .
    "fcid " .
    "status:Accepted,Pending,Denied,undef " .
    "connectsuccess:true,false " .
    "pingresult:down,up " .
    "mac " .
    "lastersponse " .
    "lastchunk " .
    "volstate " .
    "mutstate:0,1 " .
    "curlocator " .
    "curevent " .
    "nextevent " .
    $readingFnAttributes;

    }

sub LoeweTV_Define($$) {
    my ( $hash, $def ) = @_;
    my @a = split( "[ \t][ \t]*", $def );
    my $name = $hash->{NAME};
    my $ip = $a[2];
    my $tvmac = $a[3];
    my $fcid = $a[4];
    if ($fcid = undef){$fcid = 1234};
    $hash->{ip} = $ip;
    $hash->{tvmac} = $tvmac;
    $hash->{fcid} = $fcid;
    $hash->{mac} = "";
    $hash->{clientid} = "?";
    $hash->{status} = "Denied";
    Log3 $name, 5, "LoeweTV $name: called function LoeweTV_Define()";
    return undef;
}

sub LoeweTV_Set($$@) {
    my ($hash, $name, @aa ) = @_;
    my ($cmd, @args) = @aa;
    #my $name = $hash->{NAME};
    #print "LoeweSet was executed!";
    #print Dumper $hash;
    #print $cmd;
    #print @args;
    Log3 $name, 5, "LoeweTV $name: called function LoeweTV_Set()";
    return undef;
}

sub LoeweTV_Get($$@) {
    my ( $hash, $name, $opt, @args ) = @_;
    print Dumper $hash;
    print Dumper $opt;
    print Dumper @args;
    my $action = $opt;
    my $RCkey = $args[0];
    if ( ! defined($action)){$action = "GetDeviceData"};
    #$hash->{action} = $action;
    #$hash->{RCkey} = $args[0];
    #$hash->{action} = $a[0];
    #$hash->{RCkey} = $a[1];
    #$hash->{action} = "GetDeviceData";
    #$hash->{RCkey} = "";
    print "RUNNING SETKEY   \n";
    if (! defined $hash->{RCkey}){$hash->{RCkey} = ""};
    if (! defined $hash->{fcid}){$hash->{fcid} = "1234"};
    &LoeweTV_hostUp($hash,$hash->{ip},$hash->{tvmac},$hash->{mac});
    if (! defined $hash->{clientid}){$hash->{clientid} = "?"};
    &LoeweTV_checkAccess($hash,$hash->{clientid},$hash->{fcid});
    if ($hash->{status} eq "Accepted") {&LoeweTV_sendRequest($hash,$action,$RCkey);}
    Log3 $name, 5, "LoeweTV $name: called function LoeweTV_Get()";
    return undef,
}

sub LoeweTV_hostUp {
#my($hash{ip}, $hash{tvmac}, $hash{mac}) = @_;
my ( $hash, @a ) = @_;
my $ip = $a[0];
print "RUNNING PING: ";
if (ping(host=>$ip)) {$hash->{pingresult} = "up";print "ONLINE \n"}else{print "OFFLINE \n";Net::Wake::by_udp($hash->{ip},$hash->{tvmac});Net::Wake::by_udp($hash->{ip},$hash->{tvmac});Net::Wake::by_udp($hash->{ip},$hash->{tvmac});Net::Wake::by_udp($hash->{ip},$hash->{tvmac});Net::Wake::by_udp($hash->{ip},$hash->{tvmac});&LoeweTV_checkAccess($hash,$hash->{clientid},$hash->{fcid});&LoeweTV_sendRequest($hash,"InjectRCKey",22)};
return($hash->{pingresult});
}

sub LoeweTV_checkAccess {
print "RUNNING CHECKACCESS   \n";
#my($clientid,$fcid) = @_;
my ($hash,@a) = @_;
my $n = 1;
while (($hash->{status} ne "Accepted") and ($n<=3)) {$n=$n+1;&LoeweTV_sendRequest($hash,"RequestAccess",0,)};
print "RAN CHECKACCESS: $hash->{status}   \n";
return($hash->{status});
}

sub LoeweTV_sendRequest {
my($hash, $action, $RCkey) = @_;
print "STARTING SENDREQUEST: $action   \n";
if ( ! defined($action)){$action = "GetDeviceData"};
my ($message, $response, $request, $userAgent, $noob, $twig2, $content, $handlers);
our $result ="";
my $header = "<env:Envelope
xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:ltv='urn:loewe.de:RemoteTV:Tablet'>
<env:Body>\n";
my $action_xml1 = " <ltv:$action>\n";
my $header2 = " <ltv:fcid>".$hash->{fcid}."</ltv:fcid>
<ltv:ClientId>".$hash->{clientid}."</ltv:ClientId>\n";
my $action_xml2 = " \n </ltv:$action>";
my $footer = "\n</env:Body>
</env:Envelope>\n";
my %actions = (
        "RequestAccess" => [sub {$content='<ltv:DeviceType>Apple iPad</ltv:DeviceType>
<ltv:DeviceName>FHEM</ltv:DeviceName>
<ltv:DeviceUUID>'.$hash->{mac}.'</ltv:DeviceUUID>
<ltv:RequesterName>Assist Media App</ltv:RequesterName>'},
{'m:ClientId' => sub {$hash->{clientid} = $_->text_only('m:ClientId');},
'm:AccessStatus' => sub {$hash->{status} = $_->text_only('m:AccessStatus');},}
],
        "InjectRCKey",  => [sub {$content='<InputEventSequence>
<RCKeyEvent alphabet="l2700" value="'.$RCkey.'" mode="press"/>
<RCKeyEvent alphabet="l2700" value="'.$RCkey.'" mode="release"/>
</InputEventSequence>'}],
        "GetDeviceData"  => [sub {$content='';$result="m:MAC-Address"}],
        "GetChannelList"    => [sub {$content="<ltv:ChannelListView>".$RCkey."</ltv:ChannelListView>
<ltv:QueryParameters>
<ltv:Range startIndex='".$ARGV[4]."' maxItems='9999'/>
<ltv:OrderField field='userChannelNumber' type='ascending'/>
</ltv:QueryParameters>";$result="m:GetChannelListResponse"}],
"GetListOfChannelLists" => [sub {$content="<ltv:QueryParameters>
<ltv:Range startIndex='".$RCkey."' maxItems='9999'/>
<ltv:OrderField field='userChannelNumber' type='ascending'/>
</ltv:QueryParameters>";$result="m:ResultItemChannelLists"}],
"GetMediaItem"    => [sub {$content='<MediaItemReference mediaItemUuid="'.$RCkey.'"/>';$result="m:ShortInfo"}],
"GetMediaEvent"    => [sub {$content='<MediaEventReference mediaEventUuid="'.$RCkey.'"/>';$result="m:ShortInfo"}],
"GetChannelInfo" => [sub {$content=""}],
"GetCurrentPlayback"    => [sub {$content='';},
{"m:Locator" => sub {$hash->{lastchunk} = $_->text_only();},}
],
"GetCurrentEvent"    => [sub {$content="<ltv:Player>0</ltv:Player>";},
{"m:Name" => sub {$hash->{curevent}[0] = $_->text("m:Name");},
"m:ExtendedInfo" => sub {$hash->{curevent}[1] = $_->text("m:ExtendenInfo");},
"m:Locator" => sub {$hash->{curlocator} = $_->text_only("m:Locator");}},
],
"GetNextEvent"    => [sub {$content="<ltv:Player>0</ltv:Player>";$result="m:GetNextEventResponse"}],
"SetActionField"    => [sub {$content="<ltv:InputText>".$RCkey."</ltv:InputText>";$result="m:Result"}],
"SetVolume"    => [sub {$content="<Value>".$RCkey."</Value>";$result="m:Value"}],
"GetVolume"    => [sub {$content="";$result="m:Value"}],
"SetMute"    => [sub {$content="<Value>".$RCkey."</Value>";$result="m:Value"}],
"GetMute"    => [sub {$content="";$result="m:Value"}],
"GetDRPlusArchive" => [sub {$content="<ltv:QueryParameters>
<ltv:Range startIndex='".$RCkey."' maxItems='1000'/>
<ltv:OrderField field='userChannelNumber' type='ascending'/>
</ltv:QueryParameters>";$result="ltv:ResultItemDRPlusFragment"}],
    );
if ($actions{$action}[0]) {$actions{$action}[0]->();$handlers=$actions{$action}[1];} else {print "Unknown action: $action\n";};
$message = $header.$action_xml1.$header2.$content.$action_xml2.$footer;
$request = HTTP::Request->new(POST => 'http://'.$hash->{ip}.':905/loewe_tablet_0001');
$userAgent = LWP::UserAgent->new(agent => 'Assist Media/23 CFNetwork/808 Darwin/16.0.0');
$request->header('Accept' => '*/*');
$request->header('Accept-Encoding' => 'gzip, deflate');
$request->header('Accept-Language' => 'de-de');
$request->header('Connection' => 'keep-alive');
$request->header('SOAPAction' => $action);
$request->content_type("application/soap+xml; charset=utf-8");
$request->content($message);
$response = $userAgent->request($request);
$noob = $response->content;
$twig2 = XML::Twig->new(twig_handlers => $handlers,keep_encoding => 1)->parse($noob);
if($response->code == 200) {
$hash->{connectsuccess} = "true";
$hash->{lastresponse} = $response->content;
}
else {
$hash->{connectsuccess} = "false";
$hash->{lastresponse} = $response->error_as_HTML;
}
if($hash->{action} eq "RequestAccess"){return($hash->{status})}else{return($hash->{status})};
}

1;


=pod
=item device
=item summary control for Loewe TV devices via network connection
=item summary_DE Steuerung von Loewe TV Ger&auml;ten &uuml;ber das Netzwerk
=begin html

<a name="LoeweTV"></a>
<h3>LoeweTV</h3>

=end html

=begin html_DE

<a name="LoeweTV"></a>
<h3>LoeweTV</h3>

=end html_DE

=cut

CoolTux

Und warum nimmst Du get? Dafür ist doch set da. Mit set sendest Du Daten/Befehle an das Endgerät und mit get holst Du Informationen vom Endgerät.


Grüße
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

der.einstein

Das war designbedingt erstmal einfacher, da im Ausgangs-Skript nicht zwischen Get/Set unterschieden wurde, am Ende wurden ja nur Befehle an den TV gesendet. Wird aber jetzt geändert  8)

Folgende Fragen:
1. Wie implementiere ich, dass FHEM anzeigt, ob der TV online (nur LAN) ist, bzw. an ist (Programm wird angezeigt)? Wie ich die Infos vom TV kriege weiß ich, aber wie teile ich das FHEM mit? Kommt hier Pollen ins Spiel?
2. Wie implementiere ich, dass FHEM darüberhinaus einen "erweiterten Status" anzeigt, d.h. welches Programm wird angezeigt, welcher Film läuft? Wie oben: Ich weiß, wie ich es vom TV kriege, aber wie teile ich das FHEM mit.

Besten Dank!

CoolTux

Kurz als Anmerkung
Ich helfe gerne und werde Dir auch sicherlich weiter hier helfen, aber glaube mir es nützt Dir nichts wenn Du nicht wenigstens Dir das Developer Guide durch liest.


Nun zu Deinen Fragen. Die ja eigentlich einfach sein sollte. Zu mindest in der theoretischen Beantwortung.
Mit Readings. Alle Zustande eines Gerätes werden in FHEM mit Hilfe von Readings da gestellt.
Du musst also die Informationen Du Dein Gerät Dir (von alleine = push, über Zwang = pollen) liefert aufarbeiten und dann als sinnvolle Reading darstellen.

Liefert das Gerät denn Informationen als Response zum Beispiel nach jedem Schaltbefehl? Kannst Du allgemeine Informationen durch eine Request Anforderung abrufen?
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

der.einstein

Zu meiner Verteidigung: ich hab das Developer Wiki durchgelesen und ausgedruckt. Leider bin ich damit alleine nicht zu etwas gekommen was funktioniert hat.

Readings, ok, dann werd ich mich da schlau machen.

Das Gerät liefert immer Antworten (meist sinnvoll) zurück, die von einer Bestätigung bis zu allgemeinen Infos reichen.

Gesendet von meinem LG-D855 mit Tapatalk


CoolTux

Wir können gerne zusammen schauen. Wichtig ist erstmal das Du ein allgemeines Konstrukt auf baust.
Nicht alles in eine Routine bauen sondern versuchen sinnvoll auf mehrere kleine zu verteilen.

Ich gehe davon aus das der Fernsehr nicht von sich aus die Daten liefert sondern nur beim absetzen eines Befehls als Response etwas kommt.

Kannst Du einen allgemeinen Befehl absetzen wo Du eine relativ große Anzahl von Daten bekommst? Also kein schalte mal um oder so, sondern he wie geht es Dir. Oder stell Dich mal vor wo Du Daten geliefert bekommst wie Modell Firmware aktueller Sender,aktuelles Volume und so.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

CoolTux

Kannst Du mir etwas bei Deinem Code helfen?

{"m:Locator" => sub {$hash->{lastchunk} = $_->text_only();},}

$hash->{lastchunk} ist das der $hash von FHEM? Und sehe ich das richtig. Du schreibst den Wert von ' $_->text_only() ' nach $hash->{lastchunk} ??

Wäre dann folgendes korrekt


'm:AccessStatus' => sub {readingsSingleUpdate($name,'state',"$_->text_only('m:AccessStatus'",1);}


Schreibe den Wert ' $_->text_only('m:AccessStatus ' als Reading in state. Hierzu wird eine Funktion aufgerufen.


Ich versuche mich gerade in Deinen Code ein zu arbeiten. Allerdings muß ich gestehen das ich Ihn so sehr schlecht lesen kann. Daher habe ich mir erlaubt Ihn zu entzerren und Lesefreundlich zu machen. Hoffe ist ok.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

CoolTux

Hier mal eine Version zum testen wenn Du magst.
Kann sein das er noch so einiges an meckert, wäre super wenn Du das dann bitte hier einstellen würdest. Solltest Du lieber alleine weiter machen wollen und nur Fragen stellen wollen ist das auch ok. Aber bitte Bescheid geben. Nicht das ich umsonst weiter mache   ;D


package main;

use strict;
use warnings;


my $missingModul = "";
eval "use JSON;1" or $missingModul .= "JSON ";
eval "use LWP::UserAgent;1" or $missingModul .= "LWP::UserAgent ";
eval "use HTTP::Request::Common;1" or $missingModul .= "HTTP::Request::Common ";
eval "use XML::Twig;1" or $missingModul .= "XML::Twig ";
#use Net::Address::Ethernet;
#require Net::Address::Ethernet;
#Net::Address::Ethernet->import(get_address);
eval "use Net::Ping::External qw(ping);1" or $missingModul .= "Net::Ping::External ";
eval "use Net::Wake;1" or $missingModul .= "Net::Wake;1 ";
use Data::Dumper::Simple;





# Declare functions
sub LoeweTV_Define($$);
sub LoeweTV_Undef($$);
sub LoeweTV_Initialize($);
sub LoeweTV_Get($@);
sub LoeweTV_Set($@);
sub LoeweTV_hostUp($);
sub LoeweTV_checkAccess($);
sub LoeweTV_sendRequest($$$);




sub LoeweTV_Initialize($) {
    my ($hash) = @_;
   
    #$hash->{GetFn}      = "LoeweTV_Get";
    $hash->{SetFn}      = "LoeweTV_Set";
    $hash->{DefFn}      = "LoeweTV_Define";
    $hash->{UndefFn}    = "LoeweTV_Undef";

    $hash->{AttrList}   = "ip " .
                        "tvmac " .
                        "action " .
                        "RCkey " .
                        "clientid " .
                        "fcid " .
                        "status:accepted,Pending,Denied,undef " .
                        "connectsuccess:true,false " .
                        "pingresult:down,up " .
                        "mac " .
                        "lastersponse " .
                        "lastchunk " .
                        "volstate " .
                        "mutstate:0,1 " .
                        "curlocator " .
                        "curevent " .
                        "nextevent " .
                        $readingFnAttributes;
}

sub LoeweTV_Define($$) {

    my ( $hash, $def ) = @_;
   
    my @a               = split( "[ \t][ \t]*", $def );

   
    return "too few parameters: define <NAME> LoeweTV <HOST> <TV-MAC> <FC-ID>" if( @a != 5 ) ;
    return "Cannot define Loewe device. Perl modul ${missingModul}is missing." if ( $missingModul );

   
   
   
    my $name            = $hash->{NAME};
    my $host            = $a[2];
    my $tvmac           = $a[3];
    my $fcid            = $a[4];
   
   
    $fcid               = 1234 if($fcid = undef);
   
    $hash->{HOST}       = $host;
    $hash->{TVMAC}      = $tvmac;
    $hash->{FCID}       = $fcid;
    #$hash->{MAC}        = "";
    $hash->{CLIENTID}   = "?";
    #$hash->{STATUS}     = "Denied";
   
   
    Log3 $name, 3, "LoeweTV $name: defined LoeweTV device";
   
    $modules{LoeweTV}{defptr}{HOST} = $hash;
    readingsSingleUpdate($hash,'state','denied',1);
   
    return undef;
}

sub LoeweTV_Undef($$) {

    my ( $hash, $arg ) = @_;


    #RemoveInternalTimer($hash);
    delete $modules{LoeweTV}{defptr}{HOST} if( defined($modules{GardenaSmartBridge}{defptr}{HOST}) );

    return undef;
}

sub LoeweTV_Set($@) {
   
    my ($hash, $name, $cmd, @args) = @_;
    my ($arg, @params) = @args;

   
    if( lc $cmd eq 'setactionfield' ) {

    } elsif( lc $cmd eq 'setvolume' ) {
   
    } elsif( lc $cmd eq 'setmute' ) {
   
    } elsif( lc $cmd eq '' ) {
   
    } elsif( lc $cmd eq '' ) {
   
   
    } elsif( lc $cmd eq '' ) {
   
   
    } elsif( lc $cmd eq '' ) {
   
   
    } else {
   
        my $list    = 'SetActionField SetVolume:slider,0,1,100 SetMute:on,off';
       
        return "Unknown argument $cmd, choose one of $list";
    }
   
    #my $name = $hash->{NAME};
    #print "LoeweSet was executed!";
    #print Dumper $hash;
    #print $cmd;
    #print @args;
   
   
    $hash->{helper}{RCkey} = "" if( not defined $hash->{helper}{RCkey} );
   
    $hash->{helper}{fcid} = "1234" if( not defined $hash->{helper}{fcid} );
   
    LoeweTV_hostUp($hash);
   
   
   
   
   
   
   
   
   
    if (! defined $hash->{CLIENTID}){$hash->{CLIENTID} = "?"};
   
    &LoeweTV_checkAccess($hash,$hash->{CLIENTID},$hash->{FCID});
   
    if ($hash->{status} eq "accepted") {&LoeweTV_sendRequest($hash,$action,$RCkey);}
   
   
   
    Log3 $name, 5, "LoeweTV $name: called function LoeweTV_Set()";
    return undef;
}

# sub LoeweTV_Get($@) {
#     my ( $hash, $name, $opt, @args ) = @_;
#     print Dumper $hash;
#     print Dumper $opt;
#     print Dumper @args;
#     my $action = $opt;
#     my $RCkey = $args[0];
#     if ( ! defined($action)){$action = "GetDeviceData"};
#     #$hash->{action} = $action;
#     #$hash->{RCkey} = $args[0];
#     #$hash->{action} = $a[0];
#     #$hash->{RCkey} = $a[1];
#     #$hash->{action} = "GetDeviceData";
#     #$hash->{RCkey} = "";
#     print "RUNNING SETKEY   \n";
#     if (! defined $hash->{RCkey}){$hash->{RCkey} = ""};
#     if (! defined $hash->{FCID}){$hash->{FCID} = "1234"};
#     &LoeweTV_hostUp($hash,$hash->{ip},$hash->{tvmac},$hash->{mac});
#     if (! defined $hash->{CLIENTID}){$hash->{CLIENTID} = "?"};
#     &LoeweTV_checkAccess($hash,$hash->{CLIENTID},$hash->{FCID});
#     if ($hash->{status} eq "accepted") {&LoeweTV_sendRequest($hash,$action,$RCkey);}
#     Log3 $name, 5, "LoeweTV $name: called function LoeweTV_Get()";
#     return undef,
# }

sub LoeweTV_hostUp($) {

    my $hash        = shift;
   
    my $host        = $hash->{HOST};
    my $tvmac       = $hash->{TVMAC};

    print "RUNNING PING: ";
   
    if (ping(host=>$host)) {
        $hash->{helper}{pingresult} = "up";print "ONLINE \n"
       
    } else {
   
        print "OFFLINE \n";
        ##### Wieso so oft???
        # by_udp($host,$tvmac)    sollte das nicht ausreichen??
        Net::Wake::by_udp($host,$tvmac);
        Net::Wake::by_udp($host,$tvmac);
        Net::Wake::by_udp($host,$tvmac);
        Net::Wake::by_udp($host,$tvmac);
        Net::Wake::by_udp($host,$tvmac);
       
        LoeweTV_checkAccess($hash,$hash->{CLIENTID},$hash->{FCID});
        LoeweTV_sendRequest($hash,"InjectRCKey",22);
    }
   
    return($hash->{helper}{pingresult});
}

sub LoeweTV_checkAccess($) {

    my ($hash)      = shift;
    my $name        = $hash->{NAME};
    my $n           = 1;
   
   
    while ((ReadingsVal($name,'state','denied') ne "accepted") and ($n<=3)) {
   
        $n=$n+1;
        LoeweTV_sendRequest($hash,"RequestAccess",0)
    };
   
   
   
    print "run CHECKACCESS: ReadingsVal($name,'state','denied')   \n";
   
   
    return(ReadingsVal($name,'state','denied'));
   
   
    }

sub LoeweTV_sendRequest($$$) {

    my($hash, $action, $RCkey)  = @_;
   
    my $name                    = $hash->{NAME};
   

    print "STARTING SENDREQUEST: $action   \n";
   
    $action = "GetDeviceData" if( ! defined($action));
   
    my ($message, $response, $request, $userAgent, $noob, $twig2, $content, $handlers);
   
    our $result ="";
   
    my $header = "<env:Envelope
        xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'
        xmlns:ltv='urn:loewe.de:RemoteTV:Tablet'><env:Body>\n";
   
    my $action_xml1 = "<ltv:$action>\n";
   
    my $header2 = "<ltv:fcid>".$hash->{FCID}."</ltv:fcid>
            <ltv:ClientId>".$hash->{CLIENTID}."</ltv:ClientId>\n";

    my $action_xml2 = "\n</ltv:$action>";
   
    my $footer = "\n</env:Body></env:Envelope>\n";
   
   
    my %actions = (
            "RequestAccess"         =>  [sub {$content='<ltv:DeviceType>Apple iPad</ltv:DeviceType>
                                            <ltv:DeviceName>FHEM</ltv:DeviceName>
                                            <ltv:DeviceUUID>'.$hash->{mac}.'</ltv:DeviceUUID>
                                            <ltv:RequesterName>Assist Media App</ltv:RequesterName>'},
                                            {'m:ClientId' => sub {$hash->{CLIENTID} = $_->text_only('m:ClientId');},
                                            'm:AccessStatus' => sub {readingsSingleUpdate($name,'state',"$_->text_only('m:AccessStatus'",1);},}
                                        ],
                                   
            "InjectRCKey"           =>  [sub {$content='<InputEventSequence>
                                            <RCKeyEvent alphabet="l2700" value="'.$RCkey.'" mode="press"/>
                                            <RCKeyEvent alphabet="l2700" value="'.$RCkey.'" mode="release"/>
                                            </InputEventSequence>'}],
                                       
            "GetDeviceData"         =>  [sub {$content='';$result="m:MAC-Address"}],
           
            "GetChannelList"        =>  [sub {$content="<ltv:ChannelListView>".$RCkey."</ltv:ChannelListView>
                                            <ltv:QueryParameters>
                                            <ltv:Range startIndex='".$ARGV[4]."' maxItems='9999'/>
                                            <ltv:OrderField field='userChannelNumber' type='ascending'/>
                                            </ltv:QueryParameters>";$result="m:GetChannelListResponse"}
                                        ],
                                       
            "GetListOfChannelLists" =>  [sub {$content="<ltv:QueryParameters>
                                            <ltv:Range startIndex='".$RCkey."' maxItems='9999'/>
                                            <ltv:OrderField field='userChannelNumber' type='ascending'/>
                                            </ltv:QueryParameters>";$result="m:ResultItemChannelLists"}
                                        ],
                                       
            "GetMediaItem"          =>  [sub {$content='<MediaItemReference mediaItemUuid="'.$RCkey.'"/>';$result="m:ShortInfo"}],
           
            "GetMediaEvent"         =>  [sub {$content='<MediaEventReference mediaEventUuid="'.$RCkey.'"/>';$result="m:ShortInfo"}],
           
            "GetChannelInfo"        =>  [sub {$content=""}],
           
            "GetCurrentPlayback"    =>  [sub {$content='';},
                                            {"m:Locator" => sub {$hash->{lastchunk} = $_->text_only();},}
                                        ],
                                       
            "GetCurrentEvent"       =>  [sub {$content="<ltv:Player>0</ltv:Player>";},
                                            {"m:Name" => sub {$hash->{curevent}[0] = $_->text("m:Name");},
                                            "m:ExtendedInfo" => sub {$hash->{curevent}[1] = $_->text("m:ExtendenInfo");},
                                            "m:Locator" => sub {$hash->{curlocator} = $_->text_only("m:Locator");}},
                                        ],
                                       
            "GetNextEvent"          => [sub {$content="<ltv:Player>0</ltv:Player>";$result="m:GetNextEventResponse"}],
           
            "SetActionField"        => [sub {$content="<ltv:InputText>".$RCkey."</ltv:InputText>";$result="m:Result"}],
           
            "SetVolume"             => [sub {$content="<Value>".$RCkey."</Value>";$result="m:Value"}],
           
            "GetVolume"             => [sub {$content="";$result="m:Value"}],
           
            "SetMute"               => [sub {$content="<Value>".$RCkey."</Value>";$result="m:Value"}],
           
            "GetMute"               => [sub {$content="";$result="m:Value"}],
           
            "GetDRPlusArchive"      => [sub {$content="<ltv:QueryParameters>
                                            <ltv:Range startIndex='".$RCkey."' maxItems='1000'/>
                                            <ltv:OrderField field='userChannelNumber' type='ascending'/>
                                            </ltv:QueryParameters>";$result="ltv:ResultItemDRPlusFragment"}
                                        ],
    );


    if ($actions{$action}[0]) {
   
        $actions{$action}[0]->();
        $handlers=$actions{$action}[1];
   
    } else {
        print "Unknown action: $action\n";
    };

    # Aufbau der Messages
    $message = $header.$action_xml1.$header2.$content.$action_xml2.$footer;
   
   
    # Aufbau der HTTP Verbindung
    $request = HTTP::Request->new(POST => 'http://'.$hash->{ip}.':905/loewe_tablet_0001');
   
    # Aufbau des Agents
    $userAgent = LWP::UserAgent->new(agent => 'Assist Media/23 CFNetwork/808 Darwin/16.0.0');
   
    Aufbau des Headers
    $request->header('Accept' => '*/*');
    $request->header('Accept-Encoding' => 'gzip, deflate');
    $request->header('Accept-Language' => 'de-de');
    $request->header('Connection' => 'keep-alive');
   
    $request->header('SOAPAction' => $action);
   
    # !!!
    $request->content_type("application/soap+xml; charset=utf-8");
   
    # ???
    $request->content($message);
    $response = $userAgent->request($request);
   
   
    $noob = $response->content;
   
   
   
   
   
   
    $twig2 = XML::Twig->new(twig_handlers => $handlers,keep_encoding => 1)->parse($noob);
   
   
   
   
    if($response->code == 200) {
        $hash->{connectsuccess} = "true";
        $hash->{lastresponse} = $response->content;
   
    } else {
        $hash->{connectsuccess} = "false";
        $hash->{lastresponse} = $response->error_as_HTML;
    }
   
    if($hash->{action} eq "RequestAccess"){
        return($hash->{status})
    }else{
        return($hash->{status})
    };
}

1;


=pod
=item device
=item summary control for Loewe TV devices via network connection
=item summary_DE Steuerung von Loewe TV Ger&auml;ten &uuml;ber das Netzwerk
=begin html

<a name="LoeweTV"></a>
<h3>LoeweTV</h3>

=end html

=begin html_DE

<a name="LoeweTV"></a>
<h3>LoeweTV</h3>

=end html_DE

=cut
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

der.einstein

Also die Funktion "text_only" kommt von XML::Twig und entnimmt Werte aus XML/SOap.
Diese Rückgabe-Werte hab ich dann nach "lastchunk" geschoben. Das macht z. B. Bei einfachen Dingen wie "GetVolume" Sinn, es gibt nur 1 Wert zurück.
Das Ganze ist nur vorläufig, ich wusste jetzt auch nicht wohin mit dem Wert sonst, wenn nicht in den Geräte-Hash.

Ah, ok, du hast die Subroutine gändert, damit sie gleich den Wert in ein Reading schiebt? Das könnte so klappen. 

Eine einfache Funktion für "Hallo, ich bin der Fernseher" ist "GetDeviceData". Die gibt Namen, Mac, Status, Sw-Version etc. zurück.

Werde deinen Code sehr gerne heut Abend testen.

Grüße!


Gesendet von meinem LG-D855 mit Tapatalk


der.einstein

Der TV sendet nur an FHEM oder irgendwen, wenn er vorher angefragt wurde.
Es gibt zwar ein Subscription Feature, das ist mir aber aktuell zu hoch. Hierbei soll der TV sich einmal beim SOap Server (!) registrieren und sendet dann ungefragt Antworten, wenn z. B. mit der normalen Fernbedienung geschalten wurde.

Gesendet von meinem LG-D855 mit Tapatalk


CoolTux

Zitat von: der.einstein am 07 September 2017, 16:18:12
Der TV sendet nur an FHEM oder irgendwen, wenn er vorher angefragt wurde.
Es gibt zwar ein Subscription Feature, das ist mir aber aktuell zu hoch. Hierbei soll der TV sich einmal beim SOap Server (!) registrieren und sendet dann ungefragt Antworten, wenn z. B. mit der normalen Fernbedienung geschalten wurde.

Gesendet von meinem LG-D855 mit Tapatalk

Na das ist doch ne coole Sache  ;D
Ich werde sehen das ich dann heute Abend noch bisschen was anpassen jetzt wo ich weiß was Du da willst.
Um beim Beispiel zu bleiben. Wenn diese Funktion bei einem getVolume einen Wert zurück gibt, dann ist das doch ein Wert der weiter verarbeitet wird und an den Fernsehr gesendet wird, oder? Das ist ja noch nicht das tatsächliche Volume vom Fernsehr. Wozu im Hash parken und nicht in eine einfache Variable?
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

der.einstein

Achso, naja eigentlich passiert beides.
Bei meinem ersten Skript, dass ich hochgeldane habe sende ich den "GetVolume" Befehl ab (ohne Argument sozusagen).
Dann bekommt man, wenn der TV den Befehl akzeptiert, was er sollte, eine Antwort zurück.
Bei mir war das dann "220000" --> das ist die Lautstärke.
Mit "SetVolume 110000" konnte ich die Lautsstärke leiser machen und mit "SetVolume 220000" wieder lauter. --> hier gibt es als Antwort "0".
Ähnlich ist es bei "GetMute" und "SetMute". Hier setzt bzw. erhält man "0" oder "1".

CoolTux

Und was genau soll 220000 sein? Eventuell 22 als Lautstärke?

Es geht ja darum Informationen des Gerätes in Readings zu schreiben. Da hilft die 220000 erstmal wenig, wir müssen das zur Lautstärke des Fernsehrs zuordnen können.

Aber davon mal ganz ab musst Du mir bitte bei der Reihenfolge helfen.
Angefangen mit dem was wir tatsächlich brauchen um ein Gespräch an zu fangen bis dahin wo wir Informationen bekommen die wir auswerten können.


Also, was brauchen wir um einen ersten Kontakt mit dem Fernsehr auf zu bauen?
Beispiel: TV IP, TV MAC
Was bekommen wir zurück nach unserer ersten Anfrage und brauchen wir die Info?
Beispiel: Token, oder eine ID die wir immer für die Verbindung brauchen.

Als zweites rufen alle wichtigen Informationen für die Readings ab. Modell, Firmware, aktueller Sender, aktuelles Volume, welcher Eingang (SCART) und so weiter.

Wir müssen also eine Kommunikationsroutine aufbauen bevor wir überhaupt irgendwas schalten wollen. Denn erstmal ist interessant  wie der aktuelle Status ist bevor wir was schalten. Wenn schon Volume 12 ist müssen wir es ja nicht einstellen, also als set senden.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

der.einstein

Also,
Zunächst muss man die IP des TV wissen,
Wenn er in dem Moment an ist, kann er seine MAC selbst melden (GetDeviceData, benötigt kein Handshake).
Mit IP und MAC muss ein RequestAccess gesendet werden (inkl. FHEM-MAC), dies 3 mal: 1. Bekanntmachung von FHEM 2. Handshake 3. Einholen der Antwort mit Rückgabewert "Accepted". Hier erhält man eine ClientId zurück, diese sollte fortan immer mit übertragen werden.
Von da an kann ich alle anderen Befehle senden. Es gibt immer einen Rückgabewert. Dieser ist eine Soap-Message. Ist es nur 1 Wert, d. H. Scalar, ist es kein Problem den zu extrahieren. Aber beim abfragen der Senderliste ist es aufwendiger.
Es gibt auch z. B. die Funktionen "GetCurrentPlayback", die mir anzeigt, was der TV grade macht (TV, Web, EPG) und "GetCurrentEvent", das mir die aktuelle Sendung auf dem Kanal anzeigt.

Grüße.

Gesendet von meinem LG-D855 mit Tapatalk