DevIo: DevIo_SimpleRead: nur begrenzte Zeichenzahl möglich?

Begonnen von Spiff, 21 Juli 2014, 20:53:57

Vorheriges Thema - Nächstes Thema

Spiff

Hi,

ich schaue mir gerade genauer das MediaPortal-Plugin an. Es empfängt und sendet Kommandos an diese HTPC-Software.

Mir sind ein paar Nachrichten aufgefallen, die vom Modul nicht interpretiert werden können.
Es scheint so zu sein, dass die Nachrichten manchmal zu lang sind.

FHEM teilt die Nachricht dann jeweils nach 256 Zeichen auf und erkennt diese dann als neue Nachricht an. Benutzt wird DevIo_SimpleRead.

Bin ich da auf der richtigen Fährte? Gibt es Möglichkeiten, die Nachrichten nach dem Empfang wieder zusammenzusetzen? Wie erkenne ich dann, dass die Nachrichten auch wirklich zusammengehören?

Ich kann das zwar eigentlich aus dem Inhalt der Nachrichten ableiten, aber ginge das auch FHEM-programmtechnisch, bevor ich den Inhalt interpretiere?

Danke & viele Grüße
Spiff

Puschel74

Hallo,

bist du dir sicher das du in Anfängerfragen richtig bist?

Zitatich schaue mir gerade genauer das MediaPortal-Plugin an.
Sollte das nicht eher nach Multmedia?

ZitatFHEM teilt die Nachricht dann jeweils nach 256 Zeichen auf und erkennt diese dann als neue Nachricht an. Benutzt wird DevIo_SimpleRead.
Oder Richtung fhem.pl (das wäre dann Sonstiges).

Das lässt sich aber alles hier nachlesen und noch vor dem Posten richtig einordnen http://forum.fhem.de/index.php/topic,13092.0.html
Wozu?
Damit die Frage schneller beantwortet werden kann weil sie von Anfang an im richtigen Bereich gestellt wird.

Damit du die Frage aber im passenden Bereich nicht nochmal stellen musst kann sie auch gerne verschoben werden - du musst nur sagen wohin  ;)

Grüße
Zotac BI323 als Server mit DBLog
CUNO für FHT80B, 3 HM-Lan per vCCU, RasPi mit CUL433 für Somfy-Rollo (F2F), RasPi mit I2C(LM75) (F2F), RasPi für Panstamp+Vegetronix +SONOS(F2F)
Ich beantworte keine Supportanfragen per PM! Bitte im Forum suchen oder einen Beitrag erstellen.

ntruchsess

Im FHEM Develoment Board wäre die Chance darauf eine qualifizierte Antwort zu bekommen wohl höher ;-)

DevIo_SimpleRead ließt einen Stream. (Serielle Schnittstelle (auch über USB), Socketverbindung, Unix-Stream...). Es liegt in der Natur eines Streams, dass man die Zeichen dann selber parsen und z.B. das Ende einer Nachricht am Inhalt, oder daran, dass - je nach verwendetem Protokoll - der Stream am Ende einer Nachricht geschlossen wird, erkennen muss. Ist halt ziemlich low-level I/O. Wenn man Glück hat, dann hat schon jemand anderes einen Parser für das verwendete Protokoll geschrieben, dann muss man nur noch den Parser geeignet an den Stream anflanschen und Ihm die Arbeit des zerpflückens überlassen...

Gruß,

Norbert
while (!asleep()) {sheep++};

Spiff

Hi!

Zitat von: Puschel74 am 21 Juli 2014, 21:00:16
bist du dir sicher das du in Anfängerfragen richtig bist?

Ich ääh...  'tschuldigung. :-[
Also nachdem, was ich hier so gelesen habe und ich mich deswegen als blutiger Anfänger einschätze und zu dem Profibereich niemals Zugang bekommen würde, fand ich das hier ganz passend.
Aber wenn verschieben, dann eher in Richtung Sonstiges. Dankesehr . :)

