Tasker: send/get Beispiel mit csrf Token

Begonnen von Schlimbo, 20 Juli 2017, 09:15:19

Vorheriges Thema - Nächstes Thema

Schlimbo

Hallo zusammen,
ich nutze auf meinen Android Geräten für viele Automatisierungsaufgaben die APP "Tasker".
Da des Öfteren hier im Forum die Frage auftaucht, wie über Tasker Befehle an FHEM gesendet werden können oder über Tasker FHEM- Readings/Attributes/Internals ausgelesen werden können, möchte ich hier mal meine Lösung vorstellen:

Um die send/get Logik an zentraler Stelle zu Pflegen habe ich mir zwei "Treiber" Tasks erstellt ("FHEM send" und "FHEM get") diese Tasks können dann von allen anderen Tasks verwendet werden und man muss sich über die Kommunikation keine Gedanke mehr machen.

Task: FHEM send (Befehle von Tasker an FHEM senden)
Beschreibung:
Gesendet wird über HTTP Post, bevor dies jedoch funktioniert, muss der csrf Token bekannt sein.
Da sich der Token nur selten ändert (FHEM Neustart), führe ich die Abfrage nicht bei jedem Send durch.
Befehle werden immer erst einmal mit dem letzten bekannten Token versucht zu senden, schlägt das fehl wird der Token aktualisiert und der Befehle erneut gesendet.

Task export Description: FHEM send
FHEM send (1395)
Abort Existing Task
<Parse CSRF Token>
A1: Perform Task [ Name:csrfToken Priority:%priority+1 Parameter 1 (%par1): Parameter 2 (%par2): Return Value Variable:%return Stop:Off ] If [ %FHEMcsrfToken ~R FHEMcsrfToken ]
<Übergabe Parameter 1: CMD>
A2: Variable Set [ Name:%cmd To:%par1 Recurse Variables:Off Do Maths:Off Append:Off ]
A3: Variable Convert [ Name:%cmd Function:URL Encode Store Result In:%cmd ]
<FHEM Daten Senden>
A4: HTTP Post [ Server:Port:%FHEM_SERVER_IP:%FHEM_SERVER_PORT/fhem?cmd=%cmd&XHR=1&fwcsrf=%FHEMcsrfToken Path: Data / File: Cookies: User Agent: Timeout:5 Content Type: Output File: Trust Any Certificate:On Continue Task After Error:On ]
A5: Flash [ Text:FHEM Server: %FHEM_SERVER_IP
Fehler beim Senden
%HTTPR Long:Off ] If [ %HTTPR !~ 200 ]
<falscher CSRF Token>
A6: If [ %HTTPR ~ 400 ]
<Parse CSRF Token>
A7: Perform Task [ Name:csrfToken Priority:%priority+1 Parameter 1 (%par1):%header() Parameter 2 (%par2): Return Value Variable:%return Stop:Off ]
<maximal 1 weiterer Sendeversuch>
A8: Variable Set [ Name:%goto To:%goto+1 Recurse Variables:Off Do Maths:On Append:Off ]
<Daten erneut Senden>
A9: Goto [ Type:Action Label Number:1 Label:FHEM Daten Senden ] If [ %goto < 2 ]
A10: End If


Verwendung:
Verwendet wird der "FHEM send" Task über "Perform Task" und als Übergabeparameter (%par1) wird der Befehle übergeben.
z.B.:
set rgr_Bewohner state home

FHEM Server IP und Port sind in Variablen gespeichert und müssen vor dem ersten Benutzen Initialisiert werden.

Beispiel Aufruf:
FHEM send Beispiel (1511)
A1: Variable Set [ Name:%FHEM_SERVER_IP To:192.168.1.2 Recurse Variables:Off Do Maths:Off Append:Off ]
A2: Variable Set [ Name:%FHEM_SERVER_PORT To:8083 Recurse Variables:Off Do Maths:Off Append:Off ] If [ %FHEM_SERVER_PORT !Set ]
A3: Perform Task [ Name:FHEM send Priority:%priority+1 Parameter 1 (%par1):set rgr_Bewohner state home Parameter 2 (%par2): Return Value Variable: Stop:Off ]


