20

Heizung reloaded

Inzwischen ist es September und nach dem wir den Fehler in der alten Heizung nicht finden konnten und teurer Komponenten Austausch auf Verdacht der nächste Schritt gewesen wären haben wir uns für eine neue Heizung entschieden.

Die neue Heizung ist eine Weishaupt WTC-15A Kompaktgerät mit einem WCM-COM 1.0 Home, also hat meine Heizung nun eine Ethernet Schnittstelle.

Die erste Kontaktaufnahme war etwas holprig, mein Linux Laptop und das WCM-COM fanden sich nicht. Der Blick in die Doku half auch nur bedingt weiter da keine weiteren Angaben zur verwendeten IP Adresse enthalten sind und sich die Beschreibung auf Windows mit Internet Explorer bezieht.

Ein tcpdump auf der Schnittstelle zeigte nur DHCP Requests der Steuerung und Multicast DNS Announcements für wcm-com.local. Nachdem ich mit wieder vergegenwärtigt hatte was Windows macht wenn es keinen DHCP Server findet war die Lösung allerdings offensichtlich: auto-IP oder Automatic Private IP Addressing (APIPA). Damit konnte ich was WCM-COM Modul unter der DNS Namen wcm-com.local ansprechen.

Die nächste Überraschung war das ich zwar die Weboberfläche öffnen konnte aber ausser ein paar Rahmen und Navigation nix angezeigt wurde. Hier half der Wechsel des Browsers von Chromium zu Firefox. Inzwischen habe ich herausgefunden daß Google Chrome auch geht, aber mit Chromium hat die Box so ihre Schwierigkeiten…

Leider habe ich im Heizungsraum bei Renovierung der Hauses keine Ethernet Dose so dass ich weiterhin Wlan nutze um das WCM-COM Modul zu erreichen. Hierfür habe ich den Raspberry Pi aus meinen Heizungsmonitoring Setup umfunktioniert und die LAN Seite mit einer statischen Config versehen. dnsmasq sorgt dafür dass das WCM-COM auf der LAN Seite an statische IP Adresse bekommt und NAT auf der WLAN Seite reicht den Port 80 auf die Heizung weiter. Ein Masquerading auf der WLAN Seite sorgt dafür das die Heizung nach aussen kommunizieren kann.

Nach aussen hin spricht das WCM-COM SMTP wenn man den Mail Versand konfiguriert und XMPP wenn man den Zugriff auf die Heizung via App aktiviert. Bei dem Versand von Mails ist die Box aber recht pingelig mit meinem eigenen Mailserver baut sie eine Verbindung auf und legt gleich wieder auf nach dem sie das CaCert Zertifikat gesehen hat.

Leider ist der Zugriff auf die Heizung immer nur auf einem Weg möglich so dass der Zugriff auf das Webinterface nur möglich wenn man die App nicht gestartet hat und umgekehrt.

Eine offizielle API hat das WCM-COM nicht so dass ich darauf angewiesen war die WebApp auf dem WCM-COM mal genauer anzusehen. Die WebApp setzt auf einem ganzen Satz moderner Web-Techniken auf, die Seiten werden als XML Seiten an den Browser geliefert und der Browser nimmt Stylesheets auf der Heizung zum Erzeugen der angezeigten Seite. Die Programm-Logik steckt in Javascript Dateien und die Daten die die WebApp anzeigt kommen von einem JSON Endpunkt der via JS alle 30 Sekunden abgefragt wird.

Freundlicherweise ist das Javascirpt auf dem WCM-COM nicht obfuscated so dass es durchaus nachvollziehbar war wie und welche Daten abgefragt werden.

Ich habe also mein NodeRed Flow entsprechend erweitert und frage nun alle 10 Sekunden die Werte ab die mich interessieren:

weishaupt-nodered.png

Der JSON Request der an WCM-COM geschickt wird ist etwas obskur, da wird ein Array mir Array von Integern gesendet und in der Antwort kommt das Array mit Werten gefüllt zurück..

{"prot":"coco","telegramm":
  [
   [10,0,1,373,0,0,0,0],
   [10,0,1,138,0,0,0,0],
   [10,0,1,2572,0,0,0,0],
   [10,0,1,2,0,0,0,0],
   [10,0,1,3101,0,0,0,0],
   [10,0,1,325,0,0,0,0],
   [10,0,1,12,0,0,0,0],
   [10,0,1,14,0,0,0,0]
  ]
}

Was die einzelnen Werte bedeuten darf man sich aus dem Javascript Sourcen der WebApp zusammensuchen, für das oben gezeigte Telegram verwende ich folgende Funktion um dort Werte für meine InfluxDB zu machen:

// name: Decode WCM-COM
// outputs: 1
msg.payload = msg.payload.telegramm;

whinfo = {};


whinfo["[10,0,1,2572,0,0].name"] = "AussentempAvg";
whinfo["[10,0,1,2572,0,0].type"] = "TEMP"; 

whinfo["[10,0,1,2,0,0].name"] = "Waermeanforderung";
whinfo["[10,0,1,2,0,0].type"] = "TEMP"; 

whinfo["[10,0,1,12,0,0].name"] = "Aussentemp";
whinfo["[10,0,1,12,0,0].type"] = "TEMP"; 

whinfo["[10,0,1,14,0,0].name"] = "Warmwasser";
whinfo["[10,0,1,14,0,0].type"] = "TEMP"; 

whinfo["[10,0,1,138,0,0].name"] = "Laststellung";
whinfo["[10,0,1,138,0,0].type"] = "VALUE"; 

whinfo["[10,0,1,373,0,0].name"] = "Betriebsphase";
whinfo["[10,0,1,373,0,0].type"] = "VALUE"; 

whinfo["[10,0,1,3101,0,0].name"] = "Vorlauftemp";
whinfo["[10,0,1,3101,0,0].type"] = "TEMP"; 

whinfo["[10,0,1,325,0,0].name"] = "Abgastemp";
whinfo["[10,0,1,325,0,0].type"] = "TEMP"; 

for(var i = 0; i < msg.payload.length; i++) {
    var obj = msg.payload[i];
    var idx = "["+obj[0]+","+obj[1]+","+obj[2]+","+obj[3]+","+obj[4]+","+obj[5]+"]";

    var oname = whinfo[idx+".name"];
    var otype = whinfo[idx+".type"];

    if ((oname !== undefined) && (otype !== undefined)) {
        nmsg = {};
        nmsg.topic = msg.topic + "/" + oname;
        switch (otype) {
            case "TEMP":
                var temp;
                temp = (obj[6] + obj[7]*256) / 10;
                nmsg.payload = temp;
                break;
            case "VALUE":
                var value;
                value = (obj[6] + obj[7]*256);
                nmsg.payload = value;
                break;
        }
        // node.warn(nmsg)
        node.send(nmsg);
    }
}

return null;

Den Rest der nodered config ist in meinem Git Repository zu finden.