Freitag, 16. März 2018

IoT-Server: Umstellung Softwarestruktur & Plugins

Hallo,

In den letzten Wochen habe ich die Softwarestruktur meines IoT-Servers grundlegend überarbeitet.

Dieser lief und läuft auch weiterhin auf einem RaspberryPi 3B. Als Betriebssystem verwende ich WindowsIoT. Diese Wahl habe ich getroffen, um den Server in C# programmieren zu können. Bisher war dies allerdings nur über sogenannte "Background Tasks" möglich. Diese sind praktisch im Webinterface zu verwalten und können Remote per VisualStudio debuggt werden. Allerdings haben sie den Nachteil, dass sie wie Windows-Store-Apps gewissen Einschränkungen unterliegen.

Dazu gehört, dass sie nicht auf beliebige Dateien im Dateisystem zugreifen können, sondern nur Zugriff auf einen zur App gehörenden Ordner haben. Eine weitere Einschränkung ist, dass Code nicht dynamisch nachgeladen werden kann. Während das am Anfang nicht unbedingt ein Problem darstellte, hat das Projekt mittlerweile eine gewisse Größe erreicht. Dadurch nimmt die Übertragung des Projekts auf den Raspberry beim Debuggen viel Zeit in Anspruch. Daher wollte ich eine Aufspaltung des Projektes in den "Core-Server" und Plugins durchführen. Praktisch kann man diese Unterteilung in verschiedene Assemblys auch mit Background-Tasks durchführen, jedoch müssen alle verwendeten Assemblys in der gleichen Projektmappe liegen.

.NET Core Anwendung

Als ich mit der Programmierung des Servers 2016 begonnen habe, war ich auf die Background-Tasks angewiesen, da es keine relevanten Alternativen gab. Mittlerweile gibt es jedoch .NET Core Anwendungen. Diese ermöglichen die Programmierung von C# Anwendungen, theoretisch Plattform- und Architekturabhängig. Jedoch muss für jede Plattform/Architektur-Kombination eine passende Runtime-Umgebung installiert werden. Die offiziell freigegebenen sind [hier] erhältlich, die noch in der Entwicklung befindlichen (dazu gehört aktuell auch WindowsIoT auf dem Raspberry) dagegen [hier]. Da es aktuell noch keinen Installer für WindowsIoT gibt, habe ich die Dateien aus dem ZIP-Archiv einfach in den Windows/System32 Ordner kopiert.

Nun musste meine Server-Anwendung noch von "IoT-Background-Task" auf ".Net Core Anwendung" umgestellt werden. Da es dafür keine triviale Möglichkeit gibt, habe ich einfach eine neue Projektmappe mit den gleichen Projekten angelegt und die Quelldateien rüberkopiert. Dabei habe ich festgestellt, dass einige verwendete Klassen bzw. Namespaces hier nicht existieren. Die entsprechenden Codeabschnitte mussten also auf alternative Klassen umgestellt werden. Das betrifft konkret die Bereiche TCP/UDP-Kommunikation, sowie Dateisystemzugriff und Datenverschlüsselung. Außerdem muss ein neuer Programmeinstiegspunkt angelegt werden.

Sind alle Umstellungen abgeschlossen und wird die Projektmappe erfolgreich kompiliert, so kann das Startprojekt (in meinem Fall "HomeAutomationServerLauncher") via Rechtsclick und "Veröffentlichen" freigegeben werden. Dabei sollte darauf geachtet werden, dass als "Target-Runtime" "Portable" oder die Runtime des Zielsystems ausgewählt wird. Läuft dieser Prozess ohne Fehler durch, so liegen die erzeugten Dateien im "Target-Location"-Ordner.

Veröffentlichen eines Projektes unter Visual Studio
Das erzeugte Projekt befindet sich anschließend in "Target-Location"

Beim Betrachten der erzeugten Dateien fällt auf, dass keine ausführbare Datei (".exe") dabei ist. Diese wird nicht benötigt, da wir mit der "dotnet.exe" aus der .NET Runtime bereits eine solche haben. Das Programm kann also nun über PowerShell oder einer anderen Console per

dotnet "C:\Program Files\HomeAutomationServer\HomeAutomationServerLauncher.dll"

gestartet werden.

Autostart mit dem TaskScheduler

Um die Anwendung automatisch nach dem Start des Betriebssystems auszuführen, habe ich diesen Befehl in eine Batch-Datei geschrieben und diesen an den Windows-TaskScheduler angehängt. Dazu habe ich folgenden Befehl verwendet:

