Allgemein
Mit Hilfe des Azure App Service bietet sich die Möglichkeit ein auf die eigenen Bedürfnisse abgestimmtes Frontend (Website oder Webanwendung) mit verschiedensten Funktionen zu implementieren. Ein weiterer Vorteil dieses Services besteht darin, dass er sich beliebig skalieren lässt und die komplette Infrastruktur von Azure bereitgestellt wird.
Dieser Service wurde bei diesem Projekt genutzt, um eine eigene Website (Web-App) zu erstellen. Diese dient dazu, verschiedenste Informationen über die gewonnen Daten der Smart Home Komponenten zu liefern ohne einen direkten Zugriff auf den Microsoft Azure Account zu haben. Hierzu gehören unter anderem Live- und Historische-Daten. Für die Programmierung dieser Web-App wurde Hypertext Markup Language (HTML), Cascading Style Sheets (CSS) und Javascript verwendet. Hierbei wurde HTML als Grundlage für die Seitengestaltung genutzt. Mithilfe von CSS wurde das Aussehen der Seiten verbessert und optimiert. Der komplette Quellcode für die Funktionalität der Web-App wurde in Javascript geschrieben.
Link zur Website: https://h-dasmarthomeprojekt.azurewebsites.net/HistoryDataHtml/temperaturHumidityHistory.html

Funktion der Web-App

Aus der Abbildung ist zu entnehmen, wie der Informationsfluss innerhalb der Web-App grob funktioniert. Zu beachten ist hierbei, dass nur der Browser(Client) außerhalb der Azure Cloud liegt. Alle anderen Komponenten laufen in der Azure Cloud-Umgebung. Die Verbindung von der Cloud nach außen wird über einen WebSocket realisiert, welcher vom Web-App-Server geöffnet wird. Jeder neue Client verbindet sich automatisch mit dem WebSocket des Servers und kann somit über diesen bidirektional kommunizieren.
Damit Daten im Browser angezeigt werden, gibt es zwei Arten der Datengewinnung. Dem Nutzer können durch die beiden Arten sowohl Live- als auch Historische-Daten der Hardwarekomponenten angezeigt werden.
Das Anzeigen der Live-Daten funktionieren so, dass sobald Daten von einer Hardwarekomponente an die Cloud, genauer an den Azure-Event-Hub verschickt werden, diese aus dem Event-Hub abgegriffen und an die Web-App weitergeleitet werden. Dies passiert indem eine Instanz eines iotHubReader, welcher auf dem Server der Web-App läuft, den IoT Event-Hub überwacht und auf eingehende Nachrichten der Hardwarekomponenten wartet. Wird eine Nachricht empfangen, wird diese als JSON-Objekt codiert und über die broadcast Funktion an alle verbundenen Clients geschickt.
var iotHubReader = new iotHubClient(process.env['Azure.IoT.IoTHub.ConnectionString'], process.env['Azure.IoT.IoTHub.ConsumerGroup']);
iotHubReader.startReadMessage(function (obj, date) {
try {
console.log(date);
date = date || Date.now()
wss.broadcast(JSON.stringify(Object.assign(obj, { time: moment.utc(date).format('YYYY:MM:DD[T]hh:mm:ss') })));
} catch (err) {
console.log(obj);
console.error(err);
}
});
// Broadcast to all.
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
try {
console.log('sending data ' + data);
client.send(data);
} catch (e) {
console.error(e);
}
}
});
};
Die vom Server verschickte Nachricht wird vom Client über die Funktion onmessage empfangen. Dort wird der Inhalt der Nachricht ausgewertet und in das entsprechenden Diagramme geladen. Die in diesem Projekt zum Anzeigen der Daten verwendeten Diagramme stammen von einem Open Source Projekt namens Chart.js. Im folgenden ist ein Codebeispiel für den Temperatursensor und den Bewegungsmelder gegeben.
ws.onmessage = function (message) {
var messageObj = parseMesseage(message);
if(!messageObj.time && !messageObj.temperature && !messageObj.telegram) {
return;
}
if(messageObj.telegram){
switch (messageObj.telegram.friendlyId){
/*This is the temperature Sensor*/
case "SmartMotionDetector_2":
updateTempSensorChart(messageObj, TempSensor1Chart);
break;
case "SmartMotionDetector_1":
updateMotionDetectorChart(messageObj, MotionDetectorChart);
break;
default:
break;
}
}
}
Sind für den Nutzer die Live-Daten zurzeit nicht interessant, kann auf historische Daten zurückgriffen werden. Hierfür sendet der Client eine Anfrage über den WebSocket, als JSON-Objekt verpackt, an den Server welcher in der Azure Umgebung läuft. In dieser Anfrage stehen der Tabellenname, der Sensorname und die Anzahl der Datenpunkte welche angefordert werden sollen. Im folgenden ist der Code für die Anfrage an den Server für die Historischen-Daten des Temperatursensors zu sehen:
function getTemperatureData(webSocket)
{
var request =
{
tableName : "tabTemperatureSensor",
friendlyId: "SmartMotionDetector_2",
amountOfDataPoints : 100
}
webSocket.send(JSON.stringify(request));
}
Sobald der Server die Anfrage erhalten hat, wird die Nachricht geparsed und der Server greift auf die Datenbank zu, um die geforderten Information abzurufen.
wss.on('connection', function connection(ws){
ws.on('message', function incoming(message){
message = JSON.parse(message);
const myQuery = new SQLQuery();
myQuery.on('done', async () => {
let myVar = await myQuery.readTable(message.tableName,message.friendlyId,message.amountOfDataPoints);
console.log("Das sind die Daten aus der Tabelle",myVar);
wss.broadcast(JSON.stringify(myVar));
});
});
});
Nachdem die Informationen aus der Datenbank vorhanden sind, werden diese vom Server als JSON-Objekt verpackt und über die broadcast Funktion an alle Clients verschickt. Der Client der die Anfrage gestellt hat parsed die Nachricht und fügt die Informationen dem passenden Diagramm hinzu.
webSocket.onmessage = function(message){
parsedMessage = JSON.parse(message.data);
if(!(parsedMessage === undefined)){
if(!parsedMessage.telegram){
if(parsedMessage[0].value == "SmartMotionDetector_2"){
if(!tempSensorHisotoryFinsihed){
updateTemperatureSensoreChart(parsedMessage,TempSensor1Chart);
tempSensorHisotoryFinsihed = true;
}
}else if(parsedMessage[0].value == "SmartMotionDetector_1"){
if(!motionSensorHisotoryFinsihed){
updateMotionDetectorChart(parsedMessage, MotionDetectorChart);
motionSensorHisotoryFinsihed = true;
}
}
}
}
};
Eine direkte Anfrage vom Browser an die Datenbank ist nicht möglich und auch nicht vorgesehen. Der Browser würde hierfür die Einlogdaten der Datenbank benötigt und diese somit für jeden, der die Website aufruft, einsehbar machen. Dies muss vermieden werden. Der Weg über den Server ist somit nötig, um die Sicherheit der Datenbank zu gewährleisten. Unautorisierte Anfragen von Dritten können durch diesen Weg ausgeschlossen werden.