ECMD-Problem: USB-Device-Antworten kommen immer versetzt bei ECMD an

Begonnen von Uef, 30 Oktober 2013, 21:24:57

Vorheriges Thema - Nächstes Thema

Uef

Hallo zusammen,

ich bin FHEM-Anfänger und dies ist mein erster Eintrag im Forum und gleich benötige ich Unterstützung.
Aber zunächst mal ein Lob an das ganze Projekt  mit einer tollen Website und Unmenge an Informationen.

Trotzdem komme ich aktuell nicht weiter:
Ich habe FHEM auf meiner FritzBox 7390 (ohne Freetz, aktuelle Firmware) installiert und baue aktuelle eine Anbindung an meine Heizung auf Basis des OpenTherm-Protokolls.
Dazu habe ich einen Arduino an die USB-Schnittstelle der FB angeschlossen, in FHEM die erforderlichen ECMD-Definitionen angelegt und für den Arduino ein passendes Sketch geschrieben.
Bis dato deckt das allerdings erstmal nur eine Basisfunktionalität ab, da ich erstmal die Kommunikation zwischen der Fritzbox/FHEM und dem Arduino hinbekommen will, bevor es mit OpenTherm selbst weitergeht.
So weit, so gut.

Der Arduino wird von der FB und FHEM erkannt und ich kann auch Kommandos an den Arduino schicken, die dort aus ausgeführt werden (z.B. die Onboard-LED ein- und ausschalten).
Was nicht funktioniert, sind die Replies des Arduinos an ECMD. Die kommen zwar irgendwie an, werden aber erst als Antwort zum nächsten Kommando angezeigt.
Teilweise werden aber auch nur Teile der Antwort genommen, der Rest ist aber nicht verloren, sondern taucht als (falsche) Antwort auf das nächste Kommando auf.

Hier ein Beispiel aus dem Log:
erst schicke ich ein "Hallo 13" an den Arduino, der auf den Befehl "Hallo" hin alles als Echo zurückschicken soll (also "Hallo 13").
dann frage ich die Version ab, voraufhin der Arduino mit einem festen Text anworten soll.
Als Antwort auf das "Hallo 13" kommt aber nur das "H" an, der Rest des Textes dann als Antwort auf die Versionsfrage:

2013.10.30 18:14:42 4: HTTP FHEMWEB:192.168.0.2:56224 GET /fhem&room=Unsorted&cmd=get+myOT+hello+13
2013.10.30 18:14:42 5: Cmd: >get myOT hello 13<
2013.10.30 18:14:42 5: ECMDDevice: Analyze command >{"HELLO 13"}<
2013.10.30 18:14:42 5: ARDUINO sending HELLO 13
2013.10.30 18:14:42 5: ECMD (ReadAnswer): H
2013.10.30 18:14:42 5: H
2013.10.30 18:14:42 5: Triggering myOT (1 changes)
2013.10.30 18:14:42 5: Notify loop for myOT hello: H
2013.10.30 18:14:42 4: eventTypes: ECMDDevice myOT hello: H -> hello: H
2013.10.30 18:14:42 4: ECMDDevice myOT hello H
.....
2013.10.30 18:17:09 4: Connection closed for FHEMWEB:192.168.0.2:56327
2013.10.30 18:17:09 4: HTTP FHEMWEB:192.168.0.2:56346 GET /fhem&room=Unsorted&cmd=get+myOT+version
2013.10.30 18:17:09 5: Cmd: >get myOT version<
2013.10.30 18:17:09 5: ECMDDevice: Analyze command >{"VERSION"}<
2013.10.30 18:17:09 5: ARDUINO sending VERSION
2013.10.30 18:17:09 5: ECMD (ReadAnswer): ello 13
2013.10.30 18:17:09 5: ello 13
2013.10.30 18:17:09 5: Triggering myOT (1 changes)
2013.10.30 18:17:09 5: Notify loop for myOT version: ello 13
2013.10.30 18:17:09 4: eventTypes: ECMDDevice myOT version: ello 13 -> version: ello .*
2013.10.30 18:17:09 4: ECMDDevice myOT version ello 13


