Devio DevIo_SimpleWrite

Begonnen von Sidey, 06 März 2016, 22:25:13

Vorheriges Thema - Nächstes Thema

Sidey

Hi,

bin gerade dabei die Funktionen aus devio näher zu analysieren um diese dann in meinem IO Device zu nutzen.

In SimpleWrite fand ich folgende Zeile: 

Log3 ($name, 5, $ishex ? "SW: $msg" : "SW: ".unpack("H*",$msg));

Ich habe bislang nicht geblickt, wieso ein unpack gemacht wird, wenn $ishex nicht wahr ist.
Kann es sein, dass es einfach ein kleiner Fehler ist und es so korrekt ausgedrückt wäre:

Log3 ($name, 5, $ishex ?  "SW: ".unpack("H*",$msg) : "SW: $msg" );

Grüße Sidey
Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem,zigbee2mqtt

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker

rudolfkoenig

Diese Zeile funktioniert in mehreren Modulen so, wie geplant.
Falls ishex gesetzt ist, sind die uebergebenen Daten ein hex-String, sonst binaer. Binaer will man nicht auf dem Bildschirm haben, deswegen unpack.

Sidey

Achso, ich dachte man kann alles übergeben, was ein ASCII Zeichen ist, wenn ishex nicht gesetzt ist.

Dafür gibt es dann wohl keine Möglichkeit. Richtig?

Man könnte doch auf Hex oder bin prüfen, in dem man nach 0x oder b$ sucht. Wäre das eine Überlegung wert?

Sidey
Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem,zigbee2mqtt

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker

Markus Bloch

@rudi: Das stimmt. Das Problem ist nur, wenn man kein Hex überträgt sondern Zeichenketten (z.B. bei TCP), dann werden die durch das unpack unleserlich gemacht.

Ich behelfe mir hier mit einer separaten Log-Ausgabe in meinen Modulen um zu zeigen, was gerade geschrieben wurde.

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Sidey

Hi,

bin noch über eine andere Baustelle gestolpert.
Wenn man di Expect Funktion nutzt, dann kann man zum einen ja nicht definieren, ob man einen hexwert oder nicht überträgt. Also wird immer angenommen, es ist ein Binär Wert.

Zum anderen liefert die readTimeout Funktion nur so viel Daten, wie halt gerade in dem Moment abgerufen werden können.

Der Grund liegt meines Erachtens darin, dass es kein definiertes Endezeichen gibt, wonach gesucht wird.
Also weiss die Read Funktion nicht, wonach gesucht wird.
Die Expect Methode könnte man ja um genau diesen Parameter erweitern, damit definiert werden kann, wie lange gelesen werden soll. Selbstverständlich wieder mit einer maximalen Anzahl an Versuchen.

Wie setzen denn andere das DevIO Modul ein?
Schreibt hier jeder seine eigenen Funktionen für read/write ?

Genau das habe ich derzeit, bzw. habe ich die von einem anderen Modul kopiert. Jetzt wollte ich eigentlich auf das DevIO Modul umstellen und einen gut getesteten Standard verwenden, da meine eigenen Funktionen FHEM blockieren können.

Grüße Sidey
Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem,zigbee2mqtt

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker

rudolfkoenig

ZitatMan könnte doch auf Hex oder bin prüfen, in dem man nach 0x oder b$ sucht. Wäre das eine Überlegung wert?
Nope.

Zitatwenn man kein Hex überträgt sondern Zeichenketten (z.B. bei TCP), dann werden die durch das unpack unleserlich gemacht.
Das stimmt, z.Zt geht das nur mit einer eigenen Version von SimpleWrite.

Habe gerade alle DevIo_SimpleWrite Aufrufe angeschaut: fuer ishex wird bisher undef,'',0 und 1 uebergeben.
Wir koennten ishex also erweitern: bin:0/undef/'', hex:1, ascii:2.

Expect ist nur was fuer Hacker, da es FHEM blockiert.

Markus Bloch

DevIo_Expect() dient nur reinweg der Prüfung ob die Gegenseite antwortet. Man übergibt DevIo eine Nachricht auf welche die Gegenstelle in jedem Fall antworten würde (bsp: Newline => "invalid command ..."). Wenn die Gegenstelle innerhalb von X Sekunden nicht antwortet, wird die Verbindung geschlossen, da die Gegenseite scheinbar nicht mehr antwortet.

