Solarregler Datalogger

Vorgeschichte

Auf unserem Haus ist eine Solaranlage installiert, die zur Warmwassererzeugung und zur Heizungsunterstützung dient. Leider haben die Klempner, die die Anlage damals installiert haben, bei der Montage der Anlage nicht besonders viel Wert auf eine vernünftige Verkabelung und sichere Montage des Solarreglers gelegt. Ursprünglich war der Regler direkt mit Kabelbindern an den isolierten Solarrohren befestigt und die Kabel überhaupt nicht zugentlastet. Entsprechend hatte nach ein paar Jahren der erste Regler Wackelkontakte auf der Hauptplatine durch die mechanische Belastung. Den Ersatzregler habe ich dann etwas besser montiert. Er ist auf eine zusätzliche Montageplatte geschraubt und die Kabel wurden zusätzlich über die Plate zugentlastet. So richtig zufrieden bin ich mit der Lösung auch noch nicht, aber leider ist die ganze Anlage so verbaut, dass es kaum andere Möglichkeiten gibt. Ansonsten müsste ich die gesamte Verkabelung der Anlage verlängern und umlegen.

Leider ist diese Lösung auch immer noch nicht technisch perfekt. Es kommt immer noch von Zeit zu Zeit vor, dass eines der Sensorkabel sich löst oder einen Wackelkontakt hat. Entsprechend misst die Anlage dann falsche Temperaturen und steuert die Solarpumpe und das Solarventil falsch an.

Im Sommer 2017 trat dann mal wieder eine Wackelkontakt auf, den ich aber erst zufällig bemerkt habe, als auch abends nach Sonnenuntergang die Solarpumpe noch lief. So was ist natürlich sehr ärgerlich, weil so die schöne Solarwärme nachts einfach wieder auf das Dach gepumpt wird und außerdem die Solarpumpe noch zusätzlich Strom verbrät. 😡 Um solche Fehler in Zukunft zu vermeiden, wollte ich das Monitoring an der Anlage verbessern. Zum Glück hat der neue Solarregler, ein Resol DeltaSol BS Plus , eine Busschnittstelle, die nur noch angezapft und ausgelesen werden muss…

Das Ziel

Der Solarregler DeltaSol BS Plus Regler soll mit einem Beaglebone ausgelesen werden, die Daten in einer Datenbank mitgeschrieben und grafisch aufbereitet werden. Dazu sollen die Daten des Solarreglers alle 5 Minuten in eine Round Robin Datenbank mit RRDTools geschrieben werden. Aus der Datenbank sollen dann entsprechend Diagramme erzeugt werden, die über den Webserver ausgeliefert werden.

Die Schnittstelle

Der DeltaSol BS Plus hat eine von Resol selbst definierte halb-duplex Schnittstelle, die sich VBus nennt. Bei meinem Regler ist dieser Bus als 2.Leiter Stromschnittstelle ausgeführt. Default-mäßig liegt dort eine Spannung von max. 8.2V mit 35mA an. Während einer Datenübertragung zieht jetzt ein Transistor im Regler den Bus bei einer “0” gegen GND. Zur Übertragung der “1” liegt die normale Betriebsspannung an. Die Übertragung selbst erfolgt normalerweise mit 9600 Baud mit 8 Datenbit, 1 Startbit und einem Stopbit.

Die vollständige Definition der Schittstelle und Parameter findet man z.B. unter VBus Spezifikation auf Github. Die Spezifikation dort wird übrigens direkt von Resol Mitarbeitern zur Verfügung gestellt, was ich persönlich sehr lobenswert finde! 👍

Um diese Schittstelle z.B. mit der seriellen Schnittstelle eines Beaglebone mitzulesen gibt es auf der Seite oben auch diverse Beispiel Schaltungen, die nicht besonders kompliziert aufgebaut sind. Allerdings lässt sich der Aufwand, wenn man nur einen Slave zum Auslesen an die Schnittstelle hängen möchte, sehr stark vereinfachen. Eigentlich reichen ein Optokoppler und zwei Widerstände. Wenn der Anschluss der Bus-Leitungen die Polung nicht beachtet werden soll, dann sind noch zusätzlich 4 Dioden als Gleichrichter notwendig.

