HTTP-Aufruf aus einer Internetanwendung empfangen und verarbeiten

$raw = file_get_contents("php://input");

Michael

I finally managed to create a variable using the „WebHook RAW“ data. Not really sure why I was struggeling so much.

Ich stehe auch vor dem Problem, wie ich die Daten von einem WebHook verarbeite.
Wie kann ich diese Daten weiterverwenden?
Ich habe besagtes Testscript dem WebHook hinterlegt und es wird folgendes ausgegeben:

Testscript:

IPS_LogMessage("WebHook GET", print_r($_GET, true));
IPS_LogMessage("WebHook POST", print_r($_POST, true));
IPS_LogMessage("WebHook IPS", print_r($_IPS, true));
IPS_LogMessage("WebHook RAW", file_get_contents("php://input"));
echo "Message: " . $_GET['Message'];

Ausgabe:

02.01.2023, 19:20:32 | WebHook GET          | Array
(
)

02.01.2023, 19:20:32 | WebHook POST         | Array
(
)
02.01.2023, 19:20:32 | WebHook IPS          | Array
(
    [SENDER] => WebHook
    [THREAD] => 40
    [SELF] => 55586
)
02.01.2023, 19:29:11 | WebHook RAW          | 

Es gibt auch noch $_SERVER.
Aber wenn der aufrufenden Dienst dem Webhook keine Daten übergibt, dann kannst du da auch nichts auswerten.
Michael

Das ist das Ergebnis für $_SERRVER
Irgendwas scheint wohl anzukommen…

02.01.2023, 20:37:45 | WebHook Server       | Array
(
    [HTTP_CONNECTION] => keep-alive
    [PHP_SELF] => /hook/traccar_live
    [HTTP_HOST] => 192.168.178.76:3777
    [REMOTE_PORT] => 59422
    [HTTP_USER_AGENT] => Jersey/2.37 (HttpUrlConnection 17.0.4)
    [REQUEST_METHOD] => GET
    [HTTP_ACCEPT] => text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
    [QUERY_STRING] => 
    [SCRIPT_NAME] => /hook/traccar_live
    [SERVER_PROTOCOL] => HTTP/1.1
    [PHP_AUTH_PW] => 
    [HOOK] => /hook/traccar_live
    [REMOTE_ADDR] => 192.168.178.76
    [PHP_AUTH_USER] => 
    [REQUEST_URI] => /hook/traccar_live
    [REQUEST_TIME_FLOAT] => 1672688265.719
    [REQUEST_TIME] => 1672688265
    [argv] => Array
        (
        )

    [argc] => 0
)

Wie hast du dir das Ausgeben lassen? Da hast du doch die korrekte php Variable?

So, nun erhalte ich endlich Daten…
Kann mir jemand kurz einen Tipp geben wie ich da zB einen der Werte als Variable ausgeben kann damit ich das auch einigermassen kapiere?

02.01.2023, 21:56:39 | WebHook RAW          | {"position":{"id":0,"attributes":{"batteryLevel":76.0,"distance":0.0,"totalDistance":43597.06,"motion":true},"deviceId":2,"protocol":"osmand","serverTime":"2023-01-02T20:56:39.010+00:00","deviceTime":"2023-01-02T20:56:38.000+00:00","fixTime":"2023-01-02T20:56:38.000+00:00","outdated":false,"valid":true,"latitude":XX.27677,"longitude":X.899438,"altitude":427.2935776924714,"speed":0.2767868441631396,"course":0.0,"address":null,"accuracy":4.722346341965834,"network":null},"device":{"id":2,"attributes":{},"groupId":0,"name":"Stefs_iPhone","uniqueId":"756155","status":"online","lastUpdate":"2023-01-02T20:56:39.026+00:00","positionId":421160,"geofenceIds":[6],"phone":"","model":"","contact":"","category":"person","disabled":false,"expirationTime":null}}

Leider verrätst du uns nicht, worin die Daten gespeichert sind. Annahme, du hast aus dem obigen Code nichts geändert:

IPS_LogMessage("WebHook RAW", file_get_contents("php://input"));

zu

$rawdata = file_get_contents("php://input");
$decoded = json_decode($rawdata, true);
print_r($decoded);
// in $decoded['position']['attributes']['batteryLevel'] müsste jetzt 76.0 stehen.
1 „Gefällt mir“

Wow danke für die Unterstützung, so habe ich die Funktion geschnallt.

