FHEM Forum

FHEM - Entwicklung => FHEM Development => Thema gestartet von: Thorsten Pferdekaemper am 16 März 2017, 10:21:55

Titel: Broadcast und receive über UDP
Beitrag von: Thorsten Pferdekaemper am 16 März 2017, 10:21:55
Hi,
zum "Discovery" für Roomba980 Staubsaugerroboter wird über UDP broadcast der Text "irobotmcs" geschickt, worauf die Sauger mit ein paar Informationen antworten. Ich habe versucht, das in Perl hinzuschreiben, aber wohl nicht ganz richtig:

sub discovery($){

    my $sock = new IO::Socket::INET(
            LocalPort => 5678,  # TODO: do we have to use this port?
    PeerPort => 5678,
                    Proto => 'udp',
    Timeout => 1,
    Broadcast => 1);   # TODO: error handling or die('Error opening socket.');
    my $data = "irobotmcs";
    print $sock $data;

my ($datagram,$flags);
    while (1) {
        $sock->recv($datagram,100,$flags);
        print "Received datagram from ", $sock->peerhost,
                  ", flags ", $flags || "none", ": $datagram";
    }
    $sock->close();
};

Ich weiß, dass das eine Endlosschleife ist und blockiert, aber das ist nicht der Punkt. Es scheint einfach gar nichts zu empfangen. Bevor ich jetzt anfange, großartig nachzuforschen, wollte ich fragen, ob das jemand vielleicht schon einmal gemacht hat und mir ein paar Zeilen Coding spendieren könnte.

Das ganze ist übrigens der Versuch, folgendes nodejs-Coding nach Perl zu bringen:

function discovery (cb, full) {
  const server = dgram.createSocket('udp4');

  server.on('error', (err) => {
    server.close();
    cb(err);
  });

  server.on('message', (msg) => {
    try {
      let parsedMsg = JSON.parse(msg);
      if (parsedMsg.hostname && parsedMsg.ip && parsedMsg.hostname.split('-')[0] === 'Roomba') {
        server.close();
        console.log('Robot found! with blid/username: ' + parsedMsg.hostname.split('-')[1]);
        console.log(parsedMsg);
        cb(null, full ? parsedMsg : parsedMsg.ip);
      }
    } catch (e) {}
  });

  server.on('listening', () => {
    console.log('Looking for robots...');
  });

  server.bind(5678, function () {
    const message = new Buffer('irobotmcs');
    server.setBroadcast(true);
    server.send(message, 0, message.length, 5678, '255.255.255.255');
  });
}


Danke&Gruß,
    Thorsten
Titel: Antw:Broadcast und receive über UDP
Beitrag von: rudolfkoenig am 16 März 2017, 10:31:24
LocalPort braucht man, wenn man einen Server haben will, PeerPort fuer einen Client. Keine Ahnung was passiert, wenn man beide spezifiziert, mein Bauch sagt, lieber zwei IO::Socket::INET Instanzen verwenden.
Und ich wuerde parallel ein tcpdump oder Vergleichbares starten, um zu sehen, was passiert.
Titel: Antw:Broadcast und receive über UDP
Beitrag von: Thorsten Pferdekaemper am 16 März 2017, 10:51:06
Hi,
ok, das werde ich dann mal ausprobieren.
...aber: Das klingt nicht so, als ob Du das schonmal gemacht hast. Hat es irgendwer schon einmal gemacht?
Gruß,
   Thorsten
Titel: Antw:Broadcast und receive über UDP
Beitrag von: Thorsten Pferdekaemper am 17 März 2017, 09:59:15
So, teilweise Erfolg:

    my $sock = new IO::Socket::INET(
PeerPort => 5678,
PeerAddr => "255.255.255.255",
                Proto => 'udp',
Type => SOCK_DGRAM,
Timeout => 1);
my $localport = $sock->sockport();
    my $data = "irobotmcs";
syswrite($sock,$data);

my $datagram;
    while (1) {
        $sock->recv($datagram,100,0);
        print "Received datagram from ", $sock->peerhost, ": $datagram";
    }

Damit sehe ich in Wireshark den Broadcast rausgehen und ich sehe auch die Antwort des Staubsaugers. Allerdings funktioniert das Empfangen nicht mit dem Coding oben. Ich vermute mal, dass ich nach dem Öffnen des Client-Sockets einen Server-Socket aufmachen muss, der auf die Antwort lauscht. Dazu war jetzt aber noch keine Gelegenheit...
Gruß,
   Thorsten
Titel: Antw:Broadcast und receive über UDP
Beitrag von: CoolTux am 17 März 2017, 10:08:39
Ich denke mal eine zweite Socketverbindung brauchst Du nur wenn die Antwort über vom Roomba aufgemachte Verbindung kommt. Aber eigentlich sollte doch die bereits eröffnete Verbindung Verwendung finden. Um die Antwort zu erhalten fehlt Dir aber auf jeden Fall ein sysread.


Grüße
Titel: Antw:Broadcast und receive über UDP
Beitrag von: Thorsten Pferdekaemper am 17 März 2017, 10:27:01
Zitat von: CoolTux am 17 März 2017, 10:08:39
Ich denke mal eine zweite Socketverbindung brauchst Du nur wenn die Antwort über vom Roomba aufgemachte Verbindung kommt. Aber eigentlich sollte doch die bereits eröffnete Verbindung Verwendung finden. Um die Antwort zu erhalten fehlt Dir aber auf jeden Fall ein sysread.
Das kann ich auch mal ausprobieren, wobei mir nicht so ganz klar ist, wo jetzt der Unterschied zwischen sysread und recv ist.
Ich dachte inzwischen, dass man bei UDP sowieso keine "offene Verbindung" hat. ...aber ich werde mal verschiedene Varianten ausprobieren.
Danke&Gruß,
   Thorsten
Titel: Antw:Broadcast und receive über UDP
Beitrag von: Thorsten Pferdekaemper am 21 März 2017, 11:18:32
Hi,
nach viel rumprobieren:

    my $sock = new IO::Socket::INET(
                Proto => 'udp',
Type => SOCK_DGRAM,
Timeout => 60,
Broadcast => 1);   # TODO: error handling or die('Error opening socket.');
$sock->sockopt(SO_BROADCAST, 1);
    $sock->sockopt(SO_REUSEADDR, 1);
    my $data = "irobotmcs";
my $broadcastAddr = sockaddr_in( 5678, INADDR_BROADCAST );
    send( $sock, $data, 0,  $broadcastAddr );
my $datagram;
    while (1) {
sysread($sock,$datagram,200);
        print "Received datagram from ", $sock->peerhost, ": $datagram";
    }
    $sock->close();

Das funktioniert jetzt erwartungsgemäß, wobei ich auch nicht weiß, was man da noch weglassen kann. Anscheinend ist wichtig, dass man keine PeerAddr angibt.
Gruß,
   Thorsten