Hausautomation: fhem



  • Den Air-Q habe ich in die Hausautomation fhem eingebunden. 3 alternative Lösungen (teils mit Einschränkungen) existieren:

    1. MQTT: Air-Q sendet die Daten zyklisch an den MQTT-Broker (mosquitto). fhem erhält vom Broker die Daten im JSON-Format. Problem hier: Air-Q hat häufiger Probleme beim Senden der Daten, sollte aber wohl irgendwann von Corant wohl behoben sein. Aber prinzipiell funktioniert es, es fehlen nur ab und zu die Daten.
    2. Http post: Der Air-Q sendet via http-post die Daten an den Server. Problem hier: Man kann zwar http-post im Air-Q aktivieren, aber Air-Q hat da noch einen Bug und sendet nie etwas, sollte aber wohl irgendwann von Corant wohl behoben sein. Dann werde ich hier auch noch eine alternative Lösung implementieren.
    3. via fhem httpmod: Das funktioniert tadellos. fhem holt zyklisch die Daten und decodiert den JSON-String in die einzelnen Readings.
      Aber fhem kann nicht die Daten direkt vom Air-Q holen, da diese codiert sind. Ich habe dazu eine kleine php-Seite dazwischen geschaltet, die die Decodierung übernimmt und den so erhalten JSON-String dann liefert.

    Bei Interesse einfach melden.



  • Cool, hab für mein fhem auch eine Lösung über die JSON-Daten implementiert, auch in PHP. Ist noch nicht ganz reif für eine Herausgabe, aber funktioniert im Augenblick sehr stabil.
    Das php Skript holt und dekodiert den JSON jeder Station, speichert ihn in einer STATION/JAHR/MONAT/TAG/TIMESTAMP.json, schreibt die wichtigsten Eckdaten der Räume in separate statische Dateien (die per CustomReadings in fhem einlese), loggt Eckdaten wie Uptime etc. und wird bei mir aber noch per Cronjob "manuell" alle sieben Minuten angestoßen.

    Bei Interesse auch gerne melden. 🙂



  • Hier Beschreibung und Code, um einen air-Q in die Hausautomation fhem einzubinden.

    Voraussetzung:
    Ein Web-Server mit php, z.B. Raspberry PI mit Apache und php.
    Für php muss openssl installiert sein.
    Es ist möglich und sinnvoll, wenn das alles auf dem fhem Server selbst installiert wird.

    Installation:
    Trage im unten stehendem php-Script das Passwort und die IP-Adresse des air-Q ein.
    Kopiere dieses php-Script auf den Web-Server.
    Z.B. nach /var/www/html/airq/get.php

    Aufruf erfolgt dann über

    http://<Server-IP>/airq/get.php?cmd={ping | config | data | log | dirbuff | file&request=<Year/Month/Day/Filename>}
    

    Achtung: mit https bekommt man Probleme, da man von einer https-Seite keine Daten über http holen kann und der air-Q kein https versteht.

    Einbindung in fhem:

    define airq_01_http HTTPMOD http://127.0.0.1/airq/get.php?cmd=data 300
    attr airq_01_http enforceGoodReadingNames 1
    attr airq_01_http extractAllJSON 2
    

    Erklärung:
    ...HTTPMOD http://127.0.0.1/airq/get.php?cmd=data...: Die IP-Adresse muss angepasst werden, falls das php-Script nicht auf dem fhem-Server instaliert ist.
    ... 300 ...: Hier wird ein Scan-Intervall von 300 vorgegeben, d.h. alle 300 sek. = 5 Minuten werden Daten abegfragt
    attr airq_01_http enforceGoodReadingNames 1: Um "gute" Namen für die Readings zu bekommen.
    attr airq_01_http extractAllJSON 2: Wenn fhem das erste Mal Daten empfängt werden gemäß der erhaltenen JSON-Attribute gleich die Readings automatisch erstellt.

    Weitere Möglichkeiten mit dem Script:
    Ist das Script so konfiguriert, dass man es auch vom lokalen Netzwerk aus aufrufen kann

    header('Access-Control-Allow-Origin: *'); 
    

    dann kann man folgende Kommandos auch direkt in einem Browser absetzen, bzw. die Daten in eigene HTML-Seiten einbinden.

    • http://<Server-IP>/airq/get.php?cmd=ping
      Kurze Information über den air-Q als JSON.
    • http://<Server-IP>/airq/get.php?cmd=config
      Die komplette Konfiguration des air-Q als JSON.
    • http://<Server-IP>/airq/get.php?cmd=data
      Aktuelle Sensordaten als JSON. Dies wird in der fhem Anbindung genutzt.
    • http://<Server-IP>/airq/get.php?cmd=log
      Die letzten Log-Einträge im air-Q. Sehr praktisch, wenn mal etwas schief läuft auf dem air-Q.
    • http://<Server-IP>/airq/get.php?cmd=dirbuff
      Liest das Datei-Verzeichnis mit den historischen Messdaten auf dem air-Q aus und gibt JSON zurück.
    • http://<Server-IP>/airq/get.php?cmd=file&request=<Year/Month/Day/Filename>
      Liest historische Messdaten vom air-Q. Die Dateinamen bekommt man über .../dirbuff siehe oben.

    Und hier das Script:

    <?php
    $password = "Hier das air-Q Passwort eintragen"; // config: set your air-Q password here
    $airq = "http://<Hier die IP-Adresse des air-Q eintragen>";  // config: use your own ip-adress
    
    // falls die Seite im lokalen Netz auch außerhalb des Servers aufgerufen werden muss, braucht man Access-Control-Allow-Origin
    header('Access-Control-Allow-Origin: *'); 
    
    function decrypt($msgb64,$password)
    {
        $airqpass = $password;
    	if (strlen($airqpass) < 32) {
    		for ($i = strlen($airqpass); $i < 32; $i++) {
    			$airqpass = $airqpass . '0';
    		}
    	} else {
    		if (strlen($airqpass) > 32) {
    			$airqpass = substr($airqpass,0,32);
    		}
    	}
    
    	$key = utf8_encode ($airqpass);
    //	$cyphertext = base64_decode ($msgb64);
    //	But with verly long messages there could be some problems in base64_decode
    	$decoded = "";
    	for ($i=0; $i < ceil(strlen($msgb64)/256); $i++)
    	   $decoded = $decoded . base64_decode(substr($msgb64,$i*256,256));
    	$cyphertext = $decoded;
    
    
    	$iv = substr($cyphertext,0,16);
    	$cyphertext = substr($cyphertext,16,strlen($cyphertext));
    
    //	With php version <= 7.1 you can use the following, but this is deleted in version 7.2 and above
    //	$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cyphertext, MCRYPT_MODE_CBC, $iv);
    	
    	$decrypted = openssl_decrypt($cyphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    	
    	return utf8_encode($decrypted);
    }
    
    function encrypt($msgb64,$password)
    {
        $airqpass = $password;
    	if (strlen($airqpass) < 32) {
    		for ($i = strlen($airqpass); $i < 32; $i++) {
    			$airqpass = $airqpass . '0';
    		}
    	} else {
    		if (strlen($airqpass) > 32) {
    			$airqpass = substr($airqpass,0,32);
    		}
    	}
    
    	$key = utf8_encode ($airqpass);
    	
    	$iv = substr(openssl_random_pseudo_bytes(32),0,16);
    
    	$encrypted = openssl_encrypt($msgb64, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    	return base64_encode($iv . $encrypted);
    }
    
    $_GET_lower = array_change_key_case($_GET, CASE_LOWER);
    $_POST_lower = array_change_key_case($_POST, CASE_LOWER);
    $cmd = '';
    if (array_key_exists('cmd', $_GET_lower)) {$cmd = $_GET_lower['cmd'];}
    if (array_key_exists('cmd', $_POST_lower)) {$cmd = $_POST_lower['cmd'];}
    $request = '';
    if (array_key_exists('request', $_GET_lower)) {$request = $_GET_lower['request'];}
    if (array_key_exists('request', $_POST_lower)) {$request = $_POST_lower['request'];}
    
    
    // Possible comands: ping, config, data, log, dirbuff, file&request=..
    
    if ($cmd == '') {
    	header('Content-Type: text/html');
    	echo 'Usage: ../get.php?cmd=ping | config | data | log | dirbuff | file&request=<Year/Month/Day/Filename>';
    } else {
    	$ch = curl_init(); 
    	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    	$output = "";
    	$url = $airq . '/' . $cmd;
    	if ($cmd == 'file') {
    		$url = $url . '?request=' . encrypt($request,$password);
    	} 
    	curl_setopt($ch, CURLOPT_URL, $url); 
    	$output = curl_exec($ch);
    	if ($cmd == 'dirbuff') {
    		$output = decrypt($output,$password);
    	} else {
    		if ($cmd == 'file') {
    		$output = decrypt($output,$password);
    		} else {
    			$json = json_decode($output, true);
    			$output = decrypt($json["content"],$password);
    		}
    	}
    	if ($cmd == 'log') {
    		header('Content-Type: text/html');
    		echo str_replace("\\\"","\"",str_replace("\\n\", \"","",substr($output,2,strlen($output)-6))); // delete [], /n
    	} else {
    		header('Content-Type: application/json');
    		echo $output;
    	}
    }
    ?>
    


  • klasse. Danke Euch!!


Log in to reply