Task: FHEM get (Readings/Readings-Timestamp/Attributes/Internals mit Tasker auslesen)
Beschreibung:
Der Abruf erfolgt mittels "HTTP Get", auch hier wird der csrf Token nur bei bedarf aktualisiert.

Beim Aufruf von "FHEM get" wird erst geprüft, ob die gewünschten Daten schon von einem hervorgegangen "HTTP Get" in der Variable %HTTPD vorhanden sind, sind die Daten schon vorhanden wird kein neuer "HTTP Get" Aufruf durchgeführt sondern die vorhandenen Daten nur geparst, dies spart Zeit wenn mehrerer Readings vom gleichen Gerät angefragt werden wollen.
Soll sichergestellt werden, dass beim Aufruf von "FHEM get" immer aktuelle Daten vom Server geholt werden, kann dies durch das löschen der Variable %HTTPalt vor dem jeweiligen "FHEM get" Aufruf erzwungenen werden.

Task export Description: FHEM get
FHEM get (1248)
Abort Existing Task
<Übergabe Parameter 1: Device Name>
A1: Variable Set [ Name:%device To:%par1 Recurse Variables:Off Do Maths:Off Append:Off ]
<Internal>
A2: If [ %par2 ~R INT: ]
<Übergabe Parameter 2: Internal>
A3: Variable Search Replace [ Variable:%par2 Search:INT: Ignore Case:Off Multi-Line:Off One Match Only:On Store Matches In:%par2 Replace Matches:On Replace With: ]
A4: Variable Set [ Name:%search_str To:<INT key="%par2" value=" Recurse Variables:Off Do Maths:Off Append:Off ]
<Attribut>
A5: Else If [ %par2 ~R ATTR: ]
<Übergabe Parameter 2: Attribut>
A6: Variable Search Replace [ Variable:%par2 Search:ATTR: Ignore Case:Off Multi-Line:Off One Match Only:On Store Matches In:%par2 Replace Matches:On Replace With: ]
A7: Variable Set [ Name:%search_str To:<ATTR key="%par2" value=" Recurse Variables:Off Do Maths:Off Append:Off ]
<Reading Timestamp>
A8: Else If [ %par2 ~R timestamp: ]
<Übergabe Parameter 2: Reading timestamp>
A9: Variable Search Replace [ Variable:%par2 Search:timestamp: Ignore Case:Off Multi-Line:Off One Match Only:On Store Matches In:%par2 Replace Matches:On Replace With: ]
A10: Variable Set [ Name:%search_str To:<STATE key="%par2" value=" Recurse Variables:Off Do Maths:Off Append:Off ]
A11: Variable Set [ Name:%timestamp To:true Recurse Variables:Off Do Maths:Off Append:Off ]
<Reading>
A12: Else
A13: Variable Set [ Name:%search_str To:<STATE key="%par2" value=" Recurse Variables:Off Do Maths:Off Append:Off ]
A14: End If
<Parse CSRF Token>
A15: Perform Task [ Name:csrfToken Priority:%priority+1 Parameter 1 (%par1): Parameter 2 (%par2): Return Value Variable:%return Stop:Off ] If [ %FHEMcsrfToken ~R FHEMcsrfToken ]
A16: If [ %HTTPD !~R %device | %HTTPD !~R %search_str | %device !~ %HTTPalt ]
<FHEM Daten Abrufen>
A17: HTTP Get [ Server:Port:%FHEM_SERVER_IP:%FHEM_SERVER_PORT/fhem?XHR=1&cmd=xmllist%20%device&fwcsrf=%FHEMcsrfToken Path: Attributes: Cookies: User Agent: Timeout:10 Mime Type: Output File: Trust Any Certificate:On ]
A18: [X] Set Clipboard [ Text:%FHEM_SERVER_IP:%FHEM_SERVER_PORT/fhem?XHR=1&cmd=xmllist%20%device&fwcsrf=%FHEMcsrfToken Add:Off ]
A19: [X] Set Clipboard [ Text:%HTTPD Add:Off ]
A20: Flash [ Text:Get new Data Long:Off ]
A21: End If
A22: If [ %HTTPD ~R %device & %HTTPD ~R %search_str ]
A23: Variable Set [ Name:%httpd To:%HTTPD Recurse Variables:Off Do Maths:Off Append:Off ]
A24: Perform Task [ Name:XML decode Priority:%priority Parameter 1 (%par1):%httpd Parameter 2 (%par2): Return Value Variable:%httpd Stop:Off ]
A25: Variable Split [ Name:%httpd Splitter:%search_str Delete Base:Off ]
<Internal/Attribut>
A26: If [ %search_str ~R <INT | %search_str ~R <ATTR ]
A27: Variable Split [ Name:%httpd2 Splitter:"/> Delete Base:Off ]
<Value>
A28: Variable Set [ Name:%value To:%httpd21 Recurse Variables:Off Do Maths:Off Append:Off ]
<Reading timestamp>
A29: Else If [ %timestamp Set ]
A30: Variable Split [ Name:%httpd2 Splitter:" measured=" Delete Base:Off ]
A31: Variable Split [ Name:%httpd22 Splitter:"/> Delete Base:Off ]
<Value>
A32: Variable Set [ Name:%value To:%httpd221 Recurse Variables:Off Do Maths:Off Append:Off ]
<Reading>
A33: Else
A34: Variable Split [ Name:%httpd2 Splitter:" measured=" Delete Base:Off ]
<Value>
A35: Variable Set [ Name:%value To:%httpd21 Recurse Variables:Off Do Maths:Off Append:Off ]
A36: End If
A37: Variable Set [ Name:%HTTPalt To:%device Recurse Variables:Off Do Maths:Off Append:Off ]
A38: Return [ Value:%value Stop:On ]
A39: Else
A40: Flash [ Text:FHEM Server: %FHEM_SERVER_IP
Fehler beim Abrufen von: %device:%par2
%search_str Long:Off ]
<falscher CSRF Token>
A41: If [ %HTTPR ~ 400 ]
A42: Perform Task [ Name:csrfToken Priority:%priority+1 Parameter 1 (%par1): Parameter 2 (%par2): Return Value Variable: Stop:Off ]
<maximal 1 weiter Versuch, die Daten erneut abzurufen>
A43: Variable Set [ Name:%goto To:%goto+1 Recurse Variables:Off Do Maths:On Append:Off ]
<Daten erneut Abrufen>
A44: Goto [ Type:Action Label Number:1 Label:FHEM Daten Abrufen ] If [ %goto < 2 ]
A45: End If
A46: End If


Verwendung:
Dar Aufruf erfolgte wieder über "Perform Task" als Übergabeparameter 1 (%par1) wird der FHEM Device Name übergeben, Übergabeparameter 2 (%par2) wird das Readings, Attributes oder Internals übergeben.

Syntax Übergabeparameter 2:
Reading auslesen: Übergabeparameter 2 (%par2) = <Reading>
Reading Timestamp auslesen: Übergabeparameter 2 (%par2) = timestamp:<Reading>
Attribut auslesen: Übergabeparameter 2 (%par2) = ATTR:<Attribut>
Internal auslesen: Übergabeparameter 2 (%par2) = INT:<interna l>

Als Rückgabewert wird nur der gewünschte Wert geliefert.

Beispiel:
FHEM get Beispiel (1510)
A1: Variable Set [ Name:%FHEM_SERVER_IP To:192.168.1.2 Recurse Variables:Off Do Maths:Off Append:Off ]
<Server mit https & basicAuth>
A2: [X] Variable Set [ Name:%FHEM_SERVER_IP To:https://fhem:123@192.168.1.2 Recurse Variables:Off Do Maths:Off Append:Off ]
A3: Variable Set [ Name:%FHEM_SERVER_PORT To:8083 Recurse Variables:Off Do Maths:Off Append:Off ]
A4: Variable Clear [ Name:%HTTPalt Pattern Matching:Off ]
A5: Perform Task [ Name:FHEM get Priority:%priority+1 Parameter 1 (%par1):rgr_Bewohner Parameter 2 (%par2):lastState Return Value Variable:%value Stop:Off ]
A6: Flash [ Text:%value Long:Off ]


Helper Tasks:
Die csrf Token Aktualisierung und XML-encode wurden in eigene Tasks ausgelagert.

csrfToken
csrfToken (1279)
A1: Variable Set [ Name:%header To:%par1 Recurse Variables:Off Do Maths:Off Append:Off ] If [ %par1 Set ]
A2: HTTP Get [ Server:Port:%FHEM_SERVER_IP:%FHEM_SERVER_PORT/fhem&XHR=1 Path: Attributes: Cookies: User Agent: Timeout:10 Mime Type: Output File: Trust Any Certificate:On ] If [ %par1 !Set ]
A3: Variable Set [ Name:%header To:%header() Recurse Variables:Off Do Maths:Off Append:Off ] If [ %par1 !Set ]
A4: Variable Split [ Name:%header Splitter:X-FHEM-csrfToken: Delete Base:Off ]
A5: Variable Set [ Name:%token To:%header2 Recurse Variables:Off Do Maths:Off Append:Off ]
<Leerzeichen entfernen>
A6: Variable Search Replace [ Variable:%token Search:  Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With: ]
<Debug>
A7: [X] Popup [ Title: Text:CSRF Token:"%token"

HTTP Header:
%header

HTTP Response Code:%HTTPR

HTTP DATEN:
%HTTPD Background Image: Layout:Popup Timeout (Seconds):20 Show Over Keyguard:On ]
<Token Aktualisieren>
A8: If [ %token !~ %FHEMcsrfToken ]
A9: Variable Set [ Name:%FHEMcsrfToken To:%token Recurse Variables:Off Do Maths:Off Append:Off ]
A10: Flash [ Text:neuer csrfToken empfangen:
%token Long:Off ]
A11: End If


XML decode
XML decode (1484)
<&>
A1: Variable Search Replace [ Variable:%par1 Search:&amp; Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With:& ]
<'>
A2: Variable Search Replace [ Variable:%par1 Search:&apos; Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With:' ]
<<>
A3: Variable Search Replace [ Variable:%par1 Search:&lt; Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With:< ]
<>>
A4: Variable Search Replace [ Variable:%par1 Search:&gt; Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With:> ]
<">
A5: Variable Search Replace [ Variable:%par1 Search:&quot; Ignore Case:Off Multi-Line:Off One Match Only:Off Store Matches In: Replace Matches:On Replace With:" ]
A6: Return [ Value:%par1 Stop:On ]


Wer es nutzen möchte kann die FHEM.prj.xml herunterladen und in Tasker als Projekt importieren.

Gruß
Schlimbo

Update (20.07.2017)

  • Anpassungen für HTTPS und basicAuth

rabehd

#1
werde ich mir mal anschauen.

Aber: https://forum.fhem.de/index.php/topic,72717.msg643211.html#msg643211 Thema: Verbindung von einer nicht-lokalen Adresse ab sofort nur mit Passwort

Ich habe bei mir auch https eingeschaltet und brauche User-Passwort.
Seitdem klappte es bei mir mit Tasker nicht mehr.
Auch funktionierende Lösungen kann man hinterfragen.

Schlimbo

nutze es bei mir nur Lokal oder über VPN. ;)

Schlimbo

Hallo rabehd,
habe es gerade mit https und basicAuth getestet: Es funktioniert 8)
Es muss nur bei allen "HTTP get" und "HTTP post" Befehlen die Checkbox "Trust Any Certificate" aktiviert werden und die Variable %FHEM_SERVER_IP auf "https://<user>:<passwort>@<server IP>" gesetzt werden.

rabehd

Wunderbar, dann kann ich meine Anwesenheitsschaltung per Tasker wieder aktivieren.
Danke für Deine Mühe.  :) Ich war daran gescheitert und auf PRESENCE mit PING und BLUETOOTH umgestiegen.

Ich baue es in den nächsten Tagen ein.
Auch funktionierende Lösungen kann man hinterfragen.

MBHG

Grandios, danke. Endlich kann ich per nfc am Handy schalten. Ohne viel Aufwand!
-----------------------------------------------------------
https://smarthome.family.blog Debian Linux, NanoCUL 868, Signalduino, 4x HM-SW4, 11x HM Asksin Unisensor, NodeMCU ESP8266, RCS 1000 N Comfort, Magic Home, Rauchmelder PT2262, Babble