Raspberry Pi Touchdisplay Helligkeit automatisch justieren

Aus Laub-Home.de Wiki
Zur Navigation springen Zur Suche springen
Raspberry Pi Touchdisplay inkl. BH1750 Licht Sensor
Raspberry Pi Touchdisplay inkl. BH1750 Licht Sensor

Ich habe mich mit dem Thema beschäftigt, wie man die Helligkeit des offiziellen 7" Raspberry Pi Touchdisplay automatisch an die Umgebungshelligkeit anpassen kann. Dies sollte sich ähnlich einem Mobiltelefon oder einem modernem Laptop Bildschirm verhalten und bei kompletter Dunkelheit das Display ausschalten. Also, wenn es super hell in einem Raum ist (in Lux), dann soll der Helligkeitswert (in %) dementsprechend hoch sein. Ist es eher dunkel, dann sollte auch das Display gedimmt werden. Zusätzlich möchte ich noch eine Anbindung an openHAB haben und hier die automatische Helligkeit zu justieren und ebenfalls das Display An und Auszuschalten. Als Helligkeitsensor kommt der BH1750 Sensor und als Software Lösung ein Python Script mit den entsprechenden Libraries zum Zuge. Ein wenig Bastelgeschick ist von Nöten, wenn ihr den Sensor wie ich direkt hinter das Display bauen wollt.

Voraussetzungen

Ich habe bereits anhand der folgenden Anleitungen ein Setup gebaut, welches ich als Ausgangspunkt hier verwende. Es ist jedoch nicht notwendig dies alles durchzuführen / durchzusehen. Alle erforderlichen Schritte sind hier beschrieben. Sollte etwas unklar sein, können die folgenden Anleitungen gerne zu Rate gezogen werden:

Tools for Display Sensor
Feile, Schlitzschraubendreher, Kreuzschlitzschraubendreher, Rasierklinge

Zusammengefasst wird folgendes benötigt:

Display Tools
Laubsäge, Permanentmarker, Spanner, Holzbrett

Die folgenden Werkzeuge habe ich verwendet:

  • kleiner Kreuzschlitz- und Schlitzschraubendreher
  • Wasserfester Permanent Marker (Edding)
  • Lötkolben mit Lötzinn
  • Akkuschrauber
  • 1,5mm Metall/Holz Bohrer
  • altes Holzbrett
  • Laubsäge
  • Spanner
  • feine kleine Feile
  • Rasierklinge

Sensor einbauen

Zuerst bauen wir den Helligkeitssensor sauber in das Display ein oder besser gesagt hinter das Display ein. Man kann diesen Schritt auch überspringen, wenn man den Sensor einfach so liegen lassen möchte, oder ihn ganz wo anders untergebracht hat. Schöner ist es jedoch wenn dieser kaum sichtbar am Display und dem Rahmen verbaut ist. Um den Sensor schön sauber einbauen zu können sollte man sich am besten damit vertraut machen, wie der Rahmen und das Display zusammengebaut werden. Hat man diesen ersten Überblick gewonnen, einfach wieder alles auseinanderbauen und dann dieser Schritt für Schritt Anleitung folgen.

Touchdisplay Versionen

Bei meinem Versuch sind mir zwei Touchdisplay Versionen untergekommen. Leider ist es nur mit einer der beiden möglich den Sensor direkt zu verbauen. Hier der Vergleich der Seitenleisten der Displays:

Touchdisplay Version 1.jpgTouchdisplay Version 2.jpg

Wie man sehen kann geht bei der einen Version die Touchsensorik bis in den äußeren Rahmen, was es leider unmöglich macht, hier ein Guckloch für den Sensor zu schaffen. Leider konnte ich nicht herausfinden wie die Revision heißt, mit der es funktioniert, da auf der Elektronik bei beiden exakt das selbe steht. Ich kann nur sagen, dass das Display, mit dem es funktioniert, neuer bestellt ist und dieses von www.berrybase.de gekauft wurde. Solltet ihr also ein Display haben, wie im ersten Bild, bitte nicht versuchen ein Loch rein zumachen. Danach funktioniert die Touchfunktionalität nicht mehr!

Sensor Pinbar anlöten

Bevor ich die Pinbar an den Sensor gelötet habe, habe ich mit der Feile ca. 1mm von den kurzen, anzulötenden Pins, weggefeilt. Somit schauen diese nach dem Löten nicht weiter raus, als die Bausteine auf der Platine. Damit liegt der Sensor später beim Einbauen besser auf dem Display Rahmen auf. Nun kann der Sensor sauber verlötet werden. Wenn ihr nicht wisst wie das geht, hier ist eine super Anleitung, nach der ich auch vorgegangen bin:

