ECMD teilt String (willkürlich) auf

Begonnen von Freibeuter, 04 Juni 2014, 11:08:08

Vorheriges Thema - Nächstes Thema

Freibeuter

Hallo,
leider komme ich mit dem neuen ECMD nicht mehr an die Daten von meiner Almemo Messwererfassung ran.
Da ich zu wenig Perl kann, habe ich mir bisher den gesamten AntwortString in ein Reading schreiben lassen und dieses dann in FHEM ausgewertet:
Dafür sende ich ein "S1" + CHR(13) an das Almemound bekam dann folgenden String:
"18:59:02 00: +0022.6 �C 01: -0080.1 �C 02: +0006.8 �C 03: +0022.7 �C 05: +0000.2  % 16:  - - -  �C"

Nun sieht die Antwort so aus:
2014.06.04 10:32:44 3: RS232: write "S1\n"
2014.06.04 10:32:44 3: RS232: read "S1\r\n"
2014.06.04 10:32:44 3: RS232: read "\01718:59:02"
2014.06.04 10:32:45 3: RS232: read " 00: +0022.6 �C 01: -0080.1 �C 02: +0006.8 �C 03: +0022.7 �C 05: +0000.2  % 16:  - - -  �C.\r\n\022\003"

und manchmal ist der "Zeilenumbruch" auch noch mitten in einem Wert:
2014.06.04 10:32:29 3: RS232: write "S1\n"
2014.06.04 10:32:29 3: RS232: read "S1\r\n"
2014.06.04 10:32:29 3: RS232: read "\01718:58:"
2014.06.04 10:32:30 3: RS232: read "47 00: +0022.6 �C 01: -0080.1 �C 02: +0006.8 �C 03: +0022.7 �C 05: +0000.2  % 16:  - - -  �C.\r\n\022\003"

Wie kann ich ECMD dazu bringen erst nach einem CR den String auszugeben?
Vielen Dank!

Classdef sieht so aus :
get Temp cmd {"S1\n"}
reading TempS match ".*"


und in FHEM:
serial /dev/ttyUSB0@9600


Dr. Boris Neubert

Hallo,

Du brauchst eine maßgeschneiderte Regexp im match.

Viele Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Freibeuter

#2
Hallo Boris,
vielen Dank für die schnelle Antwort.

So weit bin ich schon:
get Temp cmd {"S1\n"}
get Temp expect "S1\r\n017\d+:\d+:\d%20\d:.*C.\r\n\022\003"
Oder besser so :
get Temp cmd {"S1\n"}
get Temp expect "S1\r\n017\d+:\d+:\d 00: \d.\d �C 01: \d.\d �C 02: \d.\d �C 03: \d.\d �C 05: \d.\d % 16:  - - -  �C.\r\n\022\003"

Aber wie verarbeite ich das �C was wohl ein °C sein soll, kann ich auch Leerzeichen eingeben oder %20 dafür einsetzen ?
Gruß Peter F.

Freibeuter

Wieder wird nicht der ganze String ausgelesen, was mache ich falsch ?
RS232: unexpected answer "S1\r\n" received (wrote "S1\n", expected S1\r\n017\d+:\d+:\d 00: \d.\d �C 01: \d.\d �C 02: \d.\d �C 03: \d.\d �C 05: \d.\d % 16:  - - -  �C.\r\n\022\003)

Meine Commandref:
get Temp cmd {"S1\n"}
get Temp expect "S1\r\n017\d+:\d+:\d 00: \d.\d �C 01: \d.\d �C 02: \d.\d �C 03: \d.\d �C 05: \d.\d % 16:  - - -  �C.\r\n\022\003"


Icinger

HI, ich habe das selbe Problem, das die Antworten von meinem Smartmeter von ECMD willkürlich gesplittet werden (siehe http://forum.fhem.de/index.php/topic,24194.0.html

Ich habe das jetzt so gelöst, dass ich ein Reading auf .* mache und mir in der 99_myutils den String immer weiter zusammensetze.
Bei jedem Aufruf der Sub wird dann einfach der String bei CRs aufgesplittet und weiterverarbeitet.

lg, ici
Verwende deine Zeit nicht mit Erklärungen. Die Menschen hören (lesen) nur, was sie hören (lesen) wollen. (c) Paulo Coelho

Dr. Boris Neubert

Hallo Peter,

Soforthilfe:  ein Punkt match jedes Zeichen.

Am besten schaust Du Dir einmal http://perldoc.perl.org/perlre.html an oder ein anderes der unzähligen Tutorials zu Perl Regular Expressions.

Viele Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Dr. Boris Neubert

Hallo,

wenn ich nochmal darüber nachdenke: der match hilft nicht.

Die Ursache ist in der commandref beschrieben:
ZitatData received from the physical device is processed as it comes in chunks. If for some reason a datagram from the device is split in transit, pattern matching and processing will most likely fail.

DevIO.pm liefert die Teile, wie sie vom Device kommen, an das Modul weiter. Das gibt es auch mit anderen Modulen. Dort gibt es ein PARTIAL-Internal, das die Einzelteile einsammelt, bis das Datagramm komplett ist. Im Prinzip wäre die ganze Sache auch bei ECMD über ein PARTIAL-Internal zu lösen.

Bei ECMD ist das aber nicht so einfach, weil die Datagramme ja alles Mögliche sein können.

Ich hatte mir bereits folgende Lösung dazu ausgedacht: wenn es eine match-Direktive zu einem Kommando gibt, werden Fragmente solange gesammelt, bis es einen Match gibt. Das führt bei unerwarteten Antworten zwangsläufig zu einer endlosen Warterei, so daß noch eine geeignete Abbruchbedingung benötigt wird. Dabei ist es bisher geblieben.

Du kannst mit etwas mehr Perl-Kenntnissen das Verhalten aber replizieren: baue Dir einen Postprozessor, welcher die empfangenen Fragmente in einem Partial-Reading sammelt. Nach jedem Sammeln wird geprüft, ob es einen Match gibt. Falls ja, wird das Reading in die Bestandteile zerlegt und in andere Readings eingetütet und das Partial-Reading geleert.

ici macht das Ganze wohl auch mit einer Hilfsfunktion in 99_myutils.pm. Das wird vermutlich die einfachste Lösung sein.

Viele Grüße
Boris



Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Icinger

Hallo Boris,

als Abbruch-Bedingung, wenn ein Device was anderes sendet als im Expect erwartet, wäre mMn

1) Wenn empfangene Zeichenkette länger als erwartet und/oder
2) Timeout nach x (Mili)sekunden, falls Device gar nichts sendet

