FHEM Forum

FHEM - Entwicklung => FHEM Development => Thema gestartet von: timmib am 25 Januar 2021, 12:33:18

Titel: Readings nach FHEM schicken
Beitrag von: timmib am 25 Januar 2021, 12:33:18
Guten Tag,

ich würde gerne einen neues FHEM Modul entwickelnm welches die neuesten Werte aus einer externen Datenbank als Reading hat.

Bei der externen Datenbank handelt es sich um InfluxDB. Dazu gehört auch Kapacitor mit dem man z.B. per MQTT und auch HTTPPost verschicken kann.

Im Moment habe ich den Eindruck, dass MQTT die beste Option ist, da FHEM out-of-the-box kein HTTP-Post unterstützt. Aktives Pollen der Datenbank kommt nicht in Frage. FHEM sollte passiv auf Änderungen warten.

Hat jemand einen Vorschlag für mich?

Viele Grüße

Tim
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 25 Januar 2021, 13:03:48
Zitatda FHEM out-of-the-box kein HTTP-Post unterstützt.
Das ist nicht richtig.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 25 Januar 2021, 15:28:38
Ich denke schon das es richtig ist.


Welchen Namen hat denn das I.O. Device ?

MfG
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 25 Januar 2021, 15:45:49
ZitatIch denke schon das es richtig ist.
Womoeglich haben wir unterschiedliche Auffassungen von HTTP-Post, oder was "FHEM out-of-the-box" bedeutet.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: Otto123 am 25 Januar 2021, 16:01:19
Zitat von: M.Schulze am 25 Januar 2021, 15:28:38
Welchen Namen hat denn das I.O. Device ?
Ich würde meinen der Name spielt hierbei keine Rolle, aber in der Standardinstallation heißt der WEB ;) oder ich habe nicht verstanden was HTTP-Post ist...
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 25 Januar 2021, 16:20:25
Die Tatsache das FHEMWEB HTTP-Posts erfassen kann und Readings draus machen kann ist allenfalls ein "nice to have".

Ich rede von der Anbindung von vielen, verschiedene Geräten über das HTTP Protokoll.

Das sind Geräte die einen Webserver besitzen und auch Requests (HTTP-Posts?) auslösen können.

Als zweistufiges Modell für Module wie im Wiki beschrieben. Wo das erste Modul den Server aufbaut, das Parsen übernimmt, und die 2. Stufe z.B. nur den Query auswertet und den Input für die Response vorbereitet.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: herrmannj am 25 Januar 2021, 17:29:13
Ein Webserver löst sicher keinen request aus, das macht der Client. Bitte nicht mit Worthülsen rumwerfen. Und falls doch fehlt Bitcoin und AI für ein Bingo
Titel: Antw:Readings nach FHEM schicken
Beitrag von: betateilchen am 25 Januar 2021, 19:18:28
Zitat von: herrmannj am 25 Januar 2021, 17:29:13
Und falls doch fehlt Bitcoin und AI für ein Bingo

und Blockchain  8)

Seit wann haben "Commercial User" eigentlich Berechtigungen im Developer Board? Muss ich wohl verpasst haben.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: KölnSolar am 25 Januar 2021, 19:36:49
Möchte mit Bingo spielen. ;D