Das Ergebnis sieht dann so aus:

BH1750 Sensor gelötet.jpg

Ich habe dann noch zusätzlich ein wenig die Seiten der Platine abgefeilt. damit der Sensor ein wenig kleiner wird, aber bitte vorsichtig sein, damit nicht in eine Leiterbahn gefeilt wird!

Anpassen des Pimoroni Rahmens

Hierfür benötigt ihr definitiv ein wenig Feingefühl. Ich habe den ersten Rahmen direkt beim ersten Versuch ein paar mal gebrochen und auch das Ergebnis war nicht so wie ich es mir vorgestellt habe. Also, viel Geduld und Muße ist hier gefordert, da es sich stellen weise um nur 1-2mm starke Stege handelt. Der Trick der mich beim zweiten Mal zum Erfolg brachte, war es mit einem feinen 1,5mm Bohrer zuerst die Ecken auszubohren, dafür habe ich die Kunststoffteile auf ein altes Holzbrett gelegt und bis in dieses durchgebohrt. Ich habe dann mittels Laubsäge vorsichtig die Stücke ausgesägt und zum Feinjustieren dann die kleine Feile genutzt. Mit einem Spanner habe ich die Rahmen Teile an meinem Tisch festgemacht, so war das Arbeiten relativ gut machbar. Zu beachten ist auch, lasst die Folie auf den Kunststoffteilen bis alles fertig ist.

TempSensor in Pimoroni Rahmen 3.jpgTempSensor in Pimoroni Rahmen 4.jpg

Kommen wir nun zum ersten Schritt, dem untersten Kunststoffteil, welches direkt auf dem Touchdisplay Rahmen liegt. Legt dieses einfach auf den Touchdisplay Rahmen, legt den Sensor bündig mit dem Metall Deckel des Displays auf, so dass die Pins Oben sind. Schaut am besten das die Pins direkt unterhalb der gebogenen Ecke des Rahmens sind, damit ein genug breiter Steg übrig bleibt. Schaut einfach auf dem Bild. Wenn ihr ihn richtig positioniert habt, mal einfach die Umrandung mit dem Permanent Marker nach. Nun bohrt in die beiden gezeichneten 90° Ecken vorsichtig zwei Löscher, diese dienen nun dafür das Sägeblatt der Laubsäge durchzuführen und einen sauberen Schnitt von einem zum anderen Loch zu sägen. Wenn ihr durchgesägt habt, einfach das Sägeblatt um 90° drehen und die letzten Millimeter ins Freie Sägen. Dann noch die andere Seite ebenfalls aussägen und fertig. Jetzt könnt ihr das Ganze noch sauber mit der Feile nacharbeiten. Das Ergebnis sieht dann so aus:

TempSensor in Pimoroni Rahmen 1.jpg

kommen wir nun zur 2ten Schicht. Hier Markieren wir uns wo die Pins austreten sollen. Dafür habe ich einfach die zweite Kunstoffplatte bündig angelegt und eine Markierung gezeichnet, wo und wie lange die Pin Leiste ist. Ist diese eingezeichnet, bohren wir am äußeren Ende zwei kleine Löscher, zu denen wir mit der Laubsäge zu sägen. Am Ende des zweiten Schnittes einfach die Säge so drehen, damit der feine Steg zum 2ten Loch ebenfalls durchgesägt ist. Nun wieder mit der Feile das Ganze sauber und passend machen. Das Ergebnis sieht dann so aus:

TempSensor in Pimoroni Rahmen 2.jpg

nun kommen wir schon zum letzten Teil. hier legen wir einfach das zweite auf und zeichnen die Aussparung der Pin Leiste nach. Dann Bohren wir 4 Löscher und die Ecken und Sägen das ganze sauber aus. Zum Schluss natürlich wieder Feintuning mit der Feile. Liegt nun alles auf und der Sensor auf dem Display sieht das Ergebnis so aus:

TempSensor in Pimoroni Rahmen 5.jpg

Und zu guter Letzt der Test ob die Jumper Kabel auch passen:

TempSensor in Pimoroni Rahmen 6.jpg

Guckloch am Touchdisplay Rahmen

Das Guckloch bekommt man durch vorsichtiges abschaben der Lackierung mit der Rasierklinge hin. Markiert euch hierfür die Stelle, an der der Sensor sitzen wird. Der Sensor selbst ist der Chip oberhalb der Beschriftung. Dann schabt ein etwa 5mm x 5mm großes Rechteck frei. Ausbesserungen kann man mit einem schwarzen Lackstift vornehmen, solltet ihr euch etwas vermessen oder etwas zu weit den Lack weggekratzt haben. Wichtig ist, nicht zu viel Druck aufwenden, damit der Kunstoff des Display nicht verkratzt und somit nicht durchsichtig ist.

