Antworten
Dez 15, 2017 - 11:38
In der API-Dokumentation gibt es einen HTTP-Aufruf "GetStates", der aber mit meinem Gateway V5 nicht funktioniert. Beim weiteren Stöbern habe ich aber einen (undokumentierten) HTTP-Call gefunden, der ebenfalls den Status von der Komponenten abruft. Nun haben ich folgendes gemacht - ein Script erstellt, das zyklisch den Status der Komponeten abruft, verschiedenen Stati auswertet (Batterie, Timeout etc) und in einer Variable vermerkt, welchen maximalen Fehler es bei den Komponenten gab. Dabei habe ich die Informationen klassifiziert (0=ok, 1=timeout, dutycycl, 2=sabotage, 3=lowbat).
- diese Script wird zyklisch aufgerufen, ich habe ein 5m-Intervall eingestellt,
- diese Variable wird benutzt, um in einem Butten über eine Status-Regel zu visulaisieren, ob es ein Problem gibt
- über den Button kann ein Webseiten-Element aufgerufen werden, in dem der Hinhalt eines kleine PHP-Scriptes dargestellt wird, das den Status für alle Komponenten auflistet.
Als Nebeneffekt konnte ich auch die RSSI-Werte ermitteln und gebe sie aus (Wert von der Komponente / Wert von der Zentrale); ich bin mit nicht ganz sicher ( und konnten das aus den Foren auch nicht wirklich herauslesen), wie aussagekräftig diese Werte sind, sie geben aber auf jeden Fall einen guten Anhalt, wie stark die Verbindung ist (je negativer, desdo schlechter). Es gibt je nach Komponente auch unterschiedliche Informationen, bei Bedarf sollte man sich den JSON-Output mal genauer anschauen. Ich habe hier nur HomeMatic-Komponenten ausgewertet, weil meine anderen Typen von Komponenten, die ich habe, nichts liefern, was mir in diesem Zusammenhang nutzen würde. Das kann aber bei anderen Typen ganz anders sein. Leider habe ich (noch) keine Weg gefunden, um die Adresse der Komponente in den Nam,en zu übersetzen, daher befindet sich in dem PHP-Script eine Tabelle mit der Übersetzung. Zudem besteht die Möglichkeit, Komponenten anzugeben, die ignoriert werden sollen - ich habe z.B. Komponenten, die angelernt sind, aber nicht in Betrieb und die melden immer "timeout".
// HomeMatic-Komponenten auf Fehler (Batterie) überprüfen
// Zugangsdaten Gateway
var password = "xxxx";
var host = "xxx.xxx.xxx.xxx";
var url = "http://" + host + "/cmd?XC_FNC=GetStates&auth=" + password;
var addr2ignore = [
"HM-LC-Sw1-Pl-CT-R1.BidCos-RF.NEQ1262893"
];
var http = require('http');
var req = http.get(url, function(res) {
var body = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
body += String(chunk);
});
res.on('end', function() {
var jbody = JSON.parse( body );
var devices = jbody["XC_SUC"];
var alertLevel = 0;
for (var i = 0; i < devices.length; i++) {
var device = devices[i];
var type = device["type"];
if (type != "HM")
continue;
var addr = "", name = "", model = "";
if (device.adr) {
addr = device["adr"];
var ign = false;
for (var j = 0; j < addr2ignore.length; j++) {
if (addr2ignore[j] == addr) {
ign = true;
break;
}
}
if (ign)
continue;
var n = addr.indexOf(".BidCos-RF.");
if (n < 0)
n = addr.indexOf(".HmIP-RF.");
if (n > 0)
model = addr.substr(0, n);
if (model == "HM-RCV-50")
continue;
}
var lowbat = "", timeout = "", error = "", dutycycle = "";
var state_obj = device["state"];
if (state_obj.lowbat)
lowbat = state_obj["lowbat"];
if (state_obj.timeout)
timeout = state_obj["timeout"];
if (state_obj["error"])
error = state_obj["error"];
if (state_obj["0_dutycycle"])
dutycycle = state_obj["0_dutycycle"];
if (lowbat) {
if (alertLevel < 3)
alertLevel = 3;
}
if (error.length && error != "no_error") {
if (alertLevel < 2)
alertLevel = 2;
}
if (timeout) {
if (alertLevel < 1)
alertLevel = 1;
}
if (dutycycle) {
if (alertLevel < 1)
alertLevel = 1;
}
}
switch(alertLevel) {
case 0:
alertTag = "ok"; break;
case 1:
alertTag = "info";
break;
case 2:
alertTag = "warn";
break;
case 3:
alertTag = "alarm";
break;
default:
alertTag = "";
break;
}
console.log ("alertTag=" + alertTag);
executeDeviceCommand(
"Gateway",
"HM_AlertLevel",
{"value":"setValue","ext":alertTag},
function(err) {
err && console.error(err.message);
}
);
});
});
- diese Script wird zyklisch aufgerufen, ich habe ein 5m-Intervall eingestellt,
- diese Variable wird benutzt, um in einem Butten über eine Status-Regel zu visulaisieren, ob es ein Problem gibt
- über den Button kann ein Webseiten-Element aufgerufen werden, in dem der Hinhalt eines kleine PHP-Scriptes dargestellt wird, das den Status für alle Komponenten auflistet.
Als Nebeneffekt konnte ich auch die RSSI-Werte ermitteln und gebe sie aus (Wert von der Komponente / Wert von der Zentrale); ich bin mit nicht ganz sicher ( und konnten das aus den Foren auch nicht wirklich herauslesen), wie aussagekräftig diese Werte sind, sie geben aber auf jeden Fall einen guten Anhalt, wie stark die Verbindung ist (je negativer, desdo schlechter). Es gibt je nach Komponente auch unterschiedliche Informationen, bei Bedarf sollte man sich den JSON-Output mal genauer anschauen. Ich habe hier nur HomeMatic-Komponenten ausgewertet, weil meine anderen Typen von Komponenten, die ich habe, nichts liefern, was mir in diesem Zusammenhang nutzen würde. Das kann aber bei anderen Typen ganz anders sein. Leider habe ich (noch) keine Weg gefunden, um die Adresse der Komponente in den Nam,en zu übersetzen, daher befindet sich in dem PHP-Script eine Tabelle mit der Übersetzung. Zudem besteht die Möglichkeit, Komponenten anzugeben, die ignoriert werden sollen - ich habe z.B. Komponenten, die angelernt sind, aber nicht in Betrieb und die melden immer "timeout".
Dez 15, 2017 - 12:16
das fehlende Script (sorry, aber irgendwie muss ich das wohl übersprunge haben)
und: es ist ein Gateway V5+
<?php
// Zugangsdaten Gateway
$gateway_password = "xxxx";
$gateway_host = "xxx.xxx.xxx.xxx";
$gateway_url = "http://" . $gateway_host . "/cmd?XC_FNC=GetStates&auth=" . $gateway_password;
// Mapping Adresse zu "<Raum>: <Gerät>"
$addr2name = array(
"HM-CC-RT-DN.BidCos-RF.NEQ1636560" => "Kellerflur: Thermostat",
"HM-CC-RT-DN.BidCos-RF.NEQ1641783" => "Waschküche: Thermostat",
"HmIP-FSM.HmIP-RF.000895699E5C07" => "Gewächshaus: Schaltbox rechts",
"HmIP-FSM.HmIP-RF.000895699E6A25" => "Gewächshaus: Schaltbox links",
"HMIP-PS.HmIP-RF.0002170990E154" => "Garage: Steckdose Hydrawise",
"HMIP-PS.HmIP-RF.000217099E49E7" => "Flur: Stehlampe (Steckdose)",
"HM-WDS10-TH-O.BidCos-RF.OEQ0087723" => "Gewächshaus: Temperatur/Feuchte-Sensor",
);
// Komponenten, die ignoriert werden sollen
$addr2ignore = [
"HM-LC-Sw1-Pl-CT-R1.BidCos-RF.NEQ1262893",
"HM-MOD-EM-8.BidCos-RF.OEQ0175938:0",
"HM-MOD-EM-8.BidCos-RF.OEQ0175938:4",
"HM-MOD-EM-8.BidCos-RF.OEQ0175938:8",
"HM-PBI-4-FM.BidCos-RF.OEQ0177931:2",
"HM-PBI-4-FM.BidCos-RF.OEQ0177931:3",
"HM-PBI-4-FM.BidCos-RF.OEQ0177931:4",
];
function exit_with_error($msg) {
error_log($msg);
echo "<br>\n";
echo "<br>\n";
echo "<center>$msg</center><br>\n";
echo "<br>\n";
echo "</body>\n";
echo "</html>\n";
exit(1);
}
date_default_timezone_set("Europe/Berlin");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $gateway_url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$cdata = curl_exec($ch);
curl_close($ch);
date_default_timezone_set("Europe/Berlin");
$now = time();
# HTML-Seite beginnen
echo "<!DOCTYPE html>\n";
echo "<html>\n";
echo "<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n";
echo "<link href=\"https://fonts.googleapis.com/css?family=Open+Sans\" rel=\"stylesheet\">\n";
echo "<title>Status von HomeMatic-Komponenten</title>\n";
echo "<style>\n";
echo "html { height: 100%; color: #ffffff; background-color: #333333; overflow: hidden; }\n";
echo "body { table-cell; text-align: left; vertical-align: top; height: 100%; }\n";
echo "</style>\n";
echo "</head>\n";
echo "<body>\n";
echo "<style>\n";
echo "body { margin: 1; padding: 0; font-family: 'Open Sans', sans-serif; font-size: 9px;}\n";
echo "table { border-collapse: collapse; border: 0px solid; margin: 0.5em; width: 100%; }\n";
echo "th, td { padding: 1; }\n";
echo "tbody th { text-align: left; }\n";
echo "#spalte_name { width: 180px; }\n";
echo "#spalte_signal { width: 60px; }\n";
echo "</style>\n";
if ( $cdata == "" ) {
exit_with_error("no data from \"$api_url\"");
}
$jdata = json_decode($cdata);
if ( $jdata == "" ) {
exit_with_error("malformed data \"$data\" from \"$api_url\"");
}
#var_dump($jdata, true);$devices = $jdata->XC_SUC;
$components = array();
$alertCount = array();
foreach ($devices as $i => $value) {
$device = $devices[$i];
$type = $device->type;
# nur HomeMatic beachten
if ($type != "HM")
continue;
$adr = $device->adr;
$ign = 0;
foreach ($addr2ignore as $j => $value) {
if ($addr2ignore[$j] == $adr) {
$ign = 1;
break;
}
}
if ($ign)
continue;
$model = "";
$n = strpos($adr, ".BidCos-RF.");
if ($n == "")
$n = strpos($adr, ".HmIP-RF.");
if ($n)
$model = substr($adr, 0, $n);
# HM-RCV-50 ist der Gateway selbst
if ($model == "HM-RCV-50")
continue;
$name = $addr2name[$adr];
$state_obj = $device->state;
# var_dump($state_obj, true);
if (isset($state_obj->lowbat))
$lowbat = $state_obj->lowbat ? "1" : "0";
else
$lowbat = "";
if (isset($state_obj->timeout))
$timeout = $state_obj->timeout ? "1" : "0";
else
$timeout = "";
if (isset($state_obj->error))
$error = $state_obj->error;
else
$error = "";
if (isset($state_obj->{"0_dutycycle"}))
$dutycycle = $state_obj->{"0_dutycycle"} ? "1" : "0";
else
$dutycycle = "";
if (isset($state_obj->{"0_sticky_unreach"}))
$sticky_unreach = $state_obj->{"0_sticky_unreach"} ? "1" : "0";
else
$sticky_unreach = "";
# Signalstärke an der Komponenten
if (isset($state_obj->{"0_rssi_device"})) {
$rssi_device = $state_obj->{"0_rssi_device"};
if ($rssi_device == -65535)
$rssi_device = "";
}
else
$rssi_device = "";
# Signalstärke am Gateway
if (isset($state_obj->{"0_rssi_peer"})) {
$rssi_peer = $state_obj->{"0_rssi_peer"};
if ($rssi_peer == -65535)
$rssi_peer = "";
}
else
$rssi_peer = "";
$alertText = "";
$alertLevel = 0;
if ($lowbat) {
if ($alertText != "")
$alertText .= ".";
$alertText .= "lowbat";
if ($alertLevel < 3)
$alertLevel = 3; }
if ($error != "" && $error != "no_error") {
if ($alertText != "")
$alertText .= ".";
$alertText .= $error;
if ($alertLevel < 2)
$alertLevel = 2;
}
if ($timeout) {
if ($alertText != "")
$alertText .= ".";
$alertText .= "timeout";
if ($alertLevel < 1)
$alertLevel = 1;
}
if ($dutycycle) {
if ($alertText != "")
$alertText .= ".";
$alertText .= "dutycycle";
if ($alertLevel < 1)
$alertLevel = 1;
}
$component = array(
name => $name,
addr => $adr,
model => $model,
text => $alertText,
level => $alertLevel,
rssi_device => $rssi_device,
rssi_peer => $rssi_peer
);
$components[] = $component;
$n = $alertCount[$alertLevel];
if ($n == "")
$n = 0;
$n = $n + 1;
$alertCount[$alertLevel] = $n;
}
$status = "";
for ($lvl = 3; $lvl >=0; $lvl--) {
$n = $alertCount[$lvl];
if (! $n)
continue;
switch ($lvl) {
case 0:
$status = "$n Komponenten ok";
break;
case 1:
$status = "$n Hinweis(e)";
break;
case 2:
$status = "$n Warnung(en)";
break;
case 3:
$status = "$n Alarm";
break;
}
if ($status != "")
break;
}
# HTML-Ausgabe
$dt = date('d.m. H:i', $now);
$s = "<font size=\"-1\">Stand:</font> ";
$s .= $dt;
$s .= " ";
$s .= "<font size=\"-1\">Status:</font> ";
$s .= $status;
echo "<center>$s</center><br>\n";
sort($components);
for ($lvl = 3; $lvl >=0; $lvl--) {
$b = 0;
foreach ($components as $i => $value) {
$component = $components[$i];
$name = $component["name"];
$addr = $component["addr"];
$model = $component["model"];
$text = $component["text"];
$level = $component["level"];
$rssi_device = $component["rssi_device"];
$rssi_peer = $component["rssi_peer"];
if ($level != $lvl) continue;
if (! $b) {
switch ($lvl) {
case 0:
$title = "Übersicht";
break;
case 1:
$title = "Hinweis";
break;
case 2:
$title = "Warnung";
break;
case 3:
$title = "Alarm";
break;
}
echo "<font +1><b>$title</b></font>\n";
echo "<table>\n";
echo "<colgroup><col id=\"spalte_name\"></colgroup>\n";
echo "<colgroup><col id=\"spalte_signal\"></colgroup>\n";
echo "<colgroup><col></colgroup>\n";
echo "<thead>\n";
echo "<tr>\n";
echo "<th>Bezeichnung</th>\n";
echo "<th>Signal (dBm)</th>\n";
if ($lvl)
echo "<th>Meldung</th>\n";
else
echo "<th></th>\n";
echo "</tr>\n";
echo "</thead>\n";
echo "<tdata>\n";
$b = 1;
}
echo "<tr>\n";
echo "<td>$name</td>\n";
$signal = "";
if ($rssi_device != "" || $rssi_peer != "")
$signal = "$rssi_device/$rssi_peer";
echo "<td>$signal</td>\n";
if ($lvl)
echo "<td>$text</td>\n";
else
echo "<td> </td>\n";
echo "</tr>\n";
}
if ( $b ) {
echo "</tdata>\n";
echo "</table>\n";
}
}
echo "</body>\n";
echo "</html>\n";
exit(0);
und: es ist ein Gateway V5+
Von
toll...ich wurde sagen da fehlt das PHP script noch :)
Von
und ist da oben V5 gemeint oder V5+?
Von
Das Mapping ist in der devive_db hinterlegt, das musst Du auslesen dann kannst Du Name und Seriennummer zuordnen.
Von
ich hoffe auf einen api-Aufruf. mein mapping habe ich aus der device_db geholt, aber ich habe ja vom Gateway keinen Zugriff auf diese Datei (denke ich).
obwohl ... ich müsste mal schauen, ob man auch auf dem Gateway per Script eine Datei einlesen kann. Das basiert ja, wenn ich das richtig verstanden habe, auf BusyBox, also ein soweit normales Linux.
Bei mir könnte ich das mit meinem (2.) NEO-Server auf meiner Synology machen, aber ich hatte versucht das so zu machen, das Leute ohne spezielle Kenntnisse das nutzen könnten.
Vielleicht meldet sich Mediola ja noch wegen der neuen API bei mir (ich hatte die angemailt) - die Hoffnung stirbt zuletzt ;-)
Von
leider war mein Versuch, die device_db aus eine Gateway-Script heraus zu öffnen nicht von Erfolg gekrönt. Es sagt immer, das die Datei nicht da ist.
Da bin ich zu wenig Spezialist von node.js, um das analysieren zu können, leider.
Neuen Kommentar hinzufügen