Modul für Irobot Roomba 980

Begonnen von kukamee, 22 Februar 2017, 02:34:53

Vorheriges Thema - Nächstes Thema

Lippie

Guten Morgen,
Danke für den Tipp. Mir ist aufgefallen, dass in sub set das last; für den Abschnitt von getpass fehlte. Habe das noch eingefügt.
Jetzt funktioniert es bei mir zuverlässig. Kann mir nicht so recht vorstellen, dass das wirklich die Ursache sein soll...
Habe gleich noch die Hilfe aktualisiert, so dass jetzt alles aktuell sein sollte.
Gruß
Sebastian

Thorsten Pferdekaemper

Hi Sebastian,
ich wollte das jetzt gerade ins Git packen, aber ich habe vorher bei mir getestet. Leider geht das auf die Bretter mit...

JSON text must be an object or array (but found number, string, true, false or null, use allow_nonref to allow this) at ./FHEM/42_Roomba980.pm line 881.

Das hat mich etwas gewundert, da ich dachte, dass wir das mal gefixt hätten. Dann habe ich bemerkt, dass Du anscheinend für Deine Weiterentwicklungen auf eine alte Version aufgesetzt hast. Könntest Du Dir mal die Version im Git anschauen und das ganze abgleichen? Das wäre nett.
Außerdem sehe ich in Deiner Datei immer wieder Leerzeilen, also in etwa so:

sub processMessage($$){

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

# message empty?

if(!$msgtext){

    Log3($hash->{NAME},3, "Received empty message");

return;

};

Das finde ich ein bisschen störend und ich glaube, dass ich mir bei einer ähnlichen Aktion vor einer Weile die Mühe gemacht hatte, das wieder ordentlich zu formatieren. Kannst Du mal nachsehen, wie das bei Dir aussieht?

EDIT: Doch, das kann schon das "last" gewesen sein. In diesem speziellen Fall entspricht ein "last" einem "return undef". (Glaube ich.)

Gruß,
   Thorsten
FUIP

Lippie

Zitat von: Thorsten Pferdekaemper am 05 November 2019, 10:28:22
Hi Sebastian,
ich wollte das jetzt gerade ins Git packen, aber ich habe vorher bei mir getestet. Leider geht das auf die Bretter mit...

JSON text must be an object or array (but found number, string, true, false or null, use allow_nonref to allow this) at ./FHEM/42_Roomba980.pm line 881.

Das hat mich etwas gewundert, da ich dachte, dass wir das mal gefixt hätten. Dann habe ich bemerkt, dass Du anscheinend für Deine Weiterentwicklungen auf eine alte Version aufgesetzt hast. Könntest Du Dir mal die Version im Git anschauen und das ganze abgleichen? Das wäre nett.
Außerdem sehe ich in Deiner Datei immer wieder Leerzeilen, also in etwa so:

sub processMessage($$){

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

# message empty?

if(!$msgtext){

    Log3($hash->{NAME},3, "Received empty message");

return;

};

Das finde ich ein bisschen störend und ich glaube, dass ich mir bei einer ähnlichen Aktion vor einer Weile die Mühe gemacht hatte, das wieder ordentlich zu formatieren. Kannst Du mal nachsehen, wie das bei Dir aussieht?

EDIT: Doch, das kann schon das "last" gewesen sein. In diesem speziellen Fall entspricht ein "last" einem "return undef". (Glaube ich.)

Gruß,
   Thorsten

Abend Thorsten,

erstmal Sorry dafür, dass ich nicht gleich nach dem GIT-Repo gefragt habe.
Ich habe tatsächlich auf einer 2017er Version aufgesetzt, die ich aus dem Thread gezogen habe.
Die Formatierung war auch für mich etwas irritierend, hatte das aber erstmal nicht angefasst.

Habe meine Erweiterungen/Änderungen in den aktuellen Stand im GIT eingepflegt und hochgeladen. Hast einen Pull-Request.

Ist trotzdem einiges passiert. Hoffe, das ist OK für Dich.

Viele Grüße
Sebastian


Thorsten Pferdekaemper

Zitat von: Lippie am 05 November 2019, 20:43:42
Ist trotzdem einiges passiert. Hoffe, das ist OK für Dich.
Ja, klar. Ich finde es gut, wenn sich da jemand kümmert. Ich schaffe das momentan nicht.

Ich habe mal versucht, das Ding auf meiner Testinstanz zum Laufen zu bringen. Zuerst gab es nur Fehlermeldungen wegen JSON::XS, in der Form:

2019.11.05 21:39:44 3: Could not decode message: JSON text must be an object or array (but found number, string, true, false or null, use allow_nonref to allow this) at ./FHEM/42_Roomba980.pm line 495.
--> {"state":{"reported":{"bbrun":{"hr":168,"min":14,"sqft":615,"nStuck":35,"nScrubs":238,"nPicks":272,"nPanics":365,"nCliffsF":2514,"nCliffsR":920,"nMBStll":6,"nWStll":3,"nCBump":0},"bbsys":{"hr":23500,"min":51}}}}

Ich habe dann mal JSON::XS durch JSON ersetzt und zumindest dieser Fehler war weg. "set connect" hat dann erstmal funktioniert.
Weißt Du, warum JSON::XS benutzt wird und nicht JSON? Soweit ich gelesen habe, ist JSON die "sicherere" Alternative.

Nach dem connect schmiert allerdings mein FHEM dann komplett ab. Im Log findet sich nichts passendes und ich habe bisher nicht herausgefunden, was da genau los ist. Die ganzen vielen Readings werden erst einmal ordentlich gesetzt und irgendwann danach (oder manchmal auch währenddessen) kracht's dann. Hier muss ich vielleicht nochmal nachforschen.

Ich habe dann auch mal (ohne connect) das discovery ausprobiert. Das hat nicht funktioniert. Hier habe ich mir mal nach dem sysread eine Debug-Ausgabe gemacht, es scheint aber nie etwas zurück zu kommen. Muss man da noch etwas beachten?

Gruß,
   Thorsten

FUIP

Thorsten Pferdekaemper

Hi,
ich habe jetzt nochmal discovery mit blinkendem Wlan-Symbol probiert. Das klappt auch nicht.

getpass klappt allerdings wunderbar.

Gruß,
   Thorsten
FUIP

Lippie

Hi,

dass mit getpass freut mich.

Um das Thema JSON::XS oder JSON habe ich mich nie gekümmert. Das hatte ich so übernommen.

Warum discovery bei Dir nicht tut, ist eigenartig. Damit hatte ich noch nie Probleme.

In meiner alten Version hatte ich noch zusätzliche Maßnahmen drin, unplausible Nachrichten abzufangen, da es immer wieder sporadisch zu Abstürzen kam.
Ich würde das mal noch übertragen ins GIT.

Gruß
Sebastian

Thorsten Pferdekaemper

Zitat von: Lippie am 06 November 2019, 17:45:38
Warum discovery bei Dir nicht tut, ist eigenartig. Damit hatte ich noch nie Probleme.
Ich probiere das momentan unter Windows, was etwas "unüblich" ist. Vielleicht liegt's ja daran. Mal sehen, vielleicht schaffe ich es morgen mal, mir eine kleine Testinstallation unter Linux zu machen.
Gruß,
   Thorsten
FUIP

Lippie

Zitat von: Thorsten Pferdekaemper am 06 November 2019, 20:56:22
Ich probiere das momentan unter Windows, was etwas "unüblich" ist. Vielleicht liegt's ja daran. Mal sehen, vielleicht schaffe ich es morgen mal, mir eine kleine Testinstallation unter Linux zu machen.
Gruß,
   Thorsten

Das bestätigt meine Vermutung, dass dein Rechner/Server zu schnell ist. Im discover wird zwar 99999 mal nach Rückmeldung geschaut, allerdings, ohne vorher etwas zu warten. Die while  - Schleife ist also fertig bevor etwas empfangen wird.

VG
Sebastian

Lippie

anbei nochmal eine Überarbeitung mit den angesprochenen Änderungen:
- discovery nutzt jetzt den internen Timer, um mit zeitlichem Versatz den UPD-Socket auszulesen
- im Read habe ich zusätzlich noch einen Abfangteil zusätzlich implementiert, mit dem es bei mir schon mal gut lief.
- JSON::XS ersetzt durch JSON

@Thorsten: schau mal bitte, obs nun besser läuft.

Gruß
Sebastian

Thorsten Pferdekaemper

Hi,
(Vorsicht, nicht erschrecken. Das wird jetzt etwas länglich, was aber nicht bedeutet, dass das alles ganz schlecht ist. Das Gegenteil ist der Fall. Ich freue mich, das sich da jemand anderes so reinhängt und will das unterstützen.)

Ich glaube nicht wirklich, dass es unter Windows am "zu schnell" liegt. Ich hatte mir ein komplett eigenes Programm gebastelt, dass den UDP-Broadcast macht und danach "ewig" auf eine Antwort wartet. In Wireshark sehe ich die Antwort, aber das Programm bekommt nichts mit.
...aber wie gesagt: Erstmal das ganze unter Linux ausprobieren. Nach einigem Gebastel habe ich es hinbekommen. Ich habe ein relativ neues Raspbian (buster) genommen und FHEM frisch installiert. ...also alles komplett leer und neu. Dann Deine neue Datei rein und das:

define roomba Roomba980

D.h. erstmal kein IP:Port und kein Blid/Password, da wir das alles da erst per discover und getpass rausfinden wollen. Soweit so gut. Jetzt die Problemchen mit ihren Lösungen (falls vorhanden). Das Folgende ist einigermaßen in der Reihenfolge, in der das für mich aufgetreten ist.

Zuerst einmal ein Schönheitsfehler

PERL WARNING: Use of uninitialized value in split at ./FHEM/42_Roomba980.pm line 134.

Das liegt wohl daran, dass ich beim Define keine Parameter angegeben habe. Das könnte man abfangen.

disconnected, waiting to reappear
Als nächstes kamen Massenweise "disconnected, waiting to reappear"-Meldungen ins Log. Ich bin dem nicht mehr nachgegangen und es hat dann auch aufgehört. Ich glaube aber, dass ich FHEM neu gestartet hatte und es erst danach aufgehört hat. Die Logdatei hatte dann schon 6MB...
(Ich weiß auch nicht mehr genau, ob das vor oder nach dem discovery-Versuch passiert war.)

discovery
Jetzt voller Spannung das Discovery probiert. Dabei kam dann eine "unexpected end of string"-Meldung ins Log. Danach ein kompletter FHEM-Crash. Der Absturz kommt in decode_json, etwa Zeile 895. Das Problem war, dass beim sysread nur 300 Zeichen gelesen werden. Bei mir hat die Antwort aber 309 Zeichen. Ich habe das mal auf 500 gesetzt. Damit funktioniert es bei mir. (Juhuu...) Allerdings wäre es schöner, das irgendwie flexibel zu haben wie beim getpass. ...allerdings habe ich da auch keine perfekte Idee. Vielleicht einfach auf einen hohen Wert setzen scheint ja zu gehen.
Ich frage mich außerdem, was hier passiert, wenn man tatsächlich mehrere Roombas hat...

getpass ohne Port
Der nächste Schritt: getpass. Auch hier erstmal ein Crash:

Expected 'PeerService' at ./FHEM/42_Roomba980.pm line 930.

Das lag daran, dass ich den Port vergessen hatte und einfach nur die IP angegeben hatte. Das sollte nicht zum Crash führen. Am besten wäre es, wenn die 8883 automatisch ergänzt würde. Einen anderen Port gibt's ja sowieso nicht, oder?

getpass, SSL-Fehler
Jetzt getpass mit Port. Aber auch hier: Erstmal Fehlanzeige. Das Problem war, dass der Roomba anscheinend nicht mit "modernen" SSL-Implementierungen umgehen kann und irgendwas unpassendes zurückschickt:

GetPass SSL connect attempt failed error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small

Das Coding sieht jetzt bei mir so aus und damit klappt's:

sub getpass($;$){
    my ($hash,$host) = @_;
if($host){
my $conn = IO::Socket::SSL->new(PeerAddr => $host,
   Timeout => 3,
   SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
   SSL_cipher_list => 'DEFAULT:!DH');     
if($conn) {
$conn->blocking(0);
my $data = pack('H*', $GetPwPacket);
print $conn $data;
$hash->{GetPassConn} = $conn;
RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+3, "Roomba980::getpass", $hash, 0);
}else{
Log3($hash->{NAME},3, "GetPass connection error");
if($!) {
Log3($hash->{NAME},3, "GetPass ".$!);
};
if($SSL_ERROR) {
Log3($hash->{NAME},3, "GetPass ".$SSL_ERROR);
};
readingsSingleUpdate($hash,"Roomba-PW","connection refused. Make sure, sync mode is enabled (WIFI-LED is green blinking). For enabling press home-button for about 2 seconds.",1);
}
}else{

D.h. das mit dem SSL_cipher_list ist neu und die Log-Ausgabe für $! und $SSL_ERROR. Letzteres ist ganz nett, wenn es mal nicht klappt.

connect, SSL-Fehler
Jetzt habe ich die DEF ergänzt durch IP, Port, Blid und Password. Dann ein connect: Wieder Fehlanzeige. Das Problem ist hier aber dasselbe wie bei getpass. Am Ende von OpenDev habe ich auch hier den SSL_cipher_list-Kram eingefügt und es klappt damit!

Passwort verschwindet
Noch eine Kleinigkeit. Es gibt da einen Kommentar in OpenDev:

Cleanup Roomba-PW after successfull connect

Allerdings passiert das auch, wenn der connect nicht geklappt hat. Vielleicht könnte man sich überlegen, das Passwort komplett stehen zu lassen bzw. es gleich automatisch zu übernehmen. Aber dazu siehe unten.

Für später: Alles automatisieren?
Der "Workflow" ist jetzt also in etwa:
   1. define roomba Roomba980
   2. set roomba discoverNewRoomba
   3. set roomba getpass IP:Port
   4. DEF eintragen mit IP:Port blid passwd
   5. set roomba connect
Das könnte man jetzt entsprechend dokumentieren, aber viel cooler wäre eigentlich, wenn das automatisch abläuft. ...aber das könnte man ja dann noch draufbasteln, wenn es erstmal manuell richtig rund läuft.

Gruß,
   Thorsten
FUIP

Lippie

Hi,

Danke fürs testen und die Hinweise. Allein fallen manche Dinge einfach nicht auf und so lern ich auch noch was dazu :-)

Habe fleißig Änderungen eingepflegt:

Define: 
- DEF ohne user und pw sollte nun möglich sein. DEF wird auch nur überschrieben, wenn ein user und pw angegeben wurden.
- host wird auf Zahlen , Punkte und Doppelpunkte gefiltert

Set: 
- getpass wird abgesichert aufgerufen. Wenn ein Doppelpunkt fehlt, wird der Port automatisch dazugebaut. Die IP wird auf Zahlen , Punkte und Doppelpunkte gefiltert.

OpenDev: 
- Cleanup Roomba-PW after successfull connect nur, wenn die Verbindung hergestellt werden konnte.

discovery:
- pauschale Vergrößerung des Puffers. Hoffe auch, dass es ausreicht :-)

getpass:
- habe deine Änderung eingepflegt.

"disconnected, waiting to reappear"-Meldungen schaue ich mir die Tage an.

Viele Grüße
Sebastian

Thorsten Pferdekaemper

Zitat von: Lippie am 07 November 2019, 22:09:16
Danke fürs testen und die Hinweise. Allein fallen manche Dinge einfach nicht auf
...ja, man wird manchmal ein bisschen "betriebsblind".

Zitat
- DEF ohne user und pw sollte nun möglich sein.
Auch ohne IP/Port? Das ging zumindest vorher und sollte auch so bleiben. Es ist ja gerade das Schöne am discovery, dass man auch das rausbekommt.

Zitat
"disconnected, waiting to reappear"-Meldungen schaue ich mir die Tage an.
Das habe ich schon gemacht. Man müsste nur verhindern, dass OpenDev ohne IP/Port aufgerufen wird. Anscheinend schlägt das Anlegen des Sockets nicht fehl (!), aber es geht danach irgendwo schief.

Gruß,
   Thorsten
FUIP

Lippie

Zitat von: Thorsten Pferdekaemper am 07 November 2019, 22:44:02
Auch ohne IP/Port? Das ging zumindest vorher und sollte auch so bleiben. Es ist ja gerade das Schöne am discovery, dass man auch das rausbekommt.
DEF ohne IP/Port funktioniert zumindest nicht schlechter als vorher. Ich will da noch etwas machen, dass kein Verbindungsversuch mehr gestartet wird. Das sollte einfach gehen.

Gruß
Sebastian

Lippie

Hi,

Es gibt mal wieder ein Update:
- Definieren eines neuen Moduls ohne IP, nun ohne Warnung
- in Define werden nun auch IP und Port grob gefiltert und bei Bedarf der default-Port gesetzt.

Zu Thema (teil-)automatisiertes einbinden eines neuen Roombas bin ich noch dran.

VG
Sebastian

Thorsten Pferdekaemper

Cool, ich werde das ausprobieren. Es kann aber Montag werden, da mein Kleiner immer noch ein bisschen Angst vor selbstfahrenden Ufos hat...
Von wegen automatischen Einbinden hatte ich mir auch schon ein paar Gedanken gemacht, aber ich will mich jetzt erst einmal wieder auf FUIP konzentrieren (wobei ein FUIP-View, der die gefahrene Strecke des Staubsaugers anzeigt ja schon cool wäre).
Das automatische Einbinden stelle ich mir in etwa so vor wie das Autocreate/Pairing bei Homematic: Man legt erstmal ein "leeres" Device an und sagt dann sowas wie "set roomba discover", optional mit einer Zeitangabe hinten dran. Dann versucht das Teil 60 Sekunden lang (oder auch länger), discovery und getpass zu machen. D.h. in der Zeit muss der Benutzer halt das Knöpfchen am Roomba drücken. Bei Erfolg wird dann alles automatisch eingetragen und ggf. sogar das "connect" gemacht.
Ich kann mir vorstellen, dass das jetzt gar nicht mehr so schwierig ist.
Gruß,
  Thorsten
FUIP