Zusammenbau & Verkabelung

Nun können wir alles zusammenbauen:

  1. zuerst legen wir die drei Rahmenplatten auf das Display
  2. DSI Kabel (das weiße breite welches blaue Enden auf einer Seite hat) in den DSI Connector des Touchdisplay einstecken
  3. das schwarze Jumperkabel am Touchdisplay GPIO Connector in GND stecken
  4. das rote Jumperkabel am Touchdisplay GPIO Connector in 5V stecken
  5. nun können wir den Display Rahmen fertig zusammenbauen.
  6. Raspberry Pi auf die Display Platine schrauben
  7. das DSI Kabel in den DSI Anschluss des Raspberry Pi stecken
  8. nun das schwarze Jumperkabel am Raspberry Pi GPIO in Pin 6
  9. das rote Jumperkabel am Raspberry Pi GPIO in Pin 4
  10. BH1750 Sensor wie in unten stehender Tabelle
  11. Stromzufuhr via USB-C oder Micro USB Adapter
Raspberry Pi GPIO Pin BH1750 Pin
1 (3v3 power) VCC
6 (Ground) GND
5 (GPIO3 / SCL) SCL
3 (GPIO2 / SDA) SDA
nicht benötig ADDR

In den folgenden Bildern das Ergebnis festgehalten:

Touchdisplay Zusammenbau 1.jpgTouchdisplay Zusammenbau 2.jpgTouchdisplay Zusammenbau 3.jpg

Touchdisplay Zusammenbau 4.jpg

Auto Brightness Script

Das Herzstück der automatischen Anpassung der Display Helligkeit bildet ein python3 Script. Es ermöglicht in verschiedenen Stoffen den Lux Wert des Sensors automatisch auf einen Helligkeitswert des Displays zu Mappen und dann dementsprechend das Display heller oder dunkler zu machen. Ist es komplett Dunkel, schaltet sich das Display komplett aus. Ist es wieder hell, schaltet es sich an. Das Mapping dazu befindet sich im oberen Teil des Skriptes:

# Switch levels for brightness
# lux value (lux), brightness value (%)
lux_level_1 = 0.1, 25
lux_level_2 = 20, 35
lux_level_3 = 100, 45
lux_level_4 = 200, 55
lux_level_5 = 300, 65
lux_level_6 = 450, 75
lux_level_7 = 600, 85
lux_level_8 = 800, 100

Ich habe lange getestet und denke diese Vorgaben passen ganz gut, vor allem in Betracht, aus stromspar Gründen, das Display eher dunkler zu haben. Es gibt im Skript noch den adjust Wert, mittels diesem kann man in Prozentschritten die Helligkeit ein wenig fein justieren. Dieser adjust Wert wird in der MQTT Variante verwendet um zum Beispiel via HABPanel das Display heller oder dunkler zu stellen.

Um dieses Skript nun nutzen zu können müssen als erstes ein paar Abhängigkeiten konfiguriert und installiert werden.

Zuerst via raspi-config den i2c Bus aktivieren.

raspi-config nonint do_i2c 0

nun installieren wir noch die benötigten Software Abhängigkeiten:

apt install -y python3-smbus i2c-tools python3-pip python3-systemd -y 
pip3 install --user adafruit-circuitpython-bh1750 rpi-backlight

Download des Scriptes von hier: https://raw.githubusercontent.com/alaub81/rpi_autodisplay/main/rpi_autodisplay.py

/usr/local/sbin/rpi_autodisplay.py

#!/usr/bin/python3
from rpi_backlight import Backlight
import board, adafruit_bh1750, systemd.daemon, time

### set the variables
# Switch levels for brightness
# lux value (lux), brightness value (%)
lux_level_1 = 0.1, 25
lux_level_2 = 20, 35
lux_level_3 = 100, 45
lux_level_4 = 200, 55
lux_level_5 = 300, 65
lux_level_6 = 450, 75
lux_level_7 = 600, 85
lux_level_8 = 800, 100

### do the stuff
backlight = Backlight()
backlight.fade_duration = 0.5

# just give some used variables an initial value
lastvalue = 0
# if you like to raise all DISP_BRIGHTNESS
# set values betwenn 0.2 (lower brightness) and 2 (higher brightness)
# 1 will let it as it is
adjust = 1