Das ganze ist aber wie Rudi schon sagte blockierend und sollte daher nicht verwendet werden. Momentan wird es nur von PIONIEERAVR eingesetzt. Man kann eine solches Response-Timeout im Modul selber implementieren ohne das FHEM dabei blockiert.

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Markus Bloch

Zitat von: Sidey am 07 März 2016, 09:08:19
Der Grund liegt meines Erachtens darin, dass es kein definiertes Endezeichen gibt, wonach gesucht wird.
Also weiss die Read Funktion nicht, wonach gesucht wird.
Die Expect Methode könnte man ja um genau diesen Parameter erweitern, damit definiert werden kann, wie lange gelesen werden soll. Selbstverständlich wieder mit einer maximalen Anzahl an Versuchen.

Wie setzen denn andere das DevIO Modul ein?

DevIo selber weis ja nicht, wann ein Datensatz "vollständig" ist. Insbesondere bei seriellen Geräten kommt es immer wieder vor, das Daten in einzelnen Häppchen kommen. Daher findet man in vielen Modulen einen Pufferungs-Mechanismus, der alle empfangenen Daten in einen temporären Puffer anhängt. Sobald in dem Puffer per Regexp ein vollständiger "Datensatz" erkannt wird (bspw: durch Newline getrennt) wird dieser aus dem Puffer vorne rausgeschnitten und verarbeitet.

Bsp:

sub
LGTV_RS232_Read($)
{
    my ($hash) = @_;

    my $buf = DevIo_SimpleRead($hash);
    return "" if(!defined($buf));
    my $name = $hash->{NAME};

    my $partial = $hash->{helper}{RECEIVE_BUFFER};

    Log3 $name, 5, "LGTV_RS232 ($name) - ".($partial ne "" ? "(buffer contains: $partial) " : "")."received: $buf";
   
    $partial .= $buf;

    while($partial =~ /(\w\s\d{2}\s[0-9a-zA-Z]+?x)(.*)/)
    {
        my $msg = $1;
        $partial = $2;
        $msg =~ s/x$//;

        LGTV_RS232_ParseResponse($hash, $msg);
    }
   
    $hash->{helper}{RECEIVE_BUFFER} = $partial;
   
    RemoveInternalTimer($hash);
    InternalTimer(gettimeofday()+15, "LGTV_RS232_GetStatus", $hash, 0);
}


DevIo kann ja nicht wissen wann ein Datensatz vollständig ist für die übertragenen Rohdaten.

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

rudolfkoenig

ZitatWir koennten ishex also erweitern: bin:0/undef/'', hex:1, ascii:2.
Habs implementiert und eingecheckt.

Markus Bloch

Vielen Dank. Funktioniert!

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Sidey

Zitat von: Markus Bloch am 07 März 2016, 09:29:21
DevIo selber weis ja nicht, wann ein Datensatz "vollständig" ist. Insbesondere bei seriellen Geräten kommt es immer wieder vor, das Daten in einzelnen Häppchen kommen. Daher findet man in vielen Modulen einen Pufferungs-Mechanismus, der alle empfangenen Daten in einen temporären Puffer anhängt. Sobald in dem Puffer per Regexp ein vollständiger "Datensatz" erkannt wird (bspw: durch Newline getrennt) wird dieser aus dem Puffer vorne rausgeschnitten und verarbeitet.

Hallo Markus,

ja genau. Die Daten kommen in Häppchen. Ich muss gestehen, ich habe zwar grob das Ziel vor Augen, aber den Weg noch nicht gefunden.
Das mit dem Puffer ist mir klar. Habe ich bereits so implementiert.

Ich hänge aber gerade beim "GET" Befehl. Ich sende also etwas und erwarte eine Rückmeldung, die ja auch mithilfe des return Wertes in FHEMWeb angezeigt wird.
Ich möchte also so lange einlesen bis
1) ein Timeout abgelaufen ist
oder
2) die gewünschte Antwort empfangen wurde

Da das Gerät auch eigenständig etwas sendet, kann es sein, dass vor oder nach meiner eigentlichen Antwort auch noch wichtige Informationen stecken.
Grob müsste ich nun alles in einen Puffer lesen. Finde ich dort meine Antwort, kann ich diese mittels return zurück liefern.
Damit ich die anderen Nachrichten nicht verliere, müsste ich den Puffer also auch noch mal anderweitig verarbeiten.

