Der Schlaue Schalter

Nach den Grundlagen im Arbeiten mit IR Empfänger und IR Fernbedienung, dem Servo Motor und dem Bewegungsmelder wollen wir uns jetzt an ein praktisches Projekt machen. Eine Sache, die immer noch ziemlich mühselig ist und dabei physische Arbeit braucht, ist das Benutzen eines Lichtschalters. Denn wenn wir mit diesem das Licht ein und wieder aus schalten wollen, müssen wir uns immer noch bewegen. Ansonsten brennt das Licht einfach weiter, obwohl wir das Zimmer schon verlassen haben und das kann ja auch nicht wirklich die Lösung sein.

Bei diesem Projekt ist es das Ziel, diese Probleme möglichst zu minimieren. Heißt, wir wollen mit einem Knopfdruck der IR Fernbedienung das Licht an und wieder aus machen. Um den Schalter physisch zu bewegen, benutzen wir den Servo Motor und befestigen diesen direkt an einem Lichtschalter. Du musst dabei vermutlich ein wenig experimentieren, denn das Servo kann nicht alle Lichtschalter bewegen. Doch damit wird der Lichtschalter ja nicht gleich schlau. Mit dem Bewegungssensor werden wir auch noch Bewegung messen und wenn sich zulange in einem Raum nichts bewegt hat, das Lich wieder abschalten. Natürlich kannst du das Programm auch noch auf andere Möglichkeiten zuschneiden und verändern.

Anschlüsse PiAnschlüsse Sensoren
GNDGND / – | IR Empfänger
VCCVCC / + | IR Empfänger
GPIO 17Signal / S | IR Empfänger
GNDbraunes Kabel/GND Servo
VCCrotes Kabel/VCC Servo
GPIO 12orangenes Kabel/Signal Servo
5VVCC Bewegungssensor
GPIO 21Data Bewegungssensor
GNDGND Bewegungssensor
GPIO24Taster 1
GND + 10KOhmTaster 1

schlauerschalter.py

import RPi.GPIO as gpio
import time
from evdev import InputDevice, categorize, ecodes

dev = InputDevice('/dev/input/event6')
print(dev)

servo = 18
pir = 21
button = 24
timeout = 2*60

gpio.setmode(gpio.BCM)
gpio.setup(servo, gpio.OUT)
gpio.setup(pir, gpio.IN, pull_up_down=gpio.PUD_DOWN)
gpio.setup(button, gpio.IN, pull_up_down=gpio.PUD_UP)

p = gpio.PWM(servo, 50)
p.start(4)

status = False # licht an oder aus
last_movement = time.time() # letzte Bewegung

def turn_on(): # lichtschalter an
  global status # nutze globale variable 'status'
  p.ChangeDutyCycle(11)
  status = True
  time.sleep(.2)
  
def turn_off(): # lichtschalter aus
  global status
  p.ChangeDutyCycle(4)
  status = False
  time.sleep(.2)

def switch(channel): # welchsle zwischen an und aus
  global status, last_movement
  last_movement = time.time()
  print("Taster")
  if status == False:
    turn_on()
  else:
    turn_off()

def handle_movement(channel):
  global last_movement
  print("Bewegung")
  last_movement = time.time()

# event listener
gpio.add_event_detect(button, gpio.RISING,
    callback=switch, bouncetime=300)
gpio.add_event_detect(pir, gpio.RISING,
    callback=handle_movement, bouncetime=300)

try:
  while True:
    event = dev.read_one() # lese IR keycode
    if event and event.type == 4 and event.value < 1000:
      print("Fernbedienung")
      print(categorize(event))
      if event.value == 24: # licht an
        turn_on()
        last_movement = time.time()
      elif event.value == 82: # licht aus
        turn_off()    

    if (time.time() - last_movement >= timeout
        and status==True):
      turn_off()

    time.sleep(.01)

except KeyboardInterrupt:  
   print("Beendet") 
   gpio.cleanup()

Bevor ihr das Programm jetzt ausführt und an einem richtigen Lichtschalter testet, solltet ihr vor allem die Bewegung des Servos richtig festlegen.

Was haben wir gemacht?

Die Schritt für Schritt Erklärung sparen wir uns in diesem Moment, denn das meiste sollte euch schon bekannt vorkommen. Wir werden deswegen die Verschiedene Bereiche durchgehen, welche mit Kommentaren gekennzeichnet sind. In Zeile 8 bis 11 definieren wir alle wichtigen Variablen. Interessant ist dabei die Variable timeout, denn mit dieser Variable wird festgelegt, wann das Licht automatisch wieder ausgehen soll, wenn es keine Bewegung gibt. Diese Zeit wird in Sekunden angegeben. Mit der Funktion time.time() können wir die aktuelle Zeit als Timestamp bekommen. Ein Timestamp ist die Zeitmessung in Sekunden seit einem bestimmten Zeitpunkt.
Im nächsten Block setzen wir einige Einstellungen für die GPIO Pins. Dann setzen wir die Variablen status und last_movement. Dort speichern wir, ob das Licht aktuell ein oder ausgeschaltet ist und den letzten Timestamp.
Darauf definieren wir einige Funktionen, um das Servo später betätigen zu können.

Weiter geht es mit dem Taster. Immer wenn der Taster gedrückt wird, wollen wir, dass das Licht ausgeht, wenn es vorher geleuchtet hat und umgekehrt. In Zeile 51 wird deswegen mit der Funktion add_event_detect() ein Event Listener hinzugefügt, der sobald der Taster gedrückt (also sich am GPIO Pin die Spannung verändert) die Funktion switch aufruft.

Im nächsten Block geht es um den Bewegungssensor. Immer wenn es Bewegung gibt, müssen wir auch speichern, wann es Bewegung gegeben hat. Dafür benutzen wir einen ähnlichen Aufbau wie beim Taster doch, wenn Bewegung gemessen wird, wird die Funktion handle_movement aufgerufen. Diese speichert dann einfach nur den Aktuellen Timestamp in die Variable last_movement.

Weiter geht es mit der Infrarot-Funktionalität und damit an das Herzstücks des Projekts. Das System und Aufbau ist wie bei den vorherigen Einheiten. In der While-Schleife gibt es in Zeile 60 eine Funktion, die Testet ob die Taste für Licht an gedrückt wurde, wenn das der Fall ist, wird die Funktion turn_on aufgerufen. Natürlich gibt es da auch noch die Möglichkeit, verschiedene Tasten für Licht an und aus zu definieren. Außerdem aktualisieren wir auch hier die Variable last_movement auf den aktuellen Timestamp und starten somait die Wartezeit neu. Im nächsten Schritt wird in Zeile 66 nur noch kontrolliert, wie viel Zeit vergangen ist. Wenn das mehr ist, als unsere definierte Wartezeit und das Licht an ist, wird die Funktion turn_off aufgerufen und das Licht wird ausgeschaltet.

Und so einfach ist auch dein Schlauer Schalter. Natürlich kannst du diesen auch beliebig erweitern, z.B.: Nur noch auf Bewegung reagieren oder dein Lichtschalter nur noch mit Terminal steuern. Aber das ist ganz dir und deiner Kreativität überlassen.