SCHTASKS /Create /SC ONSTART /TN HomeAutomationServer /TR "'C:\Program Files\HomeAutomationServer\Startup.bat'" /ru SYSTEM

Die Anwendung wird nun also bei jedem Windows-Start ausgeführt. Um die Anwendung sofort zu starten, kann man die Ausführung mit folgendem Befehl auslösen:

SCHTASKS /Run /TN HomeAutomationServer

Um die Anwendung wieder aus dem Scheduler zu entfernen, kann folgener Befehl verwendet werden:

SCHTASKS /Delete /TN HomeAutomationServer /f

Plugins

Da der Server nun nicht mehr in einer Sandbox läuft, kann er auch Assemblys und damit Plugins nachladen. Deswegen habe ich damit begonnen, einige Abschnitte in Plugins auszulagern. Angefangen habe ich mit der Alexa-Implementierung, da sich diese dafür besonders angeboten hat.

Bisherige Alexa-Kommunikations-Struktur

Der Grund dafür ist, dass der HTTP-Server, welcher die Alexa-Requests aus dem Internet bearbeitet, bisher in ein virtuelles Gerät ausgelagert war, welches ebenfalls als Background-Task auf dem Raspberry lief und sich intern mit dem Server verbunden hat. Nun läuft dieser als Plugin direkt auf dem Server. Gleichzeitig habe ich die zu Alexa gehörenden Logikelemente an diese Veränderung angepasst und mit in das Plugin ausgelagert. Beim Start des Servers sucht dieser nun im Plugin-Ordner nach ladbaren Assemblys und versucht in darin Plugins zu finden, welche daraufhin geladen werden.

Neue Alexa-Kommunikations-Struktur

Die Struktur mit Plugins wird es mir in Zukunft ermöglichen, den Server variabler zu gestalten und weiter zu einer einfacheren Handhabung zu verbessern. Zudem wird es, sollte ich mich jemals für eine Veröffentlichung des Projektes entscheiden, Nutzern ermöglichen, selbst den Server zu erweitern.

Donnerstag, 8. März 2018

Projektabschluss: Forschungsseminar Teil 2

Hallo,

wie bereits angekündigt, möchte ich heute die Umsetzung unseres Forschungsseminar-Projektes vorstellen. In [Teil1] ging es um die Projektidee und deren Konzeption.

Für die Umsetzung unserer erarbeiteten Konzepte hatten wir erneut ein Semester Zeit. Da wir unsere Bestelllisten bereits am Ende des ersten Semesters abgegeben hatten, konnten wir zunächst zügig unsere Lieferungen in Empfang nehmen. In Folge dessen konnte ich die geplante Schaltung auf einem Breadboard aufbauen.

Schaltungsaufbau auf Steckbrett
Mikroprozessor-Programmierung

Diesen provisorischen Aufbau habe ich genutzt, um die Programmierung zu beginnen. Es war nötig, dies zügig anzugehen, da davon die Arbeit der anderen Gruppenmitgliedern abhängte. Die Programmierung des Mikroprozessors habe ich in mehrere unabhängige Module (Antrieb, Eingabe, Kommunikation, etc.) unterteilt. Jedes der Module enthält eine "Init" und eine "Handle" Methode. Die Init-Methoden werden ein mal bei Programmstart ausgeführt, die Handle-Methoden anschließend in einer Schleife. Dadurch ist es möglich, Modulen mehr Rechenzeit zuzuordnen, wenn diese zeitkritisch behandelt werden müssen. Dies war insbesondere bei der Motorsteuerung von Vorteil, da die Steuerausgänge des Motors während einer Bewegung oft geändert werden müssen. In diesem Fall wird die Handle-Methode des Motors zehn mal öfter aufgerufen, als die Handle-Methoden der anderen Module.

Programmablaufplan Mikroprozessor

Kommunikation

Die Kommunikation mit der Einrichtungs-App erfolgt über WLAN. Ist dem System noch kein Netz bekannt, so wird ein eigener Hotspot aufgebaut. Zu diesem kann sich verbunden werden, um das System einzurichten und mit einem WLAN zu verbinden. Diese Verbindung ist optional, hat jedoch den Vorteil, dass das System von selbst die Uhrzeit aus dem Internet beziehen kann. Außerdem muss sich für spätere Änderungen nicht erneut zum Hotspot verbunden werden.

Als Transportprotokoll wird sowohl TCP, als auch UDP verwendet. TCP wird zur Übertragung von Daten verwendet, welche nur sporadisch gesendet werden, also beispielsweise die Änderung eines Parameters. UDP wird dagegen für zyklisch übertragene Daten verwendet. Dies sind sich ständig ändernde Werte wie der aktuelle Umgebungslichtwert oder die Rolloposition.