# Tell systemd that our service is ready
print('Starting up Display Service ...')
systemd.daemon.notify('READY=1')

### Functions
def sensor():
  global lux
  i2c = board.I2C()
  sensor = adafruit_bh1750.BH1750(i2c)
    i = 0
  while sensor.lux <= lux_level_1[0] and i < 15:
    time.sleep(2)
    i += 1
    #print(i)
  lux = sensor.lux
  #print("%.2f Lux" % lux)

def backlightpower(state):
  backlight.power = state

def brightness(level):
  global dpb
  global lastvalue
  dpb = round(level * adjust)
  #print("dpb after adjustment:", dpb)
  #print("value to display:", (min(max((lux_level_1[1]), dpb), (lux_level_8[1]))))
  backlight.brightness = (min(max((lux_level_1[1]), dpb), (lux_level_8[1])))
  lastvalue = level

# running
# finaly the loop
while True:
  try:
    sensor()

    # Display ON/OFF
    if lux < (lux_level_1[0]) and backlight.power == True:
      backlightpower(False)
    elif lux > (lux_level_1[0]) and backlight.power == False:
      backlightpower(True)

    # set lux levels to brightness levels (incl. adjust value) if backlight is on
    if backlight.power == True:
      if (lux_level_1[0]) <= lux < (lux_level_2[0]) and lastvalue != (lux_level_1[1]):
        brightness(lux_level_1[1])
      if (lux_level_2[0]) <= lux < (lux_level_3[0]) and lastvalue != (lux_level_2[1]):
        brightness(lux_level_2[1])
      if (lux_level_3[0]) <= lux < (lux_level_4[0]) and lastvalue != (lux_level_3[1]):
        brightness(lux_level_3[1])
      if (lux_level_4[0]) <= lux < (lux_level_5[0]) and lastvalue != (lux_level_4[1]):
        brightness(lux_level_4[1])
      if (lux_level_5[0]) <= lux < (lux_level_6[0]) and lastvalue != (lux_level_5[1]):
        brightness(lux_level_5[1])
      if (lux_level_6[0]) <= lux < (lux_level_7[0]) and lastvalue != (lux_level_6[1]):
        brightness(lux_level_6[1])
      if (lux_level_7[0]) <= lux < (lux_level_8[0]) and lastvalue != (lux_level_7[1]):
        brightness(lux_level_7[1])
      if lux >= (lux_level_8[0]) and lastvalue != (lux_level_8[1]):
        brightness(lux_level_8[1])

  except KeyboardInterrupt:
    print("Goodbye!")
    exit (0)

  except :
    print("An Error accured ... ")
    time.sleep(3)
    continue

Nun geben wir dem Script noch das Execute Recht:

chmod +x /usr/local/sbin/rpi_autodisplay.py

dann können wir das Ganze für einen ersten Test starten:

rpi_autodisplay.py

Nun kann mittels mehr oder weniger Licht am Sensor getestet werden ob das Display dimmt. Bei komplett zuhalten des Sensors sollte das Display komplett ausschalten. Wer keine MQTT Unterstützung möchte, kann den nächsten Punkt überspringen und zum Systemd Service weitergehen.

Mit MQTT Unterstützung

Das rpi_autodisplay-mqtt.py Script ist die um die MQTT Fähigkeit erweiterte Version des rpi_autodisplay.py Scripts. Dieses bietet die Möglichkeit die Werte (Display Helligkeit, Umgebungshelligkeit und den Powerzustand) via MQTT zu publizieren. Ein weiteres Feature ist, den Helligkeitswert mittels adjust Value zu manipulieren und so das Display heller oder Dunkler zu stellen. Ebenso ist es Möglich via On and Off des dp_power_switch topic das Display an und auszuschalten. Ist das Display automatisch ausgeschalten, kann es dennoch angeschaltet werden und bleibt dann für 60 Sekunden angeschaltet. Diesen Wert kann man im Script ebenfalls anpassen (ontime = 60). Weiter unten Beschreibe ich wie man dies alles in openHAB integriert und so das alles steuern kann.

Für dieses Skript brauchen wir noch zusätzlich die paho-mqtt python Library. Diese kann man via apt nach installieren:

apt install python3-paho-mqtt -y

Download des Scriptes von hier: https://raw.githubusercontent.com/alaub81/rpi_autodisplay/main/rpi_autodisplay-mqtt.py /usr/local/sbin/rpi_autodisplay-mqtt.py

#!/usr/bin/python3
from rpi_backlight import Backlight
import board, adafruit_bh1750, systemd.daemon, time
import paho.mqtt.client as mqtt, ssl

