[Bastelei] Garagentoröffner mit Arduino und Homebridge

Nachdem ich bereits mit dem Feinstaubsensor und dem Temeraturfühler erste Arduino-Luft geschnuppert hab, stand das nächste „Problem“ auf der Liste: Meine Garagentore.

Bisher hatte ich für jedes Garagentor einen Raspberry Pi mit Homebridge und homebridge-rasppi-gpio-garagedoor im Einsatz. Das hat zwar funktioniert, war mir aber immer schon ein Dorn im Auge, da die Raspberry Pis für diese einzelne Anwendung etwas oversized waren. Zudem hat ein Raspberry Pi bzw. die SD-Karte den Geist aufgegeben. Daher war es wieder etwas Zeit für eine Bastelstunde.

Da sich meine C++ Fähigkeit stark in Grenzen hält, hab ich mir große Teile des Codes aus dem Internet zusammengeklaut. Mein Ziel war es, auf dem Arduino einen Webserver laufen zu lassen. Dieser sollte bei einem normalen Aufruf den Status des Tors (OPEN, CLOSED, OPENING, CLOSING) ausgeben, mit einem Parameter (?switch=1) das angeschlossene Relais schalten.

Neben dem Relais sollte noch ein Kontaktschalter am Tor abgefragt werden, der bei geschlossenem Tor ebenfalls geschlossen ist. Auf einen „Offen“-Kontaktschalter habe ich verzichtet, da ich nur bei einem Garagentor eine zuverlässige Möglichkeit zur Befestigung gefunden hab.

Der Code

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#define RelaisPin D4
#define ClosePin D1

const char* ssid = "WLAN-SSID";
const char* password = "WLAN-PASSWORD";
const char* doorstatus = "";
int currentstate;
int timetoopen = 17;
unsigned long switchedtime;

ESP8266WebServer server(80);

void setup()
{
  pinMode(RelaisPin, OUTPUT);
  pinMode(ClosePin, INPUT_PULLUP);
  digitalWrite(RelaisPin, 1);

  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }
  server.on("/", BuildIndex);
  server.onNotFound ( handleNotFound );
  InitialDoorStatus();
  server.begin();
}

void loop()
{
  server.handleClient();
  if (millis() < (switchedtime + 200)) {
  }
  else if (digitalRead(ClosePin) != currentstate && digitalRead(ClosePin) == 1) {
    doorstatus = "OPENING";
    switchedtime = millis();
    currentstate = 1;
  }
  else if (digitalRead(ClosePin) != currentstate && digitalRead(ClosePin) == 0) {
    InitialDoorStatus();
  }
  else if (millis() > (1000 * timetoopen) + switchedtime && doorstatus == "OPENING") {
    InitialDoorStatus();
  }
  else if (millis() > (30000 + switchedtime)) {
    InitialDoorStatus();
  }
  delay(100);
}

void DoSwitch() {
  digitalWrite(RelaisPin, 1 ^ 1);
  delay(1000);
  digitalWrite(RelaisPin, 1 ^ 0);
  switchedtime = millis();
}

void BuildIndex()
{
  server.sendHeader("Cache-Control", "no-cache");
  if (server.arg("switch") == "1")
  {
    if (digitalRead(ClosePin) == 1) {
      doorstatus = "CLOSING";
    }
    else if (digitalRead(ClosePin) == 0) {
      doorstatus = "OPENING";
    }
    DoSwitch();
  }
  server.send(200, "text/html", doorstatus);
}

void InitialDoorStatus()
{
  currentstate = digitalRead(ClosePin);
  if (digitalRead(ClosePin) == 1) {
    doorstatus = "OPEN";
  }
  else if (digitalRead(ClosePin) == 0) {
    doorstatus = "CLOSED";
  }
}

void handleNotFound()
{
  server.send(404, "text/plain", "404: Not found");
}