Die Versionsnummer bekomme ich erst, wenn ich nochmal die Version abfrage; leider kommt als Antwort auf den darauffolgenden Befehl dann auch erstmal die zweite Versionsnummer - auch wenn ich eigentlich nur die LED eingeschaltet habe.

Ich hoffe, das war irgendwie verständlich.
Das Problem scheint gefühlt irgendwie auf der FHEM-Seite zu sein. Im Arduino werden die Befehle sauber abgearbeitet (LED geht an und aus) und die Antworten tauchen in FHEM auch in der richtigen Reihenfolge auf - nur halt immer um einen Kommando-Zyklus versetzt.

WAS kann das sein ? Bin schon echt verzweifelt.
Habe die gesendeten Trennzeichen "\n" auf dem Arduino überprüft und die grundsätzliche Kommunikation scheint ja auch zu gehen.

Hier zur Vollständigkeit noch die Einträge aus FHEM.cfg und die ECMD-Class-Definition:

<fhem.cfg>
define ARDUINO ECMD serial /dev/ttyUSB0@9600
attr ARDUINO classdefs OPENTHERM=/var/InternerSpeicher/fhem/OPENTHERM.class
define myOT ECMDDevice OPENTHERM 13

<OPENTHERM.class>
#
# OPENTHERM class definition
# Version: 001
# works with Arduino sketch 001
#
# define parameters
params PAR1

# definitions of commands
get version cmd {"VERSION"}
set led_on cmd {"ON"}
set led_off cmd {"OFF"}
get hello cmd {"HELLO %PAR1"}



Und für die Genießer noch der relevante Teil aus dem Arduino Sketch; bei ersten Tests hatte ich die LED auch immer mit ihrem Status "antworten" lassen, da war aber der gleiche Effekt (LED_off antwortete mit "LED an" usw.) und ich war mir nicht sicher, ob ECMD bei set Kommandos überhaupt eine Antwort verträgt, daher habe ich sie im aktuellen Stand mal auskommentiert:

#include <SerialCommand.h>

#define arduinoLED 13 // Arduino LED on board

SerialCommand sCmd; // The demo SerialCommand object

void setup() {
  pinMode(arduinoLED, OUTPUT); // Configure the onboard LED for output
  digitalWrite(arduinoLED, LOW); // default to LED off

  Serial.begin(9600);

  // Setup callbacks for SerialCommand commands
  sCmd.addCommand("ON", LED_on); // Turns LED on
  sCmd.addCommand("OFF", LED_off); // Turns LED off
  sCmd.addCommand("VERSION", Send_Version); // Returns current version to FHEM
  sCmd.addCommand("HELLO", sayHello); // Echos the string argument back
  sCmd.addCommand("P", processCommand); // Converts two arguments to integers and echos them back
  sCmd.setDefaultHandler(unrecognized); // Handler for command that isn't matched (says "What?")
  // Serial.println("Ready");
  Serial.print("\n");    // initialize ECMD receive buffer in FHEM
}

void loop() {
  sCmd.readSerial(); // We don't do much, just process serial commands
}


void LED_on() {
  digitalWrite(arduinoLED, HIGH);
  // Serial.print("LED an\n");
}

void LED_off() {
  digitalWrite(arduinoLED, LOW);
  // Serial.print("LED aus\n");
}

void Send_Version() {
  Serial.print("VER 28.08.63\n");
}


void sayHello() {
  char *arg;
  arg = sCmd.next(); // Get the next argument from the SerialCommand object buffer
  if (arg != NULL) { // As long as it existed, take it
    Serial.print("Hello ");
    Serial.print(arg);
    Serial.print("\n");
  }
  else {
    Serial.println("Hello, whoever you are");
  }
}