### set the variables
# Switch levels for brightness
# lux value (lux), brightness value (%)
lux_level_1 = 0.1, 25
lux_level_2 = 20, 35
lux_level_3 = 100, 45
lux_level_4 = 200, 55
lux_level_5 = 300, 65
lux_level_6 = 450, 75
lux_level_7 = 600, 85
lux_level_8 = 800, 100
# MQTT Config
broker = "FQDN / IP ADDRESS"
port = 8883
publish_topic="home/attic/office"
clientid = "client-dp"
hostname = "clientname"
username = "mosquitto"
password = "password"
insecure = True
qos = 1
retain_message = True
# Retry to connect to mqtt broker
mqttretry = 5
# time in seconds how long display will be on, if it is auto off
ontime = 60

### do the stuff
print('Starting up Display Service ...')
backlight = Backlight()
backlight.fade_duration = 0.5

# just give some used variables an initial value
lastvalue = 0
lastlux = 0
powerswitch = "Null"
# if you like to raise all DISP_BRIGHTNESS
# set values betwenn 0.2 (lower brightness) and 2 (higher brightness)
# will be configured through MQTT Topic
# 1 will let it as it is
adjust = 1

### Functions
def publish(topic, payload):
  client.publish(publish_topic + "/" + topic,payload,qos,retain_message)

def on_connect(client, userdata, flags, rc):
  print("MQTT Connection established, Returned code=",rc)
  client.subscribe([(publish_topic + "/" + hostname + "/dp_brightness_adjust", qos),\
    (publish_topic + "/" + hostname + "/dp_power_switch", qos)])

def on_message(client, userdata, message):
  global adjust
  global powerswitch
  global lastvalue
  #time.sleep(1)
  if "dp_brightness_adjust" in message.topic:
    #print("adjust value", str(message.payload.decode("utf-8")))
    adjust = float(message.payload.decode("utf-8"))
    lastvalue = 0
  if "dp_power_switch" in message.topic:
    #print("MQTT power payload:", str(message.payload.decode("utf-8")))
    powerswitch = (str(message.payload.decode("utf-8")).split(","))
    #print("split wert 1", powerswitch[0])

def sensor():
  global lux
  global lastlux
  i2c = board.I2C()
  sensor = adafruit_bh1750.BH1750(i2c)
    i = 0
  while sensor.lux <= lux_level_1[0] and i < 15:
    time.sleep(2)
    i += 1
    #print(i)
  lux = sensor.lux
  if ("%.0f" % lastlux) != ("%.0f" % lux) or lux <= 1:
   publish("lux", "%.2f" % lux)
   lastlux = lux

def backlightpower(state):
  backlight.power = state
  if state == True: strstate = "On"
  if state == False: strstate = "Off"
  #print("STRSTATE to MQTT", strstate)
  publish(hostname + "/dp_power_switch", strstate)

def brightness(level):
  global dpb
  global lastvalue
  dpb = round(level * adjust)
  #print("dpb after adjustment:", dpb)
  #print("value to display:", (min(max((lux_level_1[1]), dpb), (lux_level_8[1]))))
  backlight.brightness = (min(max((lux_level_1[1]), dpb), (lux_level_8[1])))
  publish(hostname + "/dp_brightness_level", "%.2f" % (min(max((lux_level_1[1]), dpb), (lux_level_8[1]))))
  lastvalue = level

# running
#MQTT Connection
mqttattempts = 0
while mqttattempts < mqttretry:
  try:
    client=mqtt.Client(clientid)
    client.username_pw_set(username, password)
    client.tls_set(cert_reqs=ssl.CERT_NONE) #no client certificate needed
    client.tls_insecure_set(insecure)
    client.connect(broker, port)
    client.loop_start()
    mqttattempts = mqttretry
  except :
    print("Could not establish MQTT Connection! Try again " + str(mqttretry - mqttattempts) + "x times")
    mqttattempts += 1
    if mqttattempts == mqttretry:
      print("Could not connect to MQTT Broker! exit...")
      exit (0)
    time.sleep(5)

# MQTT Subscription
client.on_message = on_message
client.on_connect = on_connect

# Tell systemd that our service is ready
systemd.daemon.notify('READY=1')

