Mit dem Magic Door Opener kann man von überall auf der Welt (überall wo es Internet gibt 😉 ) die Haustür (nicht Wohnungstür) öffnen und eine Notifications aufs Smartphone erhalten, sobald es an der Tür klingelt.
Die Idee kam mir als ich für Anwendungen für mein NodeMCU (ESP8266) gesucht habe. Dabei fielen meine Blicke irgendwann auf die Klingelanlage / Gegensprechanlage. Bei mir ist das die Ritto Twinbus Gegensprechanlage. Zugegeben es gibt eigentlich wenig „Use-Cases“ bei denen es Sinn macht die Tür für Fremde die Türen zu öffnen oder darüber informiert zu sein wenn es an der Tür klingelt obwohl man nicht da ist. Ich nutzte das System hauptsächlich um mit selbst die Tür aufzuschließen und um zu wissen ob der Paketbote tatsächlich bei mir geklingelt hat. Den größten Nutzen habe ich jedoch durch den Bau der Systems erlangt. Denn ich habe viel gelernt und möchte es deswegen mit euch teilen.
Ich werde das Projekt in 3-4 Artikel unterteilen. Im ersten Teil soll es nur um die Türöffner Funktion gehen. Im zweiten Teil, der schön etwas komplizierter ist, um das versenden von abgreifen von des Türklingelsignals und das versenden von Notifications zu Googles Firebase. In den letzten teilen soll es nur um die nötige Software gehen. Also das NodeMCU script, den kleinen Server und die Android App.
Beginnen wir also mit dem 1. Teil:
Dieser Teil es Projekt ist relative einfach umzusetzen und der Kostenaufwand ist auch sehr gering, solange man nichts beschädigt. Doch nun erstmal ein Video:
Einkaufsliste:
NodeMCU („Programmierbares WLAN Modul“)
3,15 € – NodeMCU eBay aus China
CMOS4066 (Bilateral Schalter – ähnlich Relais)
0,60 € x 5 (3,00 €) – eBay CMOS 4066
Kabel (Female) falls nicht vorhanden 😉
1,00 € – eBay Kabel
Oder auf Amazon.de mit schnellerem Versand:
Vorbereitung:
Zunächst habe ich mir die Gegensprechanlage genauer angeschaut. Ein Gerät der Marke Ritto Type Twinbus. Dieses habe ich geöffnet und etwas zur Platiene recherchiert.

Dank Thomas Abraham wurde ich fündig: Er beschreibt auf seiner Website was die Kontakte der Twinbus Platine für funktionen haben. Nun wusste ich also schon mal was ich machen muss, nämlich den 3. (Rot – für Türöffnung) und 4. (Blau – für GND) Kontakt verbinden. Alternativ hätte ich auch die Kontakte der kleinen Knöpfe verwenden können.
Umsetzung:

An diese Kontakte habe ich nun 2 Kabel angelötet und diese mit dem CMOS 4066 verbunden. In der Abbildung seht ihr außerdem die Verkabelung welche dann zum NodeMCU führen.

