Viessmann Heizung auslesen

Viessmann Heizung auslesen

Wir haben eine Viessmann Vitodens 200-W Gastherme inkl. Solaranlage die über eine Vitotronic verfügt. Die Vitotronic hat eine optische Schnittstelle (Optolink) über die z.B. ein Heizungsmonteur verschiedene Parameter der Anlage auslesen und auch setzen kann.

vitotronic

Dafür benötigt man normalerweise den entsprechenden Lesekopf und eine passende Software der Fa. Viessmann.

Auf https://github.com/openv/openv/ gibt es aber auch eine andere Lösung! Die Jungs dort haben viel Arbeit in die „Entschlüsselung“ des Viessmann-Protokolls gelegt und verschiedene Anwendungen zur einfachen Kommunikation mit der Heizung entwickelt.

An dieser Stelle nochmal meinen Dank an dieses hervorragende Forum!

Unter den verschiedenen Bauanleitungen für die Leseköpfe habe ich mich für die USB-Variante entschieden. Mein Raspi hat ja noch einen USB-Anschluss frei und kann neben der Stromzählung und der Homematic-Steuerung auch noch die Heizung auslesen. Nicht das ihm langweilig wird…

Das Platinchen muss über die V-Ausfräsung hinter der Klappe befestigt werden. Das habe ich dann „professionell“ mit einem Papp-V und Tape erledigt. Hält!!

platine_frei

platine_tape

Ich nutze den vcontrold und da hier eine perfekte Anleitung zur Installation dieser Komponente auf dem Raspberry PI beschrieben ist, will ich auf die Installation und Konfiguration des Daemons auch nicht näher eingehen.

Der Daemon bietet eine Schnittstelle die z.B. mittels Telnet abgefragt werden kann. Ich nutze die Template-Möglichkeit (wird z.B. hier erklärt) um mehrere Heizungswerte auszulesen und die gelieferten Werte weiter verarbeiten zu können. Dazu wird bei mir folgendes Script (update.sh) alle 6 Minuten per Cron aufgerufen:

if [ !$(pgrep vclient) ]
then vclient -h localhost:3001 -f /opt/vcontrold/vc-commands.txt -t /opt/vcontrold/update.tmpl -x /opt/vcontrold/update.sh
fi

Der Eintrag in der Crontab sieht dann folgendermaßen aus:

*/6 * * * * sudo /opt/vcontrold/update.sh

Die Datei vc-commands.txt enthält eine Liste alle Werte die ausgelesen werden sollen. Diese Werte müssen auch in der „vito.xml“ definiert sein.

getTempA
getTempWWist
getTempKist
getTempKol
getTempSpu
getBrennerStarts
getBrennerStunden1
getSolarStunden
getSolarLeistung
getPumpeStatusSolar
...

In der Datei update.tmpl werden die zurück gelieferten Werte in Variablen geschrieben und können dann beliebig weiter verarbeitet werden (z.B. eine Prüfung ob ein Wert zurück gegeben wurde).

if  [ "x$E1" != x ]; then
     echo -n `date`  >>/tmp/vc-err.txt
     echo "es ist ein Fehler aufgetreten: $C1:$E1" >>/tmp/vc-err.txt
     exit 1;
fi
if  [ "x$E2" != x ]; then
     echo -n `date`  >>/tmp/vc-err.txt
     echo "es ist ein Fehler aufgetreten: $C2:$E2" >>/tmp/vc-err.txt
     exit 1;
fi
...

Auf der openv-Webseite wird oft eine rrdb zur Auswertung der Daten genutzt. Da ich mich mit einer rrdb nicht wirklich gut auskenne, schreibe ich die Daten lieber in eine MySQL-Datenbank.

Tabellenstruktur

Hierfür habe ich folgende Tabellen in der MySQL-Datenbank angelegt:

Tabellenstruktur für Tabelle brenner