Ich greife mit dem Skript einen Webhook ab, welcher von Traccar (Tracking-Platform) kommt.
Mich interessieren dabei die Live GPS-Daten, für Events gibts schon einen Script im Forum.
Die Schwierigkeit war halt, dass verschiedene Gerät auf denselben Webhook senden, daher muss das Ganze noch auf Dummy-Module verteilt werden.

Hier das, was ich gebastelt habe. Sicher nicht perfekt, aber läuft so weit ok.
Vielleicht sieht ein Fachmann noch, warum das Skript zeitweise unbekannte Dummy-Module generiert… Wenn’s überhaupt an dem Skript liegt und nicht Traccar ganz sporadisch noch Müll sendet :wink:

<?
IPS_LogMessage("WebHook RAW", file_get_contents("php://input"));

date_default_timezone_set("Europe/Berlin");
$timestamp = time();
$datum = date("d.m.Y",$timestamp);
$uhrzeit = date("H:i",$timestamp);

$ModulID = IPS_GetParent($_IPS['SELF']);
$hooks = (file_get_contents("php://input"));
$hooks =(json_decode($hooks, true));

$VAR_Dummy = $hooks['device']['name'];
$Parent = IPS_GetParent($_IPS['SELF']);
$id = CreateDummyInstance($ModulID,$VAR_Dummy);
$ParentModul= IPS_GetObject($Parent);

$ModulID = IPS_GetParent($_IPS['SELF']);
$ModulID = IPS_GetInstanceIDByName($VAR_Dummy , $ModulID );

$battery = $hooks['position']['attributes']['batteryLevel'];
$id = CreateVariableByName($ModulID, 'Batteriestand', 2);
SetValue($id, $battery);

$latitude = $hooks['position']['latitude'];
$id = CreateVariableByName($ModulID, 'Breitengrad', 2);
SetValue($id, $latitude);

$longitude = $hooks['position']['longitude'];
$id = CreateVariableByName($ModulID, 'Längengrad', 2);
SetValue($id, $longitude);

$altitude = $hooks['position']['altitude'];
$id = CreateVariableByName($ModulID, 'Höhe', 2);
SetValue($id, $altitude);

$speed = $hooks['position']['speed'];
$id = CreateVariableByName($ModulID, 'Geschwindigkeit', 2);
SetValue($id, $speed);

$status = $hooks['device']['status'];
$id = CreateVariableByName($ModulID, 'Status', 3);
SetValue($id, $status);



function CreateVariableByName($id, $name, $type)
{
   $vid = @IPS_GetVariableIDByName($name, $id);
   if($vid===false) {
      $vid = IPS_CreateVariable($type);
      IPS_SetParent($vid, $id);
      IPS_SetName($vid, $name);
   }
   return $vid;
}

function CreateDummyInstance($id, $name)
{
   $vid = @IPS_GetInstanceIDByName($name, $id);
   if($vid===false) {
      $vid = IPS_CreateInstance("{485D0419-BE97-4548-AA9C-C083EB82E61E}");
      IPS_SetParent($vid, $id);
      IPS_SetName($vid, $name);
	  IPS_ApplyChanges($vid);
   }
   return $vid;
}
?>

Grundsätzlich coole Idee. Ich würde das noch etwas vereinfachen.
Einerseits müsste imho die Prüfung ob die Dummy Instanz vorhanden ist schon ausreichen (ggü. das auch noch bei den Variablen zu prüfen).
Und der Zugriff auf Variablen unterhalb einer bekannten Kategorie sollte u.a. aus Performance Gründen über den sogenannten Ident passieren.

Genauer:
Der Ident wäre dem vorzuziehen, da er nur einmal pro Ebene vorhanden sein darf.
Namen dagegen dürfen mehrfach in einer Ebene vorkommen.
Und Namen haben gelegentlich komische Probleme z.b. wenn das encoding nicht passt.

@mb-stern Es spricht aber nichts gegen die Nutzung des Namens.
Ich sehe nur das du viel mehrfach machst, wie die ID von dem Dummy-Modul immer noch Mal ermitteln.
Dabei liefert CreateDummyInstance doch schon die ID.
Ebenso wird mehrfach der Parent von dem Script ermittelt. Einmal reicht doch :wink:
Michael

Danke für die Überprüfung.
Das mit der Ermittlung von Parent habe ich gesehen und korrigiert.
Das mit den DummyInstanzen sehe ich irgendwie nicht bzw. weis nicht, was da zu tun ist.
Ich habe zB diese Zeile entfernt, dann werden aber die Variablen nicht mehr im Modul platziert:

$ModulID = IPS_GetInstanceIDByName($VAR_Dummy , $ModulID );

