openHAB XV: Alles kaputt – eine Geschichte vom Scheitern

Geschätzte Lesezeit: 5 Minuten.

Ich habe meine gesamte Heimautomatisierung kaputtgemacht. Aus Versehen natürlich. In diesem Artikel dokumentiere ich meine Bemühungen, es zu reparieren.

Tag 1: Kaputt.

Wie macht man alles kaputt? Man schaltet einen Computer aus, während er ein Update durchführt.

Ja, das habe ich wirklich gemacht.

Ja, ich weiß, dass das extrem dumm ist.

Nein, ich weiß nicht, wieso ich das gemacht habe.

Aber von vorne. Ich wollte eigentlich nur mal eben schnell das System aktualisieren. Dazu habe ich ja mal eine Anleitung geschrieben: openHAB XIV: System-Update für Idioten. Diese Anleitung habe ich befolgt, inklusive Backup (das wird später noch wichtig). Dann habe ich versucht, das Update durchzuführen, und irgendwann während apt-get update abgebrochen. Danach konnte ich mich nicht mehr per ssh einwählen. Oh-oh.

Tag 2: Reparieren.

Schließe ich den Raspberry Pi an einen Bildschirm an, zeigt er beim Starten eine fröhliche Fehlermeldung: Firmware not found. Ich habe es offensichtlich völlig zerstört. Das ist nicht gut.

Jetzt könnte ich einen kleinen Exkurs starten. Ich habe versucht, openHAB in einem Docker-Container auf meinem NAS zu installieren. Das hatte ich sowieso schon lange überlegt, das System umzuziehen. Die Installation hat auch geklappt, nur an der Konfiguration bin ich gescheitert. So ein System von Null aufzusetzen, ist wirklich nervig. Letztlich habe ich mich entschieden, doch den Raspberry Pi wieder in Betrieb zu nehmen. Nur wie?

Erstmal hole ich das Backup von der SD-Karte. Zum Glück habe ich in diesem Artikel gefunden, wo das Backup standardmäßig gespeichert wird: /var/lib/openhab/backups/openhab-backup-*datum*.zip. Also erstmal kopieren.

Dann muss ich die SD-Karte neu flashen, und openHAB neu installieren. Dazu habe ich zuerst ein Backup der gesamten SD-Karten gemacht. Da ich neuerdings Linux benutze, habe ich mir auch da erst eine Anleitung gesucht und gefunden.

Und dann folge ich dem normalen Installationsprogramm. Das führt gleichzeitig dazu, dass ich jetzt die aktuellste Version von openHAB installiert habe, nämlich 5.2.0. Ich erstelle den Admin-Account, wähle ein paar Bindings aus, und dann wird es Zeit, das Backup wieder einzuspielen. Jetzt werde ich nervös.

sudo systemctl stop openhab
 
sudo $OPENHAB_RUNTIME/bin/restore $OPENHAB_BACKUPS/openhab-backup-*datum*.zip

Das Ganze liefert mir folgenden Output:

##########################################
          openHAB restore script          
##########################################
                                          
Using '/etc/openhab' as conf folder...
Using '/var/lib/openhab' as userdata folder...
Making Temporary Directory
Extracting zip file to temporary folder.

 Backup Information:
 -------------------
 Backup Version         | 3.3.0 (You are on 5.2.0)
 Backup Timestamp       | 26_06_24-13_26_55
 Config belongs to user | openhab
             from group | openhab

Your current configuration will become owned by openhab:openhab.

Any existing files with the same name will be replaced.
Any file without a replacement will be deleted.

Okay to Continue? [y/N]: y
Moving system files in userdata to temporary folder
Deleting old userdata folder...
rm: cannot remove '/var/lib/openhab/persistence': Device or resource busy
Restoring system files in userdata...
Deleting old conf folder...
Restoring openHAB with backup configuration...
Deleting temporary files...
Backup successfully restored!

Nachdem das tatsächlich fehlerfrei durchgelaufen ist, wird es Zeit, openHAB wieder zu starten:

sudo systemctl start openhab

Aber das funktioniert irgendwie nicht. Seltsam, und beunruhigend. Vielleicht hilft ein Neustart.

2026-07-13_kaputt

Fantastisch, oder? Ich würde sagen, darum kümmere ich mich morgen.

Etwa eine Stunde später merke ich, dass ich einfach nur zu ungeduldig war. Ich weiß nicht, warum mein System etwas Zeit brauchte zum Starten (vielleicht hat es Bindings nach-installiert?), aber jetzt funktioniert alles. Und ich kann kaum fassen, wie einfach das war.

Tag 3: Die Uhrzeit

Eine einzige Sache funktioniert noch nicht: Die Uhrzeit. Und damit verbunden: Alle Regeln, die eine Uhrzeit benutzen, zum Beispiel meine Rollladensteuerung. Nun gut, als erstes folge ich einem alten Post, in dem ich das Problem schon einmal gelöst habe: openHAB X: Endlich die korrekte Uhrzeit. Dummerweise reicht das noch nicht aus.

Zum Glück gibt es Foren, in denen Leute das gleiche Problem schon einmal gelöst haben. Als erstes gibt es mal den Befehl timedatectl status, der liefert Folgendes:

               Local time: Di 2026-07-28 10:20:14 CEST
           Universal time: Di 2026-07-28 08:20:14 UTC
                 RTC time: n/a
                Time zone: Europe/Berlin (CEST, +0200)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Das ist alles korrekt.

Der nächste Hinweis zielt darauf ab, in der Datei /etc/default/openhab nach dem Parameter EXTRA_JAVA_OPTS. zu suchen. Und tatsächlich, dort steht folgende Zeile:

EXTRA_JAVA_OPTS="-XX:-TieredCompilation -XX:TieredStopAtLevel=1 -XX:+ExitOnOutOfMemoryError -Dxtext.qn.interning=true -Duser.timezone=Europe/London"

In dieser Zeile ändere ich ganz am Ende die Zeitzone:

EXTRA_JAVA_OPTS="-XX:-TieredCompilation -XX:TieredStopAtLevel=1 -XX:+ExitOnOutOfMemoryError -Dxtext.qn.interning=true -Duser.timezone=Europe/Berlin"

Nun noch ein Neustart des Systems, und dann funktioniert auch dies wieder. Hurra!

openHAB XIV: System-Update für Idioten

Geschätzte Lesezeit: 3 Minuten.

Mit dem Wort „Idioten“ im Titel meine ich explizit mich. Denn ich könnte diesen Artikel sehr kurz schreiben, wenn ich einfach nur zu mir selbst sagen würde: Mach es halt ordentlich, dann funktioniert es auch.

Okay, etwas länger soll es dann doch sein.

Die folgenden Schritte werden alle per SSH in der Konsole durchgeführt. Zuerst mache ich ein Backup, mit diesem Befehl:

sudo $OPENHAB_RUNTIME/bin/backup

Dann aktualiere ich die Update-Verzeichnisse, das ist ganz wichtig. Warum, erkläre ich später. Und ja, wir brauchen beide Zeilen bzw. beide Befehle.

sudo apt-get update
sudo apt update

Dann öffne ich das openHAB-Konfigurations-Tool:

sudo openhabian-config

Hier wähle ich Punkt 2, Upgrade System. Und dann rödelt das System hoffentlich ohne Fehler, und alles klappt. Hoffentlich.

Und nun komme ich zu dem (langen) Weg, der mich zu diesen kurzen Schritten gebracht hat.

Tag 1: Lass uns doch mal updaten

Man sollte alle Software immer aktuell halten. Das gilt ganz generell, und das gilt natürlich auch für openHAB. Also möchte ich mein System von der Version 3.0.1 auf die neueste Version aktualisieren (3.3.0).

Glücklicherweise habe ich ja mal einen Guide zum Update auf openHAB 3.0 geschrieben, daran kann ich mich gut orientieren. Ich öffne ich das openHAB-Konfigurations-Tool:

sudo openhabian-config

Hier wähle ich Punkt 2, Upgrade System. Aber leider bricht es immer wieder ab. Es wird gesagt, wenn du diesen Fehler siehst, geh doch mal auf diese Seite: https://github.com/openhab/openhabian/blob/main/docs/openhabian-DEBUG.md. Okay, Debugging anschalten, das mache ich dann mal. Ich navigiere mich zu /etc/:

sudo nano openhabian.conf

Ja, natürlich habe ich das sudo zuerst vergessen und mich gewundert, warum ich nicht speichern kann. Ich sagte ja, „Idiot“. Jedenfalls ändere ich debugmode=off zu debugmode=maximum (und später schalte ich es natürlich wieder aus).

Und dann klicke ich etwas rum. Ich aktualisiere eigentlich alles, was so geht. Ich reboote. Ich wähle verschiedene Branches. Ich mache alles Mögliche, aber es funktioniert nicht.

Da muss ich mir wohl doch mal das Debugging ansehen. Seltsam, da gibt es diese Zeile:

E: Failed to fetch http://raspbian.raspberrypi.org/raspbian/pool/main/b/base-files/base-files_10.3+rpi1+deb10u10_armhf.deb 404 Not Found [IP: 93.93.128.193 80]

Okay, copy-paste nach Google, und ich lande hier: https://forum-raspberrypi.de/forum/thread/47483-apt-get-probleme/. Anscheinend ist das Problem, dass der Updater nach Updates auf Servern sucht, die es nicht mehr gibt. So ein Mist, wie sage ich dem Ding denn, dass es an der richtigen Stelle suchen soll – und was ist die richtige Stelle?

Das steht zum Glück auch dort.

sudo apt-get update

Und nochmal von vorne, und leider scheitert das openHAB-Update erneut. Also lese ich den Thread weiter und finde:

sudo apt update

Mache ich auch, und versuche nochmals ein Update. Und jetzt funktioniert es!

openHAB XIII: Weihnachtsbeleuchtung mit Twinkly

Geschätzte Lesezeit: 9 Minuten.

In der Adventszeit wurde es Zeit für ein neues Projekt. Ich möchte gerne Lichterketten in mein Smart Home integrieren. Grundsätzlich sind mir dafür zwei Strategien eingefallen:

  • Lichterketten an schaltbare Steckdosen anschließen, dann kann ich sie an- und ausschalten
  • Smarte Lichterketten nutzen, die vielleicht noch mehr können als „nur“ an oder aus

Ich habe mich für die zweite Variante entschieden und zwei Lichterketten von Twinkly, genauer gesagt Twinkly Strings 400 RBG,1einmal für 98,99€ bei click-licht.de, und einmal für 129,90€ bei lampenwelt.de organisiert.

Tag 1: Die Einbindung

Grundsätzlich ist die Installation der Twinkly-Lichterketten simpel. Es sollte aber erwähnt werden, dass eine App und ein Account benötigt werden. Möglicherweise ist diese Lösung daher nicht datensparsam – damit habe ich mich noch nicht auseinander gesetzt. Jedenfalls kann man die Lichterketten über eine spezielle App ein- und ausschalten, Farben ändern, Animationen wählen, das ist schon ziemlich cool. Es gibt auch eine Zeitschalt-Funktion, allerdings kann man damit die Lichterkette nur einmal pro Tag an- und einmal ausschalten. Und es ist auch eine feste Uhrzeit, zum Beispiel geht die Lichterkette jeden tag um 16:30 Uhr an.

Ich möchte aber mehr.

Ich möchte, dass die Lichterkette morgens an- und ausgeht, und abends ebenfalls an und aus. Und außerdem soll der Beginn und das Ende helligkeitsabhängig sein. Also werde ich die Twinkly-Lichterkette in openHAB einbinden. Leider gibt es kein Binding dafür, aber trotzdem ein gutes Tutorial. Hinter diesem Link versteckt sich ein Python-Skript, das ich jetzt erst einmal hier dokumentieren möchte.

import sys
import json
import urllib.request
import codecs

ARG_ON = 'on'
ARG_OFF = 'off'
ARG_STATE = 'state'
ARG_BRIGHT = 'brightness'

ARG_IP = sys.argv[1]
ARG_ACTION = sys.argv[2]


URL = "http://" + ARG_IP + "/xled/v1/"

LOGIN_URL = URL + "login"
VERIFY_URL = URL + "verify"
MODE_URL = URL + "led/mode"
BRIGHT_URL = URL + "led/out/brightness"

AUTH_HEADER = 'X-Auth-Token'

AUTHENTICATION_TOKEN = 'authentication_token'
CHALLENGE_RESPONSE = 'challenge-response'
MODE = 'mode'
MODE_ON = 'movie'
MODE_OFF = 'off'