Hier die vollständige Schaltung für den BaegleBone-Black. Als UART wird dort der UART 2 verwendet.

Schaltplan vBus Datalogger

Zur Funktionsweise: Solange eine “1” auf dem Bus anliegt, schaltet der Optokoppler die 3.3V auf den Eingang des Beaglebone durch. Liegt eine “0” auf dem Bus an sperrt auch der Transistor im Optokoppler und über den Widerstand R1 wird das Eingangssignal auf GND gezogen.

Fast&Fearless Testaufbau der Ausleseschaltung (ohne Dioden)

Freigabe UART2 beim Beaglebone

Bevor der UART2 des Beaglebones benutzt werden kann muss der Eingangspin an Stecker P9 Pin 22 entsprechend konfiguriert werden.

sudo config-pin p9.22 uart

Diese Einstellung ist aber nur aktiv bis der Beaglebone das nächste Mal gebootet wird. Wie die Konfiguration automatisch beim Booten erfolgt, kann dem Beaglebone CANBus Artikel entnommen werden.

Dekodierung des Protokolls

Die Dekodierung des Protokolls erfolgt in einem Python Script. Dazu müssen erst mal das RRDTool und die Python-Lib dafür installiert werden:

sudo apt-get install rrdtool python-rrdtool

Außerdem mus das Python Serial Interface installiert werden:
sudo pip install pyserial

Ein Verzeichnis unter “/home/debian/solarregler” anlegen mit:
mkdir /home/debian/solarregler"

Nun das Script anlegen mit:
nano /home/debian/solarregler/resol_logger.py

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#!/usr/bin/python
# Script for logging RESOL DeltaSol BS Plus to a RRDTOOL-Databank
# Thomas Wedemeyer 2017
# www.thomas-wedemeyer.de
# Remark: 	My system is using the System schemata 9 -> WMZ is not testet

import serial
import sys
import rrdtool
import os
  
temperatur_list = [0.0 for x in range(4)]
drehzahl1 = 0
drehzahl2 = 0
relmask = 0
errormask = 0
relTime1 = 0 
relTime2 = 0
#wmz = 0	# remove comment tag for WMZ-Support


