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.