Reichweiten-Rechner für die WinMatic

Um fehlerhafte Akkus zu identifizieren, bastele ich mir einen Wegstreckenzähler

Meine WinMatic-Antriebe sind nun schon seit einigen Jahren im Einsatz. Den ersten hatte ich als Spielerei gekauft, um ihn mal auszuprobieren – und kurz danach dann viel Geld ausgegeben, um bis auf die Terrassentür alle Fenster damit auszustatten. Herrlich überflüssig, aber ein toller Spaß für erwachsene Spielkinder (sog. „Männer“).

Die Stromversorgung erfolgt über austauschbare Akku-Packs mit der schönen Typbezeichnung HM-Sec-Win-BaP, die direkt unten am Antrieb montiert werden. Sie können jederzeit geladen werden, auch ohne am Antrieb montiert zu sein, und wenn sie montiert sind und das Ladegerät angeschlossen wird, dann läuft die WinMatic auch mit Netzspannung. Wenn nur das hässliche Kabel nicht wäre.

Neue Script-Funktionen

Mit Firmware 2.29.22 wurden neue Funktionen in der Scriptsprache der CCU eingeführt, die auf dieser Seite genutzt werden. Achten Sie darauf, als Logikschicht-Version in den Systemeinstellungen der CCU nicht „Legacy“ zu wählen.

Wenn Sie eine ältere Firmware verwenden oder als Logikschicht-Version „Legacy“ ausgewählt haben, werden Sie Script-Fehler angezeigt bekommen, wenn Sie diese Anleitung umsetzen. Die Programme werden nicht funktionieren.

Aktualisieren Sie die Firmware Ihrer CCU! Wählen Sie „Standard“ als Logikschicht-Version aus!

Variablen in HomeMatic-Scripten

Die CCU hatte früher ein Limit von maximal 200 Variablen, das mit Firmware-Version 2.29.18 aufgehoben wurde. Dieses Limit bezog sich auf alle Variablen, die in allen Scripten verwendet werden. Gemeint sind Variablen, die direkt im Script definiert werden: object x; object y; var z;

Wenn Scripte nicht mehr funktionieren und bei der Prüfung unerklärliche Syntax-Fehler auftreten, sollte versuchsweise dieses Programm wieder gelöscht oder deaktiviert werden – oder, noch besser, auf die aktuelle Firmware-Version aktualisiert werden.

Strings in HomeMatic-Scripten

Durch String-Verwendung in HomeMatic-Scripten kann die CCU fehlerhaft arbeiten, instabil werden oder sogar abstürzen. Grundsätzlich gilt: Je öfter mit Strings hantiert wird, desto eher führt dies zu Problemen.

Ich empfehle daher, nach Umsetzung dieser Anleitung die CCU unter Beobachtung zu halten.

Akkus sind Verbrauchsmaterial

In den Akku-Packs befinden sich NiMh-Zellen, und die haben die unangenehme Eigenschaft, zu altern. Irgendwann muss der Akku öfter geladen werden, die „Batterie leer“-Warnung kommt früher, der Akku-Pack hat nicht mehr genug Kraft für den Drehantrieb … kurz: Irgendwann ist Schluss. Akkus sind halt Verbrauchsmaterial.

Das Problem ist, dass ich meine Akku-Packs munter im ganzen Haus herumtausche. Alle Fenster haben unterschiedliche Bewegungsprofile – manche gehen jeden Tag mehrmals auf und zu, andere bleiben über Tage geschlossen. Durch den regelmäßigen Austausch sind sehr wahrscheinlich alle Akku-Packs gleichmäßig belastet worden und sollten auch alle gleichzeitig kaputt sein. Sollten sie – aber sind sie es auch?

Wie kann ich herausfinden, welcher Akku-Pack tatsächlich kaputt ist und welcher noch nicht?

WinMatic-Bordcomputer

Wer schon mal eine Instrumententafel vor sich gesehen hat, dem wird das Konzept des Kilometerzählers nicht völlig unbekannt sein: eine Anzeige, die für jeden zurückgelegten Kilometer fleißig hochzählt.

Das bastele ich mir auch für die WinMatic: Bei vollem Akku wird der Zähler auf 0 zurückgesetzt und dann jedes Mal erhöht, wenn das Fenster bewegt wird. Dabei berücksichtige ich auch unvollständige Bewegungen – von 0% bis 100% wird mehr Strecke addiert, als wenn die WinMatic nur von 50% auf 70% bewegt wird. Auch den Verriegelungsvorgang rechne ich mit hinzu.

Wenn der Akku-Pack dann irgendwann leer ist, kann ich auf den Zählerstand gucken und weiß, ob er im Vergleich zu den anderen noch brauchbar ist oder nicht.

