In der aktuell schwierigen Corona Situation ist es auch uns in den Büro-Räumen bei avocado software engineering wichtig, die Ansteckungsgefahr so gering wie möglich zu halten. Neben der Einhaltung des Mindestabstands war Ziel unseres Projektes die Raumluftqualität zu verbessern und so u.a. auch eine Ansteckungsgefahr durch Viren aller Art zu vermindern.
Des Weiteren leidet die Konzentration bei einem hohen CO2-Wert und kann zu Kopfschmerzen führen. Ein Grund mehr für uns einen Überblick über das Raumklima zu haben und gleichzeitig ein automatisiertes System zu entwickeln, welches uns mitteilt, wann es Zeit ist zu lüften.
Implementierung der Methoden
Mit einer einzigen Methode lässt uns Tinkerforge, der Hersteller des CO2-Sensors und der Wetterstation, die Daten des Messgeräts abrufen. Das macht die Weiterverarbeitung im Backend sehr einfach. Der Masterbrick ist das Herzstück der Wetterstation. Er ist für die Übermittlung und Verarbeitung der Daten zuständig. Dieser sollte immer auf dem neusten Stand sein, um Probleme mit neuen Sensoren auszuschließen.
Um auf die CO2-Konzentration reagieren zu können, schrieben wir eine Methode, die jedem Mitarbeiter über unser Büro-internes Chat-Programm eine Nachricht schickt, sobald die CO2-Konzentration im Raum zu hoch ist. In dieser Nachricht wird darum gebeten die Fenster zu öffnen und den Raum zu lüften.
Incoming Webhooks sind eine einfache Möglichkeit Nachrichten von einem externen Service, in unserem Fall vom Backend, an einen Messanger-Dienst zu schicken. In unserem Fall lässt sich dafür eine spezifische URL für die eigene Anwendung und die darin enthaltenen Benutzer generieren. An diese URL wird dann ein HTTP POST request geschickt, in der sich ein JSON Objekt befindet, welches die Nachricht beinhaltet.
public void createWarnPost() throws JSONException {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
JSONObject formInhalt = new JSONObject();
formInhalt.put("text", "Wenn möglich den Raum lüften :wind_face: ");
formInhalt.put("color", "#fff200");
JSONArray formArray = new JSONArray();
formArray.put(formInhalt);
JSONObject mainObj = new JSONObject();
mainObj.put("channel", "town-square");
mainObj.put("attachments", formArray);
HttpEntity<String> entity = new HttpEntity<>(mainObj.toString(), headers);
restTemplate.postForEntity(mattermostPostsettings.getUrl(), entity, String.class);
}
Weiter fügten wir eine Fallunterscheidung hinzu, die ab 1300 ppm bittet, die Fenster zu öffnen bzw. ab 1500 ppm dringend dazu auffordert Frischluft zu zuführen.
Ebenso werden wir benachrichtigt, wenn 1100 ppm wieder unterschritten wird, damit wir wissen, wann die Fenster wieder geschlossen werden können. Somit entsteht eine gesunde Arbeitsumgebung für alle Angestellten.
public void co2Concentration(int co2) {
if (brickletLCD != null) {
String text = String.format("Co2 Conc %4d ppm", co2);
try {
brickletLCD.writeLine((short) 3, (short) 0, text);
if (co2 > 1300 && !warnPostPosted1300) {
mattermostPost.createWarnPost();
warnPostPosted1300 = true;
} else if (co2 > 1500 && !warnPostPosted1500) {
mattermostPost.createWarnPostUrgent();
warnPostPosted1500 = true;
} else if (co2 < 1100 && warnPostPosted1300) {
mattermostPost.createPostEnough();
warnPostPosted1300 = false;
warnPostPosted1500 = false;
}
} catch (TinkerforgeException | JSONException e) {
logger.warn(e.getMessage());
}
}
}
Wetterstation Widget aktualisieren
Um die CO2-Konzentration im Laufe des Tages festzuhalten, erweiterten wir das vorhandene Wetterstation Widget um ein Diagramm, das uns zeigt, wie hoch der Wert in den letzten 5 Stunden war. Ebenso fügten wir ein Tachometer und ein Timeline-Diagramm für die CO2-Werte hinzu.
Zuletzt ersetzten wir die alten Diagramme durch neue. Die vorhandenen Diagramme auf Basis von AmCharts 2 wurden auf Version 4 aktualisiert. Als Datenvisualisierungsbibliothek bietet AmCharts eine riesige Anzahl verschiedener Diagramme, die sehr detailliert konfiguriert werden können.
function renderCo2(id, dataArray) {
am4core.useTheme(am4themes_animated);
// Create chart instance
var chart = am4core.create(id, am4charts.XYChart);
// Add data
chart.data = dataArray
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "id";
categoryAxis.startLocation = 0.5;
categoryAxis.endLocation = 0.5;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.labels.template.adapter.add("text", function (text) {
return text + " ppm";
});
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = "co2";
series.dataFields.categoryX = "id";
series.name = "Co2";
series.tooltipText = "Co2: [b]{valueY} ppm[/]";
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = am4core.color("#c2a11f");
series.strokeWidth = 2;
series.stroke = am4core.color("#c2a11f");
series.smoothing = "monotoneX";
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.fill = am4core.color("#c2a11f");
bullet.circle.strokeWidth = 2;
series.yAxis = valueAxis;
bullet.circle.zIndex = 999;
chart.cursor = new am4charts.XYCursor();
}
Im Grunde gibt es für jede Linie oder Form eine Methode oder Variable, mit der sich zahlreiche Charts darstellen lassen. In unserem Beispiel haben wir ein XY-Chart erstellt. Zuerst wurde ein Thema deklariert und daraufhin das gewünschte Diagramm direkt erstellt. Anschließend übergeben wir ihm eine Datengrundlage. Nachdem der X- und Y-Achse, Werte, Name, Farbe usw. zugeteilt wurden, zeichnen wir mit Bullet Points im Diagramm eine Linie, welche die CO2-Werte darstellt.
Hier ist das Ergebnis:
Zusätzlich fügten wir noch ein Tachometer für die CO2-Werte hinzugefügt. Dabei ist der Bereich von 0 bis 1000 ppm grün gefärbt, 1000 bis 1500 ppm gelb und darüber hinaus sind die Werte rot markiert. Als kleine Spielerei erstellten wir auch noch ein Timeline-Diagramm für die CO2-Werte. Darauf ist zu sehen, wie sich die CO2-Konzentration über den Tag entwickelt hat.