# finaly the loop
while True:
  try:
    sensor()

    # Display ON/OFF
    if (powerswitch[0]) == "openHAB" and (powerswitch[1]) == "Off":
      if backlight.power == True:
        backlight.power = False
        #print("off")
    elif (powerswitch[0]) == "openHAB" and (powerswitch[1]) == "On" and lux > (lux_level_1[0]):
      backlightpower(True)
      #print("Display auto")
    elif (powerswitch[0]) == "openHAB" and (powerswitch[1]) == "On" and lux < (lux_level_1[0]):
      backlight.power = True
      #print("Overule Power for time", ontime)
      time.sleep(ontime)
      backlightpower(True)
    elif lux < (lux_level_1[0]) and backlight.power == True:
      #print("auto aus", lux)
      backlightpower(False)
    elif lux > (lux_level_1[0]) and backlight.power == False:
      #print("auto an", lux)
      backlightpower(True)

    # set lux levels to brightness levels (incl. adjust value) if backlight is on
    if backlight.power == True:
      if (lux_level_1[0]) <= lux < (lux_level_2[0]) and lastvalue != (lux_level_1[1]):
        brightness(lux_level_1[1])
      if (lux_level_2[0]) <= lux < (lux_level_3[0]) and lastvalue != (lux_level_2[1]):
        brightness(lux_level_2[1])
      if (lux_level_3[0]) <= lux < (lux_level_4[0]) and lastvalue != (lux_level_3[1]):
        brightness(lux_level_3[1])
      if (lux_level_4[0]) <= lux < (lux_level_5[0]) and lastvalue != (lux_level_4[1]):
        brightness(lux_level_4[1])
      if (lux_level_5[0]) <= lux < (lux_level_6[0]) and lastvalue != (lux_level_5[1]):
        brightness(lux_level_5[1])
      if (lux_level_6[0]) <= lux < (lux_level_7[0]) and lastvalue != (lux_level_6[1]):
        brightness(lux_level_6[1])
      if (lux_level_7[0]) <= lux < (lux_level_8[0]) and lastvalue != (lux_level_7[1]):
        brightness(lux_level_7[1])
      if lux >= (lux_level_8[0]) and lastvalue != (lux_level_8[1]):
        brightness(lux_level_8[1])

  except KeyboardInterrupt:
    print("Goodbye!")
    # At least close MQTT Connection
    client.disconnect()
    client.loop_stop()
    exit (0)

  except :
    print("An Error accured ... ")
    time.sleep(3)
    continue

# At least close MQTT Connection
client.disconnect()
client.loop_stop()

Bitte hier nun unter den Variablen eure MQTT Einstellungen vornehmen:

# MQTT Config
broker = "FQDN / IP ADDRESS" # --> Euer Broker FQDN oder IP Adresse
port = 8883 # --> Der Port des MQTT Brokers (hier der TLS Port, ohne wäre es 1883)
publish_topic="home/attic/office" # --> In welchen Topic soll pupliziert werden?
clientid = "client-dp" # --> MQTT Client ID, sollte eine einzigartige sein.
hostname = "clientname" # --> In diesen Topic werden die hilfs MQTT Werte publiziert (lux geht direkt in den Topic)
username = "mosquitto" # --> Falls User Auth an ist Benutzername eintragen
password = "password" # --> Falls User Auth an ist Passwort eintragen
insecure = True # --> Falls ihr nur über ein Self Signed SSL Zertifikat verfügt
qos = 1 # --> MQTT QoS Level (0, 1, 2) 
retain_message = True # --> Soll es als retained publiziert werden? (True, False)

Nun geben wir dem Script noch das Execute Recht:

chmod +x /usr/local/sbin/rpi_autodisplay-mqtt.py

Dann können wir das Ganze für einen ersten Test starten:

rpi_autodisplay-mqtt.py

Auch hier kann wieder durch hell und dunkel getestet werden ob das Display die Helligkeit ändert und ob es sich abschaltet und wieder anschaltet. Des Weiteren sollte nun Werte in den eingestellten MQTT Topics auftauchen:

MQTT Display Output.png

Systemd Service

Nachdem wir nun die Scripte installiert und erfolgreich getestet haben, wollen wir das Ganze natürlich noch über ein Systemd Script reboot fähig machen. Dafür legen wir als erstes ein unit file an:

Download hier möglich: https://raw.githubusercontent.com/alaub81/rpi_autodisplay/main/display.service

/etc/systemd/system/display.service

# systemd unit file for the rpi_autodisplay Python Script
[Unit]

# Human readable name of the unit
Description=Python Display Service

# Starting after System is online and docker is running
# Only needed if MQTT is used
Wants=network-online.target
After=network-online.target
# Only needed if MQTT Broker is running in a Docker Container on the same Host
#After=docker.service
#After=docker.socket

[Service]