Aufgrund meiner fehlenden Erfahrung mit FHEM bin ich mir auch nicht sicher, ob es sich bei meinem Problem um das gleiche handelt, das hier behandelt wurde (abwohl es schon sehr ähnlich ist):
https://groups.google.com/forum/#!topic/fhem-users/7rlgz8ik9iQ
und ob die dort besprochene Korrektur in meinem Versionsstand enthalten ist:
# $Id: fhem.pl 3872 2013-09-07 11:58:33Z rudolfkoenig $
# $Id: 66_ECMD.pm 2356 2012-12-23 09:02:02Z borisneubert $
# $Id: 67_ECMDDevice.pm 3412 2013-07-13 11:21:18Z rudolfkoenig $
# $Id: 01_FHEMWEB.pm 3963 2013-09-26 08:55:32Z martinp876 $
# $Id: 92_FileLog.pm 3759 2013-08-21 08:13:08Z rudolfkoenig $
# $Id: 99_SUNRISE_EL.pm 3738 2013-08-18 14:13:59Z rudolfkoenig $
# $Id: 99_Utils.pm 3595 2013-08-05 05:38:48Z tobiasfaust $
# $Id: 98_autocreate.pm 3957 2013-09-25 06:21:02Z rudolfkoenig $
# $Id: 91_eventTypes.pm 2982 2013-03-24 17:47:28Z rudolfkoenig $
# $Id: 91_notify.pm 3738 2013-08-18 14:13:59Z rudolfkoenig $
# $Id: 98_telnet.pm 3738 2013-08-18 14:13:59Z rudolfkoenig $
# $Id: 98_weblink.pm 3770 2013-08-23 13:29:58Z rudolfkoenig $

Vielleicht hat ja noch jemand einen Tipp für mich, damit mein Projekt nicht gleich am Anfang stirbt.

Dafür schon mal im Voraus vielen Dank.

Uef
fhem auf Raspberry2 mit MAX! (via CUL f. Raumthermostat, Fensterkontakte und Heizungen) und HM (via LanAdapter für Raumthermostat, 6-fach Taster, 4-fach Hutschiene, Statusanzeige, Stecker m. Leistungsmessung); In Entwicklung: Heizungsüberwachung via Adapter & MQTT; Stromverbrauchsüberwachung (1wire)

Uef

So, ich habe nochmal etwas geforscht und probiert:

der Fehler, dass die Antworten von Anfang an (nach Anstecken des Arduino) versetzt sind, ist nun weg; da hatte ich noch ein falsches Codestück auf dem Arduino.

Trotzdem verhaspelt sich sich der Dialog zwischen Arduino und dem ECMD-Modul bereits bei jeder 3. bis 5. Kommunikation (get-Befehl):
das ECMD-Modul bekommt nur einen Teil der Antwort vom Arduino zu sehen, also z.B. "VER 01.0" statt die komplette "VER 01.02.03". Der Rest, also "2.03" wird dann erst beim nächsten get-Befehl gelesen, egal was der eigentlich abgefragt hat. Und damit ist die Kommunikation für alle folgenden Dialoge zwischen ECMD und Arduino aus dem Tritt und unbrauchbar und kann nur durch einen reopen-Befehl an den Arduino resettet werden.

Gefühlt sieht es so aus, als würden sich zusätzliche "\n" Zeichen zufällig irgendwo in den USB-Empfangspuffer auf der Fritzbox "einschleichen" und sozusagen eine Antwort des Arduino in 2 Antworten splitten (\n ist das Trennzeichen für die ECMD-Kommunikation).

Hat sonst noch jemand Erfahrung mit der USB-Anbindung des Arduino und einen Tipp für mich, wo ich suchen könnte ?

USBMON hat die Fritzbox (ohne Freetz) leider nicht, so dass ich aktuell nicht weiß, wie ich überprüfen könnte, ob vielleicht der Arduino selbst die \n Zeichen liefert.

Der Arduino hängt mit einem ca 1m langen USB-Kabel an der Fritzbox 7390.

Any ideas ?

Uef
fhem auf Raspberry2 mit MAX! (via CUL f. Raumthermostat, Fensterkontakte und Heizungen) und HM (via LanAdapter für Raumthermostat, 6-fach Taster, 4-fach Hutschiene, Statusanzeige, Stecker m. Leistungsmessung); In Entwicklung: Heizungsüberwachung via Adapter & MQTT; Stromverbrauchsüberwachung (1wire)