Aber zurück zum TE.
Hallo Tim,
das
Zitatda FHEM out-of-the-box kein HTTP-Post unterstützt.
mit dem
ZitatAktives Pollen der Datenbank kommt nicht in Frage. FHEM sollte passiv auf Änderungen warten.
beißt sich. Bei letzterer Anforderung musst Du doch nur per DevIo (https://wiki.fhem.de/wiki/DevIo) eine Verbindung zu Deinem Server aufbauen. Der schickt dann die messages an FHEM. Per ReadFn (https://wiki.fhem.de/wiki/DevelopmentModuleIntro#X_Read) wird Dein FHEM-Modul informiert und kann die message verarbeiten.
Grüße Markus
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 25 Januar 2021, 21:05:40
Hallo zusammen,

also eins nach dem Anderen.


FHEM sollte hier die Rolle des Servers übernehmen. Kapacitor schickt dann aktiv die Werte sobald diese in der InfluxDB eintrudeln.

Viele Grüße

Tim
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 25 Januar 2021, 21:57:46
ZitatWenn FHEM aus HTTP POST Anfragen Readings machen kann wäre das super. Gibt es hier einen Link zur Dokumentation oder Beispielen? Ich kenne und nutze bisher nur GET auf .../fhem?cmd=...
Ob GET oder POST: FHEMWEB nimmt die Parameter vom URL _und_ <body>, und verarbeitet sie gleich.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: KölnSolar am 25 Januar 2021, 22:04:48
ZitatIch kenne und nutze bisher nur GET auf .../fhem?cmd=...
Das ist aber nur FHEMWEB u. nicht FHEM. FHEM besteht aus zig Servern und Clients, ein Servertyp z.B. das von Dir schon genannte MQTT. Das wäre dann der bessere Weg einen Server in FHEM zu realisieren als FHEMWEB(eigentlich nur Frontend von FHEM) vergewaltigen zu wollen.

Und irgendwie schmeißt Du die OSI-Schichten durcheinander
Zitat2.Kapacitor kann auch TCP Servern JSON zuschicken
http u. mqtt u..... setzen auf TCP auf.

Alles meine Meinung als Halbamateur. Die wahren Experten hier sehen das möglicherweise anders.(wie Rudi bereits bestätigt hat  ;))

Grüße Markus
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 26 Januar 2021, 08:29:08
Guten Morgen,

@Rudi
Dann schau ich mir FHEMWEB mal an.

@Marksu
Nene, ich schmeiß da nix durcheinander. Kapacitor kann auch ohne HTTP direkt auf Socket Ebene Daten verschicken.

ZitatDas wäre dann der bessere Weg einen Server in FHEM zu realisieren als FHEMWEB(eigentlich nur Frontend von FHEM) vergewaltigen zu wollen.
Gibt es hierzu Meinungen? Ich persönlich finde immer weniger Code ist besser als mehr Code. D.h. wenn FHEM, oder eines der out-of-the-box Module, das kann ist doch prima.

Viele Grüße

Tim
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 26 Januar 2021, 09:56:55
Ich habe jetzt mal testweise

curl -X POST -d "setreading kap x 3" http://..../fhem