denkenswert.

lg, Ici
Verwende deine Zeit nicht mit Erklärungen. Die Menschen hören (lesen) nur, was sie hören (lesen) wollen. (c) Paulo Coelho

tbnobody

Hallo,

ich stehe aktuell vor einem ähnlichen Problem. Habe einen Mikrocontroller mit dem Eventgesteuert mehrere Taster abgefragt werden. Der Status (pressed / released) wird via ECMD an FHEM gemeldet.

In der fhem.cfg sieht das folgendermaßen aus:

define I2Cgate ECMD serial /dev/ttyUSB0@9600
attr I2Cgate classdefs SWITCH=/opt/fhem/switch.classdef
define WZ_SwitchDown ECMDDevice SWITCH 4
attr WZ_SwitchDown IODev I2Cgate
define WZ_SwitchUp ECMDDevice SWITCH 3
attr WZ_SwitchUp IODev I2Cgate
define WZ_SwitchSel1 ECMDDevice SWITCH 1
attr WZ_SwitchSel1 IODev I2Cgate
define WZ_SwitchSel2 ECMDDevice SWITCH 2
attr WZ_SwitchSel2 IODev I2Cgate


Die switch.classdef Datei hat folgenden Inhalt:

params switchID

reading pressed match "p%switchID"
reading released match "r%switchID"


Laut Logfile werden die Daten zerstückelt empfangen.


2014.08.10 04:55:19 5: I2Cgate: Spontaneously received "p"
2014.08.10 04:55:19 5: I2Cgate dispatch p
2014.08.10 04:55:19 5: Triggering global (1 changes)
2014.08.10 04:55:19 5: Notify loop for global UNDEFINED ECMDDevice message p
2014.08.10 04:55:19 2: autocreate: define ECMDDevice message p
2014.08.10 04:55:19 1: ERROR: Unknown module message
2014.08.10 04:55:19 5: I2Cgate: Spontaneously received "2\r\n"
2014.08.10 04:55:19 5: I2Cgate dispatch 2


Das Ganze mit .* zu matchen und in einer Eigenen Routine zusammenzustückeln wurde ja oben beschrieben. Ich bin mir nur nicht sicher ob das auch für meinen Einsatzzweck funktioniert da die Empfangenen Daten ja verschiedene Schalter Objekte steuern.

hajo23

#9
ein Ansatz wäre:

reading firstpart match ".*(?!\n$)"
reading firstpart postproc {s/.*\n(.*)(?!\n$)/$1/s; $_}
reading lastpart match "(.*)\n"
reading lastpart postproc {s/(.*)\n/$1/; $_}


wenn "\n" das letzte Zeichen einer Message wäre, wobei lastpart immer greift. Man müsste also die Zeitstempel vergleichen, die Teile ggf. zusammenführen, auswerten und firstpart leeren.

Dr. Boris Neubert

Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Icinger

Boris for president!  ;D

Danke, klingt vielversprechend. Wird ich heute gleich mal ausprobieren.
Verwende deine Zeit nicht mit Erklärungen. Die Menschen hören (lesen) nur, was sie hören (lesen) wollen. (c) Paulo Coelho

Freibeuter

#12
Ich beiße noch immer auf Granit :-(

Ausgangssituation:
eine Ccontrol II sendet fogenden String:
A23B123C123D(chr13)
und diesen möchte ich jetzt in 3 Readings A B C auslesen:

meine Classdef dazu ist:

get temp cmd {"get-temp".chr(0x0D)}

reading temp expect "A\dB\dC\dD\r"

ich nutze partial 2
und bekomme folgendes Log:
2014.10.26 10:44:02 0: RS232: write "get-temp\r"
2014.10.26 10:44:03 0: RS232: read "A6"
2014.10.26 10:44:03 0: RS232: read "10B530C595D"

Bin für jede Hilfe dankbar, und ja es liegt an meinen noch zu schlechten Perl Kenntnissen :-(
Schönen Sonntag Euch
Peter F.


Dr. Boris Neubert

Du musst eine auf die Antwort passende Perl Regular Expression hinter expect verwenden. Am besten schlaust Du Dich zu Regex erst einmal auf.

Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!