Da ich nicht jedes mal zum Bildschirm laufen möchte, wenn ich mir die Daten anzeigen lassen will, die mein Raspberry Pi gerade so gesammelt hat, baue ich im folgenden eine einfache Web Visualisierung mit Google Charts.
Voraussetzungen
Zunächst braucht man einen laufenden Server auf seinem Raspberry Pi. Wie das geht findet Ihr hier beschrieben: Apache und PHP installieren.
Außerdem hole ich mir die anzuzeigenden Daten über ein CGI Skript daher muss der Server auch noch diese Skripte zulassen: CGI Skripte auf Apache2 einrichten
Die anzuzeigenden Daten liegen in meinem Fall in JSON Dateien auf der Platte. Hier habe ich mal die notwendigen zwei Dateien beispielhaft dargestellt. Die Dateien legt Ihr bei euch auf der Platte ab und ändert die Dateiberechtigungen so ab, dass Ihr Leseberechtigung habt.
Das hier ist der Inhalt der Datei, die die aktuellen Werte beinhalten:
{"temperature": 23.0, "humidity": 64.6, "time_code": "Sat May 23 14:50:56 2020"}
Und hier eine verkürzte Datei, die die Verläufe der Daten beinhaltet:
[{"temperature": 23.0, "humidity": 63.0, "time_code": "2020-05-22 00:00:54"}, {"temperature": 23.0, "humidity": 60.0, "time_code": "2020-05-22 00:10:57"}, {"temperature": 23.0, "humidity": 50.0, "time_code": "2020-05-22 00:20:51"}, {"temperature": 23.0, "humidity": 50.0, "time_code": "2020-05-22 00:30:52"}, {"temperature": 20.0, "humidity": 63.0, "time_code": "2020-05-22 00:40:54"}, {"temperature": 20.0, "humidity": 63.0, "time_code": "2020-05-22 00:50:54"}, {"temperature": 20.0, "humidity": 63.0, "time_code": "2020-05-22 01:00:51"}, {"temperature": 23.0, "humidity": 63.0, "time_code": "2020-05-22 01:10:52"}, {"temperature": 23.0, "humidity": 63.0, "time_code": "2020-05-22 01:20:51"}, {"temperature": 23.0, "humidity": 63.0, "time_code": "2020-05-22 01:30:52"}, {"temperature": 23.0, "humidity": 63.0, "time_code": "2020-05-22 01:40:54"}, {"temperature": 23.0, "humidity": 63.0, "time_code": "2020-05-22 01:50:54"}]
HTML Code
Als erstes baut man sich am Besten die HTML Seite zusammen. Hier kann man natürlich viel Liebe reinstecken und designtechnisch richtig abräumen. Mir reicht aber erstmal eine Tabelle mit ein paar Zeilen, in die ich drei Elemente einfüge. Eine Anzeige für die Temperatur, eine weitere für die Luftfeuchtigkeit und ein Chart um die Verläufe von Temperatur und Feuchte der letzten zwei Tage anzuzeigen.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<h1 style="text-align:center">HomeDataViewer</h1>
<table style="width:100%; text-align:center">
<tr>
<th colspan="2">Wohnzimmer</th>
</tr>
<tr>
<td id="chart1_div" style="align: center; display: inline-block; margin: 0 auto"></td>
<td id="chart2_div" style="align: center; display: inline-block; margin: 0 auto"></td>
</tr>
<tr>
<td id="curve_chart" style="align: center; display: inline-block; margin: 0 auto" colspan="2"></td>
</tr>
</table>
</body>
</html>
<script type="text/javascript">
//<![CDATA[
google.charts.load('current', { 'packages': ['gauge'] });
google.charts.setOnLoadCallback(drawGaugeChart);
function drawGaugeChart() {
var myData1 = $.ajax({
url: "/cgi-bin/getCurTemp.py",
dataType: "json",
async: false
}).responseText;
var myData2 = $.ajax({
url: "/cgi-bin/getCurHumidity.py",
dataType: "json",
async: false
}).responseText;
var currentTemp = new google.visualization.DataTable(myData1);
var currentHum = new google.visualization.DataTable(myData2);
var optionsTemp = {
width: 600, height: 180,
redFrom: 30, redTo: 40,
yellowFrom: 26, yellowTo: 30,
greenFrom: 18, greenTo: 26,
minorTicks: 5,
min: 15,
max: 40
};
var optionsHum = {
width: 600, height: 180,
redFrom: 70, redTo: 90,
yellowFrom: 60, yellowTo: 70,
greenFrom: 30, greenTo: 60,
minorTicks: 5,
min: 20,
max: 90
};
var chart1 = new google.visualization.Gauge(document.getElementById('chart1_div'));
var chart2 = new google.visualization.Gauge(document.getElementById('chart2_div'));
chart1.draw(currentTemp, optionsTemp);
chart2.draw(currentHum, optionsHum);
}
google.charts.load('current', { 'packages': ['line'] });
google.charts.setOnLoadCallback(drawLineChart);
function drawLineChart() {
var myData = $.ajax({
url: "/cgi-bin/graph_cgi.py",
dataType: "json",
async: false
}).responseText;
var data = new google.visualization.DataTable(myData);
var options = {
chart:{
title: 'Humidity & Temperature'
},
width: 900,
height: 400,
series:{
0: {axis: 'Temperature', color: 'red'},
1: {axis: 'Humidity', color: 'blue'}
},
axes: {
y:{
Temperature: {label: 'Temperature'},
Humidity: {label: 'Humidity'}
}
},
hAxes: {
format: 'E, HH:mm',
gridlines: {count: 4}
},
legend: {position: 'none'}
};
var chart = new google.charts.Line(document.getElementById('curve_chart'));
chart.draw(data, google.charts.Line.convertOptions(options));
}
//]]></script>
Die CGI Skripte
Gemäß dem HTML Code oben benötige ich drei CGI Skripte
getCurTemp.py
Das Skript liest die aktuelle Temperatur aus der JSON Datei und bringt die Daten in das von Google Charts benötigte DataTable Format. Am Schluss wird der Datensatz zurückgegeben und im Skript weiterverarbeitet.
#!/usr/bin/env python
import json
from datetime import datetime
from time import strftime, strptime
timestamp = []
temperature = []
cold = []
rows = []
#construct cols for DataTable
col1={'label':'Description', 'type':'string'}
col2={'label':'Temperature', 'type':'number'}
cols = [col1, col2]
with open('PfadZurDateiMitDenAktuellenDaten', 'r') as read_file:
data = json.load(read_file)
r1 = {'v': 'Temperature'}
r2 = {'v': float(data['temperature'])}
c = {'c': [r1, r2]}
rows.append(c)
data = {'cols': cols, 'rows': rows}
json_data = json.dumps(data)
print('Content-type: application/json; charset=utf-8\n')
print(json_data)
getCurHumidity.py
Der Aufbau und Ablauf ist exakt der gleiche, wie für die Temperatur.
#!/usr/bin/env python
import json
timestamp = []
humidity = []
cold = []
rows = []
#construct cols for DataTable
col1={'label':'Description', 'type':'string'}
col2={'label':'humidity', 'type':'number'}
cols = [col1, col2]
with open('PfadZurDateiMitDenAktuellenWerten', 'r') as read_file:
data = json.load(read_file)
r1 = {'v': 'Humidity'}
r2 = {'v': float(data['humidity'])}
c = {'c': [r1, r2]}
rows.append(c)
data = {'cols': cols, 'rows': rows}
json_data = json.dumps(data)
print('Content-type: application/json; charset=utf-8\n')
print(json_data)
graph.py
Auch hier werden lediglich die Werte aus der JSON Datei in einer Schleife ausgelesen und in DataTable Format abgespeichert. Erwähnenswert ist, dass die Zeitangabe etwas Sortierarbeit benötigt, damit Sie der von Google Charts gewünschten Nomenklatur entspricht.
#!/usr/bin/env python
import json
from datetime import datetime
from time import strftime, strptime
timestamp = []
temperature = []
humidity = []
cold = []
rows = []
#construct cols for DataTable
col1={'label':'Timestamp', 'type':'date'}
col2={'label':'Temperature', 'type':'number'}
col3={'label':'Humidity', 'type':'number'}
cols = [col1, col2, col3]
with open('PfadZurDateiMitDenVerläufen', 'r') as read_file:
data = json.load(read_file)
for index in data:
#construct date string representation. Note January is 0 in date string but 1 in datetime object returned by strptime
time = strptime(index['time_code'],'%Y-%m-%d %H:%M:%S')
timeToStr = '{}, {}, {}, {}, {}, {}'.format(time.tm_year, time.tm_mon - 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec)
r1 = {'v': 'Date({})'.format(timeToStr)}
r2 = {'v': float(index['temperature'])}
r3 = {'v': float(index['humidity'])}
c = {'c': [r1, r2, r3]}
rows.append(c)
data = {'cols': cols, 'rows': rows}
json_data = json.dumps(data)
print('Content-type: application/json; charset=utf-8\n')
print(json_data)
Fertig. Ab jetzt kann die Seite im Browser aufgerufen werden und man muss nicht einmal mehr das Bett verlassen, um auf seine Daten zuzugreifen.
Sonstiges
Alle Details zu den Google Charts findet man hier: https://developers.google.com/chart