FHEM Forum

FHEM => Sonstiges => Thema gestartet von: ujaudio am 14 November 2018, 18:39:46

Titel: sub <module>_Read($);
Beitrag von: ujaudio am 14 November 2018, 18:39:46
Ich hoffe ich darf hier die Frage stellen: Ich bin dabei ein Modul zu schreiben und es funktioniert auch soweit. Entsprechend dessen, was ich mir angelesen habe, sind auch zwei Routinen
sub Oppo_Write($@);
sub Oppo_Read($);
implementiert.
Wenn ich an mein über Ethernet angeschlossenes Gerät etwas mitteilen möchte, dann ruft meine implementierte set-Funktion die Write-Funktion auf - alles bestens.

Die Read-Funktion rufe ich niemals explizit auf, trotzdem wird sie genutzt, was ich zwar gut finde, weil somit mein Modul schon weitgehend funktioniert - nur verstanden habe ich es nicht.
Möglicherweise ist das für einen Kommunikationsspezialisten eine dumme Frage, aber mich würde interessieren, ob und wenn ja in welchen Fällen die Read-Funktion von mir explizit aufgerufen werden muss.
Titel: Antw:sub <module>_Read($);
Beitrag von: CoolTux am 14 November 2018, 18:50:56
Wie genau hast du den dein IP Socket implementiert? Über DevIo?
Im Grunde ist es so das ein Socket geöffnet wird und die Infos dazu in die Hauptschleife von FHEM geschrieben werden (selectlist ). Nun schaut select alle x mal nach ob Daten am Socket anlegen, wenn ja wird $hash->{ReadFn} aufgerufen und die Daten somit an die Funktion übergeben.
Titel: Antw:sub <module>_Read($);
Beitrag von: ujaudio am 14 November 2018, 19:00:25
Da ich noch wenig Ahnung von Kommunikation habe, habe ich das aus einem anderen Modul abgekupfert:
sub Oppo_Open($) {

  my $hash    = shift;
  my $name    = $hash->{NAME};
  my $host    = $hash->{HOST};
  my $port    = $hash->{PORT};
  my $timeout = 0.1;
   
  Log3 $name, 5, "Oppo ($name) - Open has been called";
  return if( $hash->{CD} ); # kein mehrfaches connect

  readingsSingleUpdate($hash,'state','absent',1);
   
  Log3 $name, 5, "Oppo ($name) - establish socket connection";
   
  my $socket = new IO::Socket::INET (PeerHost => $host,
                                     PeerPort => $port,
                                     Proto => 'tcp',
                                     Timeout => $timeout)
  or return Log3 $name, 4, "Oppo ($name) - couldn't connect to $host:$port";

  $hash->{FD}    = $socket->fileno();
  $hash->{CD}    = $socket;              # sysread / close won't work on fileno
  $selectlist{$name} = $hash;
   
  readingsSingleUpdate($hash,'state','on',1);
  Log3 $name, 4, "Oppo ($name) - socket connected";
  return;
}
Titel: Antw:sub <module>_Read($);
Beitrag von: CoolTux am 14 November 2018, 19:05:00
Zitat von: ujaudio am 14 November 2018, 19:00:25
Da ich noch wenig Ahnung von Kommunikation habe, habe ich das aus einem anderen Modul abgekupfert:
sub Oppo_Open($) {

  my $hash    = shift;
  my $name    = $hash->{NAME};
  my $host    = $hash->{HOST};
  my $port    = $hash->{PORT};
  my $timeout = 0.1;
   
  Log3 $name, 5, "Oppo ($name) - Open has been called";
  return if( $hash->{CD} ); # kein mehrfaches connect

  readingsSingleUpdate($hash,'state','absent',1);
   
  Log3 $name, 5, "Oppo ($name) - establish socket connection";
   
  my $socket = new IO::Socket::INET (PeerHost => $host,
                                     PeerPort => $port,
                                     Proto => 'tcp',
                                     Timeout => $timeout)
  or return Log3 $name, 4, "Oppo ($name) - couldn't connect to $host:$port";

  $hash->{FD}    = $socket->fileno();
  $hash->{CD}    = $socket;              # sysread / close won't work on fileno
  $selectlist{$name} = $hash;
   
  readingsSingleUpdate($hash,'state','on',1);
  Log3 $name, 4, "Oppo ($name) - socket connected";
  return;
}


Ist das selbe Prinzip. Nur lässt Du es nicht mittels DevIo machen sondern hast es selbst implementiert. Habe ich bisher auch so gemacht. Meine Erklärung bleibt die selbe.
$selectlist{$name} = $hash;
Hier übergibst Du Deine Socketinfo an die selectlist.
Titel: Antw:sub <module>_Read($);
Beitrag von: rudolfkoenig am 14 November 2018, 19:06:32
Durch Eintragen in selectlist hast du den Service "ReadFn aufrufen, wenn was zu lesen gibt" bestellt.

Uebrigens: statt IO::Socket::INET direkt aufzurufen, ist es in FHEM besser DevIO_OpenDev zu verwenden.
Ein aktuelles (wenn auch nicht unbedingt einsteigerfreundliches) Beispiel gibt es dafuer in 00_MQTT2_CLIENT.pm
Titel: Antw:sub <module>_Read($);
Beitrag von: ujaudio am 14 November 2018, 19:26:24
Ich schaue mir gleich mal den 00_MQTT2_CLIENT.pm an. Zuvor noch eine Frage: muss man sich aus der selectlist auch wieder austragen? und wenn ja wie?
Titel: Antw:sub <module>_Read($);
Beitrag von: CoolTux am 14 November 2018, 19:30:26
Hoffe es hilft Dir


sub LGTV_WebOS_Open($) {

    my $hash    = shift;
    my $name    = $hash->{NAME};
    my $host    = $hash->{HOST};
    my $port    = 3000;
    my $timeout = 0.1;
   
   
    Log3 $name, 4, "LGTV_WebOS ($name) - Baue Socket Verbindung auf";
   

    my $socket = new IO::Socket::INET   (   PeerHost => $host,
                                            PeerPort => $port,
                                            Proto => 'tcp',
                                            Timeout => $timeout
                                        )
        or return Log3 $name, 4, "LGTV_WebOS ($name) Couldn't connect to $host:$port";      # open Socket
       
    $hash->{FD}    = $socket->fileno();
    $hash->{CD}    = $socket;         # sysread / close won't work on fileno
    $selectlist{$name} = $hash;
   
    Log3 $name, 4, "LGTV_WebOS ($name) - Socket Connected";
   
    LGTV_WebOS_Handshake($hash);
    Log3 $name, 4, "LGTV_WebOS ($name) - start Handshake";
   
}

sub LGTV_WebOS_Close($) {

    my $hash    = shift;
    my $name    = $hash->{NAME};
   
    return if( !$hash->{CD} );

    close($hash->{CD}) if($hash->{CD});
    delete($hash->{FD});
    delete($hash->{CD});
    delete($selectlist{$name});
   
    readingsSingleUpdate($hash,'state','off',1);
   
    Log3 $name, 4, "LGTV_WebOS ($name) - Socket Disconnected";
}
Titel: Antw:sub <module>_Read($);
Beitrag von: ujaudio am 14 November 2018, 19:42:14
Danke!