Der „Bordcomputer“ berechnet mir zwischendurch aus dem aktuellen Ladezustand die voraussichtliche Reichweite sowie das absehbare Austauschdatum – praktisch vor dem Urlaub. Ich sag ja immer, niemand braucht mehr als den Dreisatz im Leben.

Systemvariablen und Gewerke

Wie immer, wenn ich irgendwas irgendwo speichern oder anzeigen lassen möchte, brauche ich Systemvariablen. In diesem Fall gibt es für jeden Akku-Pack, den ich überwachen möchte, eine eigene Systemvariable vom Typ Zeichenkette. Diese Variablen wiederum sind dem jeweiligen Akku-Pack als Kanal zugeordnet.

Bei meinen acht Fenstern muss ich also acht Systemvariablen erstellen.

Der zweite wichtige Punkt ist, dass ich alle Akku-Packs in einem eigenen Gewerk zusammenfasse. Es können durchaus auch andere Kanäle mit im Gewerk sein, aber für die Ausführungsgeschwindigkeit des Scriptes wird es am Ende am besten sein, wenn möglichst wenige Kanäle abgearbeitet werden müssen.

Mein Gewerk heißt Energiemanagement. So heißt es schon seit vielen Jahren, weil ich den Namen damals toll fand und ihn seitdem nicht geändert habe. Man muss auch zu seinen Peinlichkeiten stehen.

Hier sind außer den Akku-Packs nur noch die Sensoren für meine selbstgebastelte Energiemessung enthalten sowie der Aktor für das WinMatic-Ladegerät in meinem Treppenhaus.

WebUI-Programm und Script

Das Script, in dem die eigentliche Intelligenz des Programms steckt, lasse ich von meinem Systemtakt auslösen.

Im Prinzip wäre es natürlich besser, wenn das Script stets genau dann laufen würde, wenn irgendetwas passiert ist – das Fenster bewegt wurde oder der Ladezustand des Akkus sich geändert hat. Allerdings müsste ich dann aufgrund der Logik von WebUI-Programmen jede Bedingung für jedes Fenster doppelt einbauen – macht sechs Bedingungen pro Fenster. Da ist der Systemtakt doch deutlich übersichtlicher.

Nachteil ist natürlich, dass das Script es nicht mitbekommt, wenn das Fenster zu schnell bewegt wird. Wenn der Systemtakt nur alle zweieinhalb Minuten läuft und das Fenster zwischen zwei Auslösungen von 30% auf 60% und gleich wieder zurück auf 30% bewegt wurde, dann wird im Script keine Bewegung erkannt.

Im Normalfall kommt das bei mir nicht vor, deshalb spielt es für mich in der Praxis keine große Rolle. Dazu kommt noch, dass mein Kilometerzähler natürlich kein hochpräzises Messinstrument wird, sondern eher der groben Abschätzung der Akkureichweite dient. Da kommt es auf vereinzelte nicht erfasste Fensterbewegungen nicht an.

Den Duty Cycle brauche ich hier nicht zu verwenden: Das Script löst keine Aktionen aus, die zu irgendwelchen Funk-Aktivitäten führen würden. Es kann also uneingeschränkt immer laufen.

Das Script wird mit 12 Sekunden Verzögerung ausgeführt. Man sieht es ihm nicht an, aber es erzeugt tatsächlich etwas Last auf der CCU – und außerdem entzerre ich eh alles, was am Systemtakt hängt.

! HomeMatic-Script
! REICHWEITEN-RECHNER FüR DIE WINMATIC
! http://www.christian-luetgens.de/homematic/programmierung/klima/reichweite/Reichweite.htm

! Objekte
object o_winmatic;
object o_akku;
object o_antrieb;

! Werte
object o_akku_reichweite;
integer i_akku_level;
integer i_antrieb_level;
integer i_strecke;
time t_timestamp;

! Ergebnis
integer i_reichweite;
time t_zeit;
string s_status;

! Hilfsvariablen
string s;
integer i;

! Konstanten
string tab = "\t";
time now = system.Date ("%F %T").ToTime();

