MNH Gedankensprudel

nicht nur ein stilles Wasser

myopenhab onlinestatus grabber

17.08.21 (Allgemein)

Wer viel im Smarthome bastelt möchte manchmal wissen warum etwas nicht mehr geht.

Ist die config nun falsch oder doch der Dienst mal wieder offline wegen dem Internet?

Openhab bietet zwar die Möglichkeit den zustand von Services und Things anzuzapfen, aber leider bekommt man darüber nicht heraus ob der Cloud Service gerade offline oder online ist.

Zu diesen zweck habe ich mir ein kleines PHP Scrip geschrieben das den „Cloud Status“ auf der Homepage abfragt und als json zu Verfügung stellt.

Vorbereitung: Installiere PHP und die benötigten Extensions:

Um dieses noch in openhab selber zu nutzen verwende ich ein exec Thing und php auf dem openhab host.

Im folgend nun eine Anleitung wie dies zu Installieren ist.
Als erstes die Abhängigkeiten installieren

sudo apt install php-cli php-curl php-xml wget
sudo apt install php-cli php-curl php-xml wget und danach Installation prüfen:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
php -m | egrep "xml|curl"
curl
libxml
xml
xmlreader
xmlwriter
php -m | egrep "xml|curl" curl libxml xml xmlreader xmlwriter
php -m | egrep "xml|curl"
 curl
 libxml
 xml
 xmlreader
 xmlwriter

Skript nach

"/etc/openhab/bin"
"/etc/openhab/bin" herunterladen (am Ende des Artikels auch nochmal verlinkt):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mkdir /etc/openhab/bin && wget https://gist.githubusercontent.com/carschrotter/4d3d26867edbf254097cd72fbf21a67f/raw/382c17bb9126b3db3e535998daee43a340691ea1/myopenhab_onlinestate.php -O "/etc/openhab/bin/myopenhab_onlinestate.php"
mkdir /etc/openhab/bin && wget https://gist.githubusercontent.com/carschrotter/4d3d26867edbf254097cd72fbf21a67f/raw/382c17bb9126b3db3e535998daee43a340691ea1/myopenhab_onlinestate.php -O "/etc/openhab/bin/myopenhab_onlinestate.php"
mkdir /etc/openhab/bin && wget https://gist.githubusercontent.com/carschrotter/4d3d26867edbf254097cd72fbf21a67f/raw/382c17bb9126b3db3e535998daee43a340691ea1/myopenhab_onlinestate.php -O "/etc/openhab/bin/myopenhab_onlinestate.php"

nun kann ein erster Testlauf starten:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo -u openhab /usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php" --username="MYUSERNAME" --password="MYPASSWORD" --cookie="/etc/openhab/misc/COOKIE.TXT"
sudo -u openhab /usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php" --username="MYUSERNAME" --password="MYPASSWORD" --cookie="/etc/openhab/misc/COOKIE.TXT"
sudo -u openhab /usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php" --username="MYUSERNAME" --password="MYPASSWORD" --cookie="/etc/openhab/misc/COOKIE.TXT"

Dabei wird versucht euch auf myopenhab.org anzumelden und das Cookie mit der Session ID unter /etc/openhab/misc/COOKIE.TXT gespeichert. Im Anschluss solltet ihr noch die Benutzerrechte sowie Schreib,- und Leserechte anpassen

chown root:openhab "/etc/openhab/misc/COOKIE.TXT"
chown root:openhab "/etc/openhab/misc/COOKIE.TXT" und
chmod 660 "/etc/openhab/misc/COOKIE.TXT"
chmod 660 "/etc/openhab/misc/COOKIE.TXT"

Konfigurationsdatei anlegen:

nano "/etc/openhab/misc/myopenhab_conf.php"
nano "/etc/openhab/misc/myopenhab_conf.php" und folgenden Inhalt einfügen:

<?php
return [
"username" => "MYUSERNAME",
"password" => "MYPASSWORD",
];

„MYUSERNAME“ und „MYPASSWORD“ sind natürlich wieder durch eure Logindaten zu ersetzen.
Auch hier solltet ihr die Rechte anpassen

chown root:openhab "/etc/openhab/misc/myopenhab_conf.php"
chown root:openhab "/etc/openhab/misc/myopenhab_conf.php" und
chmod 640 "/etc/openhab/misc/myopenhab_conf.php"
chmod 640 "/etc/openhab/misc/myopenhab_conf.php"

Nun können wir schon mit dem einbinden in OpenHab anfangen. Dafür benötigt ihr das Exec Binding