# Command to execute when the service is started
# Without MQTT
#ExecStart=/usr/bin/python3 /usr/local/sbin/rpi_autodisplay.py
# Command to execute when the service is started
# With MQTT
ExecStart=/usr/bin/python3 /usr/local/sbin/rpi_autodisplay-mqtt.py

# Disable Python's buffering of STDOUT and STDERR, so that output from the
# service shows up immediately in systemd's logs
Environment=PYTHONUNBUFFERED=1

# Automatically restart the service if it crashes
Restart=on-failure

# Our service will notify systemd once it is up and running
Type=notify

# Use a dedicated user to run our service
User=root

# Send CTRL+C tot python Script to terminate it clean
KillSignal=SIGINT

[Install]

# Tell systemd to automatically start this service when the system boots
# (assuming the service is enabled)
WantedBy=default.target

Bitte prüft hier den Part mit Wants und After und kommentiert das gewünschte Script ein, bzw. aus. Ich habe hier das MQTT Script aktiviert. nun lesen wir die Datei ein

systemd daemon-reload

und starten den Daemon:

systemctl start display.service

die Status Ausgabe sollte dann wie folgt aussehen:

systemctl status display.service

Display Service Status.png

Ich habe hier die MQTT Variante gestartet. Deshalb die letzte Zeile, MQTT Connection established, Returned Code= 0.

Zu guter Letzt, nachdem das auch funktioniert hat, Aktivieren wir noch den Autostart:

systemctl enable display.service

Nun am besten einmal den Raspberry Pi Neustarten um zu testen ob danach alles wie gewünscht funktioniert.

Installation via GIT Repository

Hier findet ihr das Projekt in GitHub:

Die Installation via Git erfolgt so:

# Installation
cd /usr/src
git clone https://github.com/alaub81/rpi_autodisplay.git
cp rpi_autodisplay/rpi_autodisplay*.py /usr/local/sbin/
cp rpi_autodisplay/display.service /etc/systemd/system/
chmod +x /usr/local/sbin/rpi_autodisplay*.py
# Editieren der Dateien
nano /etc/systemd/system/display.service
nano /usr/local/sbin/rpi_autodisplay.py
nano /usr/local/sbin/rpi_autodisplay-mqtt.py
# Aktivieren des Autostart
systemctl enable display.service

openHAB / HABPanel Anbindung

Um nun die MQTT Anbindung via openHAB zu bewerkstelligen muss als erstes das MQTT Binding installiert werden. Mittels diesem legt man dann Items an, die man wiederum in einer Sitemap und oder HABPanel verwenden kann.

Display HABPanel.png

Ein Detaillierte Anleitung wie man MQTT an openHAB anbindet findet ihr hier:

Wie man einen Browser im Kiosk Mode auf dem Pi startet findet ihr hier:

Dies sind die MQTT Topics die durch das Script verfügbar sind:

rpi_autodisplay-mqtt.py Topics
Topic Wert Beispiel Topic Beschreibung
lux XXX.yy lux home/attic/office/lux BH1750 Sensor Wert in Lux
hostname/dp_brightness_level 0 - 100 % home/attic/office/laub-raspi3/dp_brightness_level Display Helligkeit in Prozent
hostname/dp_brightness_adjust 0.2 - 2.0 home/attic/office/laub-raspi3/dp_brightness_adjust Helligkeit- Manipulations Wert (1 = Normal)
hostname/dp_power_switch ON / OFF (openHAB,On / openHAB,Off) home/attic/office/laub-raspi3/dp_power_switch An und Ausschalter.

Die openHAB Werte überschreiben den Automatismus

openHAB Items

Nun müssen wir für die oben stehenden Topics in openHAB Items einrichten. Dafür habe ich zunächst für den Raspberry Pi ein eigenes MQTT Generic Thing angelegt.

Display MQTT Thing.png

Dann fügen wir für jeden Topic einen eigenen Channel dem Thing hinzu:

Display MQTT Lux.pngDisplay MQTT Display Brightness.pngDisplay MQTT Display Adjust.pngDisplay MQTT Display Power.png

nun sollte man 4 Channels im Thing sehen. Wir editieren nun noch die letzten beiden Channels, da wir hier nicht nur Daten empfangen sondern auch publizieren wollen. Deshalb gehen wir hier in die "Show More" Optionen und aktivieren bei beiden Retained und setzten den QoS auf 1 (at least once). Beim Switch Channel müssen wir noch das Outgoing Value Format mit diesem Wert füttern. Das sorgt dafür, dass der Status des MQTT openHAB,On bzw. openHAB,Off sein wird, welches vom Script dementsprechend verarbeitet wird.

openHAB,%s