Also in etwa so etwas:

   $maxTime=now()+$to;
  do
  {
  $buf=DevIo_SimpleReadWithTimeout($hash,$to);
  last if ($buf ==0);
  $partial .= $buf;
  } while( (!$partial =~ m/$regexp/) && ($maxTime < now()))
  $msg =$partial;
  $msg =~ /($regexp)\s+/g;
  return $msg if (!$timedout);xp)\s+/g;


$partial müsste ich dann ja nur noch so speichern, dass ich es später noch verarbeiten kann.

Bin ich da auf dem richtigen Weg oder habe ich was ganz einfaches übersehen?
Grüße Sidey
Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem,zigbee2mqtt

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker

justme1968

blockierend zu warten ist in FHEM keine gute idee. es ist auch nicht nötig um dem anwender das ergebniss eines GET anzuzeigen. schau dir mal asyncOutputFn an. damit lässt sich das auch nicht blockierend umsetzen. mehr findest du im thread im developer bereich und z.b. im plex modul.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Sidey

Hi,

habe mir den Thread zu asnycOutputFN angesehen.
Habe ich grob verstanden und ist auch das, was ich gesucht habe... :)

Gibt es irgendwo ein kleines Beispiel?
Ich habe leider noch nicht verstanden, wo man die Antwort auf eine Anfrage erhält.

Grüße Sidey
Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem,zigbee2mqtt

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker

justme1968

ein kleines beispiel ist der mit dem readingsProxy im thread. ein größeres beispiel ist in der neuen version des SYSSTAT moduls: https://forum.fhem.de/index.php/topic,42771.msg348498.html#msg348498 und ein noch größeres ist im plex modul hier: https://forum.fhem.de/index.php/topic,43052.msg374517.html#msg374517.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Sidey

#14
Hi andre,

Vielen Dank.
Das Beispiel im Plex Modul hilft mir ja noch eher weiter, als die anderen.

Ich habe folgendes Verstanden:

Es wird die GetFn eines Modules aufgerufen.
In $hash->{CL} steht irgendwas drinnen. Das kann ich in der GetFn auswerten.
In der Funktion sende ich nun etwas an mein USB Device. (DevIo_SimpleWrite)

Sobald ich auf die Antwort mittels DevIo_SimpleRead oder sowas warte ist FHEM ja blockiert. Also mache ich das nicht, solange ich asynchron ausgeben kann:

  SIGNALduino_SimpleWrite($hash, $gets{$a[1]}[0] . $arg);
  $hash->{getcmd}->{cmd}=$a[1];
  $hash->{getcmd}->{asyncOut}=$hash->{CL};
 
  return undef if ($hash->{CL} && $hash->{CL}->{canAsyncOutput});    # Exit for async output here
 
 
  ($err, $msg) = SIGNALduino_ReadAnswer($hash, $a[1], 0, $gets{$a[1]}[1]);



Also warte ich, bis die Daten über die ReadFN ankommen.
In ReadFN unterscheide ich dann, ob ich eine Nachricht empfange, die ich mit der normalen _parse Funktion auswerten möchte oder ob es eine ist, welche ich anzeigen möchte:


if ($rmsg && $hash->{getcmd} && $rmsg !~ m/^\002M.;.*;\003/){

my $ao = asyncOutput( $hash->{getcmd}->{asyncOut}, $hash->{getcmd}->{cmd}.": " . $rmsg );
delete($hash->{getcmd});

} elsif ($rmsg) {
Log3 $name, 5, "$name/msg parse";

    SIGNALduino_Parse($hash, $hash, $name, $rmsg);
}

Da $hash->{CL} in der read Funktion nicht gesetzt ist, habe ich mir den Abgesetzen Befehl  und das Ausgabe Device (CL} in  $hash->{getcmd} gespeichert.


EDIT:
Ich denke ich habe es verstanden. Post ist aktualisiert.

Grüße Sidey
Signalduino, Homematic, Raspberry Pi, Mysensors, MQTT, Alexa, Docker, AlexaFhem,zigbee2mqtt

Maintainer von: SIGNALduino, fhem-docker, alexa-fhem-docker, fhempy-docker