Schon seit geraumer Zeit versuche ich die Luftqualität zu messen und in fhem einzubinden.
Für Temperatur und Luftfeuchte gibt es viele Möglichkeiten, für Feinstaub habe mit einem ESP-01 und dem SDS11 Feinstaubsensor einen Sensor gebaut, der seine Daten via MQTT schickt.
Für Kohlenmonoxid, Kohlendioxid, Stickoxide, Schwefeloxide usw. war ich ständig auf der Suche nach geeigneten Sensoren.
Aber letztendlich war ich da nie erfolgreich, das scheint deutlich eine Nummer zu groß für mich zu sein.
Letztes Jahr stieß ich bei meiner Suche auf die Firma Corant GmbH, die ein neues Produkt Air-Q entwickeln wollte, das anscheinend alle meine Anforderungen übererfüllte.
Statt also weiter zu suchen, stieg ich über ein Kickstarterprogramm ein.
Ende Juni war es dann endlich soweit, ich bekam meinen Air-Q.
Dieser misst Temperatur, Luftfeuchte, Sauerstoff, Kohlenmonoxid, Kohlendioxid, Stickoxide, Schwefeloxide, Feinstaub (PM 1, PM 2.5, PM 10), Druck, Lautstärke und VOC. Irgendwann soll Schwefelwasserstoff dazu kommen.
Dazu beurteilt der Air-Q auf Basis dieser Daten gleich die Gesamt-Qualität in einem Bereich 0-1000.
Der Air-Q schickt seine Messdaten optional (!) in eine eigene Cloud, aber man kann über eine API auch direkt den Air-Q abfragen. Daneben unterstützt er auch MQTT und HTTP-Post.
Also habe ich diesen Air-Q in fhem eingebaut. Dazu muss man aber die Daten, die der Air-Q sendet, erst entschlüsseln. Diese sind nämlich aus Sicherheitsgründen verschlüsselt.
Mit eine kleinen PHP-Script (getdata.php) hole ich Daten vom Air-Q, entschlüssele diese und reiche sie weiter im JSON-Format.
<?php
$password = "<edit this>"; // config: set your air-Q password here
$airq = "http://<edit this>/data"; // config: use your own ip-adress
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));
$decrypted = openssl_decrypt($cyphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
return utf8_encode($decrypted);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $airq);
$output = curl_exec($ch);
header('Content-Type: application/json');
echo decrypt(json_decode($output, true)["content"],$password);
?>
Zeile 2 und 3 muss man entsprechend anpassen.
Dieses PHP-Skript rufe ich dann in einem HTTPMOD auf.
define airq_01_http HTTPMOD http://127.0.0.1/airq/getdata 300
attr airq_01_http enforceGoodReadingNames 1
attr airq_01_http extractAllJSON 2
Da bei mir das PHP-Script auf dem gleichen Server wie fhem liegt, kann ich http://127.0.0.1/... verwenden.
Die Logs zu definieren und dann Grafiken zu erstellen, ist alles Standard.
Funktioniert hervorragend.
Jetzt will ich noch Korrelationen mit anderen Daten analysieren. Ich zeichne mit fhem schon seit geraumer Zeit die Wetterdaten verschiedener Stationen auf und auch die Umweltdaten von der Landesanstalt für Umwelt.
Hallo Mike_GKA,
hab auch einen air-Q Basis aus der Kickstarter Kampagne, aber bisher noch nicht an mein fhem angebunden.
Da ich den fhem-internen MQTT-Server nutze, würde mich als erstes mal interessieren, wie man das Senden von MQTT-Nachrichten aktiviert, oder geht das mit dem air-q Basis nicht?
Grüße
Dieter
Hab es jetzt erst einmal mit dem php-Script und HTTPMOD probiert, das Script läuft aber bei mir auf folgenden Fehler:
PHP Fatal error: Uncaught Error: Call to undefined function curl_init() in /usr/local/bin/getdata.php:34
Stack trace:
#0 {main}
thrown in /usr/local/bin/getdata.php on line 34
Hallo Dieter,
zu air-q-Basis: Da ich keinen air-Q-Basis habe und auch meinen air-Q gekauft hatte bevor es diesen Unterschied gab, kann ich Dir da keine gesicherte Auskunft geben.
Du kannst aber folgendes probieren: Auf der SD-Karte im air-Q kann man eine Konfigurationsdatei mit Namen userconfig.json anlegen. Diese wird beim Hochfahren vom air-Q eingelesen. Für mqtt schreibe in diese Datei:
{
"mqtt": {
"device_id": "AirQ01",
"broker_URL": "192.168.182.88",
"user": "",
"password": "",
"port": 1883,
"topic": "airQ ",
"retain": true,
"ssl": false
}
}
Die Werte musst Du natürlich an Deine Umgebung anpassen.
Sollte eine userconfig.json bereits vorliegen, dann erweitere den JSON um diesen Wert.
ACHTUNG: Eine nicht sauber json-formatierte userconfig.json führt dazu, dass der air-Q gar nicht mehr richtig funktioniert!!
Zu Error: Call to undefined function curl_init():
Da ist wohl Dein Server nicht vollständig, es fehlt wahrscheinlich curl und php-curl.
I.A. kann man das nachträglich installieren mit:
sudo apt-get install curl
sudo apt-get install phpX-curl
sudo service apache2 restart
Wichtig in der 2.Zeile ersetze phpX-curl mit Deiner instaliierten PHP-Version, also z.B. php7-curl.
ah super, danke.
Das mit MQTT muss ich mir gut überlegen ;)
HTTPMOD: Den Fehler mit cURL hab ich beheben können durch Nachinstallation.
Komme jetzt trotzdem nicht weiter :(
Mein Apache-Server läuft, die Startseite sehe ich - o.k.
Hab allerdings alle Webinterfaces von FHEM mit https abgesichert ?
Du schreibst noch: "für PHP muss openssl installiert sein" ?
Dann sollte sich doch der airQ unabhängig von fhem in einem Browser abfragen lassen mit http://<Server-IP>/airq/get.php?cmd={ping | config | data | log | dirbuff | file&request=<Year/Month/Day/Filename>}
Hier der Output, wenn ich get.php von der Linux-Konsole aus aufrufe: PHP Warning: Cannot modify header information - headers already sent by (output started at /usr/local/bin/get.php:1) in /usr/local/bin/get.php on line 10
PHP Warning: Cannot modify header information - headers already sent by (output started at /usr/local/bin/get.php:1) in /usr/local/bin/get.php on line 79
Usage: ../get.php?cmd=ping | config | data | log | dirbuff | file&request=<Year/Month/Day/Filename>
Und wie im jpg siehts beim Aufruf im Browser aus - viel kann doch nicht mehr fehlen ... ;)
"für PHP muss openssl installiert sein": der air-Q verschlüsselt seine Daten, deshalb wird openssl zur Decodierung benötigt. Das hat mit https nichts zu tun. Der air-Q kann kein https!
Die Fehlermeldung irritiert mich sehr:
Die letzte Zeile ,,Usage: ../get.php?cmd=ping | config | data | log | dirbuff | file&request=<Year/Month/Day/Filename>" besagt, eigentlich, dass kein Kommando (cmd=...) angegeben wurde.
Wie rufst Du die url in der Linux-Konsole auf??
Nachtrag: Hab jetzt erst das angehängte Bild gesehen.
Hier ist ein Fehler in der URL, es fehlt "cmd". Also es muss heißen: http://192.168.178.92/get.php?cmd=ping
Hallo Dieter,
noch eines fällt mir auf. Du verwendest anscheinend nicht das gepostete php-Script, sondern das aus dem airQ-Forum (das übrigens auch von mir ist).
Das ist deutlich universeller nutzbar, aber auch damit geht eine fhem-Anbindung, aber die URL ist halt etwas anders und verlangt den Parameter "cmd".
ja richtig, ich hab dann das Script aus dem airQ Forum verwendet.
Mein Aufruf von der Linux-Konsole:
$ php get.php
Usage: ../get.php?cmd=ping | config | data | log | dirbuff | file&request=<Year/Month/Day/Filename>
$ php get.php?cmd=ping
Could not open input file: get.php?cmd=ping
Wobei mein Script in /var/www/html liegt.
Wo ich auch noch zweifle ist die Schreibweise für die Variable $airq, ist die so korrekt?
$airq = "http://192.168.178.103"; // config: use your own ip-adress
Bei Eingabe im Browser (Firefox) von 192.168.178.92/get.php?cmd=ping
scheint das Script zu laufen, hab mal Kontrollausgaben via echo eingebaut. Aber sonst kommt keine Ausgabe im Browser? Ich hab mal die Browser-Konsole mitlaufen lassen ...
Im fhem-Log steht die Fehlermeldung: airq_01_http: no parsed JSON structure available
fhem Definitionen wie beschrieben defmod airq_01_http HTTPMOD http://192.168.178.92/get.php?cmd=data 300
attr airq_01_http enforceGoodReadingNames 1
attr airq_01_http extractAllJSON 2
attr airq_01_http room airQ
[code]
[/code]
vlt stimmt was bei fhem noch nicht?
Jetzt ist es etwas schwierig auf Deine Fragen zu antworten, da ich nicht weiß was Du genau wie und in welcher Reihenfolgen gemacht hast.
Zum Bild der Konsole: Na ja, dass favicon.ico nicht gefunden wird ist ja keine Drama. Der air-Q stellt hat kein Icon zur Verfügung. Das kannst Du ignorieren.
"Habe mal Kontrollausgaben via echo eingebaut": Ok, ABER jetzt bekommst Du die Echos in den JSON-String "reingemischt" und damit ist es kein JSON -Format mehr und fhem kann es nicht verarbeiten (no parsed JSON structure available).
Da gibt es jetzt zwei Möglichkeiten:
1. Nur zum Testen: Lösche mal die Zeile "header('Content-Type: application/json');", dann bekommst Du im Browser zumindest die Echos und hoffentlich auch den JSON-String angezeigt. Aber das kann dann so in fhem nicht genutzt werden.
2. Lasse die Zeile "header('Content-Type: application/json');" im Script und lösche ALLE von Dir eingebauten Echos. Dann solte es eigentlich in fhem und auch im Browser funktionieren.
Noch zu:
Zitat
Wo ich auch noch zweifle ist die Schreibweise für die Variable $airq, ist die so korrekt?
$airq = "http://192.168.178.103"; // config: use your own ip-adress
Ja, das ist korrekt, ABER in anderen Code-Snippets schreibst Du ....92
Hat sich die IP-Adresse des airQs geändert??Edit: Das ist ja Blödsinn, einmal ist es ja die IP des airQs das andere Mal die IP des Servers. Na Ja manchmal stehe ich halt auch etwas auf dem Schlauch.
Irgendwo ist der Wurm drin, deshalb notier ich mal meine Voraussetzungen:
IP des Servers: 192.168.178.92
IP des air-q: 192.168.178.103
In /var/www/html liegen get.php und getdata.php
:/var/www/html $ ls -l
-rwxr-xr-x 1 root staff 1229 Nov 15 11:44 getdata.php
-rwxr-xr-x 1 root staff 3265 Nov 15 11:40 get.php
-rw-r--r-- 1 root root 10701 Nov 13 12:44 index.html
Die Definitionen in FHEM defmod airq_01_http HTTPMOD http://192.168.178.92/getdata.php 300
attr airq_01_http enforceGoodReadingNames 1
attr airq_01_http extractAllJSON 2
Fällt dir da noch was auf, was hakt?
Die Variablen von getdata.php $password = "xxxxxxx"; // config: set your air-Q password here
$airq = "http://192.168.178.103/data"; // config: use your own ip-adress
Der Aufruf von getdata http://192.168.178.92/getdata.php 300
Die Variablen von get.php $password = ""xxxxxxx; // config: set your air-Q password here
$airq = "http://192.168.178.103"; // config: use your own ip-adress
Der Aufruf von get http://192.168.178.92/get.php?cmd=data 300
Was steht im Fehlerlog des Webservers? Der Aufruf in deinem Screenshot oben hat einen HTTP 500-Fehler gebracht (internal server error).
MIr fällt ein kleiner Tippfehler auf in get.php
$password = ""xxxxxxx; // config: set your air-Q password here
$airq = "http://192.168.178.103"; // config: use your own ip-adress
das Apostroph sitzt falsch, richtig wäre
$password = "xxxxxxx"; // config: set your air-Q password here
$airq = "http://192.168.178.103"; // config: use your own ip-adress
Wenn das nicht weiter hilft:
Was kommt eigentlich im Browser an bei:
http://192.168.178.92/getdata.php
http://192.168.178.92/get.php?cmd=data
Was steht eventuell im Apache Error.log?
Dann versuche mal den airQ direkt anzusprechen mit
http://192.168.178.103/data
Was kommt da als Antwort?
Es müsste ein langer kryptischer JSON-String kommen der Art {"content": "--jede Menge kryptische Zeichen --"}
Zitat von: Christoph Morrison am 15 November 2021, 12:50:57
Was steht im Fehlerlog des Webservers? Der Aufruf in deinem Screenshot oben hat einen HTTP 500-Fehler gebracht (internal server error).
Gaaaaaaaaaaanz viel: Uncaught Error: Call to undefined function curl_init()
Zitat von: Mike_GKA am 15 November 2021, 12:52:33
Was kommt eigentlich im Browser an bei:
http://192.168.178.92/getdata.php
http://192.168.178.92/get.php?cmd=data
Was steht eventuell im Apache Error.log?
da kommt nichts im Browser
Scheint also daran zu liegen, dass die Funktion curl_init() nicht gefunden wird :(
Zitat von: Mike_GKA am 15 November 2021, 12:52:33
Dann versuche mal den airQ direkt anzusprechen mit
http://192.168.178.103/data
Was kommt da als Antwort?
Es müsste ein langer kryptischer JSON-String kommen der Art {"content": "--jede Menge kryptische Zeichen --"}
genau das kommt auch:
{"content": "CfiRFBo2TjLgOoIDo6d9nVnACjMu96qGFZHCLcrq6Urvh7qXFzWBOOGjrgUNy6QyCmLiiLS/l3s2iBj6kcnm9GB5nczIdUCz4/Uueh5gEt/rsFcEBdQzIIHUhDgtloR7kN5ZwblpfahCU21cNlWrc3bKW4FP3cW/TffCMiAGsoURShbdDScwpIaDeHES480QcG9QWCj+S3YzvEIwt7qAaejm+p1n/BsmI9BrhEhxMa48DZnhqhTVs4eT5yXuOzXYB7L5OqlpCuCTq9+NbHoBaF3Yrrk+BpxMNVQyKC7BeGHGVNRHmWGOhA+sEsqfwH9dHwPaYD4bDNMJ6IZIFHceDnW+Ojbp2V7TXnqelnZXTfdaX3nj17OVYNCI9URxv7t126iEIIlUdxosh4jWUdSJtzR+9J/P0yj2X1CBb9aDKPdyXyFbALZZZODOMZTkGsZ08hDF8+JSNiilMpD+Cu1Xm/PwIRFmDbrxKMHqtv2y79OGjPhwhwZDIkOnCCR9k1RRHhi2WkVGYu1CQPV+uxH3Q08oj0SlDiIK4ccoz73LO9wNxg6HtVqtBSj9Yv/cOV1gmyzOTOP/2CP7PE9Un3j9cUSzXOb+Q/jb1sahLSOzhYLY3gpCjJKf+apiTGTMs09BDSq3PoFQoUPtsC6pxHGCitayov6gYiThCTMTPpktsEBCW+Dw1ycMzSPX9JqqCrVe4e9KmdgWc69ECTpbaZG0nBhaVQmggdmM8mzwlPFz2xCVZHfoYymFLaiFv6U0B+5CFXiG6PF9954tAMvIg1V0Cj7N7opN2WFGjJb3F9bPWb/2tVvuLsOMs4dxrdRzZixlyCf6klBMRFKcq6Pxog3GfAb+iR9+Hy9eYXq2R1hzjeXi421qSx/+DiphlX/pwz6EPtGN8hA8Cx9wGxqcf2Omfw=="}
curl_init() nicht gefunden ...
Ich hab mal versucht, mit sudo apt-get install php-curl nachzuinstallieren, da kommt aber die Meldung Die folgenden Pakete haben unerfüllte Abhängigkeiten:
php-curl : Hängt ab von: php8.0-curl soll aber nicht installiert werden
E: Probleme können nicht korrigiert werden, Sie haben zurückgehaltene defekte Pakete.
Hintergrund: Ich hatte kürzlich von Stretch auf Buster upgegradet, da muss wohl was schiefgegangen sein?
Also zuerst einmal der airQ (auch in der Basic Version) sendet also seine Daten! Am airQ kann es also nicht liegen.
Jetzt auf OS-Ebene und php Installation wird es für mich etwas schwierig, da ich da absolut kein Spezialist mehr bin.
Ich würde zuerst inmal versuchen:
sudo apt-get update
sudo apt-get upgrade
Und dann php-curl nochmal installieren:
sudo apt-get install php-curl
Dann bin ich aber mit meinem "Latein" auch am Ende.
Ich habe mal gegoogelt und folgendes gefunden:
https://forums.raspberrypi.com/viewtopic.php?t=261703
https://forums.raspberrypi.com/viewtopic.php?t=246009
und vielleicht auch: https://www.mva.ch/support/tech-blog/techblog-raspberry/auf-raspibian-jessie-apache-php-7-und-mariadb-wordpress-installieren/
Vielleicht hilft das weiter?
Welche php Version setzt Du denn ein?
Danke Mike für deine Hilfe und die Anregung zum airQ, muss mal sehen, dass ich mit PHP weiterkommen.
By-the-way:
Mit MQTT hab ich die airQ-Anbindung hinbekommen, MQTT ist in FHEM sehr schön implementiert, die Readings werden mit autocreate angelegt sobald die JSON-Daten kommen
defmod MQTT2_airq1 MQTT2_DEVICE airq1
attr MQTT2_airq1 icon mqtt
attr MQTT2_airq1 readingList airq1:airq:.* { json2nameValue($EVENT) }
attr MQTT2_airq1 room MQTT2_DEVICE
attr MQTT2_airq1 stateFormat T temperature_1 / Gesundheit health / Leistung performance
setstate MQTT2_airq1 T 22.315 / Gesundheit 552 / Leistung 503
setstate MQTT2_airq1 2021-11-15 16:14:03 DeviceID 29ccb0d0399c619797c51189123c5b07
setstate MQTT2_airq1 2021-11-14 22:16:26 IODev myBroker
setstate MQTT2_airq1 2021-11-15 16:14:03 Status OK
setstate MQTT2_airq1 2021-11-15 16:14:03 TypPS 4.813
setstate MQTT2_airq1 2021-11-15 16:14:03 bat_1 0
setstate MQTT2_airq1 2021-11-15 16:14:03 bat_2 0
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt0_3_1 357.265
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt0_3_2 44.83
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt0_5_1 111.867
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt0_5_2 20.87
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt10_1 0.522
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt10_2 10.0
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt1_1 12.76
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt1_2 11.14
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt2_5_1 1.891
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt2_5_2 10.2
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt5_1 1.824
setstate MQTT2_airq1 2021-11-15 16:14:03 cnt5_2 10.2
setstate MQTT2_airq1 2021-11-15 16:14:03 co2_1 782.718
setstate MQTT2_airq1 2021-11-15 16:14:03 co2_2 73.48001
setstate MQTT2_airq1 2021-11-15 16:14:03 co_1 1.671
setstate MQTT2_airq1 2021-11-15 16:14:03 co_2 0.25
setstate MQTT2_airq1 2021-11-15 16:14:03 dCO2dt -21.74
setstate MQTT2_airq1 2021-11-15 16:14:03 dHdt -0.13
setstate MQTT2_airq1 2021-11-15 16:14:03 dewpt_1 8.807
setstate MQTT2_airq1 2021-11-15 16:14:03 dewpt_2 1.1
setstate MQTT2_airq1 2021-11-15 16:14:03 door_event 0
setstate MQTT2_airq1 2021-11-15 16:14:03 health 552
setstate MQTT2_airq1 2021-11-15 16:14:03 humidity_1 43.099
setstate MQTT2_airq1 2021-11-15 16:14:03 humidity_2 3.49
setstate MQTT2_airq1 2021-11-15 16:14:03 humidity_abs_1 8.553
setstate MQTT2_airq1 2021-11-15 16:14:03 humidity_abs_2 0.6
setstate MQTT2_airq1 2021-11-15 16:14:03 measuretime 1088
setstate MQTT2_airq1 2021-11-15 16:14:03 no2_1 26.941
setstate MQTT2_airq1 2021-11-15 16:14:03 no2_2 4.68
setstate MQTT2_airq1 2021-11-15 16:14:03 performance 503
setstate MQTT2_airq1 2021-11-15 16:14:03 person 0
setstate MQTT2_airq1 2021-11-15 16:14:03 pm10_1 3.184
setstate MQTT2_airq1 2021-11-15 16:14:03 pm10_2 10.0
setstate MQTT2_airq1 2021-11-15 16:14:03 pm1_1 1.41
setstate MQTT2_airq1 2021-11-15 16:14:03 pm1_2 10.0
setstate MQTT2_airq1 2021-11-15 16:14:03 pm2_5_1 1.659
setstate MQTT2_airq1 2021-11-15 16:14:03 pm2_5_2 10.0
setstate MQTT2_airq1 2021-11-15 16:14:03 pressure_1 1007.741
setstate MQTT2_airq1 2021-11-15 16:14:03 pressure_2 1.0
setstate MQTT2_airq1 2021-11-15 16:14:03 sound_1 34.862
setstate MQTT2_airq1 2021-11-15 16:14:03 sound_2 7.59
setstate MQTT2_airq1 2021-11-15 16:14:03 sound_max 38.1
setstate MQTT2_airq1 2021-11-15 16:14:03 temperature_1 22.315
setstate MQTT2_airq1 2021-11-15 16:14:03 temperature_2 0.49
setstate MQTT2_airq1 2021-11-15 16:14:03 timestamp 1636989184000
setstate MQTT2_airq1 2021-11-15 16:14:03 tvoc_1 1261.625
setstate MQTT2_airq1 2021-11-15 16:14:03 tvoc_2 198.71
setstate MQTT2_airq1 2021-11-15 16:14:03 uptime 55097
setstate MQTT2_airq1 2021-11-15 16:14:03 window_event 0
setstate MQTT2_airq1 2021-11-15 16:14:03 window_open 0
Ja es gibt "viele Wege nach Rom", bzw. die Daten vom airQ nach fhem zu bekommen.
Der airQ ist wirklich beispielhaft offen für alle Arten von Integrationen.
Da ich die airQ Daten auch noch anderweitig verwende, lasse ich den airQ seine Daten per http-post senden und verteile diese dann serverseitig u.a. auch an einen MQTT-Broker und fhem bedient sich dann auch über MQTT.
Den Fehler mit curl_init() konnte ich beheben, musste "nur" das richtige php7-curl installieren ;)
Jetzt bleibt noch der Fehler Trying to access array offset on value of type null in /var/www/html/get.php on line 97
$output = decrypt($json["content"],$password);
Der Vollständigkeit halber das komplette Skript "get.php". Nicht das aus dem thread hier sondern aus dem airQ-Forum <?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;
}
}
?>
heureka, mit dem Skript getdata.php läufts ;D
defmod airq_01_http HTTPMOD http://192.168.178.92/getdata 300
attr airq_01_http enforceGoodReadingNames 1
attr airq_01_http reading100JSON pm10_0
attr airq_01_http reading100Name pm10_0
attr airq_01_http reading101JSON cnt1_1
attr airq_01_http reading101Name cnt1_1
attr airq_01_http reading102JSON pressure_0
attr airq_01_http reading102Name pressure_0
attr airq_01_http reading103JSON performance
attr airq_01_http reading103Name performance
attr airq_01_http reading104JSON cnt5_0
attr airq_01_http reading104Name cnt5_0
attr airq_01_http reading105JSON pm10_1
attr airq_01_http reading105Name pm10_1
attr airq_01_http reading106JSON health
attr airq_01_http reading106Name health
attr airq_01_http reading107JSON cnt1_0
attr airq_01_http reading107Name cnt1_0
attr airq_01_http reading108JSON humidity_1
attr airq_01_http reading108Name humidity_1
attr airq_01_http reading109JSON cnt5_1
attr airq_01_http reading109Name cnt5_1
attr airq_01_http reading110JSON humidity_abs_1
attr airq_01_http reading110Name humidity_abs_1
attr airq_01_http reading111JSON uptime
attr airq_01_http reading111Name uptime
attr airq_01_http reading112JSON Status
attr airq_01_http reading112Name Status
attr airq_01_http reading113JSON dHdt
attr airq_01_http reading113Name dHdt
attr airq_01_http reading114JSON dewpt_1
attr airq_01_http reading114Name dewpt_1
attr airq_01_http reading115JSON pm1_1
attr airq_01_http reading115Name pm1_1
attr airq_01_http reading116JSON pm1_0
attr airq_01_http reading116Name pm1_0
attr airq_01_http reading117JSON cnt0_3_1
attr airq_01_http reading117Name cnt0_3_1
attr airq_01_http reading118JSON pm2_5_0
attr airq_01_http reading118Name pm2_5_0
attr airq_01_http reading119JSON co_1
attr airq_01_http reading119Name co_1
attr airq_01_http reading120JSON door_event
attr airq_01_http reading120Name door_event
attr airq_01_http reading121JSON dewpt_0
attr airq_01_http reading121Name dewpt_0
attr airq_01_http reading122JSON pm2_5_1
attr airq_01_http reading122Name pm2_5_1
attr airq_01_http reading123JSON measuretime
attr airq_01_http reading123Name measuretime
attr airq_01_http reading124JSON cnt0_3_0
attr airq_01_http reading124Name cnt0_3_0
attr airq_01_http reading125JSON timestamp
attr airq_01_http reading125Name timestamp
attr airq_01_http reading126JSON co2_1
attr airq_01_http reading126Name co2_1
attr airq_01_http reading127JSON co2_0
attr airq_01_http reading127Name co2_0
attr airq_01_http reading128JSON cnt2_5_0
attr airq_01_http reading128Name cnt2_5_0
attr airq_01_http reading129JSON sound_1
attr airq_01_http reading129Name sound_1
attr airq_01_http reading130JSON dCO2dt
attr airq_01_http reading130Name dCO2dt
attr airq_01_http reading131JSON cnt2_5_1
attr airq_01_http reading131Name cnt2_5_1
attr airq_01_http reading132JSON sound_0
attr airq_01_http reading132Name sound_0
attr airq_01_http reading133JSON tvoc_0
attr airq_01_http reading133Name tvoc_0
attr airq_01_http reading134JSON bat_1
attr airq_01_http reading134Name bat_1
attr airq_01_http reading135JSON bat_0
attr airq_01_http reading135Name bat_0
attr airq_01_http reading136JSON tvoc_1
attr airq_01_http reading136Name tvoc_1
attr airq_01_http reading137JSON DeviceID
attr airq_01_http reading137Name DeviceID
attr airq_01_http reading138JSON humidity_abs_0
attr airq_01_http reading138Name humidity_abs_0
attr airq_01_http reading139JSON co_0
attr airq_01_http reading139Name co_0
attr airq_01_http reading140JSON pressure_1
attr airq_01_http reading140Name pressure_1
attr airq_01_http reading141JSON temperature_0
attr airq_01_http reading141Name temperature_0
attr airq_01_http reading142JSON cnt10_1
attr airq_01_http reading142Name cnt10_1
attr airq_01_http reading143JSON cnt0_5_1
attr airq_01_http reading143Name cnt0_5_1
attr airq_01_http reading144JSON TypPS
attr airq_01_http reading144Name TypPS
attr airq_01_http reading145JSON humidity_0
attr airq_01_http reading145Name humidity_0
attr airq_01_http reading146JSON no2_0
attr airq_01_http reading146Name no2_0
attr airq_01_http reading147JSON no2_1
attr airq_01_http reading147Name no2_1
attr airq_01_http reading148JSON temperature_1
attr airq_01_http reading148Name temperature_1
attr airq_01_http reading149JSON cnt0_5_0
attr airq_01_http reading149Name cnt0_5_0
attr airq_01_http reading150JSON cnt10_0
attr airq_01_http reading150Name cnt10_0
attr airq_01_http room airQ
setstate airq_01_http 2021-11-15 18:40:39 DeviceID 29ccb0d0399c619797c51189123c5b07
setstate airq_01_http 2021-11-15 18:40:39 Status OK
setstate airq_01_http 2021-11-15 18:40:39 TypPS 1
setstate airq_01_http 2021-11-15 18:40:39 bat_0 0
setstate airq_01_http 2021-11-15 18:40:39 bat_1 0
setstate airq_01_http 2021-11-15 18:40:39 cnt0_3_0 393
setstate airq_01_http 2021-11-15 18:40:39 cnt0_3_1 48
setstate airq_01_http 2021-11-15 18:40:39 cnt0_5_0 129
setstate airq_01_http 2021-11-15 18:40:39 cnt0_5_1 23
setstate airq_01_http 2021-11-15 18:40:39 cnt10_0 0
setstate airq_01_http 2021-11-15 18:40:39 cnt10_1 10
setstate airq_01_http 2021-11-15 18:40:39 cnt1_0 5
setstate airq_01_http 2021-11-15 18:40:39 cnt1_1 10
setstate airq_01_http 2021-11-15 18:40:39 cnt2_5_0 0
setstate airq_01_http 2021-11-15 18:40:39 cnt2_5_1 10
setstate airq_01_http 2021-11-15 18:40:39 cnt5_0 0
setstate airq_01_http 2021-11-15 18:40:39 cnt5_1 10
setstate airq_01_http 2021-11-15 18:40:39 co2_0 922
setstate airq_01_http 2021-11-15 18:40:39 co2_1 77.66
setstate airq_01_http 2021-11-15 18:40:39 co_0 1.65
setstate airq_01_http 2021-11-15 18:40:39 co_1 0.2
setstate airq_01_http 2021-11-15 18:40:39 dCO2dt 22.44
setstate airq_01_http 2021-11-15 18:40:39 dHdt 0.04
setstate airq_01_http 2021-11-15 18:40:39 dewpt_0 9.218
setstate airq_01_http 2021-11-15 18:40:39 dewpt_1 1.1
setstate airq_01_http 2021-11-15 18:40:39 door_event 0
setstate airq_01_http 2021-11-15 18:40:39 health 481
setstate airq_01_http 2021-11-15 18:40:39 humidity_0 43.962
setstate airq_01_http 2021-11-15 18:40:39 humidity_1 3.49
setstate airq_01_http 2021-11-15 18:40:39 humidity_abs_0 8.79
setstate airq_01_http 2021-11-15 18:40:39 humidity_abs_1 0.61
setstate airq_01_http 2021-11-15 18:40:39 measuretime 968
setstate airq_01_http 2021-11-15 18:40:39 no2_0 28.03
setstate airq_01_http 2021-11-15 18:40:39 no2_1 4.6
setstate airq_01_http 2021-11-15 18:40:39 performance 370.6113
setstate airq_01_http 2021-11-15 18:40:39 pm10_0 2
setstate airq_01_http 2021-11-15 18:40:39 pm10_1 10
setstate airq_01_http 2021-11-15 18:40:39 pm1_0 2
setstate airq_01_http 2021-11-15 18:40:39 pm1_1 10
setstate airq_01_http 2021-11-15 18:40:39 pm2_5_0 2
setstate airq_01_http 2021-11-15 18:40:39 pm2_5_1 10
setstate airq_01_http 2021-11-15 18:40:39 pressure_0 1008
setstate airq_01_http 2021-11-15 18:40:39 pressure_1 1
setstate airq_01_http 2021-11-15 18:40:39 sound_0 37.7
setstate airq_01_http 2021-11-15 18:40:39 sound_1 6.3
setstate airq_01_http 2021-11-15 18:40:39 temperature_0 22.446
setstate airq_01_http 2021-11-15 18:40:39 temperature_1 0.49
setstate airq_01_http 2021-11-15 18:40:39 timestamp 1636998037000
setstate airq_01_http 2021-11-15 18:40:39 tvoc_0 1480
setstate airq_01_http 2021-11-15 18:40:39 tvoc_1 237.33
setstate airq_01_http 2021-11-15 18:40:39 uptime 63924
Mit der Fehlermeldung und insbesondere dass diese für Zeile 97 auftritt, kann ich nichts anfangen.
In Zeile 97 wird ja eine Dateianfrage bearbeitet, d.h. cmd=file wurde als Parameter übergeben. Damit kann man keine Integration in fhem machen!
Zitatheureka, mit dem Skript getdata.php läufts
Prima, dann viel Spaß mit den Werten in fhem!!
Ich bin immer noch begeistert, bekommt man doch eine Fülle von Luftqualitätsdaten. Interessant ist auch immer die Korrelation mit dem Wetter. Aktuell durch Inversionswetterlage, Nebel und den vielen Holzfeuerstellen in der Nachbarschaft ist die Luftqualität bedenklich gesunken.
Nachbarn haben Kinder mit Pseudo-Krupp und meine Enkel sind auch davon betroffen. Ich schätze mit diesen Werten kann man ein Frühwarnsystem für Pseudo-Krupp machen.
Zitat von: Mike_GKA am 15 November 2021, 18:57:10
Mit der Fehlermeldung und insbesondere dass diese für Zeile 97 auftritt, kann ich nichts anfangen.
In Zeile 97 wird ja eine Dateianfrage bearbeitet, d.h. cmd=file wurde als Parameter übergeben. Damit kann man keine Integration in fhem machen!
In dem Skript wie es bei mir läuft (hab da noch paar Leerzeilen mehr drin) ist Zeile 97 "$output = decrypt($json["content"],$password);"
if ($cmd == 'file') {
$output = decrypt($output,$password);
} else {
$json = json_decode($output, true);
$output = decrypt($json["content"],$password);
Aus der Hüfte geschossen würde ich sagen, dass curl hier gar nicht nötig ist. Ein Aufruf von file_get_contents() (https://www.php.net/manual/de/function.file-get-contents.php), wenn Parameter gebraucht werden im HTTP-Stream-Context, sollte völlig ausreichen und braucht kein zusätzliches Modul außer Openssl.
ZitatDer airQ ist wirklich beispielhaft offen für alle Arten von Integrationen.
Außer dass die Daten völlig nutzlos verschlüsselt werden? Und ist MQTT nicht nur bei dem teuren Paket dabei?
Zitat von: Christoph Morrison am 15 November 2021, 20:09:58
Und ist MQTT nicht nur bei dem teuren Paket dabei?
Ich hab einen airQ Basic aus der Finanzierungskampagne ohne Science-Option, da hab ich MQTT gestern zum Laufen bekommen
import base64
import json
from Crypto.Cipher import AES
import http.client
from Crypto import Random
########################
airqIP = '192.168.179.XXX'
airqpass = 'StrengGeheimesPasswort'
#########################
# Zur Entschlüsselung notwendige Funktionen
def encodeMessage(msg):
# AES-Schlüssel der Länge 32 aus dem air-Q-Passwort erstellen
key = airqpass.encode('utf-8')
if len(key) < 32:
for i in range(32-len(key)):
key += b'0'
elif len(key) > 32:
key = key[:32]
# Erster Schritt: AES256 verschlüsseln
iv = Random.new().read(AES.block_size)
cipher = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
msg = msg.encode('utf-8')
crypt = iv + cipher.encrypt(pad(msg))
# Zweiter Schritt: base64 enkodieren
msgb64 = base64.b64encode(crypt).decode('utf-8')
return msgb64
def pad(data):
length = 16 - (len(data) % 16)
return data + chr(length).encode('utf-8')*length
def unpad(data):
return data[:-ord(data[-1])]
def decodeMessage(msgb64):
# Erster Schritt: base64 dekodieren
msg = base64.b64decode(msgb64)
# AES-Schlüssel der Länge 32 aus dem air-Q-Passwort erstellen
key = airqpass.encode('utf-8')
if len(key) < 32:
for i in range(32-len(key)):
key += b'0'
elif len(key) > 32:
key = key[:32]
# Zweiter Schritt: AES256 dekodieren
cipher = AES.new(key=key, mode=AES.MODE_CBC, IV=msg[:16])
return unpad(cipher.decrypt(msg[16:]).decode('utf-8'))
# Verbindung zum air-Q aufbauen
headers = {'Content-type': 'application/x-www-form-urlencoded'}
connection = http.client.HTTPConnection(airqIP)
# Anfrage formulieren und Daten senden
connection.request("POST","/config","request="+encodeMessage('{"mqtt": {"device_id": "airq1","broker_URL": "192.168.179.XXX","user": "USERNAME","password": "PASSWORT","port": 1883,"topic": "airq","qos": 1,"keepalive": 10000,"averages": true,"delay": 120,"retain": false,"ssl": false}}'),headers)
contents = connection.getresponse()
connection.close()
# Daten entschlüsseln und ausgeben
msg = json.loads(contents.read())
print(msg['id'])
print(decodeMessage(msg['content']))
Quelle: https://hobbyblogging.de/air-q-mit-iobroker-vernetzen-per-mqtt
-> Christoph Morrison:
ZitatAußer dass die Daten völlig nutzlos verschlüsselt werden?
Nutzlos würde ich das nicht nennen, vielleicht für Dich und einige andere unnötig. Aber in größeren Netzwerken wäre es schon fatal, wenn jeder auf den airQ zugreifen könnte, insbesondere auch auf dei Konfiguration.
-> grappa24:
Statt die mqtt-Konfiguration per Python-Skript zu setzen kann man auch die Datei userconfig.json auf der SD-Karte editieren. Dazu muss man den airQ ausschalten und die SD-Karte entfernen und z.B. auf dem PC mit einem Texteditor editieren. Klar ist das etwas aufwendiger, aber i.a.R. macht man das ja auch nur ein Mal.
Eine weitere Alternative ist die kleine Web-Anwendung aus dem airQ-Forum: https://forum.air-q.com/topic/87/anwendung-f%C3%BCr-usercalibration-und-konfiguration-des-air-q-http-post?page=1
Zitat von: Mike_GKA am 16 November 2021, 09:55:24
Nutzlos würde ich das nicht nennen, vielleicht für Dich und einige andere unnötig. Aber in größeren Netzwerken wäre es schon fatal, wenn jeder auf den airQ zugreifen könnte, insbesondere auch auf dei Konfiguration.
Für Transportverschlüsselung gibt es TLS (https://de.wikipedia.org/wiki/Transport_Layer_Security), die - Überraschung - den Transport schützt. Über den Schutz der Konfiguration des Gerätes habe ich nichts gesagt.
Die Verschlüsselung ist ein
vendor lock in um die Science-Option verkaufen zu können, bzw. war es mal. Die Argumentation der Hersteller mit "Sicherheit" ist eine Lüge. Aber da sie ja nun den Algorithmus zur Entschlüsselung veröffentlicht haben, haben sie es wohl selbst eingesehen und nun ist es nur noch eine "nuisance", dass das Device nicht einfach nativ, ohne "Science-Option", MQTT macht sondern Gateways (das Python-/die PHP-Skripte) braucht.
Ich habe das Gefühl, da liegen noch ein paar Missverständnisse vor:
Wie wir gerade in diesem Thread herausgefunden haben, kann airQ Basic sowohl MQTT und hat auch die Verschlüsselung.
Das hier erwähnte Python-Skript dient zur Vereinfachung beim Konfigurieren des airQ. Das geht auch alles mit einem Text-Editor und der SD-Karte im airQ. Viele Konfigurationsmöglichkeiten bietet auch die Andriod- und iOS-App von airQ.
Das hier erwähnte php-Skript dient zur Integration des airQ in SmartHome-Lösungen wie z.B. fhem via HTTPMOD ohne über die airQ-Cloud zu gehen und ohne MQTT.
Zusammen heißt das, der airQ Basic lässt sich in SmartHome-Lösungen wie fhem via MQTT einbinden, OHNE sich mit Verschlüsselungen und irgendwelchen Python oder php-Skripten auseinandersetzen zu müssen.
Ich hab ja geschrieben, dass das mal anders war:
Zitathaben sie es wohl selbst eingesehen
Ich hatte den air-q damals bei Kickstarter auch in Betracht gezogen, aber das ist halt doch so ein echtes security by obscurity-Vorgehen ohne Mehrwert für den Nutzer gewesen. Ist denn nun der direkte Zugriff auch bei den "kleineren" Modellen möglich (lt. Website nicht)? Welches Modell habt ihr?
Ich hab den "normalen" mit 11 Sensoren aus der Kickstarter Kampagne.
Mit dem php-Skript von Micha kann ich die Daten mit HTTPMOD holen sowie mit dem angesprochenen Python Skript das Senden von MQTT-Nachrichten aktivieren.
Ich verstehe es auch nicht, wozu dann die Science-Option gut ist / sein soll.
Der air-q liefert via JSON für die Sensoren zwei Werte (jeweils in eckigen Klammern); der erste Wert ist der Meßwert, weiß jemand, was jeweils der zweite Wert bedeutet?
z.B. "co2": [1018.664, 80.56]
{"window_open": 0, "tvoc": [17453.72, 4078.84], "pm2_5": [1.231, 10.0], "window_event": 0, "DeviceID": "29ccb0d0399c619797c51189123c5b07", "measuretime": 1502, "humidity": [41.911, 3.79], "cnt0_3": [310.822, 40.21], "bat": [0, 0], "sound": [43.173, 4.51], "Status": "OK", "temperature": [22.247, 0.54], "cnt0_5": [98.03801, 19.54], "performance": 0, "co": [1.145, 0.18], "humidity_abs": [8.285, 0.64], "co2": [1018.664, 80.56], "uptime": 22008, "cnt2_5": [1.657, 10.0], "health": 0, "cnt10": [0.996, 10.0], "ch2o_M10": [486.192, 83.1], "no2": [26.957, 4.51], "cnt5": [0.999, 10.0], "timestamp": 1643825296000, "pressure": [1006.347, 1.0], "TypPS": 5.144, "dCO2dt": 79.99, "pm10": [2.327, 10.0], "sound_max": 55.1, "dHdt": 0.09, "pm1": [0.737, 10.0], "door_event": 0, "cnt1": [5.639, 10.45], "dewpt": [8.358, 1.2], "h2s": [47.694, 1.53], "person": 1}
Zitat von: grappa24 am 02 Februar 2022, 19:24:38
Der air-q liefert via JSON für die Sensoren zwei Werte (jeweils in eckigen Klammern); der erste Wert ist der Meßwert, weiß jemand, was jeweils der zweite Wert bedeutet?
z.B. "co2": [1018.664, 80.56]
Der zweite Wert ist die Fehlerabweichung in der Einheit des Meßwerts ;)
Hey danke für den tollen Beitrag hier zu unserem Produkt. Ich schreibe gerade eine Anleitung zum Thema und würde dich in einer Danksagung zum Thema auf der Supportseite erwähnen/verlinken. Ist das in Ordnung für dich, eventuell auch als Ansprechpartner hier im Forum zum Thema?
@Mike_GKA
@corant GmbH
Nichts zu danken. Und Ihr könnt mich gerne als Ansprechpartner nennen.