gemacht. Der Befehl wird aber nicht ausgeführt. Hier der Log.
2021.01.26 08:53:48 4: Connection accepted from WEB_192.168.178.65_49832
2021.01.26 08:53:48 5: POST /fhem HTTP/1.1
Host: 192.168.178.25:8083
User-Agent: curl/7.68.0
Accept: */*
Content-Length: 19
Content-Type: application/x-www-form-urlencoded
2021.01.26 08:53:48 4: WEB_192.168.178.65_49832 POST /fhem&setreading kap x 2;; BUFLEN:0
2021.01.26 08:53:48 4: WEB: /fhem&setreading kap x 2; / RL:3551 / text/html; charset=UTF-8 /  / Cache-Control: no-cache, no-store, must-revalidate


Laut code hatte ich gehofft hier zu landen, was ja am Ende ein AnalyzeCommand bzw. AnalyzeCommandChain auslösen wird.
https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/01_FHEMWEB.pm#L425 (https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/01_FHEMWEB.pm#L425)

Übersehe ich hier etwas?

Viele Grüße

Tim
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 26 Januar 2021, 10:14:24
Etliches:
- Syntax bleibt bei GET und POST gleich, Befehle muessen mit cmd= oder cmd.XXX= spezifiziert werden.
- sinnvollerweise spezifiziert man XHR=1, damit keine Webseite zurueckgeliefert wird
- mit der Voreinstellung braucht man (zusaetzlich zum evtl. konfigurierten Passwort) das richtige(!) fwcsrf Cookie

Folgendes funktioniert bei mir:
curl -X POST -d "cmd=setreading d TEST TEST&XHR=1&fwcsrf=csrf_933865317019376" http://localhost:8083/fhem
Titel: Antw:Readings nach FHEM schicken
Beitrag von: Otto123 am 26 Januar 2021, 10:26:48
Ergänzung: Wie man mit dem csrf Token umgehen kann findest Du dir: https://wiki.fhem.de/wiki/CsrfToken-HowTo
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 26 Januar 2021, 10:49:15
Komisch, wenn man es richtig macht geht es sofort.  ;)

Besten Dank.

So stehen die Türen für ein neues tolles Modul offen.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: CoolTux am 26 Januar 2021, 10:52:50
Wenn Du eh ein Modul für FHEM machst wieso dann der Umweg über HTTP, wieso nicht über einen eigenen TCP Socket der vom Modul verwaltet wird?
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 26 Januar 2021, 10:56:06
Genau das war ja meine Frage. Ich fände das mit einem TCPServer eleganter. sonst muss das Modul ordentlicher Weise ja ein eigenes FHEMWEB anlegen.

Gibt es dafür ein überschaubares Beispiel?
Titel: Antw:Readings nach FHEM schicken
Beitrag von: betateilchen am 26 Januar 2021, 10:58:07
ich mache schonmal Popcorn...  8)
Titel: Antw:Readings nach FHEM schicken
Beitrag von: CoolTux am 26 Januar 2021, 11:03:37
Zitat von: timmib am 26 Januar 2021, 10:56:06
Genau das war ja meine Frage. Ich fände das mit einem TCPServer eleganter. sonst muss das Modul ordentlicher Weise ja ein eigenes FHEMWEB anlegen.

Gibt es dafür ein überschaubares Beispiel?

Überschaubar ist relativ. Von meinen Modulen wüsste ich nur AMAD. Das AMADCommBridge Modul macht genau das was Du suchst.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 26 Januar 2021, 11:23:54
Danke, schau ich mir an.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 26 Januar 2021, 12:07:04
Zitat von: timmib am 26 Januar 2021, 10:56:06
Genau das war ja meine Frage. Ich fände das mit einem TCPServer eleganter. sonst muss das Modul ordentlicher Weise ja ein eigenes FHEMWEB anlegen.

Gibt es dafür ein überschaubares Beispiel?

Richtig,

FHEMWEB ist das Beispiel.

Genau so habe ich es auch gemacht:

Im define:
- TcpServer_Open

Im Read:
- TcpServer_Accept, neue Verbindungen akzeptieren
- Daten empfangen, Header trennen, Body (ggf. nach und nach)
- Header-Felder extrahieren
- Request / Response unterscheiden, 1st Line teilen
- URI parsen:


    $URI =~ /^([a-z][a-z0-9+.-]*):(?:\/\/((?:(?=((?:[a-z0-9-._~!${\}&'()*+,;=:]|%[0-9A-F]{2})*))(\3)@)?(?=(\[[0-9A-F:.]{2,}\]|(?:[a-z0-9-._~!${\}&'()*+,;=]|%[0-9A-F]{2})*))\5(?::(?=(\d*))\6)?)(\/(?=((?:[a-z0-9-._~!${\}&'()*+,;=:@\/]|%[0-9A-F]{2})*))\8)?|(\/?(?!\/)(?=((?:[a-z0-9-._~!${\}&'()*+,;=:@\/]|%[0-9A-F]{2})*))\10)?)(?:\?(?=((?:[a-z0-9-._~!${\}&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\11)?(?:#(?=((?:[a-z0-9-._~!${\}&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\12)?$/i;



MfG
Titel: Antw:Readings nach FHEM schicken
Beitrag von: CoolTux am 26 Januar 2021, 12:14:29
Hier mal etwas Code von meinem alten Lehrmeister zum Thema Headerdaten extrahieren.
Danke Andre

##### bleibt zu Anschauungszwecken erhalten
#sub Header2Hash($) {
#
#    my $string  = shift;
#    my %hash    = ();
#
#    foreach my $line (split("\r\n", $string)) {
#        my ($key,$value) = split( ": ", $line );
#        next if( !$value );
#
#        $value =~ s/^ //;
#        $hash{$key} = $value;
#    }
#
#    return \%hash;
#}
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 26 Januar 2021, 12:19:33
Merci, aber Header gibt es hierbei nicht. Der schickt dann einfach JSON.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 26 Januar 2021, 21:16:28
So, Prototyp läuft.

Kann sein, das ich mich nochmal melde wegen Close usw.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 27 Januar 2021, 00:04:04
Beta ist fertig und kann auf die Menschheit losgelassen werden.

https://forum.fhem.de/index.php?topic=118208.0 (https://forum.fhem.de/index.php?topic=118208.0)
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 29 Januar 2021, 16:45:20
Hi,

hat jemand einen Tipp ob und wie man diese Kollegen hier wegbekommt.

kapacitor_192.168.178.65_60492_MSGCNT
1
kapacitor_192.168.178.65_60492_TIME
2021-01-29 16:34:55
kapacitor_192.168.178.65_60500_MSGCNT
1
kapacitor_192.168.178.65_60500_TIME
2021-01-29 16:35:55
kapacitor_192.168.178.65_60572_MSGCNT
1
kapacitor_192.168.178.65_60572_TIME
2021-01-29 16:36:55
kapacitor_192.168.178.65_60648_MSGCNT
1
kapacitor_192.168.178.65_60648_TIME
2021-01-29 16:37:55
kapacitor_192.168.178.65_60658_MSGCNT
1
kapacitor_192.168.178.65_60658_TIME
2021-01-29 16:38:55
kapacitor_192.168.178.65_60662_MSGCNT
1
kapacitor_192.168.178.65_60662_TIME
2021-01-29 16:39:55
kapacitor_192.168.178.65_60668_MSGCNT
1
kapacitor_192.168.178.65_60668_TIME
2021-01-29 16:40:55
kapacitor_192.168.178.65_60678_MSGCNT
1
kapacitor_192.168.178.65_60678_TIME
2021-01-29 16:41:55


Kann es sein, dass beim Read was fehlt?

sub Kapacitor_Read($) {

    my $hash = shift;
    my $name = $hash->{NAME};

    if ( $hash->{SERVERSOCKET} ) {    # Accept and create a child
        TcpServer_Accept( $hash, 'Kapacitor' );
        return;
    }

    my $buf;
    my $ret = sysread( $hash->{CD}, $buf, 2048 );

    # When there is an error in connection return
    if ( !defined($ret) or $ret <= 0 ) {
        # Log3( $name, 3, "Kapacitor ($name) - Connection closed for $name" );
        return;
    }

    my $found = Dispatch($hash, $buf);
}


Vielen Dank

Tim
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 29 Januar 2021, 17:44:14
Es gibt auch eine TcpServer_Close Funktion, diese sollte man ab und zu auch aufrufen.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 29 Januar 2021, 17:49:35
Zitat von: timmib am 29 Januar 2021, 16:45:20
Hi,

hat jemand einen Tipp ob und wie man diese Kollegen hier wegbekommt.


Fhem.pl verändern.  Ich habe die Stelle auch entfernt. Ist wohl ein Überbleibsel aus alten Zeiten ...
Titel: Antw:Readings nach FHEM schicken
Beitrag von: CoolTux am 29 Januar 2021, 18:14:35
Zitat von: M.Schulze am 29 Januar 2021, 17:49:35
Fhem.pl verändern.  Ich habe die Stelle auch entfernt. Ist wohl ein Überbleibsel aus alten Zeiten ...

Das ist für ein Community Modul eine sehr sehr schlechte Lösung. Es sei denn Du lieferst einen Patch mit entsprechender Erklärung.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 29 Januar 2021, 18:29:39
Zitat von: CoolTux am 29 Januar 2021, 18:14:35
Das ist für ein Community Modul eine sehr sehr schlechte Lösung. Es sei denn Du lieferst einen Patch mit entsprechender Erklärung.

Ich denke es geht um diese beiden Zeilen in Fhem.pl.

$defs{$found}{"${name}_MSGCNT"}++;
$defs{$found}{"${name}_TIME"} = TimeNow();


${name}_  ist variabel da die port nummer mit drin ist. Die ändert sich aber kontinuierlich, nach jedem accept mit jeder neuen Verbindung wird dispatch aufgerufen.

Folge: Die definition wird zugemüllt. Funktioniert aber.

Wer braucht diese Zeilen?

Siehe Anhang


Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 29 Januar 2021, 18:44:36
Ich dachte man macht ein Close nur wenn man keine Verbindungen mehr zulassen will. also das Socket komplett schliesst. In meinem Fall kommen ja immer wieder neue Clients.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 29 Januar 2021, 18:54:31
ZitatWer braucht diese Zeilen?
Alle, die nachvollziehen wollen, welche IODevs welchen Beitrag beim Empfang leisten. Beispiel: 3 CULs verteilt auf unterschiedliche Stockwerke. Als IODev sollte man beim Dispatch nicht die aktuelle Verbindungsinstanz angeben, sondern die "definierte", wo auch die Attribute gesetzt werden.

ZitatIch dachte man macht ein Close nur wenn man keine Verbindungen mehr zulassen will.
TcpServer_Close muss man fuer jede einzelne Verbindung, die man mit Accept bekommt, aufrufen, wenn sysread undef liefert.
Sonst bleiben die Verbindungsinstanzen uebrig, und erzeugen eine Endlosschleife, da select immer wieder deren Ende meldet.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 29 Januar 2021, 19:52:14
Zitat von: rudolfkoenig am 29 Januar 2021, 18:54:31
Als IODev sollte man beim Dispatch nicht die aktuelle Verbindungsinstanz angeben, sondern die "definierte", wo auch die Attribute gesetzt werden.

Die untergeordnete logische Definition braucht zwingend  die aktuelle/passende Verbindungsinstanz zum Gerät. Aus mehreren Gründen.
Wird das erreicht wenn Dispatch statt mit der aktuelle Verbindungsinstanz mit der "ursprünglich definierten = Instanz die den Server aufbaut hat" aufgerufen wird?


Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 29 Januar 2021, 20:13:15
ZitatWird das erreicht wenn Dispatch statt mit der aktuelle Verbindungsinstanz mit der "ursprünglich definierten = Instanz die den Server aufbaut hat" aufgerufen wird?
Weiss nicht, was mit "Wird das erreicht" gemeint ist, vmtl. nicht.

Wenn die logische Definition zwingend die aktuelle Verbindung braucht, dann wuerde ich zunaechst lange darueber nachdenken, ob die Trennung der Schichten an richtiger Stelle erfolgt ist.

Wenn das nicht anders zu loesen ist, dann wuerde ich den Namen des Verbindungskanals zu den Nutzdaten bei Dispatch dazupacken, und fuer die andere Richtung bei IOWrite ebenfalls, dann kann die andere Seite das richtig zuordnen.

Ausser Dispatch/ParseFn bzw. IOWrite/WriteFn sollte zwischen den beiden Schichten keine Verbindung geben (insb. keine direkten Funktionsaufrufe), um mehrere IO-Module fuer ein logisches Modul zu erlauben. Wenn man das ignoriert, dann muessen nachfolgende IO-Module das Rad neu erfinden, und neue Benutzer weiter verwirren, siehe MQTT2_DEVICE vs. MQTT_DEVICE.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 29 Januar 2021, 20:41:34
Hi,

ich habe das jetzt brav eingebaut und sehe auch die Log einträge. Aber der zeigt die Verbindungen immernoch als offen an.

    my $ret = sysread( $hash->{CD}, $buf, 2048 );

    # When there is an error in connection return
    if ( !defined($ret) or $ret <= 0 ) {
        TcpServer_Close($hash);
        Log3 $name, 0, "Kapacitor: [$name] Connection closed";
        # Log3( $name, 3, "Kapacitor ($name) - Connection closed for $name" );
        return;
    }


kap_192.168.178.65_54936
Connected
kap_192.168.178.65_54938
Connected
kap_192.168.178.65_54940
Connected
kap_192.168.178.65_54948
Connected
kap_192.168.178.65_54952
Connected
kap_192.168.178.65_54954
Connected
kap_192.168.178.65_54956
Connected
kap_192.168.178.65_54960
Connected
kap_192.168.178.65_54966
Connected


Kapacitor: [kap_192.168.178.65_54960] Connection closed
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 29 Januar 2021, 20:45:25
Connection Management muss das Modul schon selbst machen, das Framework kann nicht beurteilen, wann irgendwelche Verbindungen "sinnlos" geworden sind.
FHEMWEB schliesst nach eine Minute Inaktivitaet alle Verbindiungen, die nicht fuer Statusupdates verwendet werden. Ueblicherweise oeffnet ein Browser 6 Kanaele, und davon ist nur einer fuer Statusupdates.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 29 Januar 2021, 21:12:38
Kapier ich nicht. Was soll ich denn noch mehr machen als Close?
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 29 Januar 2021, 21:32:21
Wennn "idle" Verbindungen notwendig sind, dann nichts.
Sonst nach eine Minute (oder 10, etc) Inaktivitaet sie schliessen.
Eine Verbindung "frisst" Ressourcen (FD, CPU, etc), ob das stoert oder nicht, muss der Modulschreiber beurteilen.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 29 Januar 2021, 22:40:37
Zitat von: timmib am 29 Januar 2021, 21:12:38
Kapier ich nicht. Was soll ich denn noch mehr machen als Close?

Also das TcpServer_Close($hash); gehört da denke ich nicht rein. Das gehört ins undefine.


Ich habe da noch ein CommandDelete drin. Vielleicht spielt das ja eine Rolle beim Schließen der Verbindung.



} elsif (!$ret) { # 0==EOF, undef=error

      CommandDelete(undef, $cname);

      Log3 $sname, 3, "Connection closed for $cname: ".
        (defined($ret) ? 'EOF' : $!);

      return;
    }



Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 29 Januar 2021, 23:53:51
Was macht denn CommandDelete?
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 30 Januar 2021, 00:48:19
Zitat von: timmib am 29 Januar 2021, 23:53:51
Was macht denn CommandDelete?

Löscht die angegebene Verbindungsinstanz. Schließt aber keine zu diesem Zeitpunkt noch offene Verbindung.

Wer schließt die Verbindungen? Client oder Server?

TcpServer_Close ist vielleicht doch nicht falsch. Jedenfalls dann nicht wenn der Server die Verbindung trennen soll. Wenn es wie bei mir ausschließlich der Client macht braucht man es nicht.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 30 Januar 2021, 11:40:22
Mein Ziel ist es, das der Server die Verbindung schließt. Evtl guck ich mir Mal den Go Code von Kapacitor an. Wäre Mal ganz spannend wie das Verbindungsmanagement machen.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 30 Januar 2021, 17:21:33
Also der schließt "direkt" nach dem Senden. Ist quasi im finally, in Go nutzt man wohl "defer" dafür.

func (h *tcpHandler) Handle(event alert.Event) {
buf := h.bp.Get()
defer h.bp.Put(buf)
ad := event.AlertData()

err := json.NewEncoder(buf).Encode(ad)
if err != nil {
h.diag.Error("failed to marshal alert data json", err)
return
}

conn, err := net.Dial("tcp", h.addr)
if err != nil {
h.diag.Error("tcp handler failed to connect", err, keyvalue.KV("address", h.addr))
return
}
defer conn.Close()

buf.WriteByte('\n')
conn.Write(buf.Bytes())
}


Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 31 Januar 2021, 09:00:17
Guten Tag,

also ich mach jetzt das Close und das Delete und trotzdem bleiben diese Internals für immer liegen.

kap_192.168.178.65_52476_MSGCNT
1
kap_192.168.178.65_52476_TIME
2021-01-31 07:57:37
kap_192.168.178.65_52488_MSGCNT
1
kap_192.168.178.65_52488_TIME
2021-01-31 07:58:01


Wie kann ich die am besten wegräumen? Es werden mehrfach in der Minute neue Verbindungen aufgebaut. Da ist das recht ungünsitg, oder?

Viele Grüße

Tim

Titel: Antw:Readings nach FHEM schicken
Beitrag von: CoolTux am 31 Januar 2021, 10:42:48
Hatte ich auch bei AMAD. Da hatte ich aber die Möglichkeit dem Client zu sagen das er die Verbindung schließen soll.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 31 Januar 2021, 11:22:19
ZitatWie kann ich die am besten wegräumen?
Siehe meine Antwort #35: https://forum.fhem.de/index.php/topic,118161.msg1127177.html#msg1127177
Kurz: fuer Dispatch die Instanz verwenden, was vom Benutzer definiert wurde.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 31 Januar 2021, 19:12:19
Hi Rudolf,

wie komme ich da dran? Muss ich die selber speichern wie beim Child?

Mein Setup ist jetzt wie folgt:
Modul Kapacitor führt den TCPServer und ist Parent.

Er kennt nur eine Art von Child, den KapacitorTask.
Dort werden die Werte für die jeweiligen Task entgegenommen. Entsprechend reagieren diese basierend auf der Task ID, die mitgeschickt wurde.
Im Parse wird dann zum Setzen der empfangen Readings auf den definierten Task gewechselt.
$modules{KapacitorTask}{defptr}{$id}

Hier landen dann auch die MSGCNT, die sich ansammeln.

Schreiben oder Antworten gibt es über den TCP Server nicht. Das Taskmanagement über die Kapacitor API mach ich vom Task aus über HTTP.

Viele Grüße

Tim





Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 01 Februar 2021, 09:18:02
Zitatwie komme ich da dran? Muss ich die selber speichern wie beim Child?
TcpServer_Accept speichert den Namen in der Verbindungs-Hash unter SNAME.
D.h. im ReadFn macht man Dispatch($defs{$hash->{SNAME}}, ...);
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 01 Februar 2021, 11:10:38
Hi,

das hilft leider nicht. Ich habe es ausprobiert.

Wie gesagt, diese Internals werden ja dem Child hinzugefügt. Also dem Gerät, was das Parse implementiert und dessen Readings ich setze.

Noch eine Idee?

Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 01 Februar 2021, 11:36:03
Vermutlich ist beim Lesen oder Verstehen meiner Beschreibung was schiefgegangen.

Ich versuchs anders:
- die XX_MSGCNT/XX_TIME Werte werden in Dispatch erhoeht, wobei XX der Name des im Dispatch spezifizierten IODevs ist.
- anhand deiner Listing ist es offensichtlich, dass dein Modul beim Dispatch Aufruf die VerbindungsInstanz spezifiziert (das, womit ReadFn aufgerufen wird), und nicht den vom Benutzer spezifizierte Instanz (aka $hash->{SNAME}).
- damit MSGCNT/TIME was Sinnvolles enthaelt (Anzahl der ueber diesen IODev empfangenen Requests), muss  Dispatch mit $defs{$hash->{SNAME} als IODev Argument aufgerufen werden.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 01 Februar 2021, 12:14:26
Das habe ich schon verstanden. Nur landen die MSGCNT/TIME bei mir nicht im Parent(aka. IODev, aka Kapacitor) sondern im Child(aka KapacitorTask).
Und das auch, wenn ich Dispatch so aurufen wie vorgeschlagen. Hier mein Read()


sub Kapacitor_Read($) {

    my $hash = shift;
    my $name = $hash->{NAME};

    if ( $hash->{SERVERSOCKET} ) {    # Accept and create a child
        TcpServer_Accept( $hash, 'Kapacitor' );
        return;
    }

    my $buf;
    my $ret = sysread( $hash->{CD}, $buf, 2048 );

    # When there is an error in connection return
    if ( !defined($ret) or $ret <= 0 ) {
        TcpServer_Close($hash);
        CommandDelete(undef, $name);
        Log3( $name, 3, "Kapacitor ($name) - Connection closed for $name" );
        return;
    }

    my $found = Dispatch($defs{$hash->{SNAME}}, $buf);
}
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 01 Februar 2021, 12:58:02
Dann sind das entweder alte Werte (d.h. die gehoeren geloescht), oder es gibt noch ein weiteres Dispatch Aufruf, ohne $hash->{SNAME}
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 01 Februar 2021, 13:58:12
Leider, weder noch.

Die Werte sind neu(siehe Anhang) und es gibt auch nur ein einziges Dispatch.

Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 01 Februar 2021, 22:48:02
Hi,

ich habe mir jetzt mal den Code vom Dispatch angeschaut und kapiert was Deine vorgeschlagene Änderung bringt.

Jetzt wird immerhin immer der selbe Werte hochgezählt und nicht mehr immer ein neuer angelegt, weil das Device und damit der Namesgeber vom Internal gleich ist.

Danke.

Viele Grüße

Tim
Titel: Antw:Readings nach FHEM schicken
Beitrag von: carlos am 02 Februar 2021, 01:36:05
Hallo,
Ich habe einen ähnlichen Fall und musste mir mit folgendem Code am Ende der read sub helfen:

    foreach my $d (keys %defs) {
      next if($defs{$d}{TYPE} ne "TraccarDevice");
      my $msgcnt = $defs{$d}{$IOname . "_MSGCNT"};
      my $time = $defs{$d}{$IOname . "_TIME"};
      if (defined($msgcnt)  && defined($time)) {
        Log3 $IOname, 3,"[$sub_name] ($IOname) - Internals: " . $IOname ."_MSGCNT = $msgcnt und " . $IOname . "_TIME = $time found in $d";
        delete($defs{$d}{$IOname . "_MSGCNT"});
        delete($defs{$d}{$IOname . "_TIME"});
        Log3 $IOname, 3,"[$sub_name] ($IOname) - Internals: " . $IOname ."_MSGCNT und " . $IOname . "_TIME deleted in $d";
      }
    }

    CommandDelete(undef, $IOname);


Gruß

Carlos
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 02 Februar 2021, 10:19:46
Ich staune und hoffe, dass der obige Code nicht als Vorlage verwendet wird.

Ich bin bereit Dispatch anzupassen, wenn jemand mir klarmacht, warum der vorgeschlagene Weg (Dispatch mit der von dem Benutzer definierten IODev Instanz aufzurufen), nicht praktikabel ist.

Titel: Antw:Readings nach FHEM schicken
Beitrag von: carlos am 02 Februar 2021, 10:29:46
ok, wenn das so nicht akzeptabel ist dann ändere ich das gerne.
In meinem Fall häufen sie die internals halt bei jeden connect des Clients an den Server im Device.
Keine Ahnung warum und wie das zu unterbinden ist.
Das
CommandDelete(undef, $IOname);
räumt ja auf aber die internal bleiben.Gruß
Carlos
Titel: Antw:Readings nach FHEM schicken
Beitrag von: timmib am 02 Februar 2021, 11:04:35
Ich finde den Counter ein nettes Feature. Man darf hier halt nicht ein temporäres Gerät verwenden sonst wird nicht gezählt sondern hinzugefügt.

Die temporären Geräte muss man halt löschen.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 02 Februar 2021, 11:19:47
ZitatKeine Ahnung warum und wie das zu unterbinden ist.
Womoeglich helfen dabei meine Hinweise im Antwort #35 und #51.
Titel: Antw:Readings nach FHEM schicken
Beitrag von: carlos am 02 Februar 2021, 12:46:48
Die hatte ich gelesen und auch verstanden.
Hat leider nicht funktioniert.
Jetzt habe ich das noch mal so umgesetzt und FHEM durch gestartet.
Was soll ich sagen, jetzt funktionierts.
Danke, wieder was gelernt.
Gruß

Carlos
Titel: Antw:Readings nach FHEM schicken
Beitrag von: M.Schulze am 02 Februar 2021, 12:53:34
Zitat von: rudolfkoenig am 02 Februar 2021, 10:19:46

Ich bin bereit Dispatch anzupassen, wenn jemand mir klarmacht, warum der vorgeschlagene Weg (Dispatch mit der von dem Benutzer definierten IODev Instanz aufzurufen), nicht praktikabel ist.

1. die 2. Stufe sollte den aktuellen Verbindungs-hash bekommen. (Es ist  bei der Server Programmierung so üblich das die Verbindung durchs Programm getragen wird)
2. die 2. Stufe kann mit der vom Benutzer definierten IODev Instanz gar nichts nützliches anfangen. Sie wäre auch einfach zu bekommen über $defs{$hash->{SNAME}}. Ginge das umgekehrt auch so einfach? Wie? Addvals? Oder gar suchen?

Bei mir ist es so

1. Stufe: Server + Protokoll Parser, speichert Parsing Ergebnis aktuell temporär im jeweiligen Verbindungs-Hash

dann Dispatch
    Dispatch($verbindungs-hash, $verbindungs-hash->{'txscheme'}, \%addvals); # Beispiel txscheme=s0, also ausschließlich s0 und nicht das umfangreiche Parsing Ergebnis des Protokolls das im Verbindungshash verbleibt. Ist halt aktuell so.


2. Stufe:
Zugriff auf Parsing-Ergebnis im Verbindungs-Hash, Schema spezifische Aktivitäten auf Basis der Nutzdaten, Vorbereitung Daten für Response ...


1. Stufe: Senden Response gemäß Protokoll über Verbindungs-Hash

MfG

Titel: Antw:Readings nach FHEM schicken
Beitrag von: rudolfkoenig am 02 Februar 2021, 13:16:12
Zitat2. die 2. Stufe kann mit der vom Benutzer definierten IODev Instanz gar nichts nützliches anfangen. Sie wäre auch einfach zu bekommen über $defs{$hash->{SNAME}}. Ginge das umgekehrt auch so einfach? Wie? Addvals? Oder gar suchen?
Offensichtlich wird der Inhalt meiner Beitraege konsequent ignoriert.

Wenn ein logisches Modul auf die Verbindungsinstanz (oder auf das benutzerdefinierte IODev) zugreift, dann ist es nicht mehr moeglich alternative IODevs  anzubieten. Etliche Hilfsmodule wie FHEM2FHEM oder STACKABLE verlassen sich auch darauf, dass die Kommunikation ausschliesslich ueber Dispatch und IOWrite laeuft.

Um die Antwort konkret zu formulieren: die zweite Stufe greift gar nicht auf das IODev zu.