Hallo zusammen,
Wie jeden Winter wurde bei uns wieder Anfang Dezember die Weihnachtsdekoration ausgepackt, dazu gehört auch mein Lichterbogen. Diesen hatte ich auch schon die beiden letzten Jahre über mein HomeAutomation-System zeitgesteuert integriert. Durch die Veränderungen der letzten Monate hat sich aber nun die Möglichkeit gegeben, die Integration zu verbessern.
Zunächst möchte ich einmal zeigen, wie die Zeitsteuerung bisher gelöst war. Dies ist im ersten untenstehenden Bild dargestellt. Die Steuerung funktioniert nach dem im Folgenden beschriebenen Prinzip.
Es existieren zunächst zwei globale Ganzzahl-Variablen. Dieses Ganzzahlen (14 und 1) stellen die Stunden von Uhrzeiten dar, genauer von einer Start-Uhrzeit und einer End-Uhrzeit. Beide zusammen ergeben einen Zeitbereich von 14Uhr-1Uhr. Diese globalen Variablen werden über zwei "Globale-Variable"-Blöcke ausgelesen und jeweils in einen "Time Generator"-Block übergeben.
Diese wandeln Werte für Stunde, Minute und Sekunde in eine Uhrzeit in Millisekunden um, wobei alle drei Eingangswerte optional sind. Die beiden Uhrzeiten in Millisekunden werden nun an einen "InDailyTime"-Block übergeben.
Dieser gibt einen Boole'schen Wert aus (also ja/nein), welcher angibt, ob sich die aktuelle Zeit innerhalb oder außerhalb der beiden Uhrzeiten befindet. Mit fortlaufender aktueller Zeit ändert sich natürlich der Ausgabewert des letzten Blocks.
|
Alte Zeitsteuerung |
Diese Variante lief so (naja fast, die globalen Variablen waren ursprünglich mal lokale Konstanten) schon die beiden letzten Jahre. Dies hat einwandfrei funktioniert, hat aber diverse Nachteile. Erstens werden mehrere Variablen für die Zeitangabe benötigt, zweitens ist das Blockschema so schon unübersichtlich und drittens wird bei die Programmierung für weitere Zeitbereiche sehr schnell deutlich unübersichtlicher, da diese jeweils das gezeigte Schema benötigen.
Durch meine letzten Anpassungen, welche ich in den letzten Blogeinträgen beschrieben habe, hat sich nun die Möglichkeit ergeben, diesen Bereich zu optimieren. Bisher war das System auf die Grunddatentypen (Integer, Bool, Float, String, etc.) beschränkt. Jetzt gibt es aber die Möglichkeit weitere Datentypen anzulegen und zu verwenden. Dadurch hat sich das Blockschema auf folgendes Bild vereinfacht.
|
Neue Zeitsteuerung |
Das Schema hat nicht nur den Vorteil übersichtlicher zu sein, sondern ist dabei auch gleichzeitig deutlich funktionaler. Es verwendet den neuen Datentyp "TimeSchedule" (Zeitplan). Diesem Datentyp ist ein neuer Editor zugeordnet. Dieser ist genau auf den Datentyp zugeschnitten. Ein Zeitplan besteht zunächst aus einer beliebigen Anzahl von Gruppen. Jede Gruppe (im Bild "Woche" und "Wochenende") besitzt eine Zuordnung, an welchen Tagen die Gruppe gültig ist, sowie eine beliebige Anzahl an Zeitbereichen. Solange mindestens ein Zeitbereich einer beliebigen Gruppe aktiv ist, ist der Ausgabewert des Zeitplans "wahr", ansonsten "falsch".
|
Zeitplan-Editor |
Die Angabe von Zeitplänen ist dadurch nun deutlich einfacher. Die neuen Zeitpläne nutze ich nun beispielsweise auch, um dem System mitzuteilen, wann es Tag ist und wann Nacht. Daran ist wiederum eine Vielzahl an Dingen gekoppelt.
Bei der Programmierung der Logik-Elemente (Die Blöcke in den ersten beiden Bildern) habe ich nun allerdings ein Problem festgestellt. Für jeden Datentyp, den ich anlege, muss ich einen "Konstante"-Block erstellen. Dies ist zwar prinzipiell möglich, zieht aber nach sich, dass mit jedem Datentyp die Anzahl der Blöcke steigt. Sollte ich mich dazu entscheiden, dass Projekt für weitere Entwickler freizugeben, müssten auch diese für jeden neuen Datentyp dieser Regelung folgen.
|
Konstanten für jeden Datentyp |
Das ist zwar so schon nicht schön, es hätte aber vorübergehend funktioniert und ich hätte mich auch später noch darum kümmern können. Allerdings hat sich in Verbindung mit dem "Globale Variablen"-System gezeigt, dass ich es mir nicht so einfach machen kann. Denn ich hätte für jeden Datentypen auch noch einen Block für die globale Variable erstellen müssen.
Das ist nun gleich noch unschöner, hätte aber auch noch funktioniert. Nun ist aber seit kurzem jedes System als Plug-In realsiert. Das heist, das System "Globale Variablen" steht für sich, das System "Zeitplan" steht für sich, etc. Um nun also einen Block "Globale Variable (Typ Zeitplan)" zu erstellen, hätte ich die Spaltung in eigene Systeme auftrennen müssen. Das wollte ich dann doch vermeiden. Daher habe ich mir was intelligenteres einfallen lassen.
Den Programmierern unter den Lesern wird der Begriff "generic" bekannt sein. Für alle anderen möchte ich kurz erklären, worum es sich dabei handelt. Als generisch wird ein Objekt bezeichnet, welches mit verschiedenen Typen umgehen kann. Als Beispiel möchte ich eine Liste (C#) nennen. Eine Liste ist ein Objekt, welches mehrere Objekte eines Types enthält. Die Liste kann dabei mit allen möglichen Datentypen umgehen und besitzt verschiedene Funktionen, welche unabhängig vom Datentyp der enthaltenen Objekte sind. In C# erkennt man solche generischen Elemente an den Pfeilen, welchen den generischen Typ angeben. Im Beispiel der Liste mit dem enthaltenen Typ einer Ganzzahl würde dies so aussehen: List<int>
Um jetzt mal zum Thema zurückzukehren, möchte ich zeigen, was ich eingentlich getan habe. Es gibt nun einen neuen generischen Konstanten-Block, welcher alle bisherigen Konstanten-Blöcke ersetzt. Je nachdem, mit welchem Datentyp dieser Block verbunden wird, ändert sich der enthaltene Datentyp. Nach dem Verbinden kann anschließend der Wert der Konstante festgelegt werden.
|
Der Datentyp des neuen "Konstante"-Blocks ändert sich je nach angeschlossenen Typ. |
|
Nach dem Verbinden kann der Wert festgelegt werden. |
Der Typ des Blocks lässt sich jedoch nicht nur durch den angeschlossenen Datentyp bestimmen. Ist noch kein Datentyp angeschlossen, so bietet das Element eine Auswahl der Datentypen, welche alle nötigen Kriterien für Konstanten erfüllen. Diese Kriterien sind: Der Typ muss ich serialisieren (~speichern) und deserialisieren (~laden) lassen, und ihm muss ein Editor zugeordnet sein.
|
Das generische Element bietet eine Auswahl, welcher Datentyp verwendet werden soll. |
Es kann natürlich auch eine Mischung aus beiden Fällen auftreten. Beispielsweise beim Verbinden mit dem Additions-Element. Dieses unterstützt Eingänge vom Typ "Ganzzahl" und "Gleitkommazahl". Da dem Element nach dem Verbinden noch nicht bekannt ist, welchen Datentyp es enthalten soll, fragt es auch hier nach.
|
Das Element fragt bei einer Auswahl an Datentypen nach, welcher verwendet werden soll. |
Hinter dem Konstanten-Element steht ein System, welches es ermöglicht den Ausgabetyp eines Logikelements genau zu spezifizieren. Dieses System kann natürlich auch von allen anderen Logikelementen verwendet werden. Dadurch habe ich nun auch das"Globale Variablen"-Plug-In überarbeitet, sodass auch hier ein neues generisches Element existiert. Jeder Datentyp, der nun also die oben genannten Kriterien erfüllt, kann nun automatisch für globale und lokale Konstanten verwendet werden, ohne dass ein eigenes Logikelement erstellt werden muss.
Damit bin ich für heute auch schon wieder am Ende. Ich bedanke mich bei allen Lesern und wünsche schöne Weihnachten, sowie einen guten Start ins neue Jahr.
Markus