Noch eine Frage, wie lege ich denn eine Variable mit Ident an? Aber ich denke dass es bei den wenigen Variablen nicht so relevant ist oder?

Hier nochmals der Script nach meiner Parent-Kosmetik :wink:

<?
IPS_LogMessage("WebHook RAW", file_get_contents("php://input"));

date_default_timezone_set("Europe/Berlin");
$timestamp = time();
$datum = date("d.m.Y",$timestamp);
$uhrzeit = date("H:i",$timestamp);

$ModulID = IPS_GetParent($_IPS['SELF']);
$hooks = (file_get_contents("php://input"));
$hooks =(json_decode($hooks, true));

$VAR_Dummy = $hooks['device']['name'];
$id = CreateDummyInstance($ModulID,$VAR_Dummy);

$ModulID = IPS_GetInstanceIDByName($VAR_Dummy , $ModulID );

$battery = $hooks['position']['attributes']['batteryLevel'];
$id = CreateVariableByName($ModulID, 'Batteriestand', 2);
SetValue($id, $battery);

$latitude = $hooks['position']['latitude'];
$id = CreateVariableByName($ModulID, 'Breitengrad', 2);
SetValue($id, $latitude);

$longitude = $hooks['position']['longitude'];
$id = CreateVariableByName($ModulID, 'Längengrad', 2);
SetValue($id, $longitude);

$altitude = $hooks['position']['altitude'];
$id = CreateVariableByName($ModulID, 'Höhe', 2);
SetValue($id, $altitude);

$speed = $hooks['position']['speed'];
$id = CreateVariableByName($ModulID, 'Geschwindigkeit', 2);
SetValue($id, $speed);

$status = $hooks['device']['status'];
$id = CreateVariableByName($ModulID, 'Status', 3);
SetValue($id, $status);



function CreateVariableByName($id, $name, $type)
{
   $vid = @IPS_GetVariableIDByName($name, $id);
   if($vid===false) {
      $vid = IPS_CreateVariable($type);
      IPS_SetParent($vid, $id);
      IPS_SetName($vid, $name);
   }
   return $vid;
}

function CreateDummyInstance($id, $name)
{
   $vid = @IPS_GetInstanceIDByName($name, $id);
   if($vid===false) {
      $vid = IPS_CreateInstance("{485D0419-BE97-4548-AA9C-C083EB82E61E}");
      IPS_SetParent($vid, $id);
      IPS_SetName($vid, $name);
	  IPS_ApplyChanges($vid);
   }
   return $vid;
}
?>

Weil du die Variablennamen mehrfach durcheinander benutzt. Oben war es schon $id :slight_smile:
Hier einmal kommentiert

<?
// Weg.. Müllt das Log nur zu, nur aktivieren wenn der Fehler mit den unbekannten Dummy-Modulen auftritt
//IPS_LogMessage("WebHook RAW", file_get_contents("php://input"));

/* Wozu war das hier ??? -> Wird gar nicht benutzt.
date_default_timezone_set("Europe/Berlin");
$timestamp = time();
$datum = date("d.m.Y",$timestamp);
$uhrzeit = date("H:i",$timestamp);
*/
// die Funktion heißt doch schon Get Parent, dann ist das eine ID vom Parent -> ParentID :)
//$ModulID = IPS_GetParent($_IPS['SELF']);
$ParentID = IPS_GetParent($_IPS['SELF']);

// unnötige Klammern entfernt.
$hooks = file_get_contents("php://input");
$hooks =json_decode($hooks, true);


//$VAR_Dummy = $hooks['device']['name'];
// Name der Dummy Instanz -> NameDummyInstanz 
$NameDummyInstanz = $hooks['device']['name'];

//Warum $id? Das ist die ID der Dummy-Instanz. -> DummyID
//$id = CreateDummyInstance($ModulID,$VAR_Dummy);
$DummyID = CreateDummyInstance($ParentID,$NameDummyInstanz);

// Oben war es erst $id und hier jetzt $ModulID... jetzt benutzen wir $DummyID
// Somit brauchen wir das hier nicht :)
//$ModulID = IPS_GetInstanceIDByName($VAR_Dummy , $ModulID );

$battery = $hooks['position']['attributes']['batteryLevel'];
$id = CreateVariableByName($DummyID, 'Batteriestand', 2);
SetValue($id, $battery);

$latitude = $hooks['position']['latitude'];
$id = CreateVariableByName($DummyID, 'Breitengrad', 2);
SetValue($id, $latitude);