def vbus_decode(rxd_list,byte_counter):
    global temperatur_list, drehzahl1,drehzahl2,relmask,errormask,relTime1,relTime2#,wmz
	
	#Check command
    if rxd_list[5] == 0x10:
	if ((rxd_list[1]!=0x10) | (rxd_list[2]!=0x0)):
		return False
        system = ((rxd_list[4]<<8) | rxd_list[3])
        print "Systemcode: ", hex(system)
        datasets = rxd_list[8]	#get the number of datasets
        print "Dataset=",datasets
        #copy the sepetts back to the msb of the bytes 
        for x in range(0,datasets-1,1):
            for bcnt in range(0,4,1):
                if(rxd_list[14+x*6] & (1<<bcnt)) > 0:
                    rxd_list[10+bcnt+x*6] = rxd_list[10+bcnt+x*6] | 0x80
        #crc is only for whiny people... so no  crc checking here

        #stip protocol information of the sepetts & crc
        protocolOffset = 0
        for i in range(0,datasets-1,1):
            for bytecnt in range(0,4,1):
                rxd_list[bytecnt+4*i] = rxd_list[10+bytecnt+4*i+protocolOffset]
            protocolOffset = protocolOffset + 2

        if system == 0x4221: #DeltaSol BS Plus V1
            if datasets != 7:
                return False
            #decoding of the message block according to VBusSpecificationResol.xml for Resol DeltaSol BS plus
            temperatur_list[0] = ((rxd_list[1]<<8) | rxd_list[0]) / 10.0
            print "Temperatur 0 =", temperatur_list[0]

            temperatur_list[1] = ((rxd_list[3]<<8) | rxd_list[2]) / 10.0
            print "Temperatur 1 =", temperatur_list[1]		

            temperatur_list[2] = ((rxd_list[5]<<8) | rxd_list[4]) / 10.0
            print "Temperatur 2 =", temperatur_list[2]

            temperatur_list[3] = ((rxd_list[7]<<8) | rxd_list[6]) / 10.0
            print "Temperatur 3 =", temperatur_list[3]	

            for x in range(0,4,1): # convert to signed temperatur
                if temperatur_list[x] > 3276.0:
                    temperatur_list[x] = temperatur_list[x] - 6553.4			
            
            drehzahl1 = rxd_list[8]
            print "Drehzahl 1=", drehzahl1			
            
            drehzahl2 = rxd_list[9]
            print "Drehzahl 2=", drehzahl2	
             
            relmask = rxd_list[10]
            print "Relmask=", hex(relmask)
            
            errormask = rxd_list[11]
            print "Errormask=", hex(errormask)
            
            time = ((rxd_list[13]<<8) | rxd_list[12])
            print "Time =", time/60,":",time%60			
            
            schema = rxd_list[14]
            print "Schema=", schema	
            
            relTime1 = ((rxd_list[17]<<8) | rxd_list[16]) 
            print "RelTime1 =", relTime1			
            
            relTime2 = ((rxd_list[19]<<8) | rxd_list[18]) 
            print "RelTime2 =", relTime2
            
            #wmz= ((rxd_list[21]<<8) | rxd_list[20]) + (((rxd_list[23]<<8) | rxd_list[22])*1000) + (((rxd_list[25]<<8) | rxd_list[24])*1000000)
            #print "WMZ = ",wmz
            return True

        elif system == 0x427b:  # DeltaSol BS Plus V2
            if datasets != 9:
                return False
            
            #decoding of the message block according to VBusSpecificationResol.xml for Resol DeltaSol BS Plus
            temperatur_list[0] = ((rxd_list[1]<<8) | rxd_list[0]) / 10.0
            print "Temperatur 0 =", temperatur_list[0]
    
            temperatur_list[1] = ((rxd_list[3]<<8) | rxd_list[2]) / 10.0
            print "Temperatur 1 =", temperatur_list[1]        
    
            temperatur_list[2] = ((rxd_list[5]<<8) | rxd_list[4]) / 10.0
            print "Temperatur 2 =", temperatur_list[2]
    
            temperatur_list[3] = ((rxd_list[7]<<8) | rxd_list[6]) / 10.0
            print "Temperatur 3 =", temperatur_list[3]   

            for x in range(0,4,1): # convert to signed temperatur
                if temperatur_list[x] > 3276.0:
                    temperatur_list[x] = temperatur_list[x] - 6553.4			
    
            drehzahl1 = rxd_list[8]
            print "Drehzahl 1=", drehzahl1            
    
            drehzahl2 = rxd_list[12]
            print "Drehzahl 2=", drehzahl2    
             
            relmask = rxd_list[10]
            print "Relmask=", hex(relmask)
            
            errormask = ((rxd_list[21]<<8) | rxd_list[20])
            print "Errormask=", hex(errormask)
            
            time = ((rxd_list[23]<<8) | rxd_list[22])
            print "Time =", time/60,":",time%60            
            
            schema = rxd_list[17]
            print "Schema=", schema    
    
            relTime1 = ((rxd_list[11]<<8) | rxd_list[10]) 
            print "RelTime1 =", relTime1            
    
            relTime2 = ((rxd_list[15]<<8) | rxd_list[14]) 
            print "RelTime2 =", relTime2
            
            #wmz= ((rxd_list[31]<<24) | (rxd_list[30]<<16) |(rxd_list[29]<<8) | rxd_list[28])*1000) + (((rxd_list[25]<<8) | rxd_list[24])*1000000)
            #print "WMZ = ",wmz
            return True
        else:
            print "System not supported"
            return True
    else:
        return False				


def check_database():
	if os.path.isfile("%s/resol_databank.rrd" % (os.path.dirname(os.path.abspath(__file__)))) == False:
		print "Database not found -> Create Database" 
		rrdtool.create(
	    	"%s/resol_databank.rrd" % (os.path.dirname(os.path.abspath(__file__))),
	     	"--start", "now",
	      	"--step", "300",			# 300sec -> 5Min
		  	"--no-overwrite",			# don't overwrite old database
		  	"DS:Temp_Collector:GAUGE:600:-25:150", # 600 sek -> 10Min Haertbeat, Min:-25, Max 150
		  	"DS:Temp_TankBottom:GAUGE:600:-25:150",
		  	"DS:Temp_TankTop:GAUGE:600:-25:150",
		  	"DS:Temp_Recirculation:GAUGE:600:-25:150",
		  	"DS:PumpSpeed:GAUGE:600:0:100",	# 600 Sec Heartbeat, Min:0, Max: 100%
		  	"DS:Valve:GAUGE:600:0:100",
		  	"DS:Error:GAUGE:600:0:255",
		  	"DS:PumpActiv:COUNTER:600:0:99999",
		  	"DS:ValveActiv:COUNTER:600:0:99999",
		  	#DS:Wmz:COUNTER:600:0:99999999
		  	"RRA:AVERAGE:0.5:1:2016", # Average 1 point, 2016 points = 7 days / 5min interval
		  	"RRA:AVERAGE:0.5:12:8760",# Average 12 points (1hour), 8760 Points = 1 Year (24*365)
		  	"RRA:MIN:0.5:288:3650", #Min 288 points (1Day), 3650 Points = 10 Years
		  	"RRA:MAX:0.5:288:3650",
		  	"RRA:LAST:0.5:288:3600") 
	else:
		print "Database allready exits"
		
		
def update_database():
	global temperatur_list, drehzahl1,drehzahl2,relmask,errormask,relTime1,relTime2

	# build data point
	data = 'N:'
	for i in range(4):
		data += str(temperatur_list[i])
		data +=':'
	
	data += str(drehzahl1)
	data +=':'
	data += str(drehzahl2)
	data +=':'
	data += str(errormask)
	data +=':'
	data += str(relTime1)
	data +=':'
	data += str(relTime2)
	#data +=':'
	#data += str(wmz)
 
 	print data
	# insert data into round-robin-database
	rrdtool.update(
  		"%s/resol_databank.rrd" % (os.path.dirname(os.path.abspath(__file__))),data)
					
 
def main():
	check_database()
	ser = serial.Serial(port = "/dev/ttyO2", baudrate=9600)
	ser.close()
	ser.open()
	rxd_list = [0 for x in range(70)]	#define a buffer for the receiver
	counter = 0
	if ser.isOpen():
		print "Serial is open!"
		try:
			while True:
				value = 0
				data = ser.read()
				value = ord(data)
				#print "Value: " , hex(value) 
				if value == 0xaa:
					#print "New Frame"
					if(counter > 0):
						if vbus_decode(rxd_list,counter) == True:
							update_database()
							ser.close()
							exit()	
					counter = 0
			
				rxd_list[counter] = value
				if(counter < 59):
					counter += 1

			
		except  KeyboardInterrupt:
			ser.close()


if __name__ == "__main__":
        main()

Was macht das Script: Das Script öffnet die TTY2 (UART2), wartet auf eine vollständige Nachricht, dekodiert sie und schreibt sie dann in die RRD-Datenbank. Wenn beim ersten Starten des Programms noch keine RRD-Datenbank angelegt ist, wird diese automatisch unter dem Namen “resol_databank.rrd” angelegt. Wenn man das Script manuell startet, werden außerdem die aktuellen Daten auf der Console ausgegeben.

Die Dekoder-Funktion ist sehr einfach zusammen gebastelt und unterstützt nur die Anlagen Resol DeltaSol BS Plus V1 und V2! Für andere Resol-Anlagen muss die Dekodierungsfunktion angepasst werden…

Bevor das Script gestartet werden kann muss es ausführbar gemacht werden mit:
chmod a+x resol_logger.py

Um das Skript alle 5 Minuten automatisch zu starten wird der Cron Dämon benutzt. Um dort einen neuen Job einzutragen fügt man nach dem Aufruf von crontab -e die folgende Zeile hinzu:
*/5 * * * * /home/debian/solarregler/resol_logger.py

