Anbindung an openHCAN

Begonnen von GU!DO, 11 Oktober 2017, 10:30:09

Vorheriges Thema - Nächstes Thema

CoolTux

 ;D
Ok noch mal. Schau mal bitte genau hier
https://forum.fhem.de/index.php/topic,78101.msg700581.html#msg700581

Grundgerüst. Es geht darum das Du erstmal verstehst wie die Daten fließen, wo sie sind, wer schaut ob Daten an liegen und wer sie wie am Ende ab holt.

Das zweistufige ist doch dann nur noch ein weiterreichen der Daten an den Dispatcher der dann entsprechend der Vorgaben die ParseFn des logischen Modules auf ruft.
https://wiki.fhem.de/wiki/DevelopmentModuleIntro#Zweistufiges_Modell_f.C3.BCr_Module

Aber so weit sind wir noch lange nicht. Erstmal die Basic. Schau dir bitte erstmal die Moduldatei an die ich in dem genannten Thread als Gerüst angehangen habe.
Hier geht es nur darum ein Device zu erstellen, danach von Hand einen Netzwerksocket auf zu bauen und die Info für den Socket in die selectlist zu schicken. Damit schaut fhem.pl in der Hauptschleife immer nach ob dort Daten anliegen. Wenn ja ruft fhem.pl die Readfunktion der Moduldatei auf und erst dort werden dann die Daten abgeholt.

Lass uns das erstmal in Ruhe hinbekommen. Dann kommt der Rest nach und nach.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

CoolTux

Zitat von: GU!DO am 31 Oktober 2017, 11:24:03
Was mir nur noch nicht klar ist:
Das Modul um das es im Thread geht, sammelt doch Daten eines externen Vissman Daemon. Müßte es, um "ordnungsgemäß" angelegt zu sein, nicht in 2 Modul Technik ausgelegt werden?

Um kurz auch diese Frage zu beantworten.
Wann glaubst du baut man ein 2 stufiges Modul?
Meiner Meinung nach erst sobald Du über ein physikalisches Modul (Bridge) mehrere logische Geräte an sprichst. Wie viele Vissmann Heizungen glaubst du hat ein Hausbesitzer?

Anders würde es bei Thermostaten aussehen. Hier können zum Beispiel mehrere Thermostate über ein Gateway angesprochen werden.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

GU!DO

ZitatWann glaubst du baut man ein 2 stufiges Modul?

Ich habe den Wikieintrag "DevelopmentModuleIntro"  gelesen (Auszug):

X_Parse    Zustellen von Daten via Dispatch() vom physischen Modul zum logischen Modul zwecks der Verarbeitung.
X_Write    Zustellen von Daten via IOWrite() vom logischen zum physischen Modul um diese an die Hardware weiterzureichen.

Das habe ich so verstanden, dass ich ein:
phyisches Modul habe, welches auf der einen Seite mit der externen Hardware redet, und auf der anderen mit einem
logischen Modul, welches einerseits die Daten in FHEM präsentiert und andererseits Ereignisse aus FHEM an das physische Modul zurück gibt.

Wie gesagt, ich schaue mir den Thread an.

Vielen Dank für Deine Hilfe!

Guido

CoolTux

Schau ihn dir an und dann Bau doch einfach mal ein Modul was die Daten vom Bus liest.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

GU!DO

So, ich war ein wenig fleißig, habe aber leider noch keinen abschließenden Erfolg gehabt. Daher hoffe ich auf Deine Hilfe.

Erstmal vielen Dank für das Modulskelett. Das hat schon mal geholfen.

Grundsätzlich gehe ich folgender Maßen vor, wenn ich Änderungen am Modul gemacht habe:
1. Ich lösche das Test-Device.
2. ich mache einen Reload des Moduls mit reload...
3. ich Erstelle ein neues Device mit define...
Ich denke das ist so ok?!?

Ich habe das Testmodul mal 78_HCAN_Test.pm genannt. Die Nummer werde ich später noch ändern, jedoch war die 78 unbenutzt, so habe ich bereits nach Eingabe von 78 + Autoconpletion mein Modul im vim geöffnet:

Folgendes wurde geloggt mit dem angepassten Modul: (Verbose auf 5 + am Anfang jeden set's eine Ausgabe seines Namens mit print)


!!!Initialize
2017.10.31 16:58:12 4: WEB_10.20.30.40_43153 GET /fhem?fw_id=67; BUFLEN:0
2017.10.31 16:58:12 4: WEB: /fhem?fw_id=67 / RL:1257 / text/html; charset=UTF-8 / Content-Encoding: gzip
/
2017.10.31 16:58:12 4: Connection accepted from WEB_10.20.30.40_43156
2017.10.31 16:58:20 4: Connection closed for WEB_10.20.30.40_43150: EOF
2017.10.31 16:58:32 4: Connection closed for WEB_10.20.30.40_43154: EOF
2017.10.31 16:58:38 4: WEB_10.20.30.40_43153 POST /fhem&fw_id=67&fwcsrf=csrf_127224906171181&cmd=define+HCAN_Test+HCAN_Test+localhost; BUFLEN:0
2017.10.31 16:58:38 5: Cmd: >define HCAN_Test HCAN_Test localhost<
!!!Define
2017.10.31 16:58:38 3: HCAN_Test (HCAN_Test) - defined with host localhost
2017.10.31 16:58:38 5: Starting notify loop for HCAN_Test, 1 event(s), first is Initialized
2017.10.31 16:58:38 5: createNotifyHash
2017.10.31 16:58:38 5: End notify loop for HCAN_Test
2017.10.31 16:58:38 5: Starting notify loop for global, 1 event(s), first is DEFINED HCAN_Test
2017.10.31 16:58:38 5: createNotifyHash
2017.10.31 16:58:38 5: End notify loop for global
2017.10.31 16:58:38 4: WEB_10.20.30.40_43153 GET /fhem?detail=HCAN_Test&fw_id=67; BUFLEN:0
!!!Set
!!!Set
2017.10.31 16:58:38 4: WEB: /fhem?detail=HCAN_Test&fw_id=67 / RL:2548 / text/html; charset=UTF-8 / Content-Encoding: gzip


Der 3. Parameter in set enthält einen Wert, der in $cmd  übernommen wird. Wenn ich $cmd händisch auf "connect" setze, wird der socket geöffnet:

!!!Define
2017.10.31 17:28:32 3: HCAN_Test (HCAN_Test) - defined with host localhost
2017.10.31 17:28:32 5: Starting notify loop for HCAN_Test, 1 event(s), first is Initialized
2017.10.31 17:28:32 5: createNotifyHash
2017.10.31 17:28:32 5: End notify loop for HCAN_Test
2017.10.31 17:28:32 5: Starting notify loop for global, 1 event(s), first is DEFINED HCAN_Test
2017.10.31 17:28:32 5: createNotifyHash
2017.10.31 17:28:32 5: End notify loop for global
2017.10.31 17:28:32 4: WEB_10.20.30.40_43322 GET /fhem?detail=HCAN_Test&fw_id=33; BUFLEN:0
!!!Set
$VAR1 = 'Dumper =connect';
!!!Open
2017.10.31 17:28:32 4: HCAN_Test (HCAN_Test) - Baue Socket Verbindung auf
2017.10.31 17:28:32 5: Starting notify loop for HCAN_Test, 1 event(s), first is connected
2017.10.31 17:28:32 5: End notify loop for HCAN_Test
2017.10.31 17:28:32 4: HCAN_Test (HCAN_Test) - Socket Connected
!!!Set
$VAR1 = 'Dumper =connect';
!!!Open
2017.10.31 17:28:32 4: HCAN_Test (HCAN_Test) - Baue Socket Verbindung auf
2017.10.31 17:28:32 5: Starting notify loop for HCAN_Test, 1 event(s), first is connected
2017.10.31 17:28:32 5: End notify loop for HCAN_Test
2017.10.31 17:28:32 4: HCAN_Test (HCAN_Test) - Socket Connected


Aktuell hätte ich folgende Fragen:
1. Öffnet FHEM _Set generell nach einem Define - oder wo wird FHEM mitgeteilt was es öffnen soll?!?
2. Woher soll $cmd den Wert "connect" bekommen, so dass das die Funktion _Open aufgerufen wird, um den Socket zu öffnen?
3. Damit Daten Empfangen werden, muß ich ein Initialsierungspaket an den Daemon senden. Bringe ich das am besten am Abschluß der set Funktion unter?
4. Damit das Modul dauerhaft liest, müssen keep_alive Pakete an den Daemon gesendet werden. In meinem Testprogramm hcan2.pl habe ich das in einer while Schleife mit Try / catch gelöstt. Wie bekomme ich das hier hin.
5. Woher kommen die notifies im Log?

Viiiilen Dank schon mal

Guido

P.S. Ich hänge das angepasste Skelett und mein Testprogramm hcan2.pl an.

CoolTux

Dein Modul kann ich mir erst nachher in Ruhe anschauen.
Ich empfehle nicht global verbose 5 setzen sondern nur für das Modul als Attribut. Dann baust du passende Log Ausgaben ein, am besten alles mit Log3 dann siehst auch gleich was.

Den Connect macht man später automatisch, entweder durch ein InternalTimer aufgerufen am Ende des Define oder was sich eher durch setzt durch ein abfangen des passenden globalen Events.
Das keepAlive kannst Du dann tatsächlich durch das dauerhafte aufrufen einer Funktion erreichen.

Die Set Funktion ist für die User. Da können dann die User entsprechende Aktionen auslösen. Hier kann man einen Connect auslösen.


if( $cmd eq 'statusSOE' ) {

        return Connect($hash);
       
    } else {
   
        my $list = 'connect:noArg';
       
        return "Unknown argument $cmd, choose one of $list";
    }


Hiermit sollte die nun eine Set Liste im Web angezeigt werden. Und zwar Connect
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

CoolTux

Habe eben mal geschaut. Sieht doch schon mal gut aus

Was aber fehlt ist
1;

Gehört zwingend ans Ende eines jeden Modules.

Kann es sein das da bis jetzt noch keine Daten eingelesen wurden? Kannst Du noch einmal eine Verbindung machen wo Du nur das verbose vom Device auf 5 stellst?
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

GU!DO

Hallo,

sorry für die späte Antwort. Ich mußte erst noch Herrscharen von Gespenstern und anderen suspekten Gestalten die vor unserer Haustür herumlungerten mit Süssem versorgen...

ZitatIch empfehle nicht global verbose 5 setzen sondern nur für das Modul als Attribut.
Danke für den Tip.
Ich hatte es im Kommentar zu Log3 so verstanden, dass Verbose Werte in den Modulen nicht mehr berücksichtigt werden - sondern nur noch global.

ZitatDen Connect macht man später automatisch, entweder durch ein InternalTimer aufgerufen am Ende des Define oder was sich eher durch setzt durch ein abfangen des passenden globalen Events.
Welcher Event wäre denn wohl passend?

ZitatDas keepAlive kannst Du dann tatsächlich durch das dauerhafte aufrufen einer Funktion erreichen.
Wäre es besser, das in einem 2. Modul zu machen, um die FHEM Schleife nicht zu "überlasten"?

if( $cmd eq 'statusSOE' )

Danke! Den code habe ich getestet - läuft super, aber woher nimmst Du statusSOE?
Ich dachte erst, ich hätte irgend etwas in der Dev.Doku übersehen, aber auch eine google Suche mit "FHEM und statusSOE" bringt nichts zu Tage.

Danke für Deine Mühen!

GU!DO

Nee, Daten fließen da noch nicht.
Der Socket wurde ja noch nicht initialisiert.

Dann muß erst ein "Anmeldepaket" an den UDP Server des Deamons geschickt werden damit dieser sich den Port vom Modul einträgt und Daten auch dorthin sendet.
Weiß nur nicht, wo und wie ich das im code unterbringe?!? In meinem Testprogramm war es in einer Schleife... Ist in FHEM wohl keine gute Idee.

In meinem Testprogramm sieht das so aus:

   #my $data = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
   #$socket->send($data);


Das ist dann gleich den keep_alive Paketen, ohne die der Daemon das Senden wieder einstellt.

Das ist das Log mit Verbose im Modul auf 5:

2017.10.31 21:39:15 3: HCAN_Test (HCAN_Test) - device HCAN_Test deleted
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_Undef redefined at ./FHEM/78_HCAN_Test.pm line 92.
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_Attr redefined at ./FHEM/78_HCAN_Test.pm line 107.
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_Set redefined at ./FHEM/78_HCAN_Test.pm line 120.
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_Open redefined at ./FHEM/78_HCAN_Test.pm line 178.
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_Close redefined at ./FHEM/78_HCAN_Test.pm line 219.
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_ReOpen redefined at ./FHEM/78_HCAN_Test.pm line 236.
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_Write redefined at ./FHEM/78_HCAN_Test.pm line 250.
2017.10.31 21:39:40 1: PERL WARNING: Subroutine HCAN_Test_Read redefined at ./FHEM/78_HCAN_Test.pm line 275.
!!!Initialize
!!!Define
2017.10.31 21:40:13 3: HCAN_Test (HCAN_Test) - defined with host localhost
!!!Set
!!!Set
!!!Set

CoolTux


if( $cmd eq 'connect' ) {

        return Connect($hash);
       
    } else {
   
        my $list = 'connect:noArg';
       
        return "Unknown argument $cmd, choose one of $list";
    }


Mein Fehler, sorry. cmd eq muss mit dem übereinstimmen was unten im $list steht. $list ist das was als set Befehl angezeigt wird und $cmd eq das was akzeptiert wird.

Als Standard Log Level ist global 3 eingestellt. Es werden also nur Logausgaben angezeigt die in den Modulen 1 2 und 3 haben
Log3 $name, 5, "Modulname ($name) - ProcessingNotification";
Das hier z.B. st 5 und würde nicht angezeigt werden.

Am besten Du stellst Deine Logausgaben im Testmodul auf 3
Log3 $name, 3, "Modulname ($name) - ProcessingNotification";


Das keepAlive ist dafür da Deine Socketverbindung aufrecht zu erhalten. So habe ich es zu mindest verstanden. In meinen Augen ist es damit Bestandteil des physikalischen Modules. Also des Modules wo die Socketverbindung verwaltet wird.

Hier machst Du einfach eine Funktion welche ein syswrite macht und sich danach verzögert durch InternalTimer wieder selbst aufruft.

Zum Thema Notify

sub blablub_Initialize($) {
...
$hash->{NotifyFn}   = "XiaomiFlowerSens_Notify";
...
}
...
sub blablub_Notify($$) {

    my ($hash,$dev) = @_;
    my $name = $hash->{NAME};
    return if (IsDisabled($name));
   
    my $devname = $dev->{NAME};
    my $devtype = $dev->{TYPE};
    my $events = deviceEvents($dev,1);
    return if (!$events);


    blablub_connect($hash) if( grep /^INITIALIZED$/,@{$events}
                                                or (grep /^DEFINED.$name$/,@{$events} and $init_done) );
    return;
}


INITIALIZED ist der globale Event wenn FHEM vollständig gestartet ist. DEFINED unteranderem wenn man ein modify macht.

Schau mal das Du erstmal Daten über die ReadFn bekommst. Wenn sich Deine Moduldatei nicht geändert hat muss in Deinem FHEM log
HCAN_Test ($name) - received buffer data, start VCLIENT_Test_ProcessRead: $buf
stehen und für $buf halt die Daten
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

CoolTux

kleinen Moment ich schaue mal das ich da was vor bereite
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

GU!DO

Das ist klasse. Ehrlich gesagt, habe ich grad fast nur Bahnhof verstanden.  :'(
Wie gesagt, totaler FHEM & perl Anfänger.
Na ja, und wenn ich ehrlich bin, tue ich mich mit Objekten auch noch etwas schwer.
Als ich angefangen habe zu Programmieren, gab es noch keine Objektorientierung.
Dann hab ich Jahre Lang nix mehr gemacht, und jetzt hab ich den Salat!  :-[

CoolTux


sub HCAN_Test_KeepAlive($) {

    my $hash    = shift;
   
    my $data    = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
   
    HCAN_Test_Write($hash,$data);
   
    InternalTimer( gettimeofday()+$hash->{INTERVAL}+30, "HCAN_Test_KeepAlive", $hash);
}


sub HCAN_Test_Write($@) {
    print("!!!Write\n");
   
     my ($hash,$data)  = @_;
     my $name                    = $hash->{NAME};
   
   
     Log3 $name, 3, "HCAN_Test ($name) - WriteFn called";
   
     return Log3 $name, 3, "HCAN_Test ($name) - socket not connected"
     unless($hash->{CD});
   
     Log3 $name, 3, "HCAN_Test ($name) - $data";
     syswrite($hash->{CD}, $data);
   
     return undef;
}



ub HCAN_Test_Open($) {
...
...

### ganz am Ende
HCAN_Test_KeepAlive($hash);
}


Und vergiss die 1;
am Ende der Moduldatei bitte nicht

Schau mal mal ob Du damit weiter kommst. Ist erstmal ohne große Prüfung.
Damit sollte nach dem Du ein set connect gemacht hast und somit ja die Connect Routine gestartet und die Socketverbindung aufgebaut wurde die Routine KeepAlive gestartet werden, welche sich am Ende wieder selbst auf rufst aber durch InternalTimer 30s verzögert.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

GU!DO

Wahnsinn, ist das für Dich eigentlich so wie eine Mail zu schreiben?

Also: Es geht noch nicht vollständig, ich wollte Dir aber schonmal den Zwischenstand mitteilen:

Erst kam das:

!!!Initialize
!!!Define
2017.10.31 22:17:50 3: HCAN_Test (HCAN_Test) - defined with host localhost
!!!Set
!!!Set
!!!Set
!!!Set
!!!Set
!!!Set
Undefined subroutine &main::Connect called at ./FHEM/78_HCAN_Test.pm line 128.


Dann habe ich Zeile 128 von "return Connect($hash);" auf "return HCAN_Test_Open($hash);" geändert.

Dann gibt es eine Warnung:
PERL WARNING: Use of uninitialized value in addition (+) at ./FHEM/78_HCAN_Test.pm line 256
Ich vermute, das liegt an der addition von undef mit 30 für den Timer?!?
InternalTimer( gettimeofday()+$hash->{INTERVAL}+30, "HCAN_Test_KeepAlive", $hash);

Seit dem kommt:

!!!Initialize
!!!Define
2017.10.31 22:26:12 3: HCAN_Test (HCAN_Test) - defined with host localhost
!!!Set
!!!Set
!!!Set
!!!Set
!!!Write
2017.10.31 22:26:24 3: HCAN_Test (HCAN_Test) - WriteFn called
2017.10.31 22:26:24 3: HCAN_Test (HCAN_Test) - socket not connected
!!!Write
2017.10.31 22:26:26 3: HCAN_Test (HCAN_Test) - WriteFn called
2017.10.31 22:26:26 3: HCAN_Test (HCAN_Test) - socket not connected
!!!Set
!!!Open
2017.10.31 22:26:30 4: HCAN_Test (HCAN_Test) - Baue Socket Verbindung auf
!!!Set
2017.10.31 22:26:30 4: HCAN_Test (HCAN_Test) - Socket Connected
!!!Write
2017.10.31 22:26:30 3: HCAN_Test (HCAN_Test) - WriteFn called
2017.10.31 22:26:30 3: HCAN_Test (HCAN_Test) - \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
!!!Set
!!!Set
!!!Set
!!!Write
2017.10.31 22:26:54 3: HCAN_Test (HCAN_Test) - WriteFn called
2017.10.31 22:26:54 3: HCAN_Test (HCAN_Test) - socket not connected
!!!Write
2017.10.31 22:26:56 3: HCAN_Test (HCAN_Test) - WriteFn called
2017.10.31 22:26:56 3: HCAN_Test (HCAN_Test) - socket not connected
!!!Write
2017.10.31 22:27:00 3: HCAN_Test (HCAN_Test) - WriteFn called
2017.10.31 22:27:00 3: HCAN_Test (HCAN_Test) - \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00



Er öffnet den Socket hält ihn dann auch offen, jedoch zeigt er keine eingehenden Pakete.
Kann es sein, dass er damit nix anfangen kann. In meinem Test-Programm muß ich die noch in hex wandeln:

print unpack("H*", $incommming),"\n";



CoolTux

 Der String der gesendet wird stimmt aber? Er muss also genau so aussehen?
Und die empfangenen Daten müssen dann noch in Hex umgewandelt werden?
Aber dennoch muss er ja irgendwas empfangen.

Hänge Mal bitte deine aktuelle Moduldatei hier an. Ich gehe jetzt schlafen aber würde Mal morgen früh das Modul soweit schreiben das ein ständiges keepAlive gesendet wird.
Teste dann das Modul auch das es sauber läd. Passen denn 30s Interval für das KeepAlive?
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net