Daten per Webhook POST-Request (Push) in FHEM empfangen?

Begonnen von roman1528, 26 Juli 2020, 18:52:32

Vorheriges Thema - Nächstes Thema

roman1528

Moin.

Kann man in FHEM Daten per Push empfangen?
Smart-me (Zähler mit WLAN) stellt eine Realtime API zur Verfügung. Diese kann Zählerdaten, sobald sie in der Cloud sind, per POST-Request weiterleiten.
https://www.smart-me.com/Description/api/realtimeapi.aspx

Kann man in FHEM dauerhaft "lauschen" und diese POST-Requests einlesen?

Wenn ja wie? Oder vielleicht auch per Script in Linux? Ohne umwege wäre es mir natürlich lieber...

Danke im Voraus.

Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

rudolfkoenig

ZitatKann man in FHEM Daten per Push empfangen?
Ja, FHEMWEB macht zwischen GET und POST keinen Unterschied.
Die Daten muessen nur im passenden Format kommen :)

roman1528

Zitat von: rudolfkoenig am 26 Juli 2020, 20:00:03Die Daten muessen nur im passenden Format kommen :)

Danke Rudolf.

Und genau da habe ich wahrscheinlich das Problem.

Ist POST nicht eigentlich als _data= im Request 'versteckt' und nicht der URL hinten angehängt? Ich denke da so an:
<form method="POST">
Wer möchte schon seine Login-Daten in der URL stehen haben?!

Zudem weiß ich nur, dass die Daten
Zitatas serialized protobuffer string in the POST request body
gesendet werden und nicht wie genau die aussehen...
Ich bräuchte also den Body des Requests und nicht allein die URL oder?

Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

rudolfkoenig

ZitatIst POST nicht eigentlich als _data= im Request 'versteckt' und nicht der URL hinten angehängt?
Wie mans nimmt. Bei POST sendet man exakt die gleichen Daten, wie bei GET, nur nicht im URL sondern im Body.
FHEMWEB kann mit _data nichts anfangen.
Die FHEMWEB (Basic-)Authentifizierung kommt  im HTTP-Header, ist nicht Teil des URLs.

Zitatserialized protobuffer string in the POST request body
Um sowas sinnvoll zu behandeln muesste man ein FHEM-Modul bauen, dass sich in FHEMWEB via $data{FWEXT} reinhaengt. Aus dieser Hinsicht ist FHEMWEB nicht besser oder schlechter, als ein beliebiger HTTP-Server.

roman1528

Zitat von: rudolfkoenig am 26 Juli 2020, 21:45:12
Wie mans nimmt. Bei POST sendet man exakt die gleichen Daten, wie bei GET, nur nicht im URL sondern im Body.

Ahh... so funktioniert das also.

Zitat von: rudolfkoenig am 26 Juli 2020, 21:45:12
FHEMWEB kann mit _data nichts anfangen.

Das hatte ich nur meinem Browser entnommen um es irgendwie beschreiben zu können...

Zitat von: rudolfkoenig am 26 Juli 2020, 21:45:12
Die FHEMWEB (Basic-)Authentifizierung kommt  im HTTP-Header, ist nicht Teil des URLs.

Authorization: Basic ist mir tatsächlich ein Begriff ;D

Zitat von: rudolfkoenig am 26 Juli 2020, 21:45:12
Um sowas sinnvoll zu behandeln muesste man ein FHEM-Modul bauen, dass sich in FHEMWEB via $data{FWEXT} reinhaengt.

Gibt es da Doku zu?

Danke!

Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

rudolfkoenig

ZitatGibt es da Doku zu?
Wenn ja, dann ist es mir unbekannt.
Es gibt aber ca 25 Module, die es verwenden.

Im Wesentlichen setzt man $data{FWEXT}{MySpecialURL}{FUNC} = "MyFunction", und MyFunction wird mit dem URL aufgerufen, falls das URL den Form http://host:port/fhem/MySpecialURL.* hat. Die Funktion liefert  mimetype und content zurueck, die (GET/POST) Parameter kann sie aus dem globalen %FW_webargs entnehmen.

roman1528

Zitat von: rudolfkoenig am 27 Juli 2020, 11:05:44Im Wesentlichen setzt man $data{FWEXT}{MySpecialURL}{FUNC} = "MyFunction", und MyFunction wird mit dem URL aufgerufen, falls das URL den Form http://host:port/fhem/MySpecialURL.* hat. Die Funktion liefert  mimetype und content zurueck, die (GET/POST) Parameter kann sie aus dem globalen %FW_webargs entnehmen.

Hab mich mal ein wenig durch's SVN und die Module gewühlt und copy-paste mir gerade ein eigenes Modul zusammen... Leider reichen meine Perl-Kenntnisse von "my $variable;" bis "print;".

Kannst du mir kurz helfen? brauche wahrscheinlich nur einen anstupser, perl oder fhem system betreffend.