Nun erstellt ihr als erstes ein Exec Thing wenn ihr eine sprechende UID wollt müsst ihr diese beim erstellen angeben. Alle anderen Parameter können auch noch später z.B. auch im YAML geändert werden. Als Befehl habe ich

/usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php" --conf="/etc/openhab/misc/myopenhab_conf.php" --cookie="/etc/openhab/misc/COOKIE.TXT"
/usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php" --conf="/etc/openhab/misc/myopenhab_conf.php" --cookie="/etc/openhab/misc/COOKIE.TXT" eingetragen. Den Status frage ich alle 3600 Sekunden ab also Jede Stunde ihr könnt aber auch 300 für z.B. alle 5 min eintragen.

Nach den speichern könnt ihr auch das Thing als Code bearbeiten

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
UID: exec:command:grab_myopenhab_onlinestate
label: myopenhab.org Status
thingTypeUID: exec:command
configuration:
transform: REGEX((.*))
interval: 3600
autorun: true
command: /usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php"
--conf="/etc/openhab/misc/myopenhab_conf.php"
--cookie="/etc/openhab/misc/COOKIE.TXT"
timeout: 15
UID: exec:command:grab_myopenhab_onlinestate label: myopenhab.org Status thingTypeUID: exec:command configuration: transform: REGEX((.*)) interval: 3600 autorun: true command: /usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php" --conf="/etc/openhab/misc/myopenhab_conf.php" --cookie="/etc/openhab/misc/COOKIE.TXT" timeout: 15
UID: exec:command:grab_myopenhab_onlinestate
label: myopenhab.org Status
thingTypeUID: exec:command
configuration:
  transform: REGEX((.*))
  interval: 3600
  autorun: true
  command: /usr/bin/php "/etc/openhab/bin/myopenhab_onlinestate.php"
    --conf="/etc/openhab/misc/myopenhab_conf.php"
    --cookie="/etc/openhab/misc/COOKIE.TXT"
  timeout: 15
Item Konfiguration für den Status

Skript um den Status abzurufen