HEADERS = {'Content-Type': 'application/json'}
LOGIN_DATA = {'challenge': 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8='}
TURN_ON_DATA = {MODE: MODE_ON}
TURN_OFF_DATA = {MODE: MODE_OFF}

if len(sys.argv) > 3: #check if the thirth argument is given, save it in a variable and create the brightness data variable
    ARG_ACTION2 = int(sys.argv[3])
    BRIGHTNESS_DATA = {'value': ARG_ACTION2, 'type': 'A'}


def formatData(data):
  return json.dumps(data).encode('utf8')

def processRequest(request):
  return urllib.request.urlopen(request)

def processRequestJSON(request):
  loginResponse = processRequest(request)
  reader = codecs.getreader("utf-8")
  return json.load(reader(loginResponse))

# login to api - get challenge response and auth token
loginRequest = urllib.request.Request(url = LOGIN_URL, headers = HEADERS, data = formatData(LOGIN_DATA))
loginData = processRequestJSON(loginRequest)

challengeResponse = loginData[CHALLENGE_RESPONSE]
authToken = loginData[AUTHENTICATION_TOKEN]

HEADERS[AUTH_HEADER] = authToken
verifyData = {CHALLENGE_RESPONSE: challengeResponse}

# verify token by responding with challenge response
verifyRequest = urllib.request.Request(url = VERIFY_URL, headers = HEADERS, data = formatData(verifyData))
verifyData = processRequestJSON(verifyRequest)

def turnOn():
  onRequest = urllib.request.Request(url = MODE_URL, headers = HEADERS, data = formatData(TURN_ON_DATA))
  processRequest(onRequest)
  print(1)

def turnOff():
  offRequest = urllib.request.Request(url = MODE_URL, headers = HEADERS, data = formatData(TURN_OFF_DATA))
  processRequest(offRequest)
  print(0)
  
def setBrightness():
  brightRequest = urllib.request.Request(url = BRIGHT_URL, headers = HEADERS, data = formatData(BRIGHTNESS_DATA))
  processRequest(brightRequest)

def getState():
  modeRequest = urllib.request.Request(url = MODE_URL, headers = HEADERS)
  modeData = processRequestJSON(modeRequest)

  if modeData[MODE] != MODE_OFF:
    print(1)
  else:
    print(0)
    
if ARG_ACTION == ARG_ON:
  turnOn()
elif ARG_ACTION == ARG_OFF:
  turnOff()
elif ARG_ACTION == ARG_STATE:
  getState()
elif ARG_ACTION == ARG_BRIGHT:
  setBrightness()

Ganz ehrlich, ich kann kein Python, ich weiß nicht genau, was dieses Skript macht. Ich kann nur sagen, dass es funktioniert. Wie? Dazu kommen wir jetzt.

Als erstes habe ich dieses Skript als twinkly.py im Ordner /var/lib/openhab/ abgespeichert. Dann habe ich mir über das openHAB-Benutzerinterface ein neues Item Lichterketten vom Typ Switch angelegt.

Und dann habe ich mir folgende lichterkette.rules gebastelt:

rule "Twinkly Christmas Tree Power State"
when 
  Item Lichterketten received command
then
  if (receivedCommand == ON) {
    executeCommandLine("python3","twinkly.py","x.x.x.37","on")
    executeCommandLine("python3","twinkly.py","x.x.x.43","on")
  }
  else {
    executeCommandLine("python3","twinkly.py","x.x.x.37","off")
    executeCommandLine("python3","twinkly.py","x.x.x.43","off")
  }
end

Hier sind zwei Dinge zu beachten. Erstens benötigt man die IP von jeder Lichterkette. Ich habe in meinem Fritzbox-Router feste IP-Adressen für die Lichterketten hinterlegt, damit dieser hart gecodede Befehl funktioniert. Zweitens ist bei dieser Rule die Syntax extrem wichtig. Ursprünglich habe ich die folgende, nicht funktionierende Zeile benutzt:

executeCommandLine("python3 twinkly.py 192.168.0.209 on")

Aber damit erhält man eine Fehlermeldung: File or directory not found when running executeCommandLine. Man muss wirklich darauf achten, dass die einzelnen Befehls-Elemente mit "," voneinander getrennt sind. Das ist ganz wichtig!

So, abschließend habe ich noch den Switch auf meiner openHAB-Startseite eingebunden. Damit bin ich erst einmal zufrieden.

Tag 2: Zeitgesteuertes Ein- und Ausschalten

ich möchte ja, dass die Lichterketten morgens und abends jeweils an- und wieder aus gehen. Dazu nutze ich Sonnenauf- und -untergang, die zugehörigen Daten fallen aus dem Astro-Binding. Das muss ich noch dokumentieren, hier gibt es erst einmal nur die Code-Schnipsel.

Für die lichterkette.rules

rule "Lichterketten morgens an"
when
   Item Tageszeit changed to "Morgen"
then
   Lichterketten.sendCommand(ON)
end

rule "Lichterketten morgens aus"
when
   Item Tageszeit changed to "Tag"
then
   Lichterketten.sendCommand(OFF)
end

rule "Lichterketten abends an"
when
   Item Tageszeit changed to "Vorabend"
then
   Lichterketten.sendCommand(ON)
end

rule "Lichterketten abends aus"
when
   Item Tageszeit changed to "Nacht"
then
   Lichterketten.sendCommand(OFF)
end

Und dann gibt es noch die tageszeit.rules, welches das oben genutzte Item Tageszeit verändert:

rule "Es wird morgen"
when
   Item Sonne_Hohenwinkel changed
then
   if (Sonne_Hohenwinkel.state == NULL || Sonne_Hohenwinkel.state > -12|"°") {
	  if (Tageszeit.state == "Nacht") {
         Tageszeit.sendCommand("Morgen")
	  }
   }
end

rule "Es wird Vormittag"
when
    Channel "astro:sun:local:rise#event" triggered START
then
    Tageszeit.sendCommand("Vormittag")
end

rule "Es wird Tag"
when
   Item Sonne_Hohenwinkel changed
then
   if (Sonne_Hohenwinkel.state == NULL || Sonne_Hohenwinkel.state > 3|"°") {
	  if (Tageszeit.state == "Vormittag") {
         Tageszeit.sendCommand("Tag")
	  }
   }
end

rule "Es ist Tag"
when
   Time cron "0 0 12 ? * * *"
then
   Tageszeit.sendCommand("Tag")
end

rule "Es wird Vorabend"
when
   Item Sonne_Hohenwinkel changed
then
   if (Sonne_Hohenwinkel.state == NULL || Sonne_Hohenwinkel.state < 3|"°") {
	  if (Tageszeit.state == "Tag") {
         Tageszeit.sendCommand("Vorabend")
	  }
   }
end

rule "Es wird Abend"
when
   Item Sonne_Hohenwinkel changed
then
   if (Sonne_Hohenwinkel.state == NULL || Sonne_Hohenwinkel.state < -2|"°") {
	  if (Tageszeit.state == "Vorabend") {
         Tageszeit.sendCommand("Abend")
	  }
   }
end

rule "Es ist Nacht 1"
when
   Time cron "0 15 22 ? * * *"
then
   Tageszeit.sendCommand("Nacht")
end

rule "Es ist Nacht 2"
when
   Time cron "0 0 4 ? * * *"
then
   Tageszeit.sendCommand("Nacht")
end

rule "Debugging"
when
   Item Tageszeit changed
then
   logWarn("Tageszeit", "Tageszeit changed. Ist jetzt: {}", Tageszeit.state)
end

Und es funktioniert. Wie durch Magie gehen die Lichterketten in der Morgen- und Abenddämmerung an und wieder aus. Jeden Tag zu einer leicht anderen Uhrzeit, immer so, dass es gerade dunkel ist.

Tag 3: Nächstes Jahr

Die obigen Schritte habe ich im Jahr 2021 durchgeführt (aber den Artikel nie veröffentlicht). Irgendwann nach Weihnachten habe ich damals die Lichterketten wieder abgebaut und die lichterkette.rules entfernt. Jetzt ist November 2022, und ich habe die Lichterketten wieder aufgehängt. Und sie sollen auch bitte wieder funktionieren, also lade ich die unveränderte lichterkette.rules wieder auf meinen openHAB-Server. Und siehe da, ich kann die Lichterketten immer noch ausschalten.

Aber nur ausschalten. Anschalten funktioniert nicht mehr. Das ist sehr seltsam.

Ich gehe in den Debugging-Modus, versuche herauszufinden, ob das if-else-Konstrukt der lichterkette.rules funktioniert. Und was soll ich sagen, daran liegt es nicht, denn es funktioniert. Also muss ja die twinkly.py defekt sein, denn was soll es sonst sein? Aber, oh Schreck, ich kann ja immer noch kein Python, was mache ich denn jetzt?

Naja, ich nutze Google. Ich finde andere Menschen mit dem gleichen Problem, aber leider ohne Lösung. Das wäre ja auch zu einfach gewesen.

Ich finde ein (inoffizielles) Twinkly-Binding, hier. Das ist doch vielversprechend, aber leider unterstützt es erst openHAB ab Version 3.2, und ich bin ja noch bei 3.0.1. - ich sollte sowieso updaten. Wie das geht, beschreibe ich in einem anderen Artikel, denn hier habe ich wieder ziemlich geflucht. Aber jetzt kommt die Magie: Nach dem Update auf openHAB 3.3 funktioniert twinkly.py wieder problemlos. Anscheinend hat das Update alles gelöst, und ich muss das Binding nicht ausprobieren. Und mein Garten erstrahlt wieder im Twinkly-Glanz.

openHAB XII: Verbindungsprobleme zu Homematic IP

Geschätzte Lesezeit: 3 Minuten.

Ich nutze Homematic IP für verschiedene Zwecke in meiner Heimautomatisierung. Unter anderem nutze ich es zur Heizungssteuerung und für die Benachrichtigung von Waschmaschine und Trockner. Außerdem möchte ich demnächst eine Rollladensteuerung etablieren.

Umso ärgerlicher ist es daher, dass die Verbindung zwischen openHAB und Homematic IP regelmäßig abschmiert. openHAb zeigt dann übrigens als Status für die CCU3 OFFLINE - COMMUNICATION_ERROR. Das liegt wahrscheinlich weder an dem einen noch an dem anderen, sondern an der Konfiguration, sprich: An mir.

Ich habe irgendwo gelesen, dass ein häufiges Problem ist, dass die WLAN-Verbindung des Raspberry Pi instabil sein kann. openHAB, welches auf den Raspberry Pi installiert ist, kann sich dann nicht mehr mit der CCU3 verbinden, und schafft es auch nach dem Wiederaufbau der WLAN-Verbindung nicht, die Verbindung zur CCU3 herzustellen. Nach einem Neustart von openHAB kann die Verbindung aber wieder aufgebaut werden – daher boote ich den RasPi immer mal wieder manuell neu. Aber das kann doch nicht die Lösung sein, oder?

Tag 1: Erstmal das Binding neu installieren

Ich habe ja alles schön dokumentiert, alle Einstellungen und Schritte und so weiter. Da kann ich das Binding ja mal löschen, und neu installieren. Vielleicht hilft es.

Tja, es hilft schon, aber nur temporär. Es läuft für ein paar Tage, und dann schmiert es wieder ab.

Tag 2: Vielleicht löst sich das Problem durch Update auf openHAB 3.0?

Haha, nein.

Tag 3: Sind es Konfigurationsprobleme?

Ich prüfe die Konfiguration des Things CCU3. Natürlich stillt die Gateway Address, die hat genau die richtige IP-Adresse. Sonst würde es ja nie verbinden.

Hm. Was ist denn die Callback Network Address? Eine Runde googlen hilft nicht wirklich. Da steht nur, man solle die openHAb-Server-Adresse dort eintragen, aber leider nicht, warum. Egal, ich probiere es, vielleicht hilft es ja.

Leider stelle ich fest, dass dies nicht die Lösung war, denn das Problem ist noch nicht behoben.

Tag 4: Der Holzhammer – Automatischer Neustart

Mir reicht es jetzt. Ich will, dass der RasPi sich einfach jede Nacht neu startet. Das ist nicht elegant, aber solange es funktioniert…

Also, Anleitung gesucht und gefunden. Ich verbinde mich per SSH und öffne crontab als Admin:

sudo crontab -e

Ich wähle nano als Editor, da ich noch nie vorher crontab geöffnet hatte. Anschließend füge ich am Ende folgende Zeile hinzu:

0 3   *   *   *    /sbin/shutdown -r 0

Automatischer Neustart, jeden Tag um 03:00 Uhr. Strg + X, Y, Enter. Seitdem habe ich keine Verbindungsprobleme mehr. Deckel drauf.

openHAB XI: Müllkalender per ical einbinden – OH 3.0

Geschätzte Lesezeit: 8 Minuten.

Mein Haus soll mich erinnern, wann ich Mülltonnen herausrollen soll. In einem vorigen Artikel hatte ich meine Bemühungen ausführlich dokumentiert, wie ich dieses Szenario für openHAB 2 implementiert hatte. Das hat auch funktioniert – und dann habe ich beschlossen, auf openHAB 3 zu aktualisieren. Seitdem geht nichts mehr, denn das zugrunde liegende Binding binding-caldav-personal1 (1.14.0) existiert nicht mehr. Also muss ich einmal von vorne beginnen.

Tag 1: Langenfeld ist doof

Bisher hatte die Stadt Langenfeld einen schönen ics-Kalender angeboten, in dem sämtliche Abfall-Abholungs-Termine vorhanden waren. Leider gibt es das nicht mehr, ich muss also als erstes sämtliche Termine händisch in meinen Kalender eintragen. Das ist doof, aber letztlich nur Fleißarbeit.

Kommen wir zu openHAB.

Es gibt ein neues Binding: iCalendar (3.0.1). Und es gibt auch einen kleinen Guide im openHAb-Forum. Ich installiere das Binding. Anschließend erzeuge ich ein neues Thing, indem ich Things > + wähle. Ich wähle das iCalendar-Binding, und den Typ Kalender (mit blauem Bridge-Label). So weit, so einfach.

Nun folgt die Konfiguration des Abfallkalenders. Ich vergebe das Label „Abfallkalender“. Außerdem gibt es einige Felder zu füllen. Der folgende Screenshot zeigt die bei mir funktionierende Lösung, aber es hat einige Versuche benötigt, bis ich das alles herausgefunden habe.

Grundsätzlich liegt mein Kalender in einer ownCloud-Instanz, im zugehörigen Kalender-Modul. Daher kann ich Benutzername und Passwort leicht korrekt ausfüllen – dabei hilft mir mein Passwortmanager1Du benutzt keinen Passwortmanager? Dann höre jetzt sofort auf, diesen Artikel zu lesen, und installiere dir einen Passwortmanager. Es ist simpel, und es erhöht deine Sicherheit im Internet extrem. Warte nicht mehr länger, mache dies genau jetzt. Los!. Die maximale Größe lasse ich bei 16 Mebibytes, das sollte schon passen. Das sind ungefähr 16 MB, und meine Kalenderdateien sind viel kleiner. Das Aktualisierungsintervall werde ich während des folgenden Testens immer mal wieder verändern, aber im Endeffekt ist 60 Minuten ein guter Wert. Das ginge sogar noch seltener, denn mein Abfallkalender ändert sich ja nicht regelmäßig.

So. Kommen wir zur Herausforderung, der URL. Und, oh je, das war wirklich schwierig. Denn hier versuche ich zwei Dinge zu verheiraten, die eigentlich nicht zusammenpassen: Ein openHAB-Binding, das ical-Dateien haben will, und eine ownCloud-Kalender-Instan, die WebDAV kommunizieren möchte. ical und WebDAV sind aber zwei völlig verschiedene Dinge, weshalb mein erster Versuch, die Adresse einzugeben, kollossal scheiterte. Analog zum letzten Mal gab ich nämlich folgende Adresse ein:

https://***/remote.php/dav/calendars/***/testkalender/

Der Status des Kalenders blieb offline, und in den Logs sah ich folgendes:

 [WARN ] [g.icalendar.internal.handler.PullJob] - Not able to read downloaded iCal. Validation failed or file not readable. Error message is: No calendar was parsed.

Ich muss ganz ehrlich sagen, ich habe hier viele Dinge ausprobiert, die ich mir nicht alle merken konnte. Irgendwann kam mal die Fehlermeldung, dass der Download abgebrochen wurde, weil die Downloadzeit zu lang war, oder so etwas in der Art. Ich kann meine Versuche nicht mehr alle nachvollziehen. Daher springe ich direkt zur Lösung des Problems.

Also, die Lösung. ownCloud kann ical-Dateien exportieren und zum Download anbieten. In meiner ownCloud-Instanz klicke ich dazu auf drei Punkte rechts neben des Kalenders, und klicke dann auf „Herunterladen“. Anschließend wird mir der Download einer ics-Datei mit dem heutigen Datum angeboten, aber diese hilft mir nicht, denn ich möchte ja, dass es immer aktualisiert wird. In der Adresszeile meines Browsers erscheint aber kurz folgende Adresse:

https://***/remote.php/dav/calendars/***/testkalender?export

Und das ist die Lösung. Das ermöglicht den Direktzugriff von openHAB auf das Exportmodul von ownCloud. Damit kann openHAB nun eine ical-Datei herunterladen, und diese verarbeiten. Natürlich hat auch das nicht auf Anhieb funktioniert – irgendwie hatte mein openHAB Schluckauf oder so. Die Anzeige des Kalenderstatus wollte einfach nur „offline“ sein. Aber in diesem Falle hat es einfach geholfen, das System ein paar Tage in Ruhe zu lassen, denn beim nächsten Nachsehen war der Status plötzlich grün.

Ich weiß, dass das albern klingt, aber ich habe wirklich nichts mehr geändert. openHAB hat sich selbst repariert. Vielleicht war irgendwo etwas im Cache, oder so, aber jetzt funktioniert es.

Tag 2: Die Regeln

Jetzt habe ich viel über die Einbindung des Things geschrieben, und das war auch definitiv die größte Herausforderung. Aber eigentlich möchte ich ja Nachrichten bekommen, wenn ich die Mülltonnen herausrollen muss. Dazu brauche ich eine Regel. Und Items. Also schaue ich mir die Channels des Abfallkalenders mal etwas genauer an.

Man sieht an dem Screenshot, dass ich die Tendenz dazu habe, einfach alle Channels erstmal mit Items zu verknüpfen, die irgendwie sinnvoll klingen, und danach zu überlegen, was ich wirklich brauche.

Der Trigger für meine Regel wird der Switch „Präsenz eines aktuellen Eintrags“. Den verknüpfe ich mit dem Item Abfallkalender_PrasenzeinesaktuellenEintrags. Dieser Switch schaltet nämlich von OFF zu ON, sobald ein Event des Kalenders beginnt. Wenn also mein Kalender sagt, dass ich heute um 07:00 die Papiermülltonnen herausrollen soll, dann schaltet dieser Switch genau um 07:00 Uhr von OFF auf ON. Und genau das triggert dann meine Regel.

Außerdem brauche ich noch den Titel des aktuellen Eintrages, denn ich will ja wissen, welche Mülltonne ich herausrollen soll. Ich verlinke also den entsprechenden Channel mit dem Item Abfallkalender_TiteldesaktuellenEintrags. Und dann kann ich auch schon die Regel überarbeiten, die ich bereits das letzte Mal benutzt habe.

zur Erinnerung, so sah die Regel in openHAB 2 mit dem calDAV-Binding aus:

rule "Abfallkalender"
when
   Item CalDav_Muelltonne changed
then
   if (CalDav_Muelltonne.state != UNDEF) {
      sendNotification("<E-Mail-Adresse>", "Abholung heute: " + CalDav_Muelltonne.state) 
   }
end

Eigentlich muss ich nicht viel ändern. CalDav_Muelltonne wird zu Abfallkalender_PrasenzeinesaktuellenEintrags. Die Statuskontrolle != UNDEF ändere ich zu == ON. Und ganz zum Schluss brauche ich noch das Item Abfallkalender_TiteldesaktuellenEintrags. Und schon sieht es so aus:

rule "Abfallkalender"
when
    Item Abfallkalender_PrasenzeinesaktuellenEintrags changed
then
    if (Abfallkalender_PrasenzeinesaktuellenEintrags.state == ON) {
        sendNotification("<E-Mail-Adresse>", "Abholung heute: " + Abfallkalender_TiteldesaktuellenEintrags.state) 
    }
end

Nun folgt der Wahnsinn: Es funktioniert. Einfach so. Ohne dass ich noch etwas anpassen oder ändern müsste. Es funktioniert!

Tag 3: Langenfeld ist nicht mehr ganz doof

Zu Beginn des neuen Jahres muss ich wieder die Termine in den Kalender eintragen. Zum Glück bietet Langenfeld mittlerweile wieder ics-Dateien an, und damit ich den Link nächstes Jahr wiederfinde, speichere ich ihn hier. Das ist der Link: https://mymuell.jumomind.com/webmodul/langenfeld/

openHAB X: Endlich die korrekte Uhrzeit

This entry is part 10 of 10 in the series openHAB
Geschätzte Lesezeit: 2 Minuten.

Es gibt da eine Kleinigkeit, die mich schon lange stört: Die Uhrzeit meiner openHAB-Installation ist falsch. Sie geht eine Stunde nach, anstatt z.B. 10:43 steht dort 09:43. Das erste Mal ist mir dies aufgefallen, als ich eine zeitgesteuerte Regel zur Beleuchtung eingerichtet habe.

Ich bin bisher davon ausgegangen, dass mein openHAB nicht weiß, dass es Sommer- und Winterzeit gibt. Diese Annahme war zu dem Zeitpunkt, als ich die Beleuchtungsregeln schrieb, durchaus valide, denn es war Juli, also Sommerzeit. Derzeit ist aber Winterzeit, und jetzt müsste die Uhr richtig gehen. Leider ist dies nicht der Fall, es ist also etwas anderes falsch eingestellt.

Zum Glück ist die Lösung total einfach. Und gefunden habe ich sie hier. Die Lösung ist: Mein openHAB hatte die falsche Zeitzone eingestellt.

So kann dies behoben werden:

  1. Ich verbinde mich per SSH und tippe sudo openhabian-config.
  2. Im sich öffnenden Menü wähle ich Option 30 – System Settings.
  3. Anschließend wähle ich Option 33 – Set System Timezone. Hier steht schon in der Beschreibung dabei, dass man diese Option wählen soll, falls die echte Zeit nicht der Systemzeit entspricht (was ja bei mir der Fall ist).
  4. Zum Schluss muss ich die korrekte Zeitzone auswählen. Das war für mich Europe > Berlin (vorher war tatsächlich Europe > London eingestellt).

Das war es auch schon. Ein kurzer Fix, aber extrem wichtig.

openHAB IX: Fritz!Box und OH 3.0

This entry is part 9 of 10 in the series openHAB
Geschätzte Lesezeit: 5 Minuten.

Seit meinem Update auf openHAB 3.0 funktioniert die Einbindung meiner Fritz!Box 7590 nicht mehr. Es wird Zeit, das zu beheben.

Ich möchte zwei Dinge realisieren:

  • Ein An/Aus-Schalter für das Gäste-WLAN
  • Anwesenheitserkennung durch Erkennung, welches Smartphone im WLAN eingewählt ist

Einen besonderen Dank möchte ich übrigens an die Leser Christian und Ralf aussprechen, die mich darauf hingewiesen haben, dass das alte Binding nicht mehr funktioniert – und die durch Nachfragen dafür gesorgt haben, dass ich mich mit dem Thema auseinander gesetzt habe.

Grundkonfiguration

Los geht es. Administration > Einstellungen > Bindings > +. Hier finden sich zwei Bindings, die prinzipiell in Frage kämen:

  • AVM FRITZ! Binding – dies scheint speziell für die Smart-Home-Features der Fritz!Box zu sein, die ich nicht benutze. Das heißt, dies ist das falsche Binding.
  • TR-064 Binding – hier finden sich viele Channels für die Fritz!Box, insbesondere sind die LAN channels interessant. Dies ist das richtige Binding.

Also gut. Ich installiere das Binding TR-064 in der Version 3.0.0. Leider finden sich keine neuen Things in meiner Inbox, ich muss das Binding also manuell konfigurieren. Glücklicherweise habe ich das ja schon einmal gemacht, daher kann ich hoffentlich viel kopieren. Und tatsächlich steht in der Dokumentation, dass das Gateway-Device manuell verbunden werden muss, der Rest funktioniert dann angeblich automatisch. Okay, dann mache ich das so.

Ich klicke Einstellungen > Things > + und wähle das TR-064-Binding. Hier wird mir direkt eine Fritz!Box vorgeschlagen, also wähne ich diese aus. Ich gebe IP-Adresse, username und Passwort ein und klicke auf Create Thing. Und siehe da, die Fritz!Box ist vorhanden, und der Status ist online. Das ist ja extrem einfach – ich mag openHAB 3.

Ich klicke das Thing an, und wähle oben Channel. Ich möchte jetzt probeweise mal die Uptime verlinken, also klicke ich auf diesen Channel und erzeuge ein neues Item für diesen Channel. Okay, jetzt sehe ich die Fritz!Box-Uptime in Sekunden. Das ist natürlich recht albern, aber es funktioniert.

Gäste-WLAN

Okay, ich möchte ja eigentlich den Schalter für das Gäste-WLAN. Also gehe ich erneut unter Einstellungen > Things > + auf das TR064-Binding. Diesmal drücke ich Scan. Jetzt wird mir ein LAN-Device angezeigt – aus der Dokumentation weiß ich, dass dieses den Channel für das WLAN besitzt. Also füge ich es hinzu, und erzeuge erneut über die Channels ein entsprechendes Item für das Gäste-WLAN. Es wird automatisch vorgeschlagen, dass es ein Switch sein soll. Das ist alles extrem einfach und straight-forward (wenn man weiß, wo man suchen muss) – ich finde das super!

Anwesenheit im WLAN

Okay, kommen wir zum (vermutlich) schwierigen Teil. Ich möchte erkennen, ob jemand anwesend ist, indem ich prüfe, ob sich das entsprechende Smartphone im WLAN befindet.

Mein erster Gedanke war, dass ich vermutlich irgendwie einen Eintrag in einer .items-Datei ergänzen muss. Aber dieser Thread hat mich auf den richtigen Weg geführt. Das Konzept ist, dass das Binding für jede MAC-Adresse einen eigenen Channel anlegen kann, den macOnline-Channel. Dazu muss man dem Binding nur sagen, welche MAC-Adressen man denn bitte überwacht haben will.

Also gehe ich über Things > LANDevice in die Konfiguration des Fritzbox-LANDevices. Im unteren Teil gibt es den Punkt Configuration, dort trage ich unter MAC Online die MAC-Adresse meines Telefons ein. Die findet man übrigens am einfachsten in der Netzwerkübersicht des Fritzbox-Menüs.

2021-01-24_fritzbox-maconline

Anschließend klicke ich auf Channels und füge den (jetzt erstmals erscheinenden) MAC Online-Channel mit der richtigen MAC-Adresse einem neuen Item hinzu. Und schon funktioniert es, ich bekomme als Status tatsächlich „ON“ angezeigt.

2021-01-24_fritzbox-maconline-2

Dieses Item kann ich jetzt nutzen, um meine Anwesenheit zu detektieren. Alles funktioniert, Haken dran.

openHAB VIII: Update auf openHAB 3.0

This entry is part 8 of 10 in the series openHAB
Geschätzte Lesezeit: 7 Minuten.

Es gibt eine neue Version, und ich möchte auf openHAB 3 aktualisieren. Vielleicht lösen sich so die Probleme mit homematic von selbst.

Also gut. Ich folge dieser Anleitung. Die sieht nämlich sehr leicht aus. Spoiler: Leider wird sich herausstellen, dass es nicht ganz so einfach ist.

Tag 1: Erst einmal alles kaputtmachen

Tolle Überschrift, oder?

Die folgenden Schritte werden alle per SSH in der Konsole durchgeführt. Zuerst mache ich ein Backup, mit diesem Befehl:

sudo $OPENHAB_RUNTIME/bin/backup

Dann öffne ich das openHAB-Konfigurations-Tool:

sudo openhabian-config

Mich begrüßt direkt diese Meldung:
2021-01-02-update-1

Wenn das Update empfohlen ist, dann mache ich das doch direkt. Ich wähle also Continue, und das System rattert vor sich hin.

Nach ein paar Augenblicken kommt der nächste Screen:
2021-01-02-update-2

Öh, ja, ich möchte openHAB 3. Also wähle ich mit dem Cursor den unteren Branch, und drücke Enter.

Es folgt das Hauptmenü. Ich wähle den zweiten Menüpunkt Upgrade System.
2021-01-02-update-3

Das System arbeitet jetzt. Nach einer Weile erhalte ich folgenden Dialog:
2021-01-02-update-4

Öh, ja, also wenn ich Java 11 brauche, dann soll das bitte auch installiert werden. Continue.

Anschließend geht es zurück in das hauptmenü. Hier wähle ich nun Punkt 3, Install openHAB. In der beschreibung steht ja, dass hier openHAB 3 installiert wird, also sollte das passen.
2021-01-02-update-5

Als nächstes werde ich gefragt, ob ich ein Backup anlegen möchte. Das habe ich zwar schon vorhin manuell gemacht, aber es schadet ja nicht. Continue.
2021-01-02-update-6

Und eine Warnmeldung, dass das Update zu openHAB 3 nicht rückgängig zu machen ist. Jaja, Continue.
2021-01-02-update-7

Jetzt rödelt das System. Nach einer Weile erhalte ich eine Erfolgsmeldung:
2021-01-02-update-10

Und direkt danach folgt eine Fehlermeldung:
2021-01-02-update-8

Das ist seltsam. Mal sehen, ob es funktioniert hat. Ich gebe http://openhab/8080 in den Browser ein.

2021-01-02-update-8-2

Okay, da ist also etwas kaputt. Ein Reboot (sudo reboot) hilft nichts. Eine schnelle Google-Recherche führt mich zu dieser Diskussion. Hier wird der Fehler genau beschrieben, aber es wird gesagt, dass das ab openHAB 2.5.1 behoben sein sollte. Ich habe doch openHAB 3 installiert?

Ich gehe also erneut per SSH auf den RasPi. Der Begrüßungsdialog von openhabian sagt aber immernoch, dass ich openHAB 2.5 installiert hätte. Seltsam. Da hat wohl etwas nicht geklappt.

Also nochmal.

sudo openhabian-config

Diesman wähle ich Menüpunkt 1, Select Branch. Und siehe da, ich habe angeblich noch den stable-Branch ausgewählt. Ich muss das Sternchen auf openHAB3 verschieben, und erst dann Enter drücken. Aber wie geht das? Keine Ahnung. Ich drücke wild auf meiner Tastatur herum, und irgendwann ist das Sternchen an der richtigen Stelle. Ich glaube, die Leertaste war richtig, aber ich bin mir nicht sicher. Egal.

2021-01-02-update-9

Weiter geht es. Punkt 3, Install openHAB.
2021-01-02-update-10

Diesmal erhalte ich nur die Erfolgsmeldung, und keine Fehlermeldung. Und der Screen per SSH sieht so aus:

2021-01-02-update-11

Das ist doch super! Erstmal rebooten (sudo reboot), und dann auf zu http://openhab/8080:
2021-01-02-update-8-2

Verdammt.

Okay, die obige Lösung sagte, man müsse openHAB einfach nur löschen und neu installieren. Das würde ich gerne vermeiden, vielleicht geht es auch anders.

Eine andere Lösung sagt, man solle den Cache leeren.

openhab-cli stop
openhab-cli clean-cache
openhab-cli start

Und nun geht es erneut zu http://openhab/8080: Die Website ist nicht erreichbar. ERR_CONNECTION_REFUSED. Verdammt.

Tag 2: Reparieren

Sieh mal einer an, jemand anderes hat den gleichen Fehler wie ich. Die Lösung: Zwinge das System, Java 11 zu nutzen. Nur wie das geht, steht hier leider nicht.

Besser gesagt, da steht, derjenige habe es über das openHAB-Konfigurations-Tool geschafft:

sudo openhabian-config

Okay, ich wähle erstmal Menüpunkt 10, Apply Improvements > Packages. Kann ja nicht schaden. Der Installer läuft erfolgreich durch – aber das war nicht, was ich gesucht habe.

Menüpunkt 40, openHAB Related, listet als Punkt 46 Zulu Java 11 auf.
2021-01-02-update-12

Super, das will ich installieren, in der 32-Bit-Variante. Der Installer läuft erneut erfolgreich durch:
2021-01-02-update-13

Okay, Reboot.

Und siehe da, es funktioniert! Ich werde in das initiale Setup von openHAB 3 geleitet:
2021-01-02-update-14

2021-01-02-update-15

Ich vergebe einen Admin-Account, lege ein paar Daten und meinen Standort fest, und komme in die neutrale Übersichtsseite. Super!

2021-01-02-update-16

Jetzt muss ich das „nur noch“ konfigurieren.

Etwas rumspielen zeigt mir, dass meine Things, Channels und Rules übernommen wurden. Meine Sitemap auch, aber irgendwie funktioniert diese (noch) nicht. Anscheinend gab es da Änderungen. Glücklicherweise sind die wichtigsten Änderungen dokumentiert, insbesondere der Abschnitt über erforderliche manuelle Anpassungen ist sehr interessant. Besonders relevant für mich: Das Gardena-Binding ist komplett neu geschrieben worden. Das muss ich mir ansehen.

Außerdem wird das Fritzbox-064-Binding nicht mehr unterstützt. Vielen Dank an Christian für den Hinweis! Auch hier muss ich eine Lösung finden, die ich hier dokumentieren werde.

openHAB VII: Waschmaschine und Trockner melden sich, wenn sie fertig sind

This entry is part 7 of 10 in the series openHAB
Geschätzte Lesezeit: 7 Minuten.

In unserem Haus stehen Waschmaschine und Trockner im Keller. Möchte ich wissen, ob eines der Geräte fertig ist, muss ich also in den Keller laufen. Das ist unpraktisch. Da muss es doch etwas besseres geben.

Natürlich gibt es etwas besseres. Es gibt dieses tolle Tutorial.

Tag 1: Installation, Items, Regeln

Das Konzept ist relativ simpel. Ich schließe die Waschmaschine und den Trockner jeweils an eine Steckdose, die den Verbrauch messen kann. Wenn der Verbrauch von einer hohen Last auf eine sehr niedrige Last fällt, muss der Waschgang fertig sein. Dann bekomme ich eine Nachricht.

Ich installiere an Waschmaschine und Trockner jeweils eine Schalt-Mess-Steckdose von Homematic IP, HmIP-PSM.1Bei amazon für 44,99€ pro Stück gekauft. Anschließend definiere ich die Items in homematic.items:

// Waschkeller
// HmIP-PSM_Waschmaschine
Number  SteckdoseWaschmaschine_Power  "Waschmaschine Verbrauch [%.1f W]" {channel="homematic:HMIP-PSM:3014F711A0001F9A499D1959:0001DBE9913DBB:6#POWER" }
Number Waschmaschine_Status "Waschmaschine [%d]"

// HmIP-PSM_Trockner
Number  SteckdoseTrockner_Power  "Trockner Verbrauch [%.1f W]" {channel="homematic:HMIP-PSM:3014F711A0001F9A499D1959:0001DA49A3492E:6#POWER" }
Number Trockner_Status "Trockner [%d]"

Es folgt die waschen.rules:

import java.util.concurrent.locks.ReentrantLock

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3

val ReentrantLock Waschmaschine_lock = new ReentrantLock()
val ReentrantLock Trockner_lock = new ReentrantLock()

rule "Status Waschmaschine"
when
    Item SteckdoseWaschmaschine_Power changed
then
    if (SteckdoseWaschmaschine_Power.state < 0.5) Waschmaschine_Status.postUpdate(MODE_OFF)
    else if (SteckdoseWaschmaschine_Power.state > 10) Waschmaschine_Status.postUpdate(MODE_ACTIVE)
    else if (SteckdoseWaschmaschine_Power.state < 4.5) {
        if (Waschmaschine_Status.state == MODE_OFF) Waschmaschine_Status.postUpdate(MODE_STANDBY)
        else if (Waschmaschine_Status.state == MODE_ACTIVE) {
			Waschmaschine_lock.lock()
			try {
				Thread::sleep(10000) // Debounce for 10 seconds
				if (SteckdoseWaschmaschine_Power.state < 4.5) { 
					Waschmaschine_Status.postUpdate(MODE_FINISHED)
					sendNotification("mail@dresse", "Waschmaschine ist fertig!")
				}
			} finally {
				Waschmaschine_lock.unlock()
			}
		}
    }
end

rule "Status Trockner"
when
    Item SteckdoseTrockner_Power changed
then
    if (SteckdoseTrockner_Power.state < 0.5) Trockner_Status.postUpdate(MODE_OFF)
    else if (SteckdoseTrockner_Power.state > 10) Trockner_Status.postUpdate(MODE_ACTIVE)
    else if (SteckdoseTrockner_Power.state < 4.5) {
        if (Trockner_Status.state == MODE_OFF) Trockner_Status.postUpdate(MODE_STANDBY)
        else if (Trockner_Status.state == MODE_ACTIVE) {
			Trockner_lock.lock()
			try {
				Thread::sleep(10000) // Debounce for 10 seconds
				if (SteckdoseTrockner_Power.state < 4.5) {
					Trockner_Status.postUpdate(MODE_FINISHED)
					sendNotification("mail@dresse", "Trockner ist fertig!")
				}
			} finally {
				Trockner_lock.unlock()
			}
		}
    }
end

Diese rules-datei ist im Prinzip copy-paste von obiger Anleitung. Okay, ich habe die entsprechende Regel verdoppelt, weil ich ja Waschmaschine und Trockner habe. Ansonsten habe ich nur noch das Lock verändert, indem ich den Import an den Anfang der Datei gesetzt habe. Das war nötig, weil ich sonst folgenden Fehler erhalten hatte:

[WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'waschen.rules' has errors, therefore ignoring it: [6,1]: missing EOF at 'import'

Zum Schluss noch die default.sitemap:

Frame label="Waschküche" {
        Text item=Waschmaschine_Status icon="whitegood" label="Waschmaschine" 
        Text item=Trockner_Status icon="whitegood" label="Trockner"
    }

Und dann schauen wir mal, ob es funktioniert.

Tag 2: Feinschliff

2020-09-21_trockner-notification

Es funktioniert.

2020-09-21_waschmaschine-notification

Öh. Es funktioniert zu gut. Das sid zu viele Nachrichten. Ich muss die Grenzen, an denen sich der Status ändert, etwas anpassen. So sieht die waschen.rules jetzt aus:

import java.util.concurrent.locks.ReentrantLock

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3

val ReentrantLock Waschmaschine_lock = new ReentrantLock()
val ReentrantLock Trockner_lock = new ReentrantLock()

rule "Status Waschmaschine"
when
    Item SteckdoseWaschmaschine_Power changed
then
    if (SteckdoseWaschmaschine_Power.state < 0.5) Waschmaschine_Status.postUpdate(MODE_OFF)
    else if (SteckdoseWaschmaschine_Power.state > 200) Waschmaschine_Status.postUpdate(MODE_ACTIVE)
    else if (SteckdoseWaschmaschine_Power.state < 2.2) {
        if (Waschmaschine_Status.state == MODE_OFF) Waschmaschine_Status.postUpdate(MODE_STANDBY)
        else if (Waschmaschine_Status.state == MODE_ACTIVE) {
			Waschmaschine_lock.lock()
			try {
				Thread::sleep(100000) // Debounce for 100 seconds
				if (SteckdoseWaschmaschine_Power.state < 2.2) { 
					Waschmaschine_Status.postUpdate(MODE_FINISHED)
					sendNotification("andreas@kolmer.one", "Waschmaschine ist fertig!")
				}
			} finally {
				Waschmaschine_lock.unlock()
			}
		}
    }
end

rule "Status Trockner"
when
    Item SteckdoseTrockner_Power changed
then
    if (SteckdoseTrockner_Power.state < 0.5) Trockner_Status.postUpdate(MODE_OFF)
    else if (SteckdoseTrockner_Power.state > 200) Trockner_Status.postUpdate(MODE_ACTIVE)
    else if (SteckdoseTrockner_Power.state < 200) {
        if (Trockner_Status.state == MODE_OFF) Trockner_Status.postUpdate(MODE_STANDBY)
        else if (Trockner_Status.state == MODE_ACTIVE) {
			Trockner_lock.lock()
			try {
				Thread::sleep(10000) // Debounce for 10 seconds
				if (SteckdoseTrockner_Power.state < 200) {
					Trockner_Status.postUpdate(MODE_FINISHED)
					sendNotification("andreas@kolmer.one", "Trockner ist fertig!")
				}
			} finally {
				Trockner_lock.unlock()
			}
		}
    }
end

Das hat geklappt, jetzt kriege ich nur noch eine Nachricht, wenn die Waschmaschine fertig ist.

Nächster Punkt: Die Sitemap ist noch nicht ganz perfekt. Da steht jetzt für die Waschmaschine eine Zahl als Status, also entweder 0, 1, 2 oder 3. Ich möchte aber viel lieber, dass da "Aus" oder "Standby" steht. Da es wie immer tolle Anleitungen gibt, hoffe ich, dass dieser Schritt einfach ist.

Ich bearbeite also meine homematicip.items:

// Waschkeller
// HmIP-PSM_Waschmaschine
Number  SteckdoseWaschmaschine_Power  "Waschmaschine Verbrauch [%.1f W]" {channel="homematic:HMIP-PSM:3014F711A0001F9A499D1959:0001DBE9913DBB:6#POWER" }
Number Waschmaschine_Status "Waschmaschine [%d]"
String Waschmaschine_Anzeige "[MAP(waschen.map):%s]"

// HmIP-PSM_Trockner
Number  SteckdoseTrockner_Power  "Trockner Verbrauch [%.1f W]" {channel="homematic:HMIP-PSM:3014F711A0001F9A499D1959:0001DA49A3492E:6#POWER" }
Number Trockner_Status "Trockner [%d]"
String Trockner_Anzeige "[MAP(waschen.map):%s]"

Und dann erstelle ich noch eine transform/waschen.map:

0=Aus
1=Standby
2=Läuft
3=Fertig
-=-
undefined=-
uninitialized=-
NULL=-

Und schon erhalte ich einen Fehler in den Logs:

[WARN ] [rest.core.item.EnrichedItemDTOMapper] - Failed transforming the state 'NULL' on item 'Waschmaschine_Anzeige' with pattern 'MAP(waschen.map):%s': Couldn't transform value because transformation service of type 'MAP' is not available.
[WARN ] [ui.internal.items.ItemUIRegistryImpl] - couldn't transform value in label because transformationService of type 'MAP' is unavailable
[WARN ] [rest.core.item.EnrichedItemDTOMapper] - Failed transforming the state 'NULL' on item 'Trockner_Anzeige' with pattern 'MAP(waschen.map):%s': Couldn't transform value because transformation service of type 'MAP' is not available.
[WARN ] [ui.internal.items.ItemUIRegistryImpl] - couldn't transform value in label because transformationService of type 'MAP' is unavailable

Tja, das wäre auch zu einfach gewesen. Aber auch für dieses Problem gibt es eine Lösung: Ich muss das Addon "MAP" installieren. Sonst geht das nicht. Also wähle ich in der PaperUI Addons > Transformations das Addon Map Transformation (transformation-map - 2.5.3). Und schon gibt es keine Fehlermeldungen mehr.

Okay, noch schnell die default.sitemap überarbeiten:

	Frame label="Waschküche" {
        Text item=Waschmaschine_Anzeige icon="whitegood" label="Waschmaschine" 
        Text item=Trockner_Anzeige icon="whitegood" label="Trockner"
    }

Sollte klappen, oder? Nein, leider nicht. Die Anzeige funktioniert nicht. Keine Ahnung, woran dies liegt. Da muss ich noch etwas basteln.

openHAB VI: Beleuchtung mit Philips Hue

This entry is part 6 of 10 in the series openHAB
Geschätzte Lesezeit: 4 Minuten.

Ich möchte das Licht im Haus steuern. Dabei geht es mir weniger um eine Simulation von Anwesenheit. Viel lieber möchte ich, dass die Helligkeit des Tageslichtes erkannt wird und die Lampen automatisch so hell gedreht werden, dass die Helligkeit im Raum konstant ist.

Das Ganze soll mit Philips Hue laufen. Dazu habe ich mir schonmal die zentrale Hue Bridge1Im Set mit zwei E27-LEDs bei amazon.de für 95,76€. und vier E27-LEDs2Zweimal amazon.de für je 39,99€, die anderen beiden wurden im Set mit der Bridge gekauft. bestellt. Die LEDs können kalt- und warmweiß sowie 16 Millionen Farben darstellen. Ich bin gespannt, was man damit für lustige Beleuchtungsszenarien erstellen kann. Und vier Pillar-Spots habe ich auch bestellt.3amazon.de; je 48,99€. Tja, und dann gab es da noch die GU10-LEDs im Angebot, also habe ich auch davon noch zwölf bestellt.4proshop.de; 29,83€ pro Stück. Die möchte ich in die Pillar-Spots und in bereits vorhandene Lampen einbauen.

Tag 1: Setup

Die Montage der Spots und der Einbau der Leuchten war genau so einfach oder schwer, wie es bei Lampen immer der Fall ist. Ich hasse Über-Kopf-Arbeit, dementsprechend habe ich geflucht. Aber dies ist keine Handwerker-Blogserie, sondern eine über openHAB. Daher komme ich nun zum Thema und merke an, dass ich mir vor der Montage sämtliche Seriennummern der Leuchtmittel aufgeschrieben habe. Ich habe nämlich irgendwo gelesen, dass die Verknüpfung der Leuchtmittel mit der Bridge nicht immer reibungslos funktioniert, und dass man dann die Seriennummer benötigt.

Die Bridge mit den Leuchten zu verknüpfen ist extrem einfach. Der erste Schritt ist, die Hue-App mit der Bridge zu verknüpfen, dazu folge ich einfach der Anleitung in der Hue-App. Alle Leuchtmittel werden auch direkt gefunden, auch dies ist wunderbar einfach. Ich füge alle Leuchtmittel zum Raum „Wohnzimmer“ hinzu, und definiere darin zwei Zonen, „Deckenleuchte 1“ und „Spots“. Das ist alles völlig simpel und funktioniert einfach und ohne Probleme, ich bin begeistert.

Auch die Verknüpfung mit openHAB ist einfach. Die Leuchten tauchen direkt in der Inbox auf, und ich füge die Leuchten als Things hinzu. Zu mehr fehlt mir erst einmal die Zeit.

Tag 2: Anwesenheitssimulation

Für einen Urlaub (der in der Vergangenheit liegt, ich dokumentiere dies erst nach dem Urlaub) möchte ich, dass meine Spots zu bestimmten Zeiten an- und wieder ausgeschaltet werden. Ich möchte, dass das Haus von außen teilweise beleuchtet aussieht.

Als erstes benötige ich ein Item, genauer gesagt einen Switch (hue.items):

Switch Hue_Wohnzimmer_Spots "Hue Wohnzimmer Spots" { channel="hue:group:ecb5fa0b0612:3:switch" }

Und dann muss ich diesen Switch noch irgendwie bedienen. Irgendwie? Naja, ich möchte ja bestimmte Uhrzeiten, das bedeutet: Ich möchte einen Cronjob. Die entsprechenden Ausdrücke generiere ich hier: http://www.cronmaker.com/?0. Und so sieht die entsprechende hue.rules aus:

rule "Simuliere Anwesenheit Licht an"
when
   Time cron "0 17 18 ? * * *"
then
   Hue_Wohnzimmer_Spots.sendCommand(ON)
end

rule "Simuliere Anwesenheit Licht aus"
when
   Time cron "0 44 21 ? * * *"
then
   Hue_Wohnzimmer_Spots.sendCommand(OFF) 
end

Dabei musste ich beachten, dass mein openHAB irgendwie auf Winterzeit steht. 18:17 entspricht also 19:17 Sommerzeit, und somit gehen die Lichter um 19:17 an. Das hat eine Weile gedauert, bis ich diesen Fehler gefunden hatte. In der Zwischenzeit war ich verwundert, warum die blöden Lampen nicht angingen. (Update: Dieses Problem der falschen Uhrzeit habe ich mittlerweile gelöst.)

Und so sieht es in den Logs aus:

[ome.event.ItemCommandEvent] - Item 'Hue_Wohnzimmer_Spots' received command ON
[nt.ItemStatePredictedEvent] - Hue_Wohnzimmer_Spots predicted to become ON
[vent.ItemStateChangedEvent] - Hue_Wohnzimmer_Spots changed from NULL to ON

Warum da in der mittleren Zeile etwas predicted wird, ist mir schleierhaft. Aber es funktioniert, das genügt mir.