Zitat von: ntruchsess am 21 Juli 2014, 21:36:56
Es liegt in der Natur eines Streams, dass man die Zeichen dann selber parsen und z.B. das Ende einer Nachricht am Inhalt, oder daran, dass - je nach verwendetem Protokoll - der Stream am Ende einer Nachricht geschlossen wird, erkennen muss. Ist halt ziemlich low-level I/O. Wenn man Glück hat, dann hat schon jemand anderes einen Parser für das verwendete Protokoll geschrieben, dann muss man nur noch den Parser geeignet an den Stream anflanschen und Ihm die Arbeit des zerpflückens überlassen...

Okay, danke für die Erklärung.

Also das Protokoll ist JSON. So wie ich das verstanden habe, wird anhand eines "{" erkannt, dass die Nachricht beginnt. Es kann aber auch sein, dass die Nachrichten in weitere Ebenen mit einem weiteren "{" eingeteilt werden. Die Routine sollte also auch die Ebenen mitzählen und die Nachrichten dann zum Schluss, wenn die Ebene mit dem letzten "}" wieder bei 0 angekommen ist, wieder zu einer Nachricht zusammensetzen.

Ich schaue mir das mit diesem Gedanken nochmal an! Danke!
Spiff

justme1968

fhem teilt die nachrichten nicht automatisch auf. wie fiele bytes bei einem einzelnen read ankommen hängt davon ab wie schnell das darunter liegende device ist, wie gross die buffer konfiguriert sind und wie schnell fhem gerade läuft bzw wie sehr es ausgelastet ist.

die bei den einzelnen reads zurück kommenden bytes must du selber zwischenspeichern und so lange aneinander hängen bis du eine vollständige nachricht erkennst. diese kannst du dann verarbeiten und den rest wieder als anfang der nächsten nachricht aufheben. und so weiter ...

gruss
  andre

edit: ja genau. in deinem fall müsstest du die klammern zählen und bei 0 hast du eine nachricht komplett.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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

ntruchsess

Zitat von: Spiff am 21 Juli 2014, 22:52:21
Also das Protokoll ist JSON. So wie ich das verstanden habe, wird anhand eines "{" erkannt, dass die Nachricht beginnt. Es kann aber auch sein, dass ...
Zum parsen von JSON würde Dir empfehlen das Rad nicht noch mal neu zu erfinden, sondern auf existierende Lösungen wie z.B. z.B. JSON::Streamin::Reader zu setzen.

Gruß,

Norbert
while (!asleep()) {sheep++};

justme1968

ja. das rad neu erfinden sollte man nicht. klammern zählen und dafür das 'einfachere' json modul zu verwenden ist ist aber nicht unbedingt das rad neun erfinden.

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

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

Spiff

Hallo,

ich bin nicht so genial, dass ich jemals auf das Rad gekommen wäre.

Deswegen bin ich auch nur nach der Suche eines Fehlers im MediaPortal-Modul gewesen und habe ihn finden können.
Die Sache mit dem Stream-Zusammensetzen war dort schon umgesetzt, nur war der Interpreter an einer Stelle so programmiert, dass hin und wieder alles vor der letzten Ebene abgeschnitten wurde.

Aber vielen Dank, jetzt weiss ich ungefähr, wie sowas funktioniert, war mir total neu.

Hier der Code mit dem Übeltäter:
sub MEDIAPORTAL_Read($) {
  my ($hash) = @_;
  my $buf = DevIo_SimpleRead($hash);
  return "" if(!defined($buf));

my $name = $hash->{NAME};
  my @array;
   
$hash->{helper}{buffer}.=$buf;
my $b=$hash->{helper}{buffer};
my $level=0;
my $startpos=-1;
my $strippos=0;
for (my $i=0;$i<length($b);$i++) {
if (substr($b,$i,1) eq "{") {
#################################################
##### Übeltäter: if ($level==0) hat gefehlt #####
#################################################
if ($level==0) {$strippos=$i;}
if ($startpos==-1) {$startpos=$i;}
$level++;
} elsif (substr($b,$i,1) eq "}") {
$level--;
if ($level==0) {
my $msg=substr($b,$startpos,($i-$startpos)+1);
$startpos=-1;
$strippos=$i+1;
ProcessMessage($hash,$msg);
}
}
}
if ($strippos<length($b)-1) {
$b=substr($b,$strippos);
} else { $b=""; }
$hash->{helper}{buffer}=$b;
  return undef;
}


Viele Grüße
Spiff