ESP8266 D1 Mini Relais als HomeKit Schalter ohne Bridge - Tutorial
-
Wenn es bisher darum ging den ESP8266 D1 Mini in HomeKit einzubinden, bin ich immer den Weg über meine Homebridge auf dem Raspberry Pi gegangen. In der letzten Zeit hat sich da sehr viel getan und mittlerweile gibt es nicht nur eine Lösung das ganze auch ohne Bridge zu erreichen. Wir werden heute einen D1 Mini ohne Bridge oder sonstiges Zubehör direkt und nativ in HomeKit einbinden. Es handelt sich dabei erstmal nur um einen einfachen Schalter der ein Relaismodul betätigt.
HomeKit-ESP8266 - Arduino IDE Bibliothek hinzufügen
Bevor wir damit beginnen unseren eigenen HomeKit-Schalter einzubinden, muss eine Bibliothek in der Arduino IDE installiert werden. Das geht über den Bibliotheksverwalter. Ihr erreicht ihn über das Menü der Arduino IDE. Die Bibliothek heißt HomeKit-ESP8266 und kann über die Suche des Bibliotheksverwalters gefunden werden.
Arduino IDE └───Werkzeuge └───Bibliotheken verwalten...
HomeKit-ESP8266 - Der Code
Um den ESP8266 in HomeKit einzubinden, ist mehr als nur eine Datei notwendig. Ihr könnt dem Tutorial weiter folgen und die Dateien selber anlegen, oder die fertigen Dateien herunterladen: makesmart-esp8266-homekit-relais.zip
Öffnet die Arduino IDE und speichert das Projekt an einem beliebigen Ort. Nachdem das getan ist, müsst ihr zwei weitere Dateien anlegen. Das über die Tastenkombination
Strg + Umschalt + N
oder über den Klick auf den Pfeil in der rechten oberen Ecke.Nennt die erste Datei
my_accessory.c
und die zweite Dateiwifi_info.h
.
Jetzt kommen wir zum eigentlichen Code. Den Code könnt ihr 1:1 für die jeweilige Datei kopieren, einfügen und speichern.
1. Datei: mein_schalter.ino
#include <Arduino.h> #include <arduino_homekit_server.h> #include "wifi_info.h" #define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__); void setup() { Serial.begin(115200); wifi_connect(); homekit_storage_reset(); my_homekit_setup(); } void loop() { my_homekit_loop(); delay(10); } //============================== // HomeKit setup and loop //============================== // Zugriff auf die Definitionen des Accessories in my_accessory.c extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch_on; static uint32_t next_heap_millis = 0; #define PIN_SWITCH 15 // Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH, on ? HIGH : LOW); } void my_homekit_setup() { pinMode(PIN_SWITCH, OUTPUT); digitalWrite(PIN_SWITCH, HIGH); cha_switch_on.setter = cha_switch_on_setter; arduino_homekit_setup(&config); // Das hier kann verwendet werden, um den Status an HomeKit zurückzusenden, // falls ein zusätzlicher pysischer Button o.ä verwendet wird. // bool switch_is_on = true/false; // cha_switch_on.value.bool_value = switch_is_on; // homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); } void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { // heap-Info alle 30 Sekunden im seriellen Monitor ausgeben next_heap_millis = t + 30 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count()); } }
2. Datei: my_accessory.c
#include <homekit/homekit.h> #include <homekit/characteristics.h> void my_accessory_identify(homekit_value_t _value) { printf("accessory identify\n"); } // Switch (HAP section 8.38) // required: ON // optional: NAME // format: bool; HAP section 9.70; write the .setter function to get the switch-event sent from iOS Home APP. homekit_characteristic_t cha_switch_on = HOMEKIT_CHARACTERISTIC_(ON, true); // max. Länge 64 homekit_characteristic_t cha_name = HOMEKIT_CHARACTERISTIC_(NAME, "Schalter"); homekit_accessory_t *accessories[] = { HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_switch, .services=(homekit_service_t*[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) { HOMEKIT_CHARACTERISTIC(NAME, "Schalter"), HOMEKIT_CHARACTERISTIC(MANUFACTURER, "makesmart Community"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "1234567"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266 D1 Mini"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){ &cha_switch_on, &cha_name, NULL }), NULL }), NULL }; homekit_server_config_t config = { .accessories = accessories, .password = "123-45-678" };
3. Datei: wifi_info.h
Im folgenden Code müsst ihr eure WLAN-Zugangsdaten anpassen. Es sind die folgenden beiden Variablen:
const char *ssid = "WIFI-SSID"; const char *password = "WIFI-PASSWD";
#ifndef WIFI_INFO_H_ #define WIFI_INFO_H_ #if defined(ESP8266) #include <ESP8266WiFi.h> #elif defined(ESP32) #include <WiFi.h> #endif const char *ssid = "WIFI-SSID"; const char *password = "WIFI-PASSWD"; void wifi_connect() { WiFi.persistent(false); WiFi.mode(WIFI_STA); WiFi.setAutoReconnect(true); WiFi.begin(ssid, password); Serial.println("WiFi connecting..."); while (!WiFi.isConnected()) { delay(100); Serial.print("."); } Serial.print("\n"); Serial.printf("WiFi connected, IP: %s\n", WiFi.localIP().toString().c_str()); } #endif
Nachdem alle drei Dateien gespeichert wurden, kann das Programm auf den ESP8266 D1 Mini geladen werden. Geht dazu wieder in den Reiter “mein_schalter” und ladet das Programm auf den ESP.
HomeKit-ESP8266 - Die Einbindung in Homekit
Die Einbindung des DIY ESP8266 Relais in HomeKit ist ziemlich einfach.Öffnet dazu die Home-App und fügt ein neues Gerät hinzu. Der Schalter sollte in den Geräten in der Nähe auftauchen. Per Tippen auf den Schalter kann dieser hinzugefügt werden. Zum Hinzufügen muss ein Code eingegeben werden, der Code zum Koppeln lautet
123-45-678
.
HomeKit-ESP8266 - Die Verdrahtung
Der ESP wurde erfolgreich in HomeKit eingebunden und kann von nun an für Automationen und Szenen verwendet werden. Aber eins fehlt noch: Das Relais. Das ist wohl das geringste Übel dieses Tutorials - hier der Schaltplan:
KY-19 Relaismodul ESP8266 D1 Mini S D8 + 5V - G
Und fertig ist das HomeKit-Relais mit dem ESP8266 D1 Mini. Nativ. Ohne Bridge. Superschnell und super einfach.
Erfolgreich getestet und im Einsatz hab ich es mit diesen Produkten vom makesmart.shop.
Solltest du mit dem Programmieren / Debugging fertig sein, ist noch ein letzter Schritt nötig.
homekit_storage_reset();
Diese Zeile muss im
setup()
auskommentiert werden. Sonst muss der ESP8266 D1 Mini jedes mal aufs neue mit HomeKit gepaired werden. Wenn die Zeile auskommentiert oder entfernt ist, wird der D1 Mini auch nach dem Abstecken wieder als der gleiche Schalter erkannt und kann eingesetzt werden.
Möchtest du mehr als ein Relais mit nur einem D1 Mini direkt via HomeKit steuern?
Der User @Menuhin hat sich die Arbeit gemacht das Programm anzupassen, um mehr Relais damit steuern zu können. Den abgeänderten Sketch und eine Beschribung dazu findet ihr hier:Update von Menuhin für weitere Relais an einem D1 Mini
Disclaimer: Ich bin gerade frisch über diese Libary gestoßen und sehe darin (für mich persönlich) sehr viel potenzial. Ich werde vermutlich noch weitere Tutorials über die Libary und das Thema allgemein veröffentlichen. Es soll nicht bei diesem einen Schalter bleiben. Thermostate, Sensoren und so weiter sind ebenfalls möglich.
-
Hallo,habe dein Tutorial nachgebaut, funktioniert super.
Auch ich möchte diese Libary für mich nutzen. Leider stecke ich noch in den Arduino Kinderschuhen…
und ich schaffe es leider nicht einen zweiten ESP anzumelden. hat du da einen Tip für mich? -
Hallo!
Erstmal vielen Dank für diese einfache und leicht verständliche Anleitung.
In einem aktuellen Projekt in meinem Partykeller soll der HomeKit-ESP einen Raspberry Pi ein- und asusschalten.
Da der Raspi es allerdings nicht besonders mag hart ausgeschaltet zu werden müsste ich über einen GPIO-Shutdown den Raspi erst herunterfahren, bevor ich ihn vom Strom trennen kann.
Damit kommen wir zu meiner Frage:
Ist es möglich den Code um folgendes Szenario zu erweitern: Sobald in HomeKit AUS geschaltet wird, wird erst für kurze Zeit ein GPIO des ESP auf High gesetzt, um den GPIO-Shutdown am Raspi zu bewirken, dann wird für ein paar Sekunden gewartet und erst dann wird über das Relais ausgeschaltet. -
Du könntest folgendes Zeile anpassen um weitere Abläufe / Befehle hinzuzufügen.
// Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { bool on = value.bool_value;h cha_switch_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH, on ? HIGH : LOW); }
befindet sich in der
mein_schalter.ino
.
Hier könntest du deinen GPIO ansteuern und danach erst das Relais aus oder wie auch immer. -
Hallo,
Danke für das Top Tutorial.
Ich habe eine Frage bezüglich dem Wiederverbinden nach abschalten. Denn wenn ich aktuell den D1 vom Strom trenne und wieder anschließe dann muss ich ihn in der App wieder neu hinzufügen anstatt das er automatisch wiedergefunden wird.Gibt es eine Möglichkeit dies im Code zu ändern.
Über deine Hilfe wäre ich sehr dankbar.
-
@Paxi08 Danke
Bringt das hier nichts?
Solltest du mit dem Programmieren / Debugging fertig sein, ist noch ein letzter Schritt nötig.
homekit_storage_reset();
Diese Zeile muss im setup() auskommentiert werden. Sonst muss der ESP8266 D1 Mini jedes mal aufs neue mit HomeKit gepaired werden. Wenn die Zeile auskommentiert oder entfernt ist, wird der D1 Mini auch nach dem Abstecken wieder als der gleiche Schalter erkannt und kann eingesetzt werden.
-
Hey echt cooles Tutorial! Bin noch Anfänger mit Arduino und mache üblicherweise nur Copy und Paste. Würde gerne ein Projekt machen wo ich das gleiche mit 4 oder 5 Relais an einem ESP mache. Wie würde das gehen?
Vielen Dank schonmal. -
@WupDich Freut mich wenn es dir gefällt.
Wenn du mehr als nur ein Accessoire auf dem ESP betreiben möchtest, müsstest du den ESP als Bridge aka Gateway definieren - nicht als Accessoire.
Ich habe das selber noch nicht gemacht und komme wohl auch nicht dazu, das selbst zu probieren in nächster Zeit.
Wenn du ein eigenes Thema aufmachst findest du vielleicht jemanden, der dir Hilfestellung bietet.
Hier ist zumindest schon mal ein Beispiel mit mehreren Accessoires auf einem ESP.
-
@cooper Wie kann ich das jetzt für meine Türe verwenden? Ich habe es jetzt soweit hinbekommen das ich beim einschalten über HomeKit das Relais 2500ms an schalte und es sich danach wieder ausschaltet. Der Status in HomeKit stimmt dann aber nicht mehr. Gibt es dafür eine Lösung? Und kann man das auch als Schloß in HomeKit anzeigen lassen?
Vielen Dank im Voraus
Grüße
Denis -
@Denss Steht im Code auskommentiert
// Das hier kann verwendet werden, um den Status an HomeKit zurückzusenden, // falls ein zusätzlicher pysischer Button o.ä verwendet wird. // bool switch_is_on = true/false; // cha_switch_on.value.bool_value = switch_is_on; // homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value);
Das mit dem Schloss weiß ich nicht, da müsste man sich mit der Libary beschäftigen.
Habe mein Schloss via Homebridge eingebunden.
-
@cooper Das hatte ich schon mal eingefügt. Dann hat sich das Relais halt ständig an und aus geschalten. Welches Plugin hast du für die Homebridge verwendet?
-
@Denss Dann musst du es wahrscheinlich auscanclen.
Hier war letztens eine Frage dazu:
https://my.makesmart.net/topic/129/relais-beim-ersten-knopfdruck-high-beim-zweiten-knopfdruck-low-setzen/3Als plugin verwende ich http-webhooks.
-
Hallo Cooper,
Ich versuche seit einigen Tagen das tolle Script umzuarbeiten für zwei oder mehrere Schalter.
Hier sind meine zwei Konfigurations-Dateien:
mein_schalter.ino
#include <Arduino.h> #include <arduino_homekit_server.h> #include "wifi_info.h" #define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__); void setup() { Serial.begin(115200); wifi_connect(); homekit_storage_reset(); my_homekit_setup(); } void loop() { my_homekit_loop(); delay(10); } //============================== // HomeKit setup and loop //============================== // Zugriff auf die Definitionen des Accessories in my_accessory.c extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch_on1; extern "C" homekit_characteristic_t cha_switch_on2; static uint32_t next_heap_millis = 0; #define PIN_SWITCH1 D8 #define PIN_SWITCH2 D7 // Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on1_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on1.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH1, on ? HIGH : LOW); } void cha_switch_on2_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on2.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH2, on ? HIGH : LOW); } void my_homekit_setup() { pinMode(PIN_SWITCH1, OUTPUT); digitalWrite(PIN_SWITCH1, HIGH); cha_switch_on1.setter = cha_switch_on1_setter; arduino_homekit_setup(&config); pinMode(PIN_SWITCH2, OUTPUT); digitalWrite(PIN_SWITCH2, HIGH); cha_switch_on2.setter = cha_switch_on2_setter; arduino_homekit_setup(&config); // Das hier kann verwendet werden, um den Status an HomeKit zurückzusenden, // falls ein zusätzlicher pysischer Button o.ä verwendet wird. // bool switch_is_on = true/false; // cha_switch_on.value.bool_value = switch_is_on; // homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); } void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { // heap-Info alle 30 Sekunden im seriellen Monitor ausgeben next_heap_millis = t + 30 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count()); } }
my_accessory.c
#include <homekit/homekit.h> #include <homekit/characteristics.h> void my_accessory_identify1(homekit_value_t _value) { printf("accessory identify\n"); } void my_accessory_identify2(homekit_value_t _value) { printf("accessory identify\n"); } // Switch (HAP section 8.38) // required: ON // optional: NAME // format: bool; HAP section 9.70; write the .setter function to get the switch-event sent from iOS Home APP. homekit_characteristic_t cha_switch_on1 = HOMEKIT_CHARACTERISTIC_(ON, true); homekit_characteristic_t cha_switch_on2 = HOMEKIT_CHARACTERISTIC_(ON, true); // max. Länge 64 homekit_characteristic_t cha_name1 = HOMEKIT_CHARACTERISTIC_(NAME, "Schalter1"); homekit_characteristic_t cha_name2 = HOMEKIT_CHARACTERISTIC_(NAME, "Schalter2"); homekit_accessory_t *accessories[] = { HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_switch, .services=(homekit_service_t*[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) { HOMEKIT_CHARACTERISTIC(MANUFACTURER, "makesmart Community"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "1234567"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266 D1 Mini"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify1), NULL }), HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){ HOMEKIT_CHARACTERISTIC(NAME, "Schalter1"), &cha_switch_on1, &cha_name1, NULL }), NULL }), HOMEKIT_ACCESSORY(.id=2, .category=homekit_accessory_category_switch, .services=(homekit_service_t*[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) { HOMEKIT_CHARACTERISTIC(MANUFACTURER, "makesmart Community"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "1234567"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266 D1 Mini"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify2), NULL }), HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){ HOMEKIT_CHARACTERISTIC(NAME, "Schalter2"), &cha_switch_on2, &cha_name2, NULL }), NULL }), NULL }; homekit_server_config_t config = { .accessories = accessories, .password = "123-45-678" };
Leider bekomme ich beim Ausführen immer die Meldung:
HomeKit: Invalid accessory declaration: no Name characteristic in AccessoryInfo service
Ich finde meinen Fehler nicht. Haben Sie eventuell einen Tipp für mich?
-
@Menuhin Leider habe ich es bisher zeitlich selber noch nicht geschafft, multiple Accessories zu testen.
Aber nachdem du schon weit gekommen bist im Sinne vom Code, dann hilft dir vielleicht ein Blick in das Beispiel mit den Multiple Accessories.
Der ESP muss bei mehr als einem Accessorie wohl als Bridge programmiert werden.
This example is a bridge (aka a gateway) which contains multiple accessories.
Würde mich freuen wenn du ein Update geben könntest, falls du was herausgefunden hast.
Bis ich mich da selber nochmal ransetzen kann, werden wohl noch ein paar Tage … vergehen.
Gruß
-
Nach ein paar Versuchen bin ich jetzt fündig geworden bei all meinen Fehlern.
Für alle, die auch gerne mehrere Schalter/Relais direkt über Homekit in der App und angeschlossen am ESP realisieren wollen, kommen hier die beiden angepassten Dateien für
mein_schalter und my_accessory.cBei mir laufen die beiden Relais an den Schnittstellen D7 und D8 meines D1-ESPs. Das müsste man ggf anpassen und natürlich ist es nach diesem Prinzip auch möglich, mehr als zwei Relais einzubinden:
mein_schalter
#include <Arduino.h> #include <arduino_homekit_server.h> #include "wifi_info.h" #define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__); void setup() { Serial.begin(115200); wifi_connect(); homekit_storage_reset(); my_homekit_setup(); } void loop() { my_homekit_loop(); delay(10); } extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch1_on; extern "C" homekit_characteristic_t cha_switch2_on; static uint32_t next_heap_millis = 0; #define PIN_SWITCH1 D8 #define PIN_SWITCH2 D7 void cha_switch1_on_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch1_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH1, on ? HIGH : LOW); } void cha_switch2_on_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch2_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH2, on ? HIGH : LOW); } void my_homekit_setup() { pinMode(PIN_SWITCH1, OUTPUT); digitalWrite(PIN_SWITCH1, HIGH); cha_switch1_on.setter = cha_switch1_on_setter; pinMode(PIN_SWITCH2, OUTPUT); digitalWrite(PIN_SWITCH2, HIGH); cha_switch2_on.setter = cha_switch2_on_setter; arduino_homekit_setup(&config); } void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { next_heap_millis = t + 30 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count()); } }
my_accessory.c
Die Datei my_accessory.c fungiert in der Tat als Bridge und wird problemlos mit mehreren Schaltern betrieben, die dann auch im Homekit variabel verschiedenen Zimmern zugeordnet werden können etc.
Sie kann ebenfalls nach dem unten stehenden Prinzip .id=1, .id=2, .id=3 um weitere Schalter erweitert werden.
Unter .id1 sind nur die grundsätzlichen Angaben für die Bridge definiert, die Schalter sind dann fortlaufend (bei mir ist Schalter1 dann .id=2 und Schalter2 ist .id=3)#include <homekit/homekit.h> #include <homekit/characteristics.h> void my_accessory_identify(homekit_value_t _value) { printf("accessory identify\n"); } homekit_characteristic_t cha_switch1_on = HOMEKIT_CHARACTERISTIC_(ON, true); homekit_characteristic_t cha_switch2_on = HOMEKIT_CHARACTERISTIC_(ON, true); homekit_accessory_t *accessories[] = { HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_bridge, .services=(homekit_service_t*[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) { HOMEKIT_CHARACTERISTIC(NAME, "Multiple Switches"), HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Homekit Switches"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "1234567"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266 D1 Mini"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), NULL }), HOMEKIT_ACCESSORY(.id=2, .category=homekit_accessory_category_switch, .services=(homekit_service_t*[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) { HOMEKIT_CHARACTERISTIC(NAME, "Switch1"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){ HOMEKIT_CHARACTERISTIC(NAME, "Schalter1"), &cha_switch1_on, NULL }), NULL }), HOMEKIT_ACCESSORY(.id=3, .category=homekit_accessory_category_switch, .services=(homekit_service_t*[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) { HOMEKIT_CHARACTERISTIC(NAME, "Switch2"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){ HOMEKIT_CHARACTERISTIC(NAME, "Schalter2"), &cha_switch2_on, NULL }), NULL }), NULL }; homekit_server_config_t config = { .accessories = accessories, .password = "123-45-678" };
wifi_info.h bleibt unverändert und muss nur bei den Werten für das eigene WLAN angepasst werden.
Viel Spaß beim Ausprobieren!
Danke nochmal an den @cooper!!! -
-
@menuhin
Vielen Dank erstmal für deine Mühe!
Einen Doppelschalter brauche ich demnächst auch, da werde ich dein Scrip hier direkt übernehmenIch habe allerdings gerade ein anderes Problem.
Ich würde gerne ein Relais betreiben und zehn Sekunden vor dem Ein- bzw. Ausschalten dieses Relais einen anderen GPIO kurz auf High setzen:#include <Arduino.h> #include <arduino_homekit_server.h> #include "wifi_info.h" #define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__); const int buttonPin = 13; void setup() { Serial.begin(115200); wifi_connect(); pinMode(buttonPin, OUTPUT); my_homekit_setup(); } void loop() { my_homekit_loop(); delay(10); } //============================== // HomeKit setup and loop //============================== // Zugriff auf die Definitionen des Accessories in my_accessory.c extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch_on; static uint32_t next_heap_millis = 0; #define PIN_SWITCH 15 // Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(buttonPin, HIGH); delay(500); digitalWrite(buttonPin, LOW); delay(10000); digitalWrite(PIN_SWITCH, on ? HIGH : LOW); } void my_homekit_setup() { pinMode(PIN_SWITCH, OUTPUT); digitalWrite(PIN_SWITCH, HIGH); cha_switch_on.setter = cha_switch_on_setter; arduino_homekit_setup(&config); // Das hier kann verwendet werden, um den Status an HomeKit zurückzusenden, // falls ein zusätzlicher pysischer Button o.ä verwendet wird. // bool switch_is_on = true/false; // cha_switch_on.value.bool_value = switch_is_on; // homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); } void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { // heap-Info alle 30 Sekunden im seriellen Monitor ausgeben next_heap_millis = t + 30 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count()); } }
Das Funktioniert auch soweit theoretisch, allerdings geht das Ganze in HomeKit nicht. Aufgrund der zehnsekündigen Verzögerung wird mir direkt in der Apple Home App angezeigt, dass das Gerät nicht erreichbar ist. Nach mehreren Minuten (z.T. dauert es auch Stunden) wird dann der aktuelle Status wieder angezeigt.
Hast du eine Idee, wie ich dieses zehnsekündige Delay implementieren kann, ohne dass es diese “Gerät antwortet nicht” Fehlermeldung in Apple Home gibt?
Gibt es irgendwo einen Parameter, wo man einstellen kann, ab welchem Intervall das Gerät als nicht erreichbar deklariert wird?Vielen Dank im Voraus!
-
@homekitdude sagte in ESP8266 D1 Mini Relais als HomeKit Schalter ohne Bridge - Tutorial:
Ich habe allerdings gerade ein anderes Problem.
Ich würde gerne ein Relais betreiben und zehn Sekunden vor dem Ein- bzw. Ausschalten dieses Relais einen anderen GPIO kurz auf High setzen:Das ist kein Problem der Library. Das gehört eher allgemein zu ESP und Single Core.
// Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(buttonPin, HIGH); delay(500); digitalWrite(buttonPin, LOW); delay(10000); digitalWrite(PIN_SWITCH, on ? HIGH : LOW); }
delay(10000);
ist blocking. Das heißt dein gesamtes Programm pausiert und ist somit in diesem Zeitraum für HomeKit einfach nicht erreichbar, weil sich der ESP dumm stellt und auf gar nichts und niemanden reagiert, solange dieser
delay()
nicht abgelaufen ist.Du solltest hier eher mit
millis()
arbeiten.https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
-
@cooper
Danke für die schnelle Antwort und den passenden Link.
Bin heute irgendwie nicht in der Lage mich zu konzentrieren, daher werd ich mich da morgen mal dran setzen und versuchen das zu implementieren
Ich werde anschließend berichten, ob es geklappt hat -
@homekitdude Würde mich freuen.
Vielleicht wäre es dann nicht schlecht, die ganzen Modifikationen oben aufzulisten wenn es noch mehr werden.Dann ist für jeden vielleicht nochmal gleich was passendes dabei.
Bzw. eher so als kleine Sammlung
-
@cooper
Versuche mich da gerade einzuarbeiten. Leider hab ich aktuell keinen zugriff auf den ESP, daher muss ich die Lösung erstmal ohne Try’n’Error finden.
Wenn es bei der Lösung nur darum geht die delay() Funktion zu meiden und durch eine Funktion mit millis() zu ersetzen, dann könnte doch die folgende Funktion schon die Lösung sein (interval = 10000):void waitTenSec(){ unsigned long currentMillis = millis(); unsigned long goal = millis() + interval; while(currentMillis < goal) { currentMillis = millis(); } }
Wenn ich das dann folgendermaßen in den Code einsetze, dann sollte es doch funktionieren
#include <Arduino.h> #include <arduino_homekit_server.h> #include "wifi_info.h" #define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__); const int buttonPin = 13; const long interval = 10000; void setup() { Serial.begin(115200); wifi_connect(); pinMode(buttonPin, OUTPUT); my_homekit_setup(); } void loop() { my_homekit_loop(); delay(10); } //============================== // HomeKit setup and loop //============================== // Zugriff auf die Definitionen des Accessories in my_accessory.c extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch_on; static uint32_t next_heap_millis = 0; #define PIN_SWITCH 15 // Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(buttonPin, HIGH); delay(1000); digitalWrite(buttonPin, LOW); waitTenSec(); digitalWrite(PIN_SWITCH, on ? HIGH : LOW); } void waitTenSec(){ unsigned long currentMillis = millis(); unsigned long goal = millis() + interval; while(currentMillis < goal) { currentMillis = millis(); } } void my_homekit_setup() { pinMode(PIN_SWITCH, OUTPUT); digitalWrite(PIN_SWITCH, HIGH); cha_switch_on.setter = cha_switch_on_setter; arduino_homekit_setup(&config); // Das hier kann verwendet werden, um den Status an HomeKit zurückzusenden, // falls ein zusätzlicher pysischer Button o.ä verwendet wird. // bool switch_is_on = true/false; // cha_switch_on.value.bool_value = switch_is_on; // homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); } void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { // heap-Info alle 30 Sekunden im seriellen Monitor ausgeben next_heap_millis = t + 30 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count()); } }
Oder hab ich einen Denkfehler? So einfach kann es doch eigentlich gar nicht sein
-
@homekitdude sagte in ESP8266 D1 Mini Relais als HomeKit Schalter ohne Bridge - Tutorial:
while(currentMillis < goal) { currentMillis = millis(); }
while(currentMillis < goal) { currentMillis = millis(); }
While ist wieder blocking…
Eigentlich kannst du das Beispiel was ich geschickt habe 1:1 verwenden.
Die Abfrage ob millis > goal ist muss einfach mit oh den loop() dann wird es ja auch laufend geprüft. -
@cooper
Soweit ich das sehe komme ich doch für mein Problem in keinem Fall an einem delay() oder der while-Schleife vorbei.// Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on.value.bool_value = on; LOG_D("Switch: %s", on ? "ON" : "OFF"); //hier wird der kurze Impuls für den buttonPin ausgegeben (die Sekunde delay() ist unkritisch) digitalWrite(buttonPin, HIGH); delay(1000); digitalWrite(buttonPin, LOW); //hier muss das digitalWrite(...) für zehn Sekunden verzögert werden digitalWrite(PIN_SWITCH, on ? HIGH : LOW); }
Nachdem der Impuls über den buttonPin abgegeben wurde müsste die Funktion doch weiter durchlaufen bzw. zu ende laufen müssen, um den ESP für HomeKit ansprechbar zu halten.
Das aber wiederum führt dazu, dassdigitalWrite(PIN_SWITCH, on ? HIGH : LOW);
ausgeführt wird und das Relais schaltet. Und zwar ohne die zehn Sekunden wartezeit, die der buttonPin benötigt und sein Script auszuführen.
Ich bekomm es grade nicht auf die Kette, wie ich da die millis()-Funktion implementieren kann, damit das läuft. Entweder ich bin zu eingerostet oder ich denke zu kompliziert… -
@homekitdude sagte in ESP8266 D1 Mini Relais als HomeKit Schalter ohne Bridge - Tutorial:
Soweit ich das sehe komme ich doch für mein Problem in keinem Fall an einem delay() oder der while-Schleife vorbei.
Nein es geht auch ohne.
Hab mich jetzt kurz an den PC gesetzt und den Sketch mal dementsprechend umgeschrieben.
Zuerst habe ich ein paar Variablen erstellt - orientier dich dabei bitte an dem Blink without delay()-Beispiel. Das sollte dir bekannt vorkommen.
const long switchDelay = 10000; unsigned long changedAt = 0; bool checkForUpdate;
Die Variable
checkForUpdate
ist da, um die Funktion des Prüfens später auszucanclen, sonst würde sie in Dauerschleife laufen.Zusätzlich dazu, habe ich die Variable
on
für den Status global gesetzt, sodass ich auch außerhalb der Funktioncha_switch_on_setter()
darauf zugreifen kann.bool on; // Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { on = value.bool_value; // hier der ganze Rest der Funktion checkForUpdate = true; }
^ innerhalb dieser Funktion wird auch dein buttonPin auf
HIGH
bzw.LOW
gesetzt.Nach Ablauf der 10 Sekunden, wird der Status und der Zustand des Relais geädert:
if (millis() - changedAt >= switchDelay && checkForUpdate == true) { checkForUpdate = false; changedAt = millis(); cha_switch_on.value.bool_value = on; homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); LOG_D("Switch: %s", on ? "ON" : "OFF"); }
Sobald
checkForUpdate = false
gesetzt wird, wird diese Abfrage übersprungen - sonst würde sich dein Relais wieder selbst aus- und wieder anschalten. Die Prüfung läuft sonst einfach durchgehend im Loop.PS: Es könnte sein, dass du den
switchDelay = 10000
etwas reduzieren musst, da du ja bereits eindelay(1000)
drinnen hast und auch nach jedem loop() nochmal eindelay(10)
drinnen ist.void loop() { my_homekit_loop(); delay(10); }
Hier siehst du nochmal die Ausschaltverzögerun und das Triggern des zusätzlichen GPIOs:
Das hier sind btw die beiden wichtigen Zeilen zum Schalten des Schalters in HomeKit.
cha_switch_on.value.bool_value = true; homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); //bzw. cha_switch_on.value.bool_value = false; homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value);
Code für Aus- und Einschaltverzögerung
#include <Arduino.h> #include <arduino_homekit_server.h> #include "wifi_info.h" #define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__); const int buttonPin = 13; void setup() { Serial.begin(115200); wifi_connect(); pinMode(buttonPin, OUTPUT); my_homekit_setup(); } void loop() { my_homekit_loop(); delay(10); } //============================== // HomeKit setup and loop //============================== // Zugriff auf die Definitionen des Accessories in my_accessory.c extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch_on; static uint32_t next_heap_millis = 0; #define PIN_SWITCH 15 const long switchDelay = 10000; unsigned long changedAt = 0; bool checkForUpdate; bool on; // Diese Funktion wird aufgerufen, wenn der Schalter in HomeKit betätigt wird void cha_switch_on_setter(const homekit_value_t value) { on = value.bool_value; digitalWrite(buttonPin, HIGH); LOG_D("buttonPin HIGH"); delay(1000); digitalWrite(buttonPin, LOW); LOG_D("buttonPin LOW"); changedAt = millis(); checkForUpdate = true; /* * Wait 10 Seconds * wird in my_homekit_loop() aufgerufen. */ } void my_homekit_setup() { pinMode(PIN_SWITCH, OUTPUT); digitalWrite(PIN_SWITCH, HIGH); cha_switch_on.setter = cha_switch_on_setter; arduino_homekit_setup(&config); // Das hier kann verwendet werden, um den Status an HomeKit zurückzusenden, // falls ein zusätzlicher pysischer Button o.ä verwendet wird. // bool switch_is_on = true/false; // cha_switch_on.value.bool_value = switch_is_on; // homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); } void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { // heap-Info alle 30 Sekunden im seriellen Monitor ausgeben next_heap_millis = t + 30 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count()); } if (millis() - changedAt >= switchDelay && checkForUpdate == true) { checkForUpdate = false; changedAt = millis(); cha_switch_on.value.bool_value = on; homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value); LOG_D("Switch: %s", on ? "ON" : "OFF"); } }
Es geht also doch ohne
delay()
undwhile
-
@cooper
Chapeau
Das hätte ich mit meinen rudimentären Java/Python/Arduino Kenntnissen aus dem Stand nicht hinbekommen.
Sehe da auch kaum Parallelen auf den ersten Blick zum Blink without delay() Beispiel. Aber im großen und ganzen hast du recht, dass das grundsätzlich sehr ähnlich ist. Nur nicht für einen Laien wie mich
Vielen Dank auf jeden Fall schon mal!️