Display MQTT Switch Advanced.png

Nun können wir zu jedem Channel einfach ein Item anlegen:

Display MQTT Lux Item.pngDisplay MQTT Display Brightness Item.pngDisplay MQTT Display Brightness Adjust Item.pngDisplay MQTT Display Switch Item.png

Das Ergebnis kann man sich nun in PaperUI Control anschauen und direkt testen:

Display MQTT PaperUI.png

als nächstes wollen wir die Items natürlich verwenden in HABPanel und in der Sitemap um sie via Handy steuern zu können.

openHAB sitemap

Ich habe nun noch die Items in meine sitemap eingebaut um auch via Mobile App das Display an und ausschalten zu können und auch die Helligkeit hoch oder runter zusetzen mit einem Slider. hier sind die beiden Code Fragmente die ich dafür verwendet habe:

Default item=LaubRaspi3MQTT_DisplayPowerSwitch label="Pi3 Display"
Slider item=LaubRaspi3MQTT_DisplayBrightnessAdjust label="Pi3 Display" icon="screen" minValue=0.2 maxValue=2 step=0.2
Default item=LaubRaspi3MQTT_DisplayBrightness label="Pi3 Display Brightness [%.1f %%]"
Default item=LaubRaspi3MQTT_Lux label="Büro Helligkeit [%.1f lux]"

Das Ergebnis sieht dann zum Beispiel so aus:

Display Sitemap.jpg

Mehr Informationen wie man Sitemaps für openHAB erstellt findet ihr hier:

HABPanel Widgets

Da ich bei mir auf den Touchdisplay HABPanel anzeigen lasse, möchte ich natürlich auch via Touchdisplay, die Werte sehen und auch via Slider das Display heller oder dunkler machen. Einen Ausschalter kann man natürlich auch bauen, bringt nur etwas um es auszuschalten, da, wenn es aus ist, man es natürlich nicht via touch wieder anschalten kann. Die folgenden Widgets habe ich eingerichtet:

Schieberegler / Slider Widget

Display HABPanel Slider Config.pngDisplay HABPanel Slider.png

Lux Helligkeit Dummy Widget

Display HABPanel Lux Config.pngDisplay HABPanel Lux.png

Display Helligkeit Dummy Widget

Display HABPanel Helligkeit Config.pngDisplay HABPanel Helligkeit.png

Alexa Steuerung

Möchte man das Display via Sprachbefehl aus oder anschalten, so muss man einfach dem Display Power Switch Item via Rest API das Alexa Metadata Switchable mitgeben:

Display Alexa Power Switch.png

dies ist der Body zum copy and pasten:

{
  "value": "Switchable",
  "config": {}
}

Nun in der Alexa App nach neuen Devices suchen und dem Display Power Switch einen Ort zuweisen. Und schon kann man via "Alexa, schalte das Display aus" das Touchdisplay ausschalten.

Stromverbrauch

Natürlich ist bei Geräten die dauerhaft mit Strom versorgt sind der Stromverbrauch interessant. Ich habe deshalb unter verschiedenen Szenarien mal gemessen. Ich hoffe meine Messwerte sind einigermaßen brauchbar. Ich habe diese Messungen anhand eines Raspberry Pi 3 Modell B, dem Original 7" Touchdisplay nur mit dem angeschlossenen BH1750 Sensor und einer MicroSD Karte.

Setup Zustand Watt Ampere Bemerkung
Nur Netzteil 0,1 W altes Apple iPod USB Netzteil
Ohne Display idle 1,8 W 0,22 A frisch Installiert und gebootet
Vollast 4,7 W 0,70 A stress -c 4
HDMI & Bluetooth aus 1,7 W 0,20 A Raspberry Pi HDMI deaktivieren

Raspberry Pi Bluetooth deaktivieren

USB aus 1,2 W 0,13 A /usr/sbin/uhubctl -a 0
Mit Display
  • HDMI aus
  • Bluetooth aus
  • USB aus
  • No Grafik Boot
25 % 2,5 W 0,33 A rpi-backlight -b 25
35 % 2,8 W 0,36 A rpi-backlight -b 35
45 % 3,2 W 0,42 A rpi-backlight -b 45
55 % 3,7 W 0,50 A rpi-backlight -b 55
65 % 4,8 W 0,68 A rpi-backlight -b 65
75 % 5,1 W 0,72 A rpi-backlight -b 75
85 % 4,9 W 0,68 A rpi-backlight -b 85
100 % 4,4 W 0,61 A rpi-backlight -b 100
aus 2,0 W 0,25 A rpi-backlight -p off

Quellen