$longitude = $hooks['position']['longitude'];
$id = CreateVariableByName($DummyID, 'Längengrad', 2);
SetValue($id, $longitude);

$altitude = $hooks['position']['altitude'];
$id = CreateVariableByName($DummyID, 'Höhe', 2);
SetValue($id, $altitude);

$speed = $hooks['position']['speed'];
$id = CreateVariableByName($DummyID, 'Geschwindigkeit', 2);
SetValue($id, $speed);

$status = $hooks['device']['status'];
$id = CreateVariableByName($DummyID, 'Status', 3);
SetValue($id, $status);



function CreateVariableByName($id, $name, $type)
{
   $vid = @IPS_GetVariableIDByName($name, $id);
   if($vid===false) {
      $vid = IPS_CreateVariable($type);
      IPS_SetParent($vid, $id);
      IPS_SetName($vid, $name);
   }
   return $vid;
}

function CreateDummyInstance($id, $name)
{
   $vid = @IPS_GetInstanceIDByName($name, $id);
   if($vid===false) {
      $vid = IPS_CreateInstance("{485D0419-BE97-4548-AA9C-C083EB82E61E}");
      IPS_SetParent($vid, $id);
      IPS_SetName($vid, $name)
   }
   return $vid;
}
/*
Nicht benutzen! weglassen
?>
*/
Michael

In der Funktion CreateVariableByName ersetzt du den Aufruf von IPS_GetVariableIDByName mit IPS_GetObjectIDByIdent($name, $dummyID) → Den Parameter $id würde ich der Verstädnis durch $dummyID ersetzen.

Und zusätzlich zu IPS_SetName setzt du auch noch IPS_SetIdent

Danke dass ihr euch so viel Mühe macht.
@Nall-chan: Mega Cool, dein Script funktioniert perfekt. Und danke für die Infos zu den Änderungen im Script.
@tobiasr: Habe versucht, deine Anpassungen noch einfliessen zu lassen in die Funktion, aber es werden danach bei jeder Aktualisierung der Daten alle Variablen erneut und zusätzlich gebildet. Irgend etwas mache ich da wohl falsch bei der Umsetzung…

function CreateVariableByName($dummyID, $name, $type)
{
   $vid = @IPS_GetObjectIDByIdent($name, $dummyID);
   if($vid===false) {
      $vid = IPS_CreateVariable($type);
      IPS_SetParent($vid, $dummyID);
      IPS_SetName($vid, $name);
      IPS_SetIdent($vid, $name);
   }
   return $vid;
}

Wie heißen die Variablen? Der Ident ist etwas störrich und darf u.a. keine Leerzeichen und Sonderzeichen erhalten. Ich vermute hier ist der Fehler.

Dazu mal das @ weglassen, dann müsste auch eine entsprechende Warnung auftauchen.

Tip zur Fehlersuche bei Idents:
Die dazugehörige Spalte in dem Objekt anzeigen lassen.

Es liegt in der Tat an den Umlauten…
Kann man diese trotzdem irgendwie verwenden?
Mir gefällt der Variablenname besser mit Umlauten…
Ansonsten belasse ich es wohl bei der Version ohne Ident…

Ob das jetzt genauso funktioniert, habe ich nicht getestet. Idee: Es werden einige der wahrscheinlichst vorkommenden Sonderzeichen durch x ersetzt. Man könnte statt x auch jedes andere Zeichen, welches in einem gültigen Ident vorkommen kann verwenden.

Das funktioniert, aber es macht das, was ich auch durch manuelles umbenennen der Variablen im Script erreiche.
Ich möchte ja eigentlich, dass die Variable ‚Höhe‘ heisst, und nicht ‚Hoehe‘.
Aber wenn das nicht geht, belasse ich es nun mal so, ich kann damit leben :wink:
So sind jedenfalls mal alle gängigen Umlaute vorausschauend korrigiert, auch wenn noch mehr dazu kommen…

function CreateVariableByName($dummyID, $name, $type)
{
   $name = str_replace("ö", "oe", $name);
   $name = str_replace("ä", "ae", $name);
   $name = str_replace("ü", "ue", $name);
   $name = str_replace("Ö", "Oe", $name);
   $name = str_replace("Ä", "Ae", $name);
   $name = str_replace("Ü", "Ue", $name);
   $vid = @IPS_GetObjectIDByIdent($name, $dummyID);
   if($vid===false) {
      $vid = IPS_CreateVariable($type);
      IPS_SetParent($vid, $dummyID);
      IPS_SetName($vid, $name);
      IPS_SetIdent($vid, $name);
   }
   return $vid;
}