#!/bin/env php
<?php
/**
* @global array $options array with script options
* needed struck like
* <?php
* [
* 'username' => 'USERNAME',
* 'password' => 'PASSWORD',
* 'cookie' => 'COOKIE.TXT'
* ]
*/
$options = getopt(null, ['username:', 'password:', 'cookie::', 'conf::', 'h', 'help', 'ignore-ssl']);
if(count(array_intersect(['h', 'help'], array_keys($options))) > 0) {
printf('Usage: %2$s %3$s --username "MyUsername" --password "MyPassword" (--cookie "/file/to/cookie") %1$sOptions:%1$22s--username The username of myopenhab account%1$s--password The password of myopenhab account%1$s--cookie (optional) The path to cookie file', PHP_EOL, PHP_BINARY, __FILE__);
exit(0);
}
//convert php default behavior given parameter is explicitly false, to true if specified
$options['ignore-ssl'] = (bool) (array_key_exists('ignore-ssl', $options) ? !$options['ignore-ssl'] : false);
if( array_key_exists('conf', $options) ) {
if(!file_exists($options['conf']) ){
printf('Conf file "%2$s" not found!%1$s', PHP_EOL, $options['conf'] );
exit(1);
}
$conf_file_content = @include($options['conf']);
if(!is_array($conf_file_content)){
printf("Conf file has wrong format!%1\$sWrite as follow:%1\$s%1\$s<?php%1\$sreturn ['username' => 'MyUsername', 'password' => 'MyPassword'];%1\$s%1\$s", PHP_EOL);
exit(1);
}
$options = array_merge($conf_file_content, $options);
}
//is not set on comandline or config file use default value
$options['cookie'] = array_key_exists('cookie', $options) ? $options['cookie'] : "COOKIE.TXT";
//only for debuging
//print_r($options);
if( !array_key_exists('username', $options ) || !array_key_exists('password', $options ) ) {
printf('Username and password neded using: %s %s --username "MyUsername" --password "MyPassword"' .PHP_EOL, PHP_BINARY, __FILE__);
exit(1);
}
$timezone = (new DateTime())->getTimezone()->getName();
const headers = [
'Connection: keep-alive',
'Cache-Control: max-age=0',
'sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"',
'sec-ch-ua-mobile: ?0',
'Upgrade-Insecure-Requests: 1',
'Origin: https://myopenhab.org',
'User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Sec-Fetch-Site: same-origin',
'Sec-Fetch-Mode: navigate',
'Sec-Fetch-User: ?1',
'Sec-Fetch-Dest: document',
'Accept-Language: en;q=0.9,en-GB;q=0.8,en-US;q=0.7'
];
//check for runtime
if(extension_loaded('curl') === false)
die("extention curl is needed ");
if(extension_loaded('dom') === false)
die("extention dom is needed ");
function bakingCurl($url, array $headers = null) {
global $options;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, $options['cookie']);
curl_setopt($ch, CURLOPT_COOKIEJAR, $options['cookie']);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers ?: headers);
if($options['ignore-ssl'] === true) {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
}
return $ch;
}
function execCurl($ch) {
$result = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($result === false || $http_code != 200) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception($error ?: 'HTTP Error: '. $http_code );
}
return $result;
}
function startpage() {
$result = execCurl(bakingCurl("https://myopenhab.org/"));
return $result;
}
/**
* Login into myopenhab.org
* @param string $csrf the from page extracted csrf
* @global string $options options like username, password or cookie
*/
function login($csrf) {
global $options;
//send the form
$ch = bakingCurl('https://myopenhab.org/login', headers + [
'Origin: https://myopenhab.org',
'Content-Type: application/x-www-form-urlencoded',
'Referer: https://myopenhab.org/',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$qu = http_build_query( [
'username'=>$options['username'],
'password'=>$options['password'],
'_csrf' => $csrf,
'submit'=>'',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $qu);
return execCurl($ch);
}
function getCsrf(\DomXPath $domxpath){
/* xpath of csrf input element in login form*/
$csrf_nodes = $domxpath->query("//form[@action='/login']/input[@name='_csrf']/@value");
if($csrf_nodes->count() == 1){
return $csrf_nodes[0]->value;
}
return false;
/*
$csrf_nodes = $domxpath->query('/html/body/div/section/div/div/div[2]/div[2]/form/input[1]');
// Traverse the DOMNodeList object to output each DomNode's nodeValue
foreach ($csrf_nodes as $node) {
if ($node->hasAttributes()) {
foreach ($node->attributes as $attr) {
if('value' == $attr->nodeName){
return $attr->nodeValue;
}
}
}
}
*/
}
function getStateFromPage($document) {
global $timezone;
if(preg_match('/(Unknown user)|(incorrect password)/i', $document)) {
throw new Exception("Wrong username or incorrect password");
}
$dom = new DomDocument();
/* Load the HTML */
@$dom->loadHTML($document);
/* Create a new XPath object */
$xpath = new DomXPath($dom);
$csrf = getCsrf($xpath);
//no csrf allredy logged in :-)
if($csrf == false) {
//using li[3] becaus class change on online/offline :-/
$status_nodes = $xpath->query('//*[@id="mainMenu"]/ul/li[3]/a');
if(count($status_nodes) == 0){
throw new Exception("Document structure not valid. Status not found!");
}
foreach ($status_nodes as $i => $node) {
$output['status'] = strtolower($node->textContent) ;
if ($node->hasAttributes()) {
foreach ($node->attributes as $attr) {
if('title' == $attr->nodeName){ //@todo not working correkt :-(
$output['since_hint'] = $attr->nodeValue;
$sinceDateTime = new DateTimeImmutable(str_replace('Since ', '', $output['since_hint']), new DateTimeZone($timezone));
$output['state_since_seconds'] = (int) (new DateTime())->getTimestamp() - $sinceDateTime->getTimestamp();
$output['state_since_datetime'] = $sinceDateTime->format('Y-m-d H:i:s');
}
}
}
}
$output['timezone'] = $timezone;
return $output;
} else {
execCurl( //set timezone for "since... " Value
bakingCurl( 'https://myopenhab.org/setTimezone?' . http_build_query(['tz' => $timezone]) )
);
//rerunn from login
return getStateFromPage(login($csrf));
}
throw new Exception("Document structure not valid");
}
try {
$document=startpage();
$state = getStateFromPage($document);
echo json_encode($state);
} catch (\Throwable $th) {
die( json_encode( ['error' => $th->getMessage()] ) );
}

Carschrotter
ist leidenschaftlicher Technik Fan beigester von allen was mit dem Web zu tuen hat und Vollblut Nerd. Deshalb war auch sein Ausbildung zum Fachinformatiker ein logischer schritt.

Kommentar schreiben

I accept that my given data and my IP address is sent to a server in the USA only for the purpose of spam prevention through the Akismet program.More information on Akismet and GDPR.

XHTML: Sie können diese Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre prompt="" escaped="">