{"id":716,"date":"2019-08-21T17:45:09","date_gmt":"2019-08-21T15:45:09","guid":{"rendered":"https:\/\/azure.teamprojects.de\/?page_id=716"},"modified":"2019-09-17T16:54:33","modified_gmt":"2019-09-17T14:54:33","slug":"azure-function","status":"publish","type":"page","link":"https:\/\/azure.teamprojects.de\/?page_id=716","title":{"rendered":"Azure Function &#8211; Smart Home Master"},"content":{"rendered":"\n<h2><strong>Allgemein<\/strong><\/h2>\n\n\n\n<p>Mit Hilfe der Azure Function wird die zentrale Nachrichtenstelle des Cloudservice implementiert. Hier werden alle Nachrichten verarbeitet, die vom IoT-Hub empfangen und an die Default-Route weitergeleitet werden.  Die implementierte Azure-Function wird im weiteren Verlauf Smart Home Master genannt, da dies der Benennung in der Software entspricht.<\/p>\n\n\n\n<p>Der Smart Home Master empf\u00e4ngt JSON-codierte Nachtrichten, deren Aufbau dem von Enocean entspricht.  Derzeit k\u00f6nnen drei Nachrichtentypen verarbeitet werden. Telegram-, Device- und Command Nachrichten.  Telegram- und Device-Nachrichten werden vom Gateway verwendet, um Informationen in die Cloud zu senden.  Die Command Nachricht wurde von uns eingef\u00fchrt. Sie erm\u00f6glicht  Ger\u00e4ten, die nicht direkt programmiert werden k\u00f6nnen,  Nachrichten an andere IoT-Ger\u00e4te zu \u00fcbermitteln. <\/p>\n\n\n\n<h2><strong>Komponenten des Smart Home Masters<\/strong><\/h2>\n\n\n\n<p>Der Smart Home Master besteht im Wesentlichen aus zwei Komponenten. Die <em>Basisklasse<\/em> ist die Annahmestelle f\u00fcr eingehenden Nachrichten. Sie decodiert entsprechend des Nachrichtentyps und leitet im Anschluss alle weiteren Aktionen ein. Der<em> Datenbank Client<\/em> ist f\u00fcr Kommunikation mit der SQL-Datenbank zust\u00e4ndig. Er verwaltet die Verbindung zum Datenbankserver, ordnet die Daten den entsprechenden Tabellen zu und versendet die SQL-Querys.  <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/azure.teamprojects.de\/wp-content\/uploads\/2019\/08\/SmartHomeMasterMainLoop-1.png\" alt=\"\"\/><figcaption>Main Loop des Smart Home Master<\/figcaption><\/figure>\n\n\n\n<p>Wird eine<em> Command Message <\/em>empfangen, muss die empfangene Nachricht an das entsprechende Zielger\u00e4t weitergeleitet werden. Hierf\u00fcr unterh\u00e4lt der Smart Home Master eine Clientverbindung zum IoT-Hub. \u00dcber diese kann er die Anweisung geben eine Cloud-to-Device Nachricht zu versenden. Das Zielger\u00e4t wird \u00fcber den Inhalt der <em>Command Message<\/em> festgelegt. <\/p>\n\n\n\n<p>Der <em>Datenbank Client<\/em> kann Ger\u00e4te zur Datenbank hinzuf\u00fcgen oder Daten eines Ger\u00e4tes speichern. Mit einer <em>Device-Nachricht<\/em>, wird dem Gateway mitgeteilt, dass ein neues Ger\u00e4t hinzugef\u00fcgt wurde oder sich die Konfiguration eines bestehenden Ger\u00e4tes ver\u00e4ndert hat.  Der Datenbank Client liest den Ger\u00e4tetyp aus der Nachricht und erstellt dementsprechend die SQL-Query.  Mittels dieser wird \u00fcberpr\u00fcft, ob f\u00fcr die spezifizierte Ger\u00e4teklasse schon eine Tabelle existiert. Ist dies nicht der Fall, wird eine entsprechende Tabelle erstellt. Im Anschluss wird gepr\u00fcft, ob ein Eintrag in der Ger\u00e4tetabelle besteht. Wenn nicht, wird ein Passender hinzugef\u00fcgt.  Diese Funktionalit\u00e4ten sind innerhalb der SQL-Querys implementiert.  <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'tabSocket') \nBEGIN     \n    CREATE TABLE tabSocket(        \n        friendlyId VARCHAR(64) NOT NULL,        \n        sensorTimeStamp VARCHAR(25) NOT NULL,        \n        button VARCHAR(32),        \n        buttonValue VARCHAR(32),        \n        PRIMARY KEY (friendlyId, sensorTimeStamp)     \n    ); \nEND<\/code><\/pre>\n\n\n\n<p>Der Beispielcode zeigt die SQL-Query zum Erzeugen der Steckdosentabelle. Zuerst wird gepr\u00fcft, ob bereits eine Tabelle f\u00fcr Steckdosen existiert. Wenn nicht, wird eine Tabelle mit den angegeben Spalten erstellt.   Ist eine Steckdosentabelle vorhanden, wird nichts weiter gemacht. <\/p>\n\n\n\n<p>Derzeit wird nur der Fall abgedeckt, dass ein Ger\u00e4t neu hinzugef\u00fcgt wurde. \u00c4nderungen an bestehenden Ger\u00e4ten werden derzeit nicht ber\u00fccksichtigt.  Folgende Device-Typen sind unterst\u00fctzt:<\/p>\n\n\n\n<ul><li>Temperatur Sensoren<\/li><li>Bewegungsmelder<\/li><li>Fenster\/T\u00fcr Sensoren<\/li><li>Lichtschalter<\/li><li>Rollladen Schalter<\/li><\/ul>\n\n\n\n<p>Wird f\u00fcr ein bekanntes Ger\u00e4t eine Nachricht des Typs <em>Telegram<\/em> empfangen, liegen neue Daten vor, die in der Datenbank abgespeichert werden sollen. Somit bekommt der <em>Datenbank Client<\/em> den Auftrag, die Daten an die Datenbank zu \u00fcbertragen und in der, zum Ger\u00e4t passenden, Tabelle abzuspeichern.  Eine Query f\u00fcr diesen Fall kann folgenderma\u00dfen aussehen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private string buildQueryStoreShutterSwitchData(Telegram payload) \n{     \n    return $@\"     \n    INSERT INTO tabShutterSwitch(friendlyId, sensorTimeStamp,  button,\n                                 buttonValue)         \n        VALUES         \n        (             \n            '{payload.friendlyId}',\n            '{ConvertFromUnixTimestamp(payload.timestamp)}',          \n            '{payload.functions[0].key}',              \n            '{payload.functions[0].value}'          \n         );      \n    \"; \n}<\/code><\/pre>\n\n\n\n<p>Die Query wird von einer Funktion zusammengesetzt. Die Query selbst ist ein String, der an die Datenbank \u00fcbertragen wird. Mit Hilfe der Spracheigenschaften von C# werden die aktuellen Daten im String ersetzt und k\u00f6nnen somit zur Datenbank gesendet werden. <\/p>\n\n\n\n<h2><strong>Telegrammaufbau<\/strong><\/h2>\n\n\n\n<h3>Header<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>header\" : {    \n    \"httpStatus\" : null,    \n    \"code\" : null,    \n    \"message\" : null,    \n    \"content\" : \"telegram\",    \n    \"gateway\" : \"DC-GW\/EO-IP v1.0.12\",    \n    \"timestamp\" : 1559642972508  \n},<\/code><\/pre>\n\n\n\n<p>Jede Nachricht, besteht aus einem Header und einem nachrichtspezifischen Teil. Der Header enth\u00e4lt allgemeine  Informationen, wie den <em>Content<\/em>, der die Art der Nachricht definiert, der<em> Kennung des Gateways<\/em> und einem <em>Time-Stamp<\/em>.  Da der Wert <em>Content <\/em>des  Headers beschreibt, um welchen Typ von Nachricht es sich handelt,  muss  dieser zuerst ausgewertet werden, bevor der Rest der Nachricht  interpretiert werden kann. <\/p>\n\n\n\n<h3>Telegram Frame<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\"telegram\" : {    \n    \"deviceId\" : \"050B5032\",    \n    \"friendlyId\" : \"Steckdose1\",    \n    \"physicalDevice\" : \"eSchalter\",    \n    \"timestamp\" : 1559642972508,    \n    \"direction\" : \"from\",    \n    \"functions\" : [ {      \n        \"key\" : \"buttonBI\",      \n        \"channel\" : null,     \n        \"value\" : \"released\",     \n        \"meaning\" : \"Button released\",\n        \"unit\" : null,      \n        \"timestamp\" : null,      \n        \"age\" : null,      \n        \"relatedDeviceId\" : null,      \n        \"relatedFriendlyId\" : null    } ],    \n    \"signal\" : null,    \n    \"telegramInfo\" : {      \n        \"rorg\" : \"F6\",\n        \"data\" : \"40\",\n        \"status\" : \"30\",      \n        \"dbm\" : -58    \n    }  \n}<\/code><\/pre>\n\n\n\n<p>\u00dcber den Telegram-Frame werden aktuelle Ger\u00e4tedaten versendet. Es wird \u00fcbermittelt, um welches Ger\u00e4t es sich handelt, wann die Daten erfasst wurden und die eigentliche Payload. Diese ist unter <em>functions<\/em> zu finden. Sie ist als Array von Json-Objekten aufgebaut.  Jedes dieser Objekte ist ein Key-Value Paar, mit zus\u00e4tzlichen Metadaten. <\/p>\n\n\n\n<h3>Device Frame<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code> \"device\" : {\n   \"deviceId\" : \"050E720B\",\n   \"friendlyId\" : \"TemperaturHumidity_1\",\n   \"physicalDevice\" : \"Temperature\",\n   \"learnInProcedure\" : \"manuallyConfigured\",\n   \"eeps\" : [ {\n     \"eep\" : \"A5-04-02\",\n     \"variation\" : null,\n     \"version\" : 0.9,\n     \"direction\" : \"from\",\n     \"baseIdChannel\" : null\n   } ],\n   \"manufacturer\" : null,\n   \"location\" : \"D21 02.03\",\n   \"firstSeen\" : 1559820902997,\n   \"lastSeen\" : null,\n   \"secured\" : false,\n   \"functionGroups\" : null,\n   \"deviceType\" : null,\n   \"iotLabel\" : null,\n   \"productId\" : null,\n   \"remanState\" : null,\n   \"remanCode\" : null,\n   \"dbm\" : null,\n   \"softSmartAck\" : false,\n   \"transmitModes\" : [ {\n     \"key\" : \"temperature\",\n     \"transmitOnConnect\" : true,\n     \"transmitOnEvent\" : true,\n     \"transmitOnDuplicate\" : false\n   }, {\n     \"key\" : \"humidity\",\n     \"transmitOnConnect\" : true,\n     \"transmitOnEvent\" : true,\n     \"transmitOnDuplicate\" : false\n   } ],\n   \"configuration\" : null,\n   \"states\" : null,\n   \"operable\" : true,\n   \"supported\" : true,\n   \"deleted\" : null\n }\n<\/code><\/pre>\n\n\n\n<p>\u00dcber den Device Frame werden allgemeine Informationen zu einem Ger\u00e4t \u00fcbertragen. Es wird angegeben, welche Id ein Ger\u00e4t hat, wie es hei\u00dft, wo es sich befindet und von welchem Hersteller es stammt. Es werden noch eine Vielzahl an Zusatzinformationen bereitgestellt, die ,an dieser Stelle, aber nicht von Bedeutung sind und nicht ben\u00f6tigt werden um die Basisfunktionalit\u00e4t zu gew\u00e4hrleisten.   <\/p>\n\n\n\n<h3>Comand Frame<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\"comand\" : {\n     \"from\" : \"deviceName\",\n     \"to\"   : \"deviceName\",\n     \"payload\": \"\" \n}<\/code><\/pre>\n\n\n\n<p>Ein Comand Frame dient dazu, eine Nachricht an ein anderes IoT-Ger\u00e4t zu versenden, dass mit dem IoT-Hub verbunden ist.  <em>From<\/em> und <em>to<\/em> geben Quelle und Ziel der Nachricht an und m\u00fcssen den Ger\u00e4tenamen im IoT-Hub entsprechen. In <em>Payload<\/em> kann ein beliebiger Nachrichtenstring gespeichert werden. Dies kann, bei Bedarf, auch ein Json-Objekt sein.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Allgemein Mit Hilfe der Azure Function wird die zentrale Nachrichtenstelle des Cloudservice implementiert. Hier werden alle Nachrichten verarbeitet, die vom IoT-Hub empfangen und an die Default-Route weitergeleitet werden. Die implementierte Azure-Function wird im weiteren Verlauf Smart Home Master genannt, da dies der Benennung in der Software entspricht. Der Smart Home Master empf\u00e4ngt JSON-codierte Nachtrichten, deren &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/azure.teamprojects.de\/?page_id=716\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eAzure Function &#8211; Smart Home Master\u201c<\/span> weiterlesen<\/a><\/p>\n","protected":false},"author":100,"featured_media":0,"parent":671,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"_links":{"self":[{"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=\/wp\/v2\/pages\/716"}],"collection":[{"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=\/wp\/v2\/users\/100"}],"replies":[{"embeddable":true,"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=716"}],"version-history":[{"count":21,"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=\/wp\/v2\/pages\/716\/revisions"}],"predecessor-version":[{"id":1160,"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=\/wp\/v2\/pages\/716\/revisions\/1160"}],"up":[{"embeddable":true,"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=\/wp\/v2\/pages\/671"}],"wp:attachment":[{"href":"https:\/\/azure.teamprojects.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=716"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}