Mein Code lädt zunächst die beiden Libraries für WLAN und den Webserver. Danach definiere ich den Relais-Pin (D4), der das Relais schaltet und den Kontaktschalter-PIN (D1) der den „Geschlossen“-Status des Tors liefert. Die timetoopen ist die Zeit, wie lange der Status des Tors nach dem Öffnen-Impuls auf „OPENING“ steht, bevor es dann auf „OPEN“ springt. Dieser Status ist später für die Homebridge Implementierung sinnvoll.

Die Variable „doorstatus“ hält den jeweiligen Status des Tors und gibt ihn über den Webserver aus. Dazu überprüft es regelmäßig den Zustand des Kontaktschalters. Bei einem Schaltvorgang setze ich den doorstatus auf OPENING (wenn der Kontaktschalter geschlossen war) bzw. CLOSING (wenn der Kontaktschalter offen war). Gleichzeitig merke ich mir die Laufzeit des Arduino beim Auslösen des Schaltvorgangs.

Beim öffnenden Tor setze ich den Status nach der angegebenen Zeit in timetoopen auf OPEN, beim Schließvorgang setzt das Schließen des Kontakts den Status von CLOSING auf CLOSED. Sollte hier nach 30sek keine Änderung des Kontaktzustands erfolgen (z.B: wenn das Tor manuell angehalten wird), frage ich den Status erneut ab.

Ich hoffe, das Script ist einigermaßen verständlich…

Die Homebridge-Anbindung

Für die Einbindung in Homebridge benutze ich homebridge-garagedoor-command mit folgenden Einstellungen:

{
	"accessory": "GarageCommand",
	"name": "Garage Door",
	"open": "curl 'http://MY_IP/?switch=1'",
	"close": "curl 'http://MY_IP/?switch=1'",
	"state": "curl 'http://MY_IP/'",
	"status_update_delay": 17,
	"poll_state_delay": 20
}

Das war’s.


Posted

in

by

Tags:

Comments