foreach (s, dom.GetObject ("Energiemanagement").EnumUsedIDs()) {
  o_akku = dom.GetObject (s);
  o_winmatic = dom.GetObject (o_akku.Device());
  o_akku_reichweite = dom.GetObject (o_akku.DPs().GetAt (2));
  if ((o_akku.HssType() == "AKKU") && (o_winmatic.HssType() == "HM-Sec-Win") && (o_akku_reichweite)) {
    s_status = o_akku_reichweite.Value().Replace ("<br />", tab).Replace (": ", tab);
    t_timestamp = s_status.StrValueByIndex (tab, 3).ToTime();
    i_antrieb_level = s_status.StrValueByIndex (tab, 5).ToInteger();
    i_strecke = s_status.StrValueByIndex (tab, 7).ToInteger();

    i_akku_level = (o_akku.DPByHssDP ("LEVEL").Value() * 100).Round().ToInteger();
    if ((i_akku_level == 100) || (t_timestamp.ToInteger() <= 0)) {
      t_timestamp = now;
      i_strecke = 0;
      i_reichweite = 0;
      t_zeit = now;
    } else {
      o_antrieb = o_winmatic.Channels().GetAt (1);
      i = o_antrieb.DPByHssDP ("LEVEL").Value();
      if (i < 0) {
        i = -100;
      } else {
        i = (i * 100).Round().ToInteger();
      }      
      if (i <> i_antrieb_level) {
        i_strecke = i_strecke + (i_antrieb_level - i).Abs().ToInteger();
        i_antrieb_level = i;
      }
      i_reichweite = (((1.0 * i_strecke) / (100 - i_akku_level)) * 100).Round().ToInteger();
      t_zeit = ((((1.0 * (now.ToInteger() - t_timestamp.ToInteger())) / (100 - i_akku_level)) * 100) + t_timestamp.ToInteger()).ToInteger().ToTime();
    }

    s_status = "<span style=\"color:black;\"><br /><br />" #
    "Volladung<br />" # t_timestamp # "<br />" #
    "Fenster: " # i_antrieb_level # "<br />" #
    "Strecke: " # i_strecke # "<br />" #
    "Reichweite: " # i_reichweite # "<br />" #
    "Akkuwechsel: " # t_zeit.Format ("%F") # 
    "</span>";
    o_akku_reichweite.State (s_status);  
  }
}

!  Ende des Scripts

Und so funktioniert das Script:

Variablendeklaration

Zunächst führe ich meine Variablen ein, mit denen ich im Script arbeiten werde. Ohne Variablendeklaration gibt es Scriptfehler, gerade so, als sei die Scriptsprache der CCU eine richtige Programmiersprache.

Ganz am Ende definiere ich noch zwei Konstanten: ein Tabulator, um irgendwelche Bugs der CCU zu umgehen, und die Zeit aus Bequemlichkeit.

Schleife

Das eigentliche Programm ist eine einzige große Schleife: Mein Gewerk Energiemanagement wird gesucht und alle Kanäle der Reihe nach abgearbeitet. o_akku enthält den Kanal (vielleicht ein Akku-Pack), o_winmatic enthält das Gerät, zu dem der Kanal gehört, und o_akku_reichweite die Systemvariable, die dem Akku-Pack zugeordnet ist.

Nur wenn o_akku tatsächlich ein AKKU ist, o_winmatic eine HM-Sec-Win und o_akku_reichweite existiert, geht es weiter.

Status-Systemvariable laden

Der Inhalt der Systemvariablen, die dem Akku-Pack zugeordnet ist, wird zunächst in s_status gespeichert. Dabei werden einige Formatierungen, die zur Anzeige benötigt werden, durch Tabulatoren ersetzt.

Danach werden die bisherigen Werte ausgelesen: t_timestamp gibt den Zeitpunkt der letzten Vollladung an, i_antrieb_level den Öffnungswinkel beim letzten Durchlauf des Scriptes und i_strecke schließlich ist der eigentliche Kilometerzähler.

Strecke zurücksetzen

In i_akku_level wird der aktuelle Ladezustand des Akkus gespeichert. Liegt er bei 100% oder enthält t_timestamp keinen sinnvollen Wert, wird der Zähler zurückgesetzt: Bei vollem Akku beginnt die Streckenmessung von vorne und wenn t_timestamp keinen Timestamp enthält, dann machen alle weiteren Berechnungen keinen Sinn.

Beim Zurücksetzen wird natürlich i_strecke zurückgesetzt, also der Kilometerzähler, außerdem t_timestamp, also der Zeitpunkt der letzten Aufladung. Was i_reichweite und t_zeit bedeuten, steht im übernächsten Absatz – aber auf jeden Fall werden auch sie hier zurückgesetzt.

Wegstreckenzähler

Wenn die Akkuladung kleiner als 100% ist, dann befindet sich die WinMatic sehr wahrscheinlich im Akkubetrieb und saugt ihren Energiespeicher langsam leer. Damit kann man rechnen.

Zunächst suche ich mir den eigentlichen WinMatic-Antrieb heraus und speichere ihn in o_antrieb. Von diesem Kanal wiederum nehme ich den Datenpunkt LEVEL, der den Öffnungswinkel und Verriegelungszustand angibt: -0.05 bedeutet verriegelt, 0.0 bis 1.0 entspricht 0% bis 100% Öffnungswinkel.

