ich programmiere gerade meinen ersten µc. Ich habe ein Hochbeet, welches automatisch gewässert, gelüftet und beleuchtet werden soll. Die Messdaten dafür kommen von einem Xiaomi MiFlora Sensor. Die Auswertung läuft über einen smarthomeng-Server, der mit dem ESP32 im Beet über MQTT kommuniziert. Ausgangsbasis war dieser Code: https://github.com/e6on/ESP32_MiFlora_MQTT
Jetzt funktioniert fast alles, für die verbliebenen Probleme erhoffe ich mir hier Hilfe :)
Den gesamten Code habe ich als Textfile beigefügt.
Problem 1:
Der Eingang für den Schwimmer des Wassertanks soll sofort übertragen werden. Der Interrupt macht aber nichts, heißt er wird einfach ignoriert. Es könnte auch ein physischen Problem mit dem Schalter sein, das überprüfe ich am WE
Problem 2:
Was kann ich in meinem loop optimieren hinsichtlich:
mehr Energie-Effizienz, also weniger idle Rechenleistung während ich auf MQTT Nachrichten oder Interrupts vom Input warte
Selbstüberwachung: Der µc soll im Fehlerfall das Problem erstmal versuchen durch einen Neustart zu lösen. Frage: Sind regelmäßige geplante Reboots sinnig und wie würdet ihr sie umsetzen?
Problem 3:
Prinzipiell kommen die MQTT Nachrichten an. Nur bei "pumpe" passiert nichts. Wahrscheinlich nur ein Tippfehler, aber ich finde ihn partout nicht :(
Serial Monitor:
1
23:16:17.147 -> --Pin set HIGH; returning to main programm
2
23:16:17.147 -> Running loop
3
23:16:17.147 -> Running loop
4
23:16:22.355 -> -- connection alive, connect.loop sent
Im Interrupt Kontext darf man nicht beliebige API Funktionen aufrufen, schon gar nicht Serial.print oder MQTT senden. Außerdem fehlt das Attribut das die Funktion im RAM gehalten wird.
Suche erstmal nach Interruptprogrammierung des ESP.
Sicher das der pumpe topic gesendet wird? Zum testen würde ich eher sowas wie MQTTExplorer verwenden.
Danke für deine Antwort.
Das Pumpen-Problem war tatsächlich ähnlich einfach wie angenommen: Da das Signal des Wasser-Sensors fehlt, gibt der smarthomeng-Server das Pumpenitem nicht frei. Deshalb wird nichts gesendet. Also gelöst.
Die Interruptprogrammierung werde ich mir dann mal zu Gemüte führen, mal sehen, ob ich selbst auf die Lösung komme :)
Im ersten Go bin ich auf folgenden Artikel gestossen: https://wolles-elektronikkiste.de/esp32-mit-arduino-code-programmieren#interrupts
Hier wird ein Interrupt über einen GPIO beschrieben, also eigentlich so wie es bei mir auch geplant ist.
Die Krux: Ich halte den Interrupt so für völlig unnütz! Die ISR setzt ja eine bool Variable, die dann im loop ausgelesen wird. Dann kann ich ja auch einfach den Input im loop auslesen und mir den Interrupt sparen, oder?
1
intinterruptPin=4;// define GPIO4 as interrupt pin
2
volatileboolevent=false;
3
4
voidIRAM_ATTReventISR(){
5
event=true;
6
detachInterrupt(interruptPin);
7
}
8
9
voidsetup(){
10
Serial.begin(115200);
11
while(!Serial){}
12
pinMode(interruptPin,INPUT_PULLDOWN);
13
attachInterrupt(interruptPin,eventISR,RISING);
14
}
15
16
voidloop(){
17
if(event){
18
Serial.println("Interrupt!");
19
delay(1000);//debouncing
20
event=false;
21
attachInterrupt(interruptPin,eventISR,RISING);
22
}
23
}
Wie würdet ihr den Eingang für den Schwimmerschalter überwachen? Vielleicht einfach ein eigener Task, der den Sensor überwacht?
Ja du kannst deinen Schwimmerschalter auch regelmäßig in der loop einlesen was für den Zweck vollkommen ausreicht.
Beim ESP kannst du auch keinen Strom sparen indem du in der loop weniger nichts machst, nicht benutzte Rechenzeit wird immer irgendwo vertrödelt - egal ob mit dem Code in der loop oder einem delay im Hintergrund.
Der Interrupt macht für Eingänge nur Sinn wenn das Signal so kurz anliegt das die Gefahr besteht das es bei entsprechender Durchlaufzeit der loop bis zur nächsten Abfrage schon wieder weg ist.
Sind regelmäßige geplante Reboots sinnig und wie würdet ihr sie
umsetzen?
Mikrocontroller laufen normalerweise viele Jahre lang fehlerfrei durch. Wenn nicht, würde ich das gerne wissen um es beheben zu können. Regelmäßige Neustarts doktorn am Symptom herum, ohne das Problem zu lösen.
Der ESP8266 (vermutlich auch der ESP32) hat schon einen Watchdog, der den Chip automatisch neu startet, wenn er hängt. Nach meiner Erfahrung nützt das wenig, weil er kurz danach wieder Fehlfunktionen hat, und oft sogar schon beim Booten (bevor die erste Zeile eigener Code ausgeführt wird) stecken bleibt.
Ernsthaft Strom sparen kannst du nur, indem du WLAN deaktivierst oder den light sleep Modus nutzt.
Der Interrupt macht für Eingänge nur Sinn wenn das Signal so kurz
anliegt das die Gefahr besteht das es bei entsprechender Durchlaufzeit
der loop bis zur nächsten Abfrage schon wieder weg ist.
Nicht nur dann. Sinnvoll ist ein Interrupt auch dann, wenn besonders schnell darauf reagiert werden muss. Wenn man immer erst wartet, bis loop() an der Abfrage vorbei kommt, kann es für manche Anwendungen zu spät sein.
Im Fall des OP trifft beides nicht zu, da sollte man ohne Interrupt arbeiten.
Hier wird ein Interrupt über einen GPIO beschrieben, also eigentlich so
wie es bei mir auch geplant ist.
Das ist ja nur eine Demo, die zeigen soll, wie man mit Interrupts umgehen kann. Sie sagt nicht, unter welchem Umständen das sinnvoll ist.
Übrigens steckt da ein "Makel" drin, den man immer wieder sieht. Wozu denn in der ISR den Interrupt aushängen und später wieder einhängen? Das führt in vielen Szenarien zu gelegentlichen Fehlern.
Was passiert z. B., wenn das nächste Ereignis erscheint, während die ISR gerade ausgehängt ist? Dann wird es unter Umständen nicht erkannt. Besser lässt man die ISR ständig eingehängt und lässt sie (oder loop) entscheiden, ob sie das Ereignis ignorieren will oder nicht.
Klar, man kann immer Gegenbeispiele für obige Argumente finden. Aber die sinnvolle Grundregel ist IMHO so.
Wie würdet ihr den Eingang für den Schwimmerschalter überwachen?
Vielleicht einfach ein eigener Task, der den Sensor überwacht?
Mir scheint, du bist auf den falschen Zeitskalen unterwegs.
Auch wenn ein richtige Flutwelle über dein Beet schwappt und es innerhalb von Bruchteilen von Sekunden flutet, nützt es dir überhaupt nichts, den Sensor im Mikrosekundenbereich auszuwerten. Was willst du dadurch veranlassen?
Vielen Dank für eure Antworten und euren Input!
Der ESP läuft, momentan noch auf einem Breadboard, am Blumenbeet. Bislang läuft alles wie erhofft, jetzt stehen erstmal die Restarbeit am Beet selbst an.
Ernsthaft Strom sparen kannst du nur, indem du WLAN deaktivierst oder
den light sleep Modus nutzt.
Also WLAN ausschalten geht schonmal nicht, das Beet muss ja Befehle via MQTT empfangen können. sleep ist eine gute Idee, um das Beet nachts länger zu pausieren. Da reicht es ja, wenn es alle 1-2h aufwacht, der Server ggf. die Lüftung verfährt und ihn danach wieder schlafen schickt. Das wäre dann aber ziemlich weit unten auf der ToDo Liste.
Mir scheint, du bist auf den falschen Zeitskalen unterwegs.
Auch wenn ein richtige Flutwelle über dein Beet schwappt und es
innerhalb von Bruchteilen von Sekunden flutet, nützt es dir überhaupt
nichts, den Sensor im Mikrosekundenbereich auszuwerten. Was willst du
dadurch veranlassen?
Ja, da hast du definitiv recht. Wenn der Sensor "leer" anzeigt, zieht die Pumpe ja nicht direkt Luft. Insofern:
Was heißt in diesem Zusammenhang "sofort"?
Wie zeitkritisch ist diese Meldung?
µs[ ], ms[ ] oder s[x] (zutreffendes bitte ankreuzen)
Ich habe jetzt folgendes im loop stehen:
1
// check if input changed
2
if(!wasserstand==digitalRead(waterSensorPin)){
3
Serial.println("input changed - sending value");
4
delay(500);
5
wasserstand=digitalRead(waterSensorPin);
6
MQTTsendWLL();
7
}
Das funktioniert wie gewünscht. Das delay von 500ms soll den Sensor etwas entprellen, dass nicht ständig eine Änderung geschickt wird wenn der Schwimmer umschaltet und die Pumpe so zum stottern bringt.
Ich schreibe einfach mal hier weiter und mache keinen neuen Post dafür auf:
Kaum läuft die erste Version, habe ich schon erste Veränderungen im Sinn. Denn der µc muss sowieso nochmal getauscht werden. Der WLAN Empfang der onboard Antenne lässt zu wünschen übrig und derzeit steht deshalb Repeater vor der Terassentür. Also will ich auf einen Seeed Xiao wechseln, da ich hier eine "richtige" WLAN Antenne anschließen kann. Außerdem läuft alles derzeit noch auf einem Breadboard, auch kein Dauerzustand. Die Schaltung von Beleuchtung (12V LED Streifen, definitive Länge und damit Stromverbrauch steht noch nicht fest), Bewässerungspumpe (12V 5A Membranpumpe) und Linearmotor für die Beetöffnung läuft derzeit über eine fertige 4 Kanal Relais + 1 Finder Doppelrelais für die Polaritätsumkehr des Linearantriebes. Für die Zukunft möchte ich den Anschluss für eine kleine Schlauch-/Dosierumpe für Düngemittel vorsehen. Funktioniert alles, finde es aber irgendwie nicht elegant genug. Außerdem nutze ich meine Projekte ja immer um etwas zu lernen.
Von Euch erhoffe ich mir nun Input zu folgenden Fragen:
Welche Art der Ansteuerung könnt ihr mir für welchen Ausgang empfehlen?
Wo finde ich einen guten Artikel zum Thema "Welche Last wie schalten"?
Meine aktuelle Idee:
2 Kanal Motortreiber für Linearantrieb (wg. Richtungswechel) und Dosierpumpe (PWM zur feinen Dosierung)
FET oder Relais für LED-Licht: FET könnte man zwar dimmen, aber braucht man das in diesem Anwendungsfall?
Relais + ?Kondensator? für Bewässerungspumpe: Hier habe ich in der Hauptsache Sorge um den µc, da er via 7805 an der selben 12V Spannungsversorgung hängt. Kondensator dann im 12V Teil oder im 5V Teil?