CREATE TABLE IF NOT EXISTS `brenner` (
 `timestamp` datetime NOT NULL,
 `brennerstarts` float NOT NULL,
 `brennerstunden` float NOT NULL,
 `brennerstatus` int(11) NOT NULL,
 KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Tabellenstruktur für Tabelle solar

CREATE TABLE IF NOT EXISTS `solar` (
 `timestamp` datetime NOT NULL,
 `solarstunden` float NOT NULL,
 `solarleistung` float NOT NULL,
 `solarpumpe` int(11) NOT NULL,
 KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Tabellenstruktur für Tabelle temperaturen

CREATE TABLE IF NOT EXISTS `temperaturen` (
 `timestamp` datetime NOT NULL,
  `aussentemperatur` float NOT NULL,
  `warmwasser` float NOT NULL,
  `speicher_unten` float NOT NULL,
  `kollektor` float NOT NULL,
  `vorlaufsolltemperaturM2` float NOT NULL,
  KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Tabellenstruktur für Tabelle snapshot

CREATE TABLE IF NOT EXISTS `snapshot` (
 `timestamp` datetime NOT NULL,
 `brennerstatus` float NOT NULL,
 `brennerstarts` float NOT NULL,
 `brennerstunden` float NOT NULL,
 `solarstunden` float NOT NULL,
 `solarleistung` float NOT NULL,
 `aussentemperatur` float NOT NULL,
 `warmwasser` float NOT NULL,
 `speicher_unten` float NOT NULL,
 `kollektor` float NOT NULL,
 `kesseltemperatur` float NOT NULL,
 `vorlauftemperaturM2` float NOT NULL,
 `vorlaufsolltemperaturM2` float NOT NULL,
 `raumsolltemperaturM1` float NOT NULL,
 `raumsolltemperaturM2` float NOT NULL,
 `raumsolltemperaturredM1` float NOT NULL,
 `raumsolltemperaturredM2` float NOT NULL,
 `warmwassersoll` float NOT NULL,
 `kesseltemperatursoll` float NOT NULL,
 `pumpestatusM1` float NOT NULL,
 `pumpestatusSP` float NOT NULL,
 `pumpestatussolar` float NOT NULL,
 `statusstoerung` varchar(100) CHARACTER SET latin1 COLLATE latin1_german1_ci NOT NULL,
 `systemzeit` varchar(100) CHARACTER SET latin1 COLLATE latin1_german1_ci NOT NULL,
 `error0` varchar(500) CHARACTER SET latin1 COLLATE latin1_german1_ci NOT NULL,
 `BetriebArt` varchar(20) NOT NULL,
 `BetriebArtM2` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Die snapshot-Tabelle soll keine Historie enthalten, sondern immer nur eine Zeile mit den alle zwei Minuten ausgelesen Werten. Das hat sich nach ein paar Monaten Betrieb als sinnvoll erwiesen, da der Raspberry doch ganz schön ackern muss um aus einer Tabelle mit > 150.000 Zeilen (und wachsend) die aktuellen Werte auf der Webseite anzuzeigen.

Werte in Datenbank speichern

In oben beschriebene Datei update.tmpl werden dann die Werte genutzt, um sie in der MySQL-Datenbank zu speichen. Dazu nutze ich den Aufruf des Kommandozeilentools „mysql“ welches bei der Installation der Datenbank enthalten ist.

Hier die drei Aufrufe mit INSERT-Statements für die Temperatur-, die Solar und die Brennerdaten. In $1, $2 , $3, … stehen die Werte gemäß der Reihenfolge der vc-commands.txt.

mysql --user= --password=  -e "INSERT INTO temperaturen (timestamp,aussentemperatur,warmwasser,kollektor,speicher_unten,vorlaufsolltemperaturM2) values (CURRENT_TIMESTAMP,$1,$2,$4,$5,$13);"
mysql --user= --password=  -e "INSERT INTO solar (timestamp,solarstunden,solarleistung) values (CURRENT_TIMESTAMP,$9,$10);"
mysql --user= --password=  -e "INSERT INTO brenner (timestamp,brennerstarts,brennerstunden,brennerstatus) values (CURRENT_TIMESTAMP,$6,$7,IFNULL('$19',0));"

Für die Snapshot-Tabelle nutze ich ein Update-Statement da diese Tabelle immer nur eine Zeile enthalten soll.

mysql --user= --password=  -e "UPDATE snapshot SET timestamp=CURRENT_TIMESTAMP,aussentemperatur=$1,warmwasser=$2,kollektor=$4,speicher_unten=$5,solarstunden=$9,solarleistung=$10,brennerstarts=$6,brennerstunden=$7,kesseltemperatur=$12,vorlauftemperaturM2=$13,vorlaufsolltemperaturM2=$14,raumsolltemperaturM1=$15,raumsolltemperaturM2=$16,raumsolltemperaturredM1=$17,raumsolltemperaturredM2=$18,brennerstatus=IFNULL('$19',0),warmwassersoll=$20,kesseltemperatursoll=$21,pumpestatusM1='$22',pumpestatussp='$23',pumpestatussolar='$24',statusstoerung='$R25',systemzeit='',error0='$R27',BetriebArt='$R29',BetriebArtM2='$R30';"

Wenn der Cron eingerichtet ist, sollte die Datenbank alle 6 Minuten mit den ausgelesenen Werten gefüllt werden.

Anzeige der Daten

Die Anzeige der Daten erfolgt mittels Webseite und PHP-Script. Auf einer Übersichtsseite lese ich die Snapshot-Tabelle aus. Das geht Dank der Snapshot-Tabelle auch recht schnell.

temp_uebersicht

Auf einer weiteren Seite werden zusätzliche Werte aus der Snapshot-Tabelle angezeigt.

temp_details

Weil die Erstellung des Graphen nicht auf der Snapshot-Tabelle basiert, dauerte die Anzeige dieser Seite auch immer recht lange. Daher wird die PNG-Grafik für den Graph nun viertelstündlich per Script erstellt und nur noch das fertige Bild in der Webseite angezeigt.

Hier der Crontab-Eintrag für das Script zur Erstellung der Grafik:

*/15 * * * * sudo php /var/www/heizung/update_graph.php &> /dev/null

und das Script selber. Zur Erstellung des Graphen nutze ich pChart.

[cclN_php]
= NOW()“;
$query = mysql_query($sql) or die(„Anfrage nicht 1 erfolgreich“);
while ($wert = mysql_fetch_array($query)) {
$aussentemperatur[]=$wert[0];
$warmwasser[]=$wert[1];
$speicher_unten[]=$wert[2];
$kollektor[]=$wert[3];
$vorlauf[]=$wert[4];
if ($zeit_tmp==$wert[5])
{ $zeit_tmp=NULL; }
else
{ $zeit_tmp=$wert[5]; }
$zeit[]=$zeit_tmp;
}
mysql_close($connection);

$MyData = new pData();
$MyData->addPoints($aussentemperatur,“TempA“);
$MyData->addPoints($warmwasser,“TempW“);
$MyData->addPoints($speicher_unten,“TempS“);
$MyData->addPoints($kollektor,“TempK“);
$MyData->addPoints($vorlauf,“TempV“);
$MyData->addPoints($zeit,“Labels“);

$MyData->setSerieWeight(„TempA“,5);
$MyData->setSerieWeight(„TempS“,5);
$MyData->setSerieWeight(„TempW“,5);
$MyData->setSerieWeight(„TempK“,5);
$MyData->setSerieWeight(„TempV“,5);

$MyData->setSerieOnAxis („TempA“, 0);
$MyData->setSerieOnAxis („TempS“, 0);
$MyData->setSerieOnAxis („TempK“, 0);
$MyData->setSerieOnAxis („TempW“, 0);
$MyData->setSerieOnAxis („TempK“, 0);
$MyData->setAxisName(0,“Temperatur“);

$MyData->setSerieDescription(„Labels“,“Uhrzeit“);
$MyData->setSerieDescription(„TempA“,“Aussentemperatur“);
$MyData->setSerieDescription(„TempS“,“Speicher“);
$MyData->setSerieDescription(„TempW“,“Warmwasser“);
$MyData->setSerieDescription(„TempK“,“Kollektor“);
$MyData->setSerieDescription(„TempV“,“Vorlauf“);
$MyData->setAbscissa(„Labels“);

$serieSettings = array(„R“=>0,“G“=>0,“B“=>200);
$MyData->setPalette(„TempA“,$serieSettings);
$serieSettings = array(„R“=>200,“G“=>0,“B“=>0);
$MyData->setPalette(„TempS“,$serieSettings);
$serieSettings = array(„R“=>0,“G“=>200,“B“=>0);
$MyData->setPalette(„TempW“,$serieSettings);
$serieSettings = array(„R“=>0,“G“=>100,“B“=>100);
$MyData->setPalette(„TempK“,$serieSettings);
$serieSettings = array(„R“=>100,“G“=>100,“B“=>100);
$MyData->setPalette(„TempV“,$serieSettings);

$myPicture = new pImage(1205,330,$MyData);
$myPicture->Antialias = FALSE;
$myPicture->drawRectangle(0,0,1204,329,array(„R“=>111,“G“=>143,“B“=>204));
$myPicture->setFontProperties(array(„FontName“=>“/var/www/heizung/fonts/verdana.ttf“,“FontSize“=>11));
$myPicture->drawText(200,35,“Temperaturen der letzten 3 Tage“,array(„FontSize“=>12,“Align“=>TEXT_ALIGN_BOTTOMMIDDLE));
$myPicture->setFontProperties(array(„FontName“=>“/var/www/heizung/fonts/verdana.ttf“,“FontSize“=>7));
$myPicture->setGraphArea(50,40,1155,300);
$labelSkip = floor(count($zeit)/48);
$scaleSettings = array(„XMargin“=>10,“YMargin“=>10,“Floating“=>TRUE,“GridR“=>180,“GridG“=>180,“GridB“=>180,“DrawSubTicks“=>FALSE,“CycleBackground“=>TRUE,“ScaleSpacing“=>10,“LabelSkip“=>$labelSkip,“DrawYLines“=>array(0));
$myPicture->drawScale($scaleSettings);
$myPicture->drawLegend(600,20,array(„Style“=>LEGEND_NOBORDER,“Mode“=>LEGEND_HORIZONTAL));
$myPicture->Antialias = FALSE;
$myPicture->setShadow(TRUE,array(„X“=>1,“Y“=>1,“R“=>0,“G“=>0,“B“=>0,“Alpha“=>10));
$myPicture->drawLineChart(array(„DisplayValues“=>FALSE,“DisplayColor“=>DISPLAY_AUTO));
$myPicture->Render(„/var/www/heizung/tmp/temperaturen.png“);
?>
[/cclN_php]

Hier noch eine Übersichtsseite verschiedener Durchschnittswerte. Diese werden direkt mit Aufruf der Seite generiert was entsprechend lange dauert. Diese Seite schaue ich aber nicht so oft an…

temp_details2

Viel Spaß mit dem Auslesen der Viessmann-Heizung!
Chris

ehz – Baudrate in „Autostart“

Um die Baudrate für den Lesekopf im Artikel http://blog.bubux.de/?p=89 beim Start des Raspi automatisch zu setzen, kann der stty-Befehl in der Datei /etc/rc.local eingefügt werden.

Das schaut dann z.B. so aus:

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

sudo stty -F /dev/ttyUSB1 1:0:8bd:0:3:1c:7f:15:4:5:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

exit 0

Bei jedem Neustart des Raspi wird die Baudrate für den Lesekopf, der im Beispiel das Device „ttyUSB1“ ist, nun automatisch gesetzt. Das Device muss natürlich ggf. angepaßt werden.

Gruß Chris