Man kennt ja diese Raumluftspender, die in einem voreingestellten Intervall eine Brise des in der Kartusche gespeicherten Dufts in den Raum entlassen. Das gewählte Modell von glade kann 3 verschiedene Intervalle, die vielleicht für viel besuchte Autobahnklos praktikabel sind, aber für normale Haushalte völlig überzogen sind. Die wählbaren Intervalle sind 9, 18 und 36 Minuten oder eben aus.
Wenn das Teil also alle 36 Minuten sprühen soll, kann an sich vorstellen, wie der Raum nach ner Weile riecht und wie sich vor dem Teil eine Pfütze mit Duftsaft bildet.
Der erste Gedanke war: „Ach da wird ein kleiner NE555 drin sein oder eine Art Kippstufe (monostabil) die über die externe Beschaltung mit Widerständen und Kondensatoren die möglichen Zeiten definieren.“
Das wäre dann extrem einfach die Zeiten zu ändern. Leider nein… Im glade ist ein eigener Mikro-Controller, der die fest hinterlegten Zeiten, den man auch nicht umkonfigurieren kann.
Im Netz fand man ein paar Informationen über die Funktion der Steuerung, aber keine Möglichkeit das Teil frei zu programmieren. Allerdings sprüht das Teil direkt einmal los, wenn die Batterien eingelegt sind. Das kann man sich mit einer externen Beschaltung ja zu Nutze machen. Einfach alle 24h einschalten, den Sprühstoss abwarten und wieder 24h warten.
Man könnte doch einen ESP32 nehmen, einen Timer darin laufen lassen der alle 24 Stunden einmal die Spannung an die glade-Platine durchschaltet. Dazu braucht es auch kaum weitere Bauteile. Ein gewöhnlicher npn-Transistor vom Typ BC547 sollte ausreichen um die benötigten 130mA durch zu schalten. Im Dauerbetrieb schafft der BC547 zwar nur 100mA laut Datenblatt, aber Peaks bis 200 sind auch drin, ohne dass er gleich durchbrennt.
Ein Transistor hat drei Anschlüsse: den Collector, die Basis und den Emitter. Die Funktionsweise ist – ganz vereinfacht gesagt – eigentlich nur ein regelbarer Widerstand zwischen Collector und Emitter. Geregelt wird über den Strom, der von der Basis zum Emitter fließt. Je mehr Stromin die Basis, desto weniger Widerstand zwischen Collector und Emitter.
Als erstes baute ich die Zeichnung nach meiner Planskizze auf (greatscott plant und zeichnet solche Sachen immer noch am schönsten) und testete nur ob es funktioniert wenn der Ausgang des ESPs den Transistor über einen Vorwiderstand durchschalten würde. Das hat schon mal geklappt und ich konnte mich an die Timergeschichte machen.
Kurzer Einschub: Warum ein ESP32 und kein günstigerer ESP8266?
Wenn ein Controller 24h nichts zu tun hat sollte er auch nicht die ganze Zeit im normalen Modus laufen. Ein funktionierendes aber auch extrem unpraktisches Programm wäre vom Ablauf her in etwa so:
Nach dem Sprühen einfach 86400 Sekunden (24h) warten und dann wieder Sprühen.
Dabei würde der kleine Prozessor aber immer im normalen Betrieb laufen und unnötig Strom verbrauchen. Da der Sprüher mit 2AA (1,5V) Batterien läuft, sollte auf den Stromverbrauch ein besonderes Augenmerk gelegt werden. ESPs bieten die Möglichkeit eine Zeit lang (max. 71 Minuten) in einen Tiefschlaf gelegt zu werden, in dem sie nur wenige µA verbrauchen. „Ist ja easy, einfach 24x ne Stunde in den Tiefschlaf und dann einmal sprühen.“ – Leider nein, der ESP „vergisst“ erst mal alles was er in seinem Arbeitsspeicher hat wenn er in den Tiefschlaf geht (Ich kenne Personen, da ist das oft nicht anders…). Wenn man den „Sprüh-Befehl“ jetzt nur alle 24h ausführen will und der ESP zwangsläufig alle 71Minuten aufwachen muss, sollte er wissen, wie oft er schon aufgewacht ist, seit er das letzte Mal gesprüht hat. Die Anzahl der Aufwachvorgänge seit dem letzten Sprühen muss also gezählt werden und falls er 24 mal aufgewacht ist muss er wieder sprühen. Dazu muss man den Zählwert irgendwo speichern. Normalerweise speichert man solche Daten in einem EEPROM-Speicher, der auch ohne Stromversorgung seinen Inhalt nicht vergisst. Ein ESP8266 hat leider keinen integrierten EEPROM-Speicher. Deshalb viel die Wahl auf den ESP32.
Wenn schon ein ESP32 verbaut ist, kann man ihn auch ganz nutzen. Da beim ESP32 ein WLAN-Chip integriert ist funkt dieser jetzt auch in mein Smarthome wenn er gesprüht hat. Der vorläufige Programmcode sieht so aus:
#include <WiFi.h>
#include <PubSubClient.h>
//#define SLEEP_DURATION 60 * 60 * 1000000 // 1 Stunde in Mikrosekunden
#define SLEEP_DURATION 3600000000 // 1 Stunde in Mikrosekunden
#define TOTAL_SLEEP_TIME 24 // Gewünschte Gesamtzeit in Stunden
// #define SLEEP_DURATION 1000000 // 1 Sekunde in Mikrosekunden
// #define TOTAL_SLEEP_TIME 20 // Wie oft Wakeup bis Aktion
const char* ssid = "SSID";
const char* password = "krasses Passwort";
const char* mqttServer = "IP des MQTT Brokers";
const int mqttPort = Port des MQTT Brokers;
const char* mqttUser = "user";
const char* mqttPassword = "pass";
const char* mqttclientID = "clientname";
int PinSprayOut = 40;
WiFiClient espClient;
PubSubClient client(espClient);
RTC_DATA_ATTR int wakeCount = 0; // Im RTC-Speicher gesicherter Zähler
void setup() {
pinMode(PinSprayOut, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
wakeCount++;
Serial.begin(115200);
delay(1000);
Serial.print("actual wakeCount: ");
Serial.println(wakeCount);
// Prüfen, ob die gewünschte Schlafzeit erreicht ist
if (wakeCount >= TOTAL_SLEEP_TIME) {
Serial.println("Desired total sleep time reached. doing stuff...");
// #################
wifiConnect();
MQTTConnect();
delay(2000);
spray();
mqttOut();
// #################
wakeCount = 0;
Serial.println("Tasks completed, going back to sleep...");
ESP.deepSleep(SLEEP_DURATION); //ESP geht schlafen
} else {
//ESP geht wieder schlafen
ESP.deepSleep(SLEEP_DURATION);
//yield();
delay(100);
Serial.println("This message will never be send to serial! So sad...");
}
}
void loop() {
// Serial.println("This message will never be send to serial! So sad...");
}
// UPs
// Serial output
void SerialOutput(void) {
Serial.println("serialout:");
// Serial.print("temp: "); Serial.print(temp_celsius); Serial.println("°C ");
Serial.println("nothing to say");
}
void spray(void) {
Serial.println("function spray started");
digitalWrite(PinSprayOut, HIGH);
digitalWrite(LED_BUILTIN, HIGH);
delay(9000); //9 Sekunden delay
digitalWrite(PinSprayOut, LOW);
digitalWrite(LED_BUILTIN, LOW);
// // Sicherstellen, dass der Client verbunden ist
// if (client.connected()) {
// client.loop(); // Wichtig, um die MQTT-Verbindung aufrechtzuerhalten
// client.publish("/actors/glade", "Sprayed ya stink away!");
// Serial.println("Sprayed...");
// } else {
// Serial.println("MQTT client not connected. Message not sent.");
// }
delay(100);
}
void mqttOut(void) {
Serial.println("Generating message for MQTT...");
// Sicherstellen, dass der Client verbunden ist
if (client.connected()) {
client.loop(); // Wichtig, um die MQTT-Verbindung aufrechtzuerhalten
client.publish("/actors/glade", "Sprayed ya stink away!");
Serial.println("Sprayed...");
} else {
Serial.println("MQTT client not connected. Message not sent.");
}
delay(500);
}
void wifiConnect(void) {
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi...");
int attempts = 0; // Zähler für Versuche
const int maxAttempts = 20; // Maximalversuche (10 Sekunden)
while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nConnected to the WiFi network with IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("\nFailed to connect to WiFi.");
}
}
void MQTTConnect(void) {
client.setServer(mqttServer, mqttPort);
// client.setCallback(callback); // Wenn du eine Callback-Funktion hast
int attempts = 0; // Zähler für Versuche
const int maxAttempts = 10; // Maximalversuche (20 Sekunden)
while (!client.connected() && attempts < maxAttempts) {
Serial.print("Connecting to MQTT...");
if (client.connect(mqttclientID, mqttUser, mqttPassword)) {
Serial.println("connected to MQTT");
client.subscribe("/actors/glade");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
attempts++;
}
}
if (!client.connected()) {
Serial.println("Failed to connect to MQTT after multiple attempts.");
}
delay(100); // Wartezeit nach dem Abonnieren
}
Da der ESP hinter die originale Platine gebaut wurde ist er praktisch unsichtbar im Sprüher versteckt.