10 Antworten zu „[Bastelei] Garagentoröffner mit Arduino und Homebridge”.

  1. Avatar von Fred
    Fred

    Hallo,
    vielen Dank für das Bastelprojekt. Ich bin auf der Suche nach genau so etwas für unsere Garage. Ich habe die gleiche Bedingungen. Ein Relais, dass einen Impuls schicken muss, da der Motor nur einen Taster Impuls brauch und einen Magnetschalter. Ich würde gerne einen WEMOS D1 Mini nutzen. Ist bei dir das Relais auch auf Impuls gestellt?
    Was gibt die Seite „state“: „curl ‚http://MY_IP/’“ den aus? Nur OPEN oder Closed?
    Danke

    Like

    1. Avatar von Michael Schmid

      Hallo Fred,
      Ja, das Relais ist auf Impuls gestellt bzw. es schließt über das Programm für 1sek. Das reicht um mein Garagentor auszulösen.
      Die Seite gibt die states OPEN, CLOSING, CLOSED, OPENING aus.

      Der Status CLOSED ist hart an den Schalteingang gekoppelt.
      Ist der Status CLOSED und der Schalter wird geöffnet (also entweder durch das script selber, oder über eine externen Funksender o.ä.) geht der Status zunächst auf OPENING, nach der eingestellten Zeit dann auf OPEN.
      Ist der Status auf OPEN und über den ESP wird geschalten, geht der Status auf CLOSING bis der Schalter geschlossen ist. Hier kann ich natürlich keine Fremdbedienung erkennen, daher warte ich 30sek. Wird nach 30sek der Schalter geschlossen, siehe 1. ansonsten springe ich zurück auf OPEN.
      Ist der Status auf OPEN und das Tor wird irgendwie manuell bedient und der Schalter geschlossen => siehe 1.

      Like

      1. Avatar von Fred
        Fred

        Okay, super vielen dank. Es funktioniert. Leider ist mein Magnetschalter ein Öffner oder Schließer. Wenn die Garage offen ist und der Magnetschalter Parallel ist, dann steht jetzt CLOSED da. Ich muss das Signal invertieren. Wo ändere ich das in deiner Programmierung?

        Like

      2. Avatar von Fred
        Fred

        Ich habe quasi oben am Motor meinen ESP hängen und dort den Magnetschalter der bei offenem Tor geschlossen ist.

        Like

      3. Avatar von Michael Schmid

        Da müsstest du alle if-abfragen von digitalRead(ClosePin) umdrehen, also aus allen „digitalRead(ClosePin) == 1“ wird „digitalRead(ClosePin) == 0“ und aus allen „digitalRead(ClosePin) == 0“ wird „digitalRead(ClosePin) == 1“

        Like

      4. Avatar von Fred
        Fred

        Es funktioniert so nicht richtig.

        ESP8266WebServer server(80);

        void setup()
        {
        pinMode(RelaisPin, OUTPUT);
        pinMode(ClosePin, INPUT_PULLUP);
        digitalWrite(RelaisPin, 1);

        Serial.begin(115200);
        WiFi.begin(ssid, password);
        while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        }
        server.on(„/“, BuildIndex);
        server.onNotFound ( handleNotFound );
        InitialDoorStatus();
        server.begin();
        }

        void loop()
        {
        server.handleClient();
        if (millis() (1000 * timetoopen) + switchedtime && doorstatus == „OPENING“) {
        InitialDoorStatus();
        }
        else if (millis() > (30000 + switchedtime)) {
        InitialDoorStatus();
        }
        delay(100);
        }

        void DoSwitch() {
        digitalWrite(RelaisPin, 1 ^ 1);
        delay(1000);
        digitalWrite(RelaisPin, 1 ^ 0);
        switchedtime = millis();
        }

        void BuildIndex()
        {
        server.sendHeader(„Cache-Control“, „no-cache“);
        if (server.arg(„switch“) == „0“)
        {
        if (digitalRead(ClosePin) == 0) {
        doorstatus = „CLOSING“;
        }
        else if (digitalRead(ClosePin) == 1) {
        doorstatus = „OPENING“;
        }
        DoSwitch();
        }
        server.send(200, „text/html“, doorstatus);
        }

        void InitialDoorStatus()
        {
        currentstate = digitalRead(ClosePin);
        if (digitalRead(ClosePin) == 0) {
        doorstatus = „OPEN“;
        }
        else if (digitalRead(ClosePin) == 1) {
        doorstatus = „CLOSED“;
        }
        }

        void handleNotFound()
        {
        server.send(404, „text/plain“, „404: Not found“);
        }

        Like

  2. Avatar von Fred
    Fred

    Also es funktioniert alles, ausser dass er von OPENING nicht in OPEN wechselt. Er bleibt bei OPENING stehen.

    Like

  3. Avatar von Fred
    Fred

    Ich habe es hinbekommen! Danke

    Jetzt habe ich ein Relais angeschlossen und leider ist dieser auch Invertiert. Also er schaltet sobald der ESP startet. Wo kann ich das ändern?

    Like

  4. Avatar von Fred
    Fred

    Ich hab jetzt auch das hinbekommen. Vielen dank für das super Tutorial. Ich habe so viele Methoden versucht, aber ihre ist die beste. Super!!!!! Sorry wegen dem

    Like

  5. Avatar von Jochen Happel
    Jochen Happel

    Hallo, vielen Dank für Dein Projekt, dass ich auch so realisiert habe. Ich habe am Tor einen magnetischen Hall-Sensor angebracht, der die Geschlossen-Stellung signalisiert. Aus Versehen hatte ich den erst falsch angebracht, so dass die Offen-Stellung gemeldet wurde. Der Fehler hat mich auf die Idee gebracht, jetzt 2 Schalter einzubauen, einer für Offen und einer für Geschlossen. Das werde ich demnächst ändern und die Software anpassen.

    Like

Hinterlasse einen Kommentar

Bloggen auf WordPress.com.