$data{FWEXT} Registrierung sollte klappt dank Geofancy und AMAD. kann ich das kontrollieren?
aber in meiner read() funktion komme ich nicht weiter.
Ich möchte den request erstmal stumpf komplett als Reading anzeigen. Damit ich erstmal sehe was da überhaupt kommt.
sub smartme_read($) {

    my ($request) = @_;

if ($request) {
readingsBeginUpdate($hash);
readingsBulkUpdate( $hash, "POSTrequest", $request );
readingsEndUpdate( $hash, 1 );
}

}


reading[Begin|Bulk|End]Update klappt ja nicht ohne Devicenamen... Dementsprechender Error im Log... aber wo bekomm ich den nun her?
was übergibt Zeile 967 01_FHEMWEB.pm?
($FW_RETTYPE, $FW_RET) = &{$h->{FUNC}}($arg);

Hier kurz das ganze File:
#
#  00_smartme.pm
#

package main;
use strict;
use warnings;

#use HttpUtils;

# Declare functions
sub smartme_Initialize($);
sub smartme_Define($$);
sub smartme_Undefine($$);
sub smartme_read($);
sub smartme_addExtension($$$);
sub smartme_removeExtension($);

# FHEM Modulfunktionen

sub smartme_Initialize($) {

    my ($hash) = @_;

    #$hash->{SetFn}      = "smartme_Set";
    $hash->{DefFn}      = "smartme_Define";
    $hash->{UndefFn}    = "smartme_Undefine";
    #$hash->{AttrFn}     = "smartme_Attr";
   
    $hash->{AttrList}   = "disable:0,1 ".
                $readingFnAttributes.
"useSetExtensions:0,1 ";
}

sub smartme_Define($$) {
    my ( $hash, $def ) = @_;
    my @a = split( "[ \t][ \t]*", $def );

    return "Usage: define <name> smartme <Serial>"
      if ( int(@a) != 3 );
    my $name  = $a[0];
    my $meterSerial = $a[2];

    $hash->{NAME} = $name;
    $hash->{SERIAL} = $meterSerial;

    Log3 $name, 3, "Smart-Me Meter defined with name: $name and Serial: $meterSerial";

    smartme_addExtension( $name, "smartme_read", $meterSerial );

    readingsBeginUpdate($hash);
    readingsBulkUpdate( $hash, "state", "initialized" );
    readingsEndUpdate( $hash, 1 );
    return undef;
}

sub smartme_Undefine($$) {
    my ( $hash, $name ) = @_;
    smartme_removeExtension( $hash->{SERIAL} );
    return undef;
}

sub smartme_read($) {

    my ($request) = @_;

if ($request) {
readingsBeginUpdate($hash);
readingsBulkUpdate( $hash, "POSTrequest", $request );
readingsEndUpdate( $hash, 1 );
}

}

sub smartme_addExtension($$$) {
    my ( $name, $func, $link ) = @_;

    my $url = "/$link";
    Log3 $name, 3, "Registering Smart-Me Meter $name for URL $url";
    $data{FWEXT}{$url}{deviceName} = $name;
    $data{FWEXT}{$url}{FUNC}       = $func;
    $data{FWEXT}{$url}{LINK}       = $link;
}

sub smartme_removeExtension($) {
    my ($link) = @_;

    my $url  = "/$link";
    my $name = $data{FWEXT}{$url}{deviceName};
    Log3 $name, 3, "Unregistering Smart-Me Meter $name for URL $url";
    delete $data{FWEXT}{$url};
}

# Eval-Rückgabewert für erfolgreiches
# Laden des Moduls
1;


# Beginn der Commandref

=pod
=item [helper|device|command]
=item summary Kurzbeschreibung in Englisch was MYMODULE steuert/unterstützt
=item summary_DE Kurzbeschreibung in Deutsch was MYMODULE steuert/unterstützt

=begin html
Englische Commandref in HTML
=end html

=begin html_DE
Deutsche Commandref in HTML
=end html

# Ende der Commandref
=cut

ZitatBeim Zähler (00) bin ich mir noch nicht sicher...

Danke im Voraus.

Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

rudolfkoenig

ZitatLeider reichen meine Perl-Kenntnisse von "my $variable;" bis "print;".
Und ich bin nicht der geborene Lehrer.


ZitatKannst du mir kurz helfen? brauche wahrscheinlich nur einen anstupser, perl oder fhem system betreffend.
Da bin ich jetzt gespannt. Ersetze deine smartme_read Funktion durch
use vars qw(%FW_webArgs);
sub
smartme_read($)
{
  my ($url) = @_;
  Log 1, "smartme URL:$url";
  foreach my $p (sort keys %FW_webArgs) {
    Log 1, "smartme param $p => $FW_webArgs{$p}";
  }     
  return ("text/plain", "hallo");
}       

Definiere "define x smartme 17", und rufe im Browser http://localhost:8083/fhem/17&p1=1&p2=2 auf.
Im FHEM-Log sollte Folgendes stehen:
Zitat2020.08.02 13:55:05.078 1: smartme URL:/17&p1=1&p2=2
2020.08.02 13:55:05.078 1: smartme param /17 =>
2020.08.02 13:55:05.078 1: smartme param p1 => 1
2020.08.02 13:55:05.078 1: smartme param p2 => 2

roman1528

Dankeschön.