Nun muss der NodeMCU für einen Einsatz vorbereitet werden. Dazu muss der NodeMCU zunächste mit einer Firmware geflash werden. Dann kann er mit dem lua-script bespielt werden:
wifi.setmode(wifi.STATION)
wifi.sta.config("BudSpencer","PaPAT2xx1", 1)
wifi.sta.connect()
print(wifi.sta.getip())
bell1 = 2
pin1 = 3
led1 = 4
gpio.mode(pin1, gpio.OUTPUT)
gpio.mode(led1, gpio.OUTPUT)
gpio.mode(bell1, gpio.INPUT, gpio.PULLUP);
gpio.write(pin1, gpio.LOW)
gpio.write(led1, gpio.HIGH)
srv=net.createServer(net.TCP)srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = "";
local , , method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if(method == nil) then
, , method, path = string.find(request, "([A-Z]+) (.+) HTTP");
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
buf = buf.."
NodeMCU Door Opener
";
buf = buf.."Door OPEN
";
local _on,_off = "",""
if (_GET.pin == "OPEN") then
gpio.write(led1, gpio.LOW)
gpio.write(pin1, gpio.HIGH)
tmr.delay(1000 * 2000)
gpio.write(led1, gpio.HIGH)
gpio.write(pin1, gpio.LOW)
end
client:send(buf);
client:close();
collectgarbage();
end)
end)
lock = 0
function callback()
if lock==0 then
lock = 1
print ("called ")
print ("notify()")
http.post('http://192.168.178.5:9999/bell',
'Content-Type: application/json\r\n',
'{"hello":"world"}',
nil)
lock = 0
end
end
gpio.trig(bell1, "up", callback)
Netzwerk (VPN, Portforwarding, DynDNS):
Damit die App später auf den NodeMCU zugreifen kann oder einen vorgeschalteten Server kann man sich entweder ein VPN oder ein Port am Router Forwarden.
Vorteil beim VPN ist die Sicherheit jedoch kann die App dann nur genutzt werden, wenn das Gerät sich mit dem VPN verbunden hat. Deswegen habe ich mich für letzte Strategie entscheiden. Dabei stößt man auf das nächste Problem. Wie finden mein Handy meinen Heimrouter im Internet ? Er benötigt ja die IP Adresse um diesen anzusprechen aber diese ändert sich permanent. Die Lösung für das Problem ist eine DynDNS. Eine DynDNS ist eine dynamischer Wegweiser der auf eure Heimrouter deutet. Eine DynDNS sieht aus wie eine Internet Domain. Beispielsweise www.sueddeutsche.de –> 195.50.176.88. Wenn ihr diese Adresse erreichen wollte, schaut ein Computer wie die IP Adresse des Servers lautet, die bei dieser Domain hinterlegt ist.
Bei vielen Routern gibt es die Möglichkeit eine DynDNS einzurichten. Der Router sendet dann automatisch bei Änderung der IP oder in bestimmen Zeitintervallen ein IP Adressen Update zu eurem DynDNS Provider.
Weiter gehts mit Teil 2:
Teil 2: „Die Seite konnte leider nicht gefunden werden!“
/*********
Türöffner per WLAN
* TÖ Anzeige per eingebauter LED
* Schaltpin an D3
* Rückmelder Bell an D4
vom CMOS 4066
PIN7 = GND
PIN14 = VSS
PIN13 = Schaltpin zu NodeMCU D3
PIN1 = Ritto Telefon 7630 PIN8
PIN2 = Ritto Telefon 7630 PIN9
*********/
// Wir laden die uns schon bekannte WiFi Bibliothek
#include
// Hier geben wir den WLAN Namen (SSID) und den Zugansschlüssel ein
const char* ssid = „Kneipenkind“;
const char* password = „stasimanrulez“;
// Wir setzen den Webserver auf Port 80
WiFiServer server(80);
// Eine Variable um den HTTP Request zu speichern
String header;
// NodeMCU hat 2 interne LED vom ESP12-LED der GPIO02 (2, D4) und NODEMCU-LED GPIO16 (16, D0, LED_BUILTIN, BUILTIN_LED)
const int bell1 = D4;
const int pin1 = D3;
const int led1 = 2;
void setup() {
Serial.begin(115200);
pinMode(bell1, INPUT);
pinMode(pin1, OUTPUT);
pinMode(led1, OUTPUT);
digitalWrite(pin1, LOW);
digitalWrite(led1, HIGH);
// Per WLAN mit dem Netzwerk verbinden
Serial.print(„Connecting to „);
Serial.println(ssid);
WiFi.hostname(„tueroeffner“);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(„.“);
}
// Die IP vom Webserver auf dem seriellen Monitor ausgeben
Serial.println(„“);
Serial.println(„WLAN verbunden.“);
Serial.println(„IP Adresse: „);
Serial.println(WiFi.localIP());
server.begin();
}
void loop(){
WiFiClient client = server.available(); // Hört auf Anfragen von Clients
if (client) { // Falls sich ein neuer Client verbindet,
Serial.println(„Neuer Client.“); // Ausgabe auf den seriellen Monitor
String currentLine = „“; // erstelle einen String mit den eingehenden Daten vom Client
while (client.connected()) { // wiederholen so lange der Client verbunden ist
if (client.available()) { // Fall ein Byte zum lesen da ist,
char c = client.read(); // lese das Byte, und dann
Serial.write(c); // gebe es auf dem seriellen Monitor aus
header += c;
if (c == ‚\n‘) { // wenn das Byte eine Neue-Zeile Char ist
// wenn die aktuelle Zeile leer ist, kamen 2 in folge.
// dies ist das Ende der HTTP-Anfrage vom Client, also senden wir eine Antwort:
if (currentLine.length() == 0) {
// HTTP-Header fangen immer mit einem Response-Code an (z.B. HTTP/1.1 200 OK)
// gefolgt vom Content-Type damit der Client weiss was folgt, gefolgt von einer Leerzeile:
client.println(„HTTP/1.1 200 OK“);
client.println(„Content-type:text/html“);
client.println(„Connection: close“);
client.println();
// Hier werden die GPIO Pins ein- oder ausgeschaltet
if (header.indexOf(„GET /auf“) >= 0) {
Serial.println(„Tuer oeffnet“);
digitalWrite(led1, LOW);
digitalWrite(pin1, HIGH);
delay(3000);
digitalWrite(led1, HIGH);
digitalWrite(pin1, LOW);
}
// Hier wird nun die HTML Seite angezeigt:
client.println(„“);
client.println(“ ESP8266 Tueroeffner“);
client.println(„“);
// Es folgen der CSS-Code um die Ein/Aus Buttons zu gestalten
client.println(“ body {„);
client.println(“ font-family:Helvetica;“);
client.println(“ background-color:#eee;“);
client.println(“ text-align:center;“);
client.println(“ padding:85px 0;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle {„);
client.println(“ position:relative;“);
client.println(“ display:inline-block;“);
client.println(“ width:80px;“);
client.println(“ height:120px;“);
client.println(“ background-color:#bbb;“);
client.println(“ -webkit-border-radius:4px;“);
client.println(“ -moz-border-radius:4px;“);
client.println(“ border-radius:4px;“);
client.println(“ text-align:center;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle input {„);
client.println(“ width:100%;“);
client.println(“ height:100%;“);
client.println(“ margin:0 0;“);
client.println(“ padding:0 0;“);
client.println(“ position:absolute;“);
client.println(“ top:0;“);
client.println(“ right:0;“);
client.println(“ bottom:0;“);
client.println(“ left:0;“);
client.println(“ z-index:2;“);
client.println(“ cursor:pointer;“);
client.println(“ opacity:0;“);
client.println(“ filter:alpha(opacity=0);“);
client.println(„}“);
client.println(„“);
client.println(„.toggle label {„);
client.println(“ display:block;“);
client.println(“ position:absolute;“);
client.println(“ top:1px;“);
client.println(“ right:1px;“);
client.println(“ bottom:1px;“);
client.println(“ left:1px;“);
client.println(“ background-image:-webkit-linear-gradient(top,#fff 0%,#ddd 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:-moz-linear-gradient(top,#fff 0%,#ddd 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:-ms-linear-gradient(top,#fff 0%,#ddd 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:-o-linear-gradient(top,#fff 0%,#ddd 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:linear-gradient(top,#fff 0%,#ddd 50%,#fff 50%,#eee 100%);“);
client.println(“ -webkit-box-shadow:0 2px 3px rgba(0,0,0,0.4),“);
client.println(“ inset 0 -1px 1px #888,“);
client.println(“ inset 0 -5px 1px #bbb,“);
client.println(“ inset 0 -6px 0 white;“);
client.println(“ -moz-box-shadow:0 2px 3px rgba(0,0,0,0.4),“);
client.println(“ inset 0 -1px 1px #888,“);
client.println(“ inset 0 -5px 1px #bbb,“);
client.println(“ inset 0 -6px 0 white;“);
client.println(“ box-shadow:0 2px 3px rgba(0,0,0,0.4),“);
client.println(“ inset 0 -1px 1px #888,“);
client.println(“ inset 0 -5px 1px #bbb,“);
client.println(“ inset 0 -6px 0 white;“);
client.println(“ -webkit-border-radius:3px;“);
client.println(“ -moz-border-radius:3px;“);
client.println(“ border-radius:3px;“);
client.println(“ font:normal 11px Arial,Sans-Serif;“);
client.println(“ color:#666;“);
client.println(“ text-shadow:0 1px 0 white;“);
client.println(“ cursor:text;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle label:before {„);
client.println(“ content:attr(data-off);“);
client.println(“ position:absolute;“);
client.println(“ top:6px;“);
client.println(“ right:0;“);
client.println(“ left:0;“);
client.println(“ z-index:4;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle label:after {„);
client.println(“ content:attr(data-on);“);
client.println(“ position:absolute;“);
client.println(“ right:0;“);
client.println(“ bottom:11px;“);
client.println(“ left:0;“);
client.println(“ color:#666;“);
client.println(“ text-shadow:0 -1px 0 #eee;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle input:checked + label {„);
client.println(“ background-image:-webkit-linear-gradient(top,#eee 0%,#ccc 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:-moz-linear-gradient(top,#eee 0%,#ccc 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:-ms-linear-gradient(top,#eee 0%,#ccc 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:-o-linear-gradient(top,#eee 0%,#ccc 50%,#fff 50%,#eee 100%);“);
client.println(“ background-image:linear-gradient(top,#eee 0%,#ccc 50%,#fff 50%,#eee 100%);“);
client.println(“ -webkit-box-shadow:0 0 1px rgba(0,0,0,0.4),“);
client.println(“ inset 0 1px 7px -1px #ccc,“);
client.println(“ inset 0 5px 1px #fafafa,“);
client.println(“ inset 0 6px 0 white;“);
client.println(“ -moz-box-shadow:0 0 1px rgba(0,0,0,0.4),“);
client.println(“ inset 0 1px 7px -1px #ccc,“);
client.println(“ inset 0 5px 1px #fafafa,“);
client.println(“ inset 0 6px 0 white;“);
client.println(“ box-shadow:0 0 1px rgba(0,0,0,0.4),“);
client.println(“ inset 0 1px 7px -1px #ccc,“);
client.println(“ inset 0 5px 1px #fafafa,“);
client.println(“ inset 0 6px 0 white;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle input:checked:hover + label {„);
client.println(“ -webkit-box-shadow:0 1px 3px rgba(0,0,0,0.4),“);
client.println(“ inset 0 1px 7px -1px #ccc,“);
client.println(“ inset 0 5px 1px #fafafa,“);
client.println(“ inset 0 6px 0 white;“);
client.println(“ -moz-box-shadow:0 1px 3px rgba(0,0,0,0.4),“);
client.println(“ inset 0 1px 7px -1px #ccc,“);
client.println(“ inset 0 5px 1px #fafafa,“);
client.println(“ inset 0 6px 0 white;“);
client.println(“ box-shadow:0 1px 3px rgba(0,0,0,0.4),“);
client.println(“ inset 0 1px 7px -1px #ccc,“);
client.println(“ inset 0 5px 1px #fafafa,“);
client.println(“ inset 0 6px 0 white;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle input:checked + label:before {„);
client.println(“ z-index:1;“);
client.println(“ top:11px;“);
client.println(„}“);
client.println(„“);
client.println(„.toggle input:checked + label:after {„);
client.println(“ bottom:9px;“);
client.println(“ color:#aaa;“);
client.println(“ text-shadow:none;“);
client.println(“ z-index:4;“);
client.println(„}“);
client.println(„“);
// Webseiten-Überschrift
client.println(„Tueroeffner“);
// Zeige den aktuellen Status, und EIN/AUS Button
client.println(„“);
// Die HTTP-Antwort wird mit einer Leerzeile beendet
client.println();
// und wir verlassen mit einem break die Schleife
break;
} else { // falls eine neue Zeile kommt, lösche die aktuelle Zeile
currentLine = „“;
}
} else if (c != ‚\r‘) { // wenn etwas kommt was kein Zeilenumbruch ist,
currentLine += c; // füge es am Ende von currentLine an
}
}
}
// Die Header-Variable für den nächsten Durchlauf löschen
header = „“;
// Die Verbindung schließen
client.stop();
Serial.println(„Client getrennt.“);
Serial.println(„“);
}
}
Für die Ritto 6220/70 an den Pin 11 und 13 ist der Türöffner anzuschließen. Hier ist die besonderheit das der Kontakt ein NC sprich ein „normal closed“ ist und erst bei Betätigung geöffnet wird. Ich habe hier einfach anstelle des CMOS4066 ein Relais angeschlossen.
Hi wo ist der zweite Teil? Mfg
https://robinhenniges.com/diy-smart-door-fuer-5-euro-door-bell-part-2/
hello Robin,
i got the esp8266 and want to write your code to it using arduino ide but it keeps giving errors. what ide did you use or what did you prepare before you programmed the esp?
Hätte es auch ein einfacher Bipolar Transistor als Schalter getan? Oder gibt es einen speziellen Grund weshalb du den CMOS4066 genutzt hast?