Meine Strecke berechnet sich wie folgt: Für jeden Prozentpunkt wird ein „Kilometer“ zu i_strecke addiert. Außerdem rechne ich den Verriegelungsvorgang wie 100 „Kilometer“. Ich rechne den Wert also so um, dass ich Werte von -100 (Fenster verriegelt) bis 100 (Fenster offen) erhalte: Von Verriegelung bis zur kompletten Öffnung sind es 200 „Kilometer“.

Den Wert vergleiche ich mit dem, der in der Systemvariablen gespeichert war. Weicht er ab, hat sich das Fenster bewegt; ich rechne die zurückgelegte Strecke aus und erhöhe i_strecke.

Bordcomputer

Nachdem ich alle Daten habe, kann ich die Werte für meinen Bordcomputer berechnen. Dreisatz.

i_reichweite gibt die voraussichtliche Gesamtreichweite des Akku-Packs an. Mein Ziel ist es ja, die Gesundheit meiner Akkus zu überwachen – mit dieser Prognose bekomme ich schon mal einen ersten Hinweis.

t_zeit enthält den Zeitpunkt, zu dem der Akku voraussichtlich bei 0% sein wird – sofern der Akku intakt ist. Wenn er halbwegs linear und gleichmäßig entleert wird, habe ich einen Anhaltspunkt, wann ich wieder ran muss.

Die beiden Werte ist nur grobe Anhaltspunkte. Defekte Akkus neigen dazu, unvermittelt von einem beliebigen Wert auf 0 zu springen – da fällt die Prognose der Reichweite schwer. Außerdem hängt die Entladung natürlich davon ab, wie oft das Fenster bewegt wird. Wenn ich einen Monat lang gar nichts mache und dann stündlich das Fenster öffne und schließe, dann gibt es natürlich keine sinnvolle Prognose für den Wechselzeitpunkt.

Status-Systemvariable speichern

Ganz zum Schluss nehme ich all meine neuen und geänderten Werte und schreibe sie zurück in die Systemvariable. Ich verwende dabei HTML-Formatierungen und schiebe noch ein paar Leerzeilen ein, um mich – man ahnt es bereits – um bekannte Bugs der CCU herumzufummeln.

Das Ergebnis kann sich sehen lassen:

Man sieht, dass der Akku-Pack meines Badfensters zuletzt am 25.09.2017 voll aufgeladen wurde. Das Fenster war beim letzten Programmlauf zu 20% geöffnet und der Antrieb hat seit der letzten Ladung schon eine Strecke von 14300 „Kilometern“ zurückgelegt.

Die Gesamtreichweite, errechnet aus dem aktuellen Ladezustand und der zurückgelegten Strecke, beträgt 47667 „Kilometer“. Wenn alles nach Plan verläuft, muss ich am 26.11.2017 den Akku wieder aufladen.

Gute Akkus – schlechte Akkus

Mein Kilometerzähler gibt natürlich nur einen groben Überblick über den Zustand der Akku-Packs. Der Stromverbrauch der WinMatic ist nicht linear: Das Schließen eines Fensters verbraucht mehr Strom als das Öffnen und beim Andrücken gibt es noch einen Bonus on top. Auch die Verriegelung verbraucht unterschiedlich viel Strom und mit Sicherheit nicht einfach exakt soviel wie das Öffnen und Schließen des Fensters. Ich mache mir die Rechnung hier durchaus einfach.

Dazu kommt womöglich noch Wind, durch den das Fenster schwerer oder leichter zu öffnen oder schließen ist, und auch die Parameter der CCU spielen eine Rolle: hohe Geschwindigkeit oder hohe Andruckkraft bedeutet hohen Stromverbrauch.

Aber man kann immerhin Akku-Packs untereinander vergleichen und vor allem leicht erkennen, wenn ein Pack unvermittelt seine Spannung verliert.

Während der Akku im Bad schon 14300 „Kilometer“ zurückkgelegt und eine Restladung von 70% hat, ist dieser Kandidat schon nach 7240 „Kilometern“ bei 0 – erkennbar daran, dass Strecke und Reichweite übereinstimmen. Und natürlich an der Anzeige 0.00% beim Ladezustand, die ich hier nicht mitfotografiert habe.

Man kann in so einem Fall einen Kreuztest machen, also den Akku-Pack noch einmal frisch aufladen und dann an einen anderen Antrieb setzen. Die Wahrscheinlichkeit ist aber doch recht hoch, dass dieses Teil einfach das Ende seiner Lebensdauer erreicht hat und ersetzt werden muss. Alles hat ein Ende, nur die Wurst hat zwei.

Navigation