Dr. Boris Neubert

Hallo,

der Kode zum Lesen vom seriellen Gerät ist ein Duplikat von den in allen Modulen zum Erstellungszeitpunkt des Moduls 66_ECMD.pm vorhandenen Kode zur Kommunikation über serielle Schnittstellen. Seitdem haben wir im Entwicklerkreis eine Reihe von wiederkehrenden Funktionsblöcken in gemeinsam genutzte Module ausgelagert. Dazu gehört die Schnittstellen-Kommunikation, welche heute in DevIO.pm liegt.

Ich habe 66_ECMD.pm nie auf die Nutzung der Routinen in DevIO.pm umgestellt (never change a running system). Ich würde auch heute 66_ECMD.pm gar nicht mehr nach der Ursache für das beschriebene Verhalten analysieren sondern gleich auf die Nutzung von DevIO.pm umstellen und dann sehen, ob das Verhalten noch auftritt und dann ggf. DevIO.pm auf die Ursachen hin abklopfen. Das ist allerdings eine umfangreiche Änderung, die erheblichen Test- und Kommunikationsaufwand mit der Anwenderschaft nach sich zieht. Ich kann das auf meine Todo-Liste nehmen aber ich kann keinen Termin dafür nennen.

Das Ganze liegt neben dem Todo, ECMD auch für den Empfang spontaner Datagramme aus dem angeschlossenen Gerät aufzubohren. Das hat schon jemand gemacht und der Kode liegt mir vor. Darin ist aber noch ein Designfehler, der nur mit demselben Aufwand zu beseitigen ist.

In Summe brauche ich allein ein Wochenende für das Rewrite. Und das habe ich im Moment nicht.

Eine flüchtige Durchsicht des Kodes hat ergeben, daß ECMD_SimpleRead verwendet wird, was $hash->{PARTIAL} nicht verwendet, um unvollständige Zeilen zwischenzuspeichern (Voraussetzung: eine Zeile endet auf LineFeed). Spricht klar für eine Migration nach DevIO.pm. Helfer willkommen!

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

betateilchen

Ich würde ja auch gerne ein paar IO-Funktionen umsetzen, aber ich habe bisher weder die Doku zu ECMD noch die Doku zu DevIO wirklich verstanden  :-[
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Uef

Hallo,

ich kann mittlerweile ergänzen, dass es am Timing bzw. an dem von Boris angesprochenen Problem mit unvollständigen Zeilen liegt: da ich mit "nur" 9600 Baud getestet habe, hat der SimpleRead oft schon zu einem Zeitpunkt den EmpfangsPuffer gelesen, an dem die Antwort des Arduino noch nicht komplett war.
Hin und wieder kam aber halt auch was dazwischen, so dass der PERL-Code "aufgehalten" wurde und die Antwort schon vollständig vorlag. Ein sleep() im Code hat  hier nachhaltig Wunder bewirkt, ist aber natürlich nicht die Lösung.

Mit dem aktuellen Stand meiner quasi nicht vorhandenen PERL-Kenntnisse bin ich vermutlich keine wirkliche Hilfe, werde mir das Ganze aber - auch auf Basis der von MichaS bereits angepassten Version von ECMD - auf jeden Fall weiter anschauen und - wie betateilchen - versuchen, es zu verstehen. Ist aber doch extrem mühsam, PERL über den Umweg des Reengineerings zu lernen  ???.

Vielleicht kriegen wir das gemeinsam ja doch gewuppt.

Uef
fhem auf Raspberry2 mit MAX! (via CUL f. Raumthermostat, Fensterkontakte und Heizungen) und HM (via LanAdapter für Raumthermostat, 6-fach Taster, 4-fach Hutschiene, Statusanzeige, Stecker m. Leistungsmessung); In Entwicklung: Heizungsüberwachung via Adapter & MQTT; Stromverbrauchsüberwachung (1wire)