Ausgabe der Temperaturkurven

Um die Auswertungsgrafiken automatisch zu erzeugen, werden zwei Bash-Scripte angelegt, die dann wieder um von Cron alle 5 Minuten bzw. einmal am Tag gestart werden.

nano /home/debian/solarregler/solarlog_day.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/sh
# Grafik erstellen
rrdtool graph /var/www/html/SolarDay.png \
-s 'now - 1 day' -e 'now' -w 640 -h 400 -t "Solaranlage Tagesverlauf" \
DEF:temp_collector=/home/debian/solarregler/resol_databank.rrd:Temp_Collector:AVERAGE \
LINE1:temp_collector#00FF00:Collector \
DEF:temp_tankb=/home/debian/solarregler/resol_databank.rrd:Temp_TankBottom:AVERAGE \
LINE1:temp_tankb#0000FF:"Tank Bottom" \
DEF:temp_tankt=/home/debian/solarregler/resol_databank.rrd:Temp_TankTop:AVERAGE \
LINE1:temp_tankt#FF0000:"Tank TOP" \
DEF:temp_rec=/home/debian/solarregler/resol_databank.rrd:Temp_Recirculation:AVERAGE \
LINE1:temp_rec#FF00FF:"Ruecklauf" \
DEF:pump=/home/debian/solarregler/resol_databank.rrd:PumpSpeed:AVERAGE \
CDEF:pump_scaled=pump,10,/ \
LINE1:pump_scaled#000000:"Pumpenspeed" \
DEF:valve=/home/debian/solarregler/resol_databank.rrd:Valve:AVERAGE \
CDEF:valve_scaled=valve,10,/ \
LINE1:valve_scaled#007f00:"Ventil" 

nano /home/debian/solarregler/solarlog_wmy.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/bin/sh
# Grafik erstellen
rrdtool graph /var/www/html/SolarMonth.png \
-s 'now - 1 month' -e 'now' -w 640 -h 400 -t "Solaranlage Monatsverlauf" \
DEF:temp_collector=/home/debian/solarregler/resol_databank.rrd:Temp_Collector:AVERAGE \
LINE1:temp_collector#00FF00:Collector \
DEF:temp_tankb=/home/debian/solarregler/resol_databank.rrd:Temp_TankBottom:AVERAGE \
LINE1:temp_tankb#0000FF:"Tank Bottom" \
DEF:temp_tankt=/home/debian/solarregler/resol_databank.rrd:Temp_TankTop:AVERAGE \
LINE1:temp_tankt#FF0000:"Tank TOP" \
DEF:temp_rec=/home/debian/solarregler/resol_databank.rrd:Temp_Recirculation:AVERAGE \
LINE1:temp_rec#FF00FF:"Ruecklauf" \
DEF:pump=/home/debian/solarregler/resol_databank.rrd:PumpSpeed:AVERAGE \
CDEF:pump_scaled=pump,10,/ \
LINE1:pump_scaled#000000:"Pumpenspeed" \
DEF:valve=/home/debian/solarregler/resol_databank.rrd:Valve:AVERAGE \
CDEF:valve_scaled=valve,10,/ \
LINE1:valve_scaled#007f00:"Ventil" \
DEF:pumptime=/home/debian/solarregler/resol_databank.rrd:PumpActiv:AVERAGE \
VDEF:pumpt=pumptime,TOTAL \
"GPRINT:pumpt:%lf"  

