Img 20191118 164108 Web

Analoge Türklingel über Discord-Bot betreiben

Da das Warp Core Cafe sehr offen ist, tragen die meisten Leute, die dort arbeiten, Kopfhörer mit Noise-Reduktion. Das ist schon dann sinnvoll wenn einer dort telefonieren will oder man einfach nur seine Ruhe möchte. Leider sorgt die Noise-Reduktion auch dafür das wir die Türklingel oft nicht mitbekommen. Selbst das beliebte Dauerklingeln bleibt oft ungehört.

Eine elegante Lösung wäre also, automatisch benachrichtigt zu werden, wenn es an der Tür klingelt. Da alle Bildschirmarbeit betreiben, fällt eine Nachricht via Messenger zwangsläufig ins Blickfeld. Derzeit nutzen wir zwei Instant-Messenger, Whatsapp und Discord.

Bots für Whatsapp zu erstellen ist schon etwas umständlich. Eine der kreativsten Lösungen, die ich gefunden habe, war von einem Programmierer, der das ganze über Selenium programmiert hat. Dennoch stellen solche Lösungen eher einen Workaround dar.

Discord hingegen ist eine echte Spielwiese. Neben vielen fertigen Bots gibt es auch jede Menge Wrapper für die API in verschiedenen Programmiersprachen.

Mit etwas Recherche habe ich dann auch IoT Projekte gefunden, die bereits eine Türklingel gebaut hatten. Die meisten haben aber tatsächlich eine komplette Türklingel gebaut und nicht eine bestehende analoge Klingel angeschlossen. Fündig wurde ich letztendlich auf heise.de. Dort wurde ein Raspberry Pi verwendet. Dazu hatten sie eine kleine Platine gebaut, an der zum einen die Türklingel angeschlossen wurde, sowie diese dann an die GPIO des Raspberry Pi.

Der Hinweis "Hat man jedoch Dauerdrücker im Freundeskreis, sollte man vorsichtshalber die 0,5-W-Variante wählen." hat mir dann verdeutlicht, dass ich diese Platine unter keinen Umständen selber bauen sollte. Ich bin wirklich nicht gut wenn es um Elektronik geht. Magnus dagegen schon und dieser war dann auch so freundlich und hat mir einen Prototypen gebaut, der entsprechend an unsere Klingel angepasst war.

Da der Bot auf einen Raspberry Pi leben wird, verwende ich Python als Programmiersprache.

Coding

Discord.py

Für die Bot-Funktionalitäten wird discord.py, ein Wrapper für die API von Discord verwendet. Die Dokumentation ist umfangreich, die Community recht groß. Allerdings habe ich die Erfahrung gemacht dass letztere sich schwer tut, wenn Leute neu dazustoßen.

Bot auf Discord anmelden

Um einen Bot zu betreiben, ist es aber notwendig, diesen zunächst auf Discord anzumelden und einen Token dafür zu erstellen. Diesen Token muss später auch in die Konfiguration des Bots eingetragen werden.

  1. Auf https://discordapp.com/developers gehen
  2. "New Application" auswählen
  3. Namen eingeben
  4. Bot wählen und dann auf "Add Bot"
  5. Token kopieren

Damit der Bot aber auf eurem Server erscheinen kann muss er dazu noch angemeldet werden. Dazu wählt man OAuth2. Bei Scope wird der Bot genommen sowie die Bot Permissions,

  • Send Messages
  • Mention Everyone

Der unten erstellten URL folgt man und wählt seinen Server aus, auf dem der Bot Zugriff haben soll.

Konfiguration

Damit das Programm Konfiguriert werden kann, wird dotenv genutzt, damit können Konfigurationsdateien ausgelesen werden, die sich auch für verschiedene Umgebungen definieren lassen.

import os

from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv())

Um jetzt den Token für den Bot zu erhalten können können wir jetzt einfach diesen Befehl nutzen,

os.getenv('TOKEN')

GPIO

Um die GPIO über Python3 anzusprechen müssen wir zunächst noch eine Bibliothek installieren.

sudo apt install python3-rpi.gpio

Die Platine wird einmal mit einem der GND-Pins verbunden, sowie einem der GPIO-Pins. Den Pin auf dem RPi fragen wir per Dauerschleife ab. Hat der von uns gewählte Pin ein Signal, wird eine Funktion aufgerufen.

import RPi.GPIO as GPIO

pin = int(os.getenv('GPIO_PIN'))
GPIO.setwarnings(False)

# Use physical pin numbering
GPIO.setmode(GPIO.BOARD)
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

while True:
    if (GPIO.input(pin) == GPIO.HIGH):
        await self._handlePressDoorbell()

Der Loop und das Dauerklingeln

Allerdings bedeutet das jetzt auch, dass wenn jemand die Türklingel gedrückt hält, ein wahres Dauerfeuer im Discord ausgelöst werden würde. Um das zu verhindern speichern wir bei jedem Durchlauf die Aktuelle Zeit in der Variable now. Haben wir jetzt ein Signal wird die Zeit von now mit has_run abgespeichert. Mit dem nächsten Durchlauf wird dann überprüft ob bereits 15 Sekunden vergangen sind.

has_run = none

while True:
    now = datetime.now()
    if (GPIO.input(self._channel) == GPIO.HIGH) and (has_run == None or (has_run + timedelta(seconds=15)) <= now):
        has_run = now
        await self._handlePressDoorbell()

Nachricht senden

Mit discord.py ist es sehr leicht, eine Nachricht zu versenden. Die Nachricht wird bei uns an einen Status-Kanal gesendet, der in der Konfiguration eingetragen wird.

# getting channel
id = int(os.getenv('CHANNEL'))
channel = self.get_channel(id)

await channel.send(content=content)

Benachrichtigungen

Unser Discord-Server ist allerdings so eingestellt, dass User nur dann eine Benachrichtigung erhalten, wenn die Nachricht mit einer Mention versehen ist. Die Frage ist aber: Wer muss wirklich wissen, dass es an der Tür klingelt? In den Status-Kanal sollen später vielleicht noch andere Sachen, einige könnten auch ohne Mention auskommen.

Um die Benachrichtigungen auf einzelne Personen zu begrenzen, kann in der Konfiguration noch ROLE angegeben werden. Dabei wird jedes Mitglied des gewählten Kanals überprüft. ob es die passende Rolle hat und dann zu den Mentions hinzugefügt.

for member in channel.members:
    for role in member.roles:

        # adding role
        if role.name == os.getenv('ROLE'):
            mentions += member.mention + ' '

mentions = mentions.strip()

Testen

Die Tests verliefen recht erfolgreich. Das Programm selber funktioniert, nur leider hat die Platine noch Ihre Eigenarten. Sie gibt nicht immer das Signal weiter. Was genau das Problem ist, konnten wir bisher nicht herausfinden.

Ich bin aber, eher durch Zufall, dann noch auf Tinkerforge gestoßen. Dort werden fertige Platinen für unterschiedliche Problemstellungen angeboten. Unter anderem auch eine Platine, die misst, ob bei einer Schaltung Strom fließt. Das ist genau das, wonach ichh gesucht habe. Ich habe mir also einen HAT Brick und den Voltage / Bricklet bestellt, um einfach mal zu schauen, wie gut das funktioniert.

Denn kompletten Code findet ihr übrigens hier: https://github.com/warp-core-cafe/mr-doorbell