Das bekomm ich jetzt hin.
Kannst du mir noch verraten wie ich in dieser, oder in weiterführenden Funktionen wieder an den $hash komme? der wird ja offensichtlich nicht mit übergeben...

Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

rudolfkoenig

In einer Modul eigenen lokalen Variable (hash) die Relation zwischen URL (Seriennummer) und Hash abspeichern.
Dieses Hash kann im DefFn gefuellt, und im UndefFn geloescht werden.

roman1528

also so?:

DefFn
$hash->{fhem}{serial} = $serial;


sub smartme_read($) {

my ( $request ) = @_;
my @req;
my $serial;
my $protobuf;
my $hash;

@req = split( /&/, $request );

( $serial = $req[0] ) =~ s/^[\/]+//;

$hash = $defs{$serial};

$protobuf = $req[1];

smartme_readProtobuf( $hash, $protobuf );

return ("text/plain", "Got it!");
}



sub smartme_readProtobuf($$) {

my ( $hash, $protobuf ) = @_;

Log 1, $hash{name}; #Global symbol "%hash" requires explicit package name (did you forget to declare "my %hash"?) at /opt/fhem/FHEM/00_smartme.pm line 478.

return undef;
}


Oder hab ich da wieder irgendwo, irgendwas übersehen? weil es nicht funktioniert :-[

Sorry, dass ich dich und nicht google damit belästige...

Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

herrmannj

Moin

kannst Du bitte ein Beispiel einstellen (oder pm falls vertraulich) wie genau die Daten aussehen die reinkommen? Dafür kannst Du im ersten Schritt auch https://requestbin.com/ verwenden.

Danke, vg
Joerg

roman1528

#12
Moin.

Von Pipedream (requestbin):
{
  "method": "POST",
  "path": "/",
  "query": {},
  "headers": {
    "x-forwarded-for": "5.148.169.199",
    "x-forwarded-proto": "https",
    "x-forwarded-port": "443",
    "host": "11b53dae23fea40973c28e9730ade7a2.m.pipedream.net",
    "x-amzn-trace-id": "Root=1-5f27d349-ea98a63fcdbea2abdc0beab6",
    "content-length": "169",
    "accept": "application/octet-stream",
    "content-type": "application/octet-stream"
  },
  "bodyRaw64": "CqYBChIJx2fm2jPkPEQRj35xkJ1Z/QwSCwiy5474y+XbOBAFGhEKBgEAAQgA/xEAAAAAAFBvQBoRCgYBAAEIAf8RAAAAAAAQaUAaEQoGAQABCAL/EQAAAAAAAElAGhEKBgEAAggA/xEAAAAAACBZQBoRCgYBAAIIAf8RAAAAAAAgVEAaEQoGAQACCAL/EQAAAAAAADRAGhEKBgEAAQcA/xE9CtejcD0OQA=="
}


Ausgabe im FHEM-Log ( $request ) unformatiert:
/5100880&
�
 ����2O�H��>�6�� �������8
�Po@
�i@
�I@
� Y@
� T@
�4@
�=
ףp=@


Das ist von der RealTimeAPI-Test-Seite von Smart-Me.com. https://www.smart-me.com/Description/api/realtimeapi.aspx

Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

roman1528

Mit:
sub smartme_read($) {

my ( $request ) = @_;
my @req;
my $serial;
my $name;
my $protobuf;

@req = split( /&/, $request );

( $serial = $req[0] ) =~ s/^[\/]+//;

# get device name
$name = $data{FWEXT}{"/".$serial}{deviceName} if ( $data{FWEXT}{"/".$serial} );

$protobuf = $req[1];

Log3 $name, 1, "Serial: " . $serial;
Log3 $name, 1, "Name: " . $name;
Log3 $name, 1, "Protobuf: " . $protobuf;

return ("text/plain", "Got it!");
}


Siehts im Log tatsächlich so aus:
2020.08.03 11:25:06 1:  Serial: 5100880
2020.08.03 11:25:06 1:  Name: smartme
2020.08.03 11:25:06 1:  Protobuf:
�
 ���q��A�W�8�.�� ��Ҥ��8
�Po@
�i@
�I@
� Y@
� T@
�4@
�=
ףp=@


Grüße^^
i3-10305T 4x3GHz;8GB RAM;250GB & 1TB NVMe:
FHEM 6.2;FTUI;8" Tablet's+Fully;NsPanelPro;HUE;ESPRGBWW;HM(CCU3);Duofern; ASC;MQTT(Tasmota);netatmo;SONOS;eBus;DbLog;XiaomiDevice;NUT;ModbusAttr

RPi3+: FHEM 6.2;I²C;GPIO;RFID;G-Tag;XiaomiBTLESens
RPi3: FHEM 6.2;DIY Relais-Board;I²C;GPIO;RFID;Photovoltaik

herrmannj

das wird aufwendiger. Mit der serial kann ich Dir helfen - aber die Daten die da reinkommen müsstest Du halt auch decodieren. Mit dem Kauderwelsch im body wirst Du so nicht viel anfangen können. Ist scheinbar OBIS. Nicht unlösbar, aber auch nicht trivial.

vg
joerg