# Grafik erstellen
rrdtool graph /var/www/html/SolarWeek.png \
-s 'now - 7 day' -e 'now' -w 640 -h 400 -t "Solaranlage Wochenverlauf" \
DEF:temp_collector=/home/debian/solarregler/resol_databank.rrd:Temp_Collector:AVERAGE \
LINE1:temp_collector#00FF00:Collector \
DEF:temp_tankb=/home/debian/solarregler/resol_databank.rrd:Temp_TankBottom:AVERAGE \
LINE1:temp_tankb#0000FF:"Tank Bottom" \
DEF:temp_tankt=/home/debian/solarregler/resol_databank.rrd:Temp_TankTop:AVERAGE \
LINE1:temp_tankt#FF0000:"Tank TOP" \
DEF:temp_rec=/home/debian/solarregler/resol_databank.rrd:Temp_Recirculation:AVERAGE \
LINE1:temp_rec#FF00FF:"Ruecklauf" \
DEF:pump=/home/debian/solarregler/resol_databank.rrd:PumpSpeed:AVERAGE \
CDEF:pump_scaled=pump,10,/ \
LINE1:pump_scaled#000000:"Pumpenspeed" \
DEF:valve=/home/debian/solarregler/resol_databank.rrd:Valve:AVERAGE \
CDEF:valve_scaled=valve,10,/ \
LINE1:valve_scaled#007f00:"Ventil" \
DEF:pumptime=/home/debian/solarregler/resol_databank.rrd:PumpActiv:AVERAGE \
VDEF:pumpt=pumptime,TOTAL \
"GPRINT:pumpt:%lf" 

# Grafik erstellen
rrdtool graph /var/www/html/SolarYear.png \
-s 'now - 1 year' -e 'now' -w 640 -h 400 -t "Solaranlage Jahresverlauf" \
DEF:temp_collector=/home/debian/solarregler/resol_databank.rrd:Temp_Collector:AVERAGE \
LINE1:temp_collector#00FF00:Collector \
DEF:temp_tankb=/home/debian/solarregler/resol_databank.rrd:Temp_TankBottom:AVERAGE \
LINE1:temp_tankb#0000FF:"Tank Bottom" \
DEF:temp_tankt=/home/debian/solarregler/resol_databank.rrd:Temp_TankTop:AVERAGE \
LINE1:temp_tankt#FF0000:"Tank TOP" \
DEF:temp_rec=/home/debian/solarregler/resol_databank.rrd:Temp_Recirculation:AVERAGE \
LINE1:temp_rec#FF00FF:"Ruecklauf" \
DEF:pump=/home/debian/solarregler/resol_databank.rrd:PumpSpeed:AVERAGE \
CDEF:pump_scaled=pump,10,/ \
LINE1:pump_scaled#000000:"Pumpenspeed" \
DEF:valve=/home/debian/solarregler/resol_databank.rrd:Valve:AVERAGE \
CDEF:valve_scaled=valve,10,/ \
LINE1:valve_scaled#007f00:"Ventil" \
DEF:pumptime=/home/debian/solarregler/resol_databank.rrd:PumpActiv:AVERAGE \
VDEF:pumpt=pumptime,TOTAL \
"GPRINT:pumpt:%lf"

Nun die Scripte noch ausführbar machen:
chmod a+x /home/debian/solarregler/solarlog_wmy.sh

bzw.

chmod a+x /home/debian/solarregler/solarlog_day.sh

Um die Skripte automatisch zu starten werden mit crontab -e die folgende Zeile hinzugefügt:
*/5 * * * * /home/debian/solarregler/solarlog_day.sh
0 0 * * * /home/debian/solarregler/solarlog_wmy.sh

Nun muss das HTML-Verzeichnis ausführbar gemacht werden mit sudo chmod a+w /var/www/html

Mit nano durch die “index.html” anlegen: nano /var/www/html/index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<html>
<head>
<title>Solarlogger Diagramms</title>
</head>
<body>
<h1>Today</h1><br>
<div>
<img src="SolarDay.png" alt="Today" />
</div>
<h1>Week</h1>
<div>
<img src="SolarWeek.png" alt="Week" />
</div>
<h1>Month</h1>
<div>
<img src="SolarMonth.png" alt="Month" />
</div>
<h1>Year</h1>
<div>
<img src="SolarYear.png" alt="Year" />
</div>
</body>

Fertig! Jetzt kann das Ergebnis auf dem Beaglebone per Webbrowser auf dem Port 8080 angezeigt werden:

Webseite mit Temperaturkurven

Zu diesem Artikel gibt es noch eine Fortsetzung, wo die Daten des Solarreglers per MQTT verschickt werden. Mehr Info’s gibt es hier.