Platinenlayout

Parallel zur Programmierung musste die Schaltung in ein Platinenlayout übertragen und umgesetzt werden. Dazu habe ich die Bauteile auf kariertem Papier gezeichnet und angeordnet. Dabei habe ich insbesondere darauf geachtet, den Leistungsteil und den Logikteil zu trennen, da diese mit unterschiedlichen Spannungen arbeiten (12V und 5V). Als Resultat ergibt sich das folgende Layout.

Platinenlayout
Diese Layout habe ich im folgenden mit der Gruppe besprochen, da die Platine auch in ein Gehäuse integriert werden musste und dafür entsprechende Anschluss- und Befestigungsmöglichkeiten gegeben sein mussten. Da es jedoch keine Einwände gab, habe ich das Layout umgesetzt. Das folgende Bild zeigt eine fertige und eine für die Bestückung vorbereitete Platine.

Fertige und vorbereitete Platine
Tasterleiste

Zur lokalen Bedienung ohne App wurde eine Tasterleiste entwickelt. Diese besteht aus vier Tastern, welche über ein Wiederstandsnetzwerk an den analogen Eingang des ESP8266 angeschlossen sind. Die Tasterleiste ist optional an das Antriebsmodul ansteckbar. Da die Belegung der Tasten variabel und Geräteübergreifend vorgesehen war, hätte so nur eine Leiste für beispielsweise zwei Rollos verwendet werden können. Auf Grund knapper Bearbeitungszeit haben wir uns jedoch dazu entschlossen, die variable Belegung außenvor zu lassen. Stattdessen wurden die vier Tasten mit Standardfunktionen belegt, welche von allen im Netzwerk befindlichen Geräten ausgeführt werden. Diese Funktionen sind: "bis ganz oben fahren", "nach oben fahren, solange gedrückt", "nach unten fahren, solange gedrückt" und "bis ganz unten fahren".

3D-Modell der Tasterleiste
Die Leiste selbst besteht aus einer kleinen Lochrasterplatine, welche die vier Taster mit jeweils einem Widerstand enthält. Die Platine ist in einem Gehäuse eingefasst, welches aus aus Rückseite, Deckel und vier Tasterblenden besteht. Die Gehäuseteile wurden per 3D-Druck gefertigt. Leider war die Qualität des 3D-Drucks nicht besonders überragend, sodass die gedruckten Teile mehrere Stunden Nacharbeit benötigten, um zusammen zu passen, obwohl beim Design bereits Toleranzen vorgesehen wurde. Dieses Problem hat auch die Gehäuse für unsere Antriebsmodule, sowie einige andere Gruppen des Seminars betroffen. Den Grund für die schlechte Qualität vermute ich in den Druckeinstellungen. Da wir die Teile jedoch in der Uni fertigen haben lassen, hatten wir keinen Einfluss darauf.

Ein weiteres Problem war der Zusammenhalt des Gehäuses der Tasterleiste. Die Front und die Rückseite sollten über einen Schnappmechanismus zusammen halten. Leider habe ich diesen zu klein dimensioniert, sodass mittlerweile drei der vier Nasen abgebrochen sind. Normalerweise hätte ich die Teile noch einmal designt und erneut gedruckt, leider mangelte es aber auch dafür an der Zeit. Stattdessen haben wir die Teile mit Metallklammern versehen und mit Klebeband fixiert - schön ist es nicht, aber es hält  ¯\_(ツ)_/¯

Die Tasterleiste von der Planung bis zum fertigen Objekt

Abschluss

Am Ende des Semesters galt es, die Module an unseren Demonstrator anzubauen und für die Abschlusspräsentation vorzubereiten. Die folgenden Bilder zeigen unseren finalen Zustand, welchen wir auch letztendlich präsentiert und verteidigt haben.

Der Demonstrator in der Gesamtansicht

Eines der drei Antriebsmodule im geschlossenen Gehäuse

Ein anderes der Antriebsmodule mit offenem Gehäuse.
Dieses wurde offen gelassen, um bei der Präsentation einen Einblick zu gewähren

Die Tasterleiste an der linken Seite des Demonstrators.
Mit dem Abschluss dieses Projekts sollte es mir nun auch wieder möglich sein, weiter an meinen privaten Projekten zu arbeiten. An einigen Dingen habe ich bereits gearbeitet, aber darüber werde ich in einem zukünftigen Blogeintrag schreiben.