"Health-Check" via REST API

Hallo zusammen,

gibt es so etwas wie einen Healthcheck für Devices, den per REST API auswerten kann? Also ja ich kann die Config für das Device per API auslesen, aber gibt es eine Möglichkeit auszuwerten, dass HomeGear mit einem Device XY noch kommunizieren kann?

Vielen Dank. Thomas

Du könntest den Parameter UNREACH auswerten und per node-blue oder PHP Script eine http endpoint zur Verfügung stellen…

Die Geräte melden sich ja von sich aus bei Homegear.

Sowas zum Beispiel, gerade mal zusammengebaut:
48

Hier wir UNREACH im Flow zwischengespeichert, da der Wert ja nur selten übertragen wird. Könnte man genauso in eine Datenbank (o.ä.) packen.
Beim Request wird dann der flow-Array ausgelesen, in JSON konvertiert und ausgegeben.

[{"id":"eec78e7.e4a717","type":"variable-in","namespace":"variable","z":"f82cf230.23b0d","variabletype":"device","family":"0","peerid":"4","channel":"0","variable":"UNREACH","refractoryperiod":"200","outputonstartup":true,"loopprevention":false,"looppreventiongroup":"","name":"","x":210,"y":120,"wires":[[{"id":"6ebdaa1.7a79754","port":0}]]},{"id":"6ebdaa1.7a79754","type":"function","namespace":"function","z":"f82cf230.23b0d","name":"write to unreachData","func":"$unreachData = getFlowData('unreach');\nif(!is_array($unreachData)){\n    $unreachData = [];\n}\n\n$peerId = $message['peerId'];\n$unreachData[$peerId] = $message['payload'];\nsetFlowData('unreach', $unreachData);\n//$message = ['payload' => $unreachData];\n\nreturn null;","inputs":1,"outputs":1,"noerr":0,"x":405,"y":120,"wires":[[]]},{"id":"be3cfbba.c853c8","type":"http-in","namespace":"http","z":"f82cf230.23b0d","name":"","server":"969c04f6.a894a8","url":"/unreach.json","method":"get","upload":false,"swaggerDoc":"","x":120,"y":280,"wires":[[{"id":"6b47a798.ba6528","port":0}]]},{"id":"6b47a798.ba6528","type":"function","namespace":"function","z":"f82cf230.23b0d","name":"get unreachData","func":"$unreachData = getFlowData('unreach');\nif(!is_array($unreachData)){\n    $unreachData = [];\n}\n\n$message['payload'] = $unreachData;\nreturn $message;","inputs":1,"outputs":1,"noerr":0,"x":285,"y":280,"wires":[[{"id":"dbf998dc.c79318","port":0}]]},{"id":"dbf998dc.c79318","type":"json","namespace":"parsers","z":"f82cf230.23b0d","name":"","x":440,"y":280,"wires":[[{"id":"916c5caa.f0308","port":0}]]},{"id":"916c5caa.f0308","type":"http-response","namespace":"http","z":"f82cf230.23b0d","name":"","server":"969c04f6.a894a8","statusCode":"","headers":{"Content-Type":"application/json"},"x":570,"y":280,"wires":[]},{"id":"71189892.cb5cb8","type":"variable-in","namespace":"variable","z":"f82cf230.23b0d","variabletype":"device","family":"0","peerid":"14","channel":"0","variable":"UNREACH","refractoryperiod":"200","outputonstartup":true,"loopprevention":false,"looppreventiongroup":"","name":"","x":205,"y":170,"wires":[[{"id":"6ebdaa1.7a79754","port":0}]]},{"id":"969c04f6.a894a8","type":"http-server","namespace":"http","z":"","listenaddress":"::","port":"8080","usetls":false}]

Lässt sich dann über http://<homegear-ip>:8080/unreach.json aufrufen, je nachdem was du im http-input-node eingestellt hast.

Sowas macht eventbasiert über mqtt aber eventuell mehr Sinn.

1 Like

Vielen Dank für deine Mühe! Kannst du mir das genauer erklären? Ich würde erwarten, dass wenn ein Gerät unreachable wird, das in HomeGear angezeigt wird und solange in dem Status bleibt bis er eben wieder reachable wird.

Ich erkläre vll. wozu ich es brauche: Ich hab mir mit glusterd und keepalived ein HA System aufgebaut. Das funktioniert soweit auch ganz gut. Nur würde ich eben gern eine Node auf FAULT stellen wollen, wenn Homegear (aus welchem Grund auch immer) nicht mehr arbeitet.

Die Geräte senden ja innerhalb des duty cycles und da gehorchen sie natürlich der 1%-Regel. Nach welcher Zeit homegear ein Gerät als UNREACHABLE markiert, kann ich nicht genau sagen. Sowie es sich aber wieder meldet wird das wieder auf false gestellt. Es gibt außerdem den Parameter STICKY_UNREACH der dir sagt, dass das Gerät auf unreachable war.

Vielleicht kann @sathya was genaueres dazu sagen.

Ich hab das gerade mal mit einem Thermostat getestet und curl -X GET http://x.x.x.x:2001/api/v1/get/13/0/UNREACH gibt mir '{“result”:“success”,“value”:true}` nachdem ich die Batterien entfernt habe. Das ist schonmal recht hilfreich um zu testen ob ein Gerät noch antwortet.

Jetzt würde ich mir eben nur noch fehlen, dass ich sicherstellen kann, dass der Daemon überhaupt noch sendet.

Naja, wenn du eine Antwort von Homegear erhältst (Port 2001) ist das ja schon mal ein gutes Zeichen :wink:

Naja - Es gibt ja durchaus Fälle wo der Daemon bzw. der Webserver noch läuft und trotzdem keine Kommunikation möglich ist, weil irgendwas schief läuft.

Ich weiß jetzt wird es etwas abstrakt, aber ich möchte z.B. den Fall abfangen, wenn das Funkmodul defekt ist

Kann man vll. ein vituelles Device aufsetzen, per Cron An,- und Aus schalten und das Log greppen?

Da muss @sathya was zu sagen…

Im schlimmsten Fall ssh <host> pidof homegear checken.

Hallo @tringler,

hier mal ein Skript von mir (interfacesOk.sh):

#!/bin/bash
# Check if interfaces are sending and receiving
result=$(/usr/bin/homegear -e rc '$interfaces=$hg->listInterfaces();$problem=count($interfaces)==0;foreach($interfaces as $interface){if($interface["ID"]=="BK90x0" && time() - $interface["LASTPACKETRECEIVED"] > 36000)$problem=true;if($interface["ID"]=="KNX" && (time() - $interface["LASTPACKETRECEIVED"] > 3600 || time() - $interface["LASTPACKETSENT"] > 3600))$problem=true;if($interface["ID"]=="USB300" && time() - $interface["LASTPACKETRECEIVED"] > 3600)$problem=true;}if($problem)print "0"; else print "1";')
if [ $? -ne 0 ] || [ $result -ne 1 ]; then
	/bin/echo -n 0
else
	/bin/echo -n 1
fi

Schnittstellen-IDs und Zeiten sind auf sinnvolle Werte anzupassen. Den PHP-Teil kannst du auch in einer interfacesOk.php in Homegears Webroot-Verzeichnis (/var/lib/homegear/www/rpc) speichern und dann über den Webserver aufrufen (https://{Homegear-IP}:2002/interfacesOk.php):

<?php

header('Content-Type: application/json');

$hg = new \Homegear\Homegear();
$interfaces = $hg->listInterfaces();
$problem = count($interfaces)==0;

foreach($interfaces as $interface)
{
	if($interface["ID"] == "BK90x0" && time() - $interface["LASTPACKETRECEIVED"] > 36000) $problem = true;
	if($interface["ID"] == "KNX" && (time() - $interface["LASTPACKETRECEIVED"] > 3600 || time() - $interface["LASTPACKETSENT"] > 3600)) $problem = true;
	if($interface["ID"] == "USB300" && time() - $interface["LASTPACKETRECEIVED"] > 3600) $problem = true;

}

if($problem) print("{\"status\": 0}"); else print("{\"status\": 1}");

Viele Grüße

Sathya

1 Like

Vielen, Vielen Dank!
Das ist ja genau das was ich gesucht habe. Leider funktioniert es bei mir nicht so wirklich. Selbst wenn ich das Skript auf folg. (siehe unten) kürze, schreibt das Log folg. Fehler:

08/17/18 11:31:51.524 Script Engine Server: Info: Starting script "/var/lib/homegear/www/rpc/healthcheck.php" with id 31.
08/17/18 11:31:51.547 Script Engine Server: Info: Client number 0 is calling RPC method: scriptHeaders
08/17/18 11:31:51.552 Info: Script with id 31 finished with exit code 255
<?php

header('Content-Type: application/json');

print("{\"status\": 0}");

$hg = new \Homegear\Homegear();
$interfaces = $hg->listInterfaces();
$problem = count($interfaces)==0;

Was sagt das Skriptengine-Log (/var/lib/homegear/homegear-scriptengine.log bzw. .err)?

Bei mir gibt es nur folg. Pfade:

drwxr-x--- 2 homegear homegear   4096 Aug 17 19:44 homegear
drwxr-x--- 1 homegear homegear   4096 Aug 17 19:44 homegear-influxdb
drwxr-x--- 1 root     root       4096 Aug 17 19:44 homegear-management

Sorry, /var/log… :roll_eyes:

Hätt ich mal sebst drauf kommen können :slight_smile: (Das war aber auch nicht der Inhalt von /var/lib/homegear - Keine Ahnung was ich da gepastet habe :roll_eyes:)

08/17/18 11:26:54.422 Script engine (/var/lib/homegear/www/rpc/healthcheck.php): PHP Fatal error:  Unknown: Failed opening required 'var/lib/homegear/www/rpc/healthcheck.php' (include_path='.:/var/lib/homegear/phpinclude') in Unknown on line 0

Der Ordner /var/lib/homegear/phpinclude ist bei mir leer.

Keine Ahnung, was uns der Fehler sagen will. Wenn das Skript dem oben entspricht, ist da doch gar kein require oder include? Kannst du einmal posten, was genau du gemacht hast und wie du das Skript aufrufst? Poste hier auch das Skript selbst als Datei (z. B. umgenannt in “datei.txt”, nicht den Inhalt), falls da ein Fehler ist.

Viele Grüße

Sathya

datei1.txt (480 Bytes)

Anbei das File.

Wo liegt es und wie hast du es aufgerufen? Generell sieht die Datei gut aus.

Pfad: /var/lib/homegear/www/rpc/healthcheck.php
Aufruf: curl -X GET -H "Content-Type: application/json" http://192.168.178.202:2001/healthcheck.php

Hm, wieso beim Request den Content-Type mitgeben? Das ist in dem fall nur beim return header wichtig. :slight_smile: