Forum: Mikrocontroller und Digitale Elektronik ESP8266, Micropython, hängt teilweise, ev. IRQ- und/oder GPIO0-Problem?


von Christian S. (somerhimson)


Lesenswert?

Hallo,

ich nutze ESP8266 mit Micropython u.a. als eine Art Dash-Button-Ersatz 
mit 4 Tasten und Zustands-LEDs.

Es ist mein erstes selbstprogrammiertes Projekt mit einem ESP8266 und 
auch meine erste Erfahrung mit Micropython gewesen. Ich habe daher 
längere Zeit und diverse "Entwicklungsiterationen" benötigt, hatte dann 
aber den Eindruck, es läuft stabil. Habe auf einem Steckbrett meine 
Schaltung aufgebaut und sie lief am Schluß über einige Tage stabil. 
Daraufhin habe ich alles auf einer Lochrasterplatine aufgebaut, ein 
Gehäuse gedruckt und es ins Wohnzimmer gepackt. Lief auch paar Tage 
stabil, woraufhin ich beflügelt noch vier baute und im Haus verteilte. 
Im Prinzip tun die auch alle das, was sie sollen, aber hin und wieder 
scheinen sie sich aufzuhängen.

Es äußert sich so, das auf einen Tastendruck einfach nicht reagiert 
wird. Ich habe daher die Status-LED so programmiert, das sie auf jeden 
Fall bei einem Tastendruck kurz aufleuchtet, egal welcher Zustand. Das 
tut sie in den Fällen nicht, gerade so, als würde klein Tastendruck 
erfolgt sein. Da es sich bei allen "Systemen" ereignet, schließe ich 
einen Tasterdefekt aus. Insbesondere, da nach einem Abziehen und 
Wiederanstecken des Stroms alles sofort wieder einwandfrei funktioniert.

Ich habe im Netz gelesen, es sollten 100 µF Low-ESR an die 
Spannungsversorgungspins des ESP gehängt werden um die Stabilität zu 
erhöhen, was für mich leider nicht half.

Ich habe bei den letzten zwei Störungen dann mal andere Tasten gedrückt, 
was komischerweise dann funktionierte. Die Gemeinsamkeit, die ich sehe 
ist, das die Taste1 hängt, welche mit GPIO0 verbunden ist. Daraufhin 
habe ich mir auch mein WLAN-Bewegungsmelderprojekt angeschaut und dort 
dasselbe gefunden. Dort ist der PIR auch an GPIO0 angeschlossen und nach 
einer gewissen Zeit (im Schnitt 1,5 Wochen) reagiert er nicht auf 
Bewegungen. Ist mir vorher nur nie aufgefallen, weil nicht drauf 
geachtet.

Mein Vermutung ist nun, das ich entweder am GPIO0 den Interrupt so nicht 
nutzen kann, oder ich vielleicht irgendwas mit einem Garbage Collector 
machen muß. Da ich damit jetzt schon paar Monate rummache und speziell 
die Fehlersuche dieses "Aufhängens" auch schon über 2 Monate geht, bin 
ich recht verzweifelt.

Kann mir jemand einen Tip geben, was dieses komischen "Aufhängen" sein 
kann?

Mein Code ist der hier (das UDP genutzt wird hat Kompatibilitätsgründe, 
meine ganze Smarthome-Geschichte ist selbst gefrickelt, in Hard- und 
Software. Ist vielleicht nicht schön, aber mit Sicherheit selten weil 
handgeklöppelt. ;-) ):
1
from machine import Pin,PWM
2
import time
3
import network
4
import socket
5
6
udpPort = 10051
7
netzlauscher = ('192.168.11.122', 10054)
8
geraetename = "DIYT01-AussenGarage1"
9
wlan_ssid = "WLAN-SSID"
10
wlan_passwort = "4711"
11
12
def wlan_connect():
13
    wlan.active(False)
14
    time.sleep(0.5)
15
    wlan.active(True)
16
    time.sleep(0.5)
17
    wlan.connect(wlan_ssid,wlan_passwort)
18
    startzeit = time.ticks_ms()
19
    while not wlan.isconnected() and startzeit + 10000 > time.ticks_ms():
20
        pass
21
22
def tasteOhneWlan(pin):
23
    print(pin,"ohne WLAN gedrueckt")
24
    for i in range(5):
25
        pwmWlan.duty(0)
26
        time.sleep(0.1)
27
        pwmWlan.duty(1023)
28
        time.sleep(0.1)
29
30
def handle_interrupt(pin):
31
    global geraetename,druckTast1,druckTast2,druckTast3,druckTast4,taster1,taster2,taster3,taster4,zustandT1,zustandT2,zustandT3,zustandT4,initFertig,netzwerkSendung
32
    entprellzeit = 4000 #Zeit in ms, die als Entprellphase gelten.
33
    zeithier = time.ticks_ms()
34
    befehlsbasis = "Befehl-"+geraetename+"-"
35
    befehlhier = "nix"
36
    if pin is taster1 and zeithier > druckTast1 + entprellzeit:
37
        druckTast1 = zeithier
38
        if wlan.isconnected():
39
            if zustandT1:
40
                befehlhier = befehlsbasis + "1b"
41
            else:
42
                befehlhier = befehlsbasis + "1a"
43
        else:
44
            tasteOhneWlan(pin)
45
    elif pin is taster2 and zeithier > druckTast2 + entprellzeit:
46
        druckTast2 = zeithier
47
        if wlan.isconnected():
48
            if zustandT2:
49
                befehlhier = befehlsbasis + "2b"
50
            else:
51
                befehlhier = befehlsbasis + "2a"
52
        else:
53
            tasteOhneWlan(pin)
54
    elif pin is taster3 and zeithier > druckTast3 + 3*entprellzeit:
55
        druckTast3 = zeithier
56
        if wlan.isconnected():
57
            if zustandT3:
58
                befehlhier = befehlsbasis + "3b"
59
            else:
60
                befehlhier = befehlsbasis + "3a"
61
        else:
62
            tasteOhneWlan(pin)
63
    elif pin is taster4 and zeithier > druckTast4 + 3*entprellzeit:
64
        druckTast4 = zeithier
65
        if wlan.isconnected():
66
            if zustandT4:
67
                befehlhier = befehlsbasis + "4b"
68
            else:
69
                befehlhier = befehlsbasis + "4a"
70
        else:
71
            tasteOhneWlan(pin)
72
    if befehlhier is not "nix":
73
        if initFertig:
74
            pwmWlan.duty(0)
75
            print(pin,"gedrueckt")
76
            netzwerkSendung.sendto(befehlhier,netzlauscher)
77
            time.sleep(0.1)
78
            pwmWlan.duty(100)
79
            time.sleep(0.1)
80
            pwmWlan.duty(250)
81
            time.sleep(0.1)
82
            pwmWlan.duty(500)
83
            time.sleep(0.1)
84
            pwmWlan.duty(750)
85
            time.sleep(0.1)
86
            pwmWlan.duty(1023)
87
        else:
88
            pwmWlan.duty(1023)
89
            print(pin,"gedrueckt")
90
            netzwerkSendung.sendto(befehlsbasis + "Init",netzlauscher)
91
            time.sleep(0.1)
92
            pwmWlan.duty(750)
93
            time.sleep(0.1)
94
            pwmWlan.duty(500)
95
            time.sleep(0.1)
96
            pwmWlan.duty(250)
97
            time.sleep(0.1)
98
            pwmWlan.duty(100)
99
            time.sleep(0.1)
100
            pwmWlan.duty(0)
101
102
ledWlan = Pin(2, Pin.OUT)
103
#ledWlan.value(False)
104
pwmWlan = PWM(ledWlan)
105
pwmWlan.freq(1023)
106
pwmWlan.duty(0)
107
ledT1 = Pin(15, Pin.OUT)
108
ledT1.value(False)
109
ledT2 = Pin(13, Pin.OUT)
110
ledT2.value(False)
111
ledT3 = Pin(12, Pin.OUT)
112
ledT3.value(False)
113
ledT4 = Pin(16, Pin.OUT)
114
ledT4.value(False)
115
116
taster1 = Pin(0, Pin.IN, Pin.PULL_UP)
117
taster1.irq(trigger=Pin.IRQ_FALLING, handler=handle_interrupt)
118
taster2 = Pin(5, Pin.IN, Pin.PULL_UP)
119
taster2.irq(trigger=Pin.IRQ_FALLING, handler=handle_interrupt)
120
taster3 = Pin(4, Pin.IN, Pin.PULL_UP)
121
taster3.irq(trigger=Pin.IRQ_FALLING, handler=handle_interrupt)
122
taster4 = Pin(14, Pin.IN, Pin.PULL_UP)
123
taster4.irq(trigger=Pin.IRQ_FALLING, handler=handle_interrupt)
124
125
druckTast1 = 0
126
druckTast2 = 0
127
druckTast3 = 0
128
druckTast4 = 0
129
130
zustandT1 = False
131
zustandT2 = False
132
zustandT3 = False
133
zustandT4 = False
134
135
defT1 = False
136
defT2 = False
137
defT3 = False
138
defT4 = False
139
initFertig = False
140
141
wlan = network.WLAN(network.STA_IF)
142
print(geraetename, "mit WLAN verbinden...")
143
wlan_connect()
144
if wlan.isconnected():
145
    ledT1.value(True)
146
    ledT2.value(True)
147
    ledT3.value(True)
148
    ledT4.value(True)
149
    wlan_conf = wlan.ifconfig()
150
    wlan_ip = wlan_conf[0]
151
    print("WLAN: ", wlan_ssid, wlan_conf)
152
    
153
    #Sendesocket definieren und vorbereiten
154
    netzwerkSendung = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
155
    
156
    #Empfangssocket definieren und vorbereiten
157
    netzwerkEmpfang = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
158
    netzwerkEmpfang.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
159
    netzwerkEmpfang.bind((wlan_ip,udpPort)) #binding the port
160
    time.sleep(2)
161
    print('Initialisierung der Tasten wird angefragt...')
162
    netzwerkSendung.sendto("Befehl-"+geraetename+"-Init",netzlauscher)
163
    time.sleep(0.3)
164
    netzwerkSendung.sendto("Befehl-"+geraetename+"-Init",netzlauscher)
165
    time.sleep(0.3)
166
    netzwerkSendung.sendto("Befehl-"+geraetename+"-Init",netzlauscher)
167
168
    print('Lausche an',wlan_ip,udpPort,'/UDP')
169
    while True:   #receiving data
170
        nachrichtUdp,senderUdp = netzwerkEmpfang.recvfrom(1024)
171
        tmpstr1 = str(nachrichtUdp)
172
        tmpstr1 = tmpstr1.split("'",2)
173
        tmpstr2 = tmpstr1[1]
174
        tmpstr2 = tmpstr2.split("\\n",2)
175
        nachrichtRein = tmpstr2[0]
176
        senderIp = senderUdp[0]
177
        print('empfangen:',nachrichtRein,'von',senderIp)
178
        
179
        if nachrichtRein is "Tast1-an":
180
            zustandT1 = True
181
        elif nachrichtRein is "Tast1-aus":
182
            zustandT1 = False
183
        elif nachrichtRein is "Tast2-an":
184
            zustandT2 = True
185
        elif nachrichtRein is "Tast2-aus":
186
            zustandT2 = False
187
        elif nachrichtRein is "Tast3-an":
188
            zustandT3 = True
189
        elif nachrichtRein is "Tast3-aus":
190
            zustandT3 = False
191
        elif nachrichtRein is "Tast4-an":
192
            zustandT4 = True
193
        elif nachrichtRein is "Tast4-aus":
194
            zustandT4 = False
195
        
196
        if not initFertig:
197
            if nachrichtRein is "Tast1-an" or nachrichtRein is "Tast1-aus":
198
                defT1 = True
199
                ledT1.value(zustandT1)
200
            elif nachrichtRein is "Tast2-an" or nachrichtRein is "Tast2-aus":
201
                defT2 = True
202
                ledT2.value(zustandT2)
203
            elif nachrichtRein is "Tast3-an" or nachrichtRein is "Tast3-aus":
204
                defT3 = True
205
                ledT3.value(zustandT3)
206
            elif nachrichtRein is "Tast4-an" or nachrichtRein is "Tast4-aus":
207
                defT4 = True
208
                ledT4.value(zustandT4)
209
            if defT1 and defT2 and defT3 and defT4:
210
                pwmWlan.duty(1023)
211
                initFertig = True
212
        else:
213
            ledT1.value(zustandT1)
214
            ledT2.value(zustandT2)
215
            ledT3.value(zustandT3)
216
            ledT4.value(zustandT4)
217
else:
218
    print("WLAN-Verbindung fehlgeschlagen")
219
    runde=0
220
    dimmwert=1023
221
    while True:
222
        if dimmwert is 1023:
223
            dimmwert = 0
224
        else:
225
            dimmwert = 1023
226
        pwmWlan.duty(dimmwert)
227
        time.sleep(0.2)
228
        runde = runde+1
229
        if runde > 150:
230
            runde=0
231
            machine.reset()

von Stefan F. (Gast)


Lesenswert?

Christian S. schrieb:
> Kann mir jemand einen Tip geben, was dieses komischen "Aufhängen" sein
> kann?

Wohl kaum, ohne Schaltplan und Bilder vom Aufbau. Liefere mal was zum 
angucken nach.

von Gerd A. (gerd_a289)


Lesenswert?

Hi, also ohne den Code lange zu analysieren (puh!) ein paar kleine 
Tipps. Der ESP8266 hat immer mal wieder mit WLAN Abrüchen zu kämpfen. 
Deshalb sollte der WLAN-Status regelmäßig geprüft werden und ggf. 
einfach ein reset() durchgeführt werden. Hilft bei mir ganz gut. 
Außerdem hab ich gemerkt, wenn die Fritzbox die Kanäle fürs WLAN ändert 
und der Kanal 1 nach oben wandert die Teile wenn sie nur weit genug weg 
sind unter Umständen keinen connect mehr hinbekommen. Und die zweite 
Sache ist bei diesen Teilen immer der limitierte Speicher. Deshalb 
verwende ich immer vorcompilierten Code (bis auf main.py), damit passt 
ne Menge Code auf die kleinen Dinger (mpy-cross compiler). Und trotz 
allem sollte man ab und an mal den Speicher putzen mit gc.collect().
Nicht verzagen, die Teile sind an sich nicht tot zu kriegen, ich hab die 
locker schon seit 3-4 Jahren mit ner Menge Sensoren laufen.
Viele Grüße
Gerd

von Gerd A. (gerd_a289)


Lesenswert?

Hi, also ohne den Code lange zu analysieren (puh!) ein paar kleine 
Tipps. Der ESP8266 hat immer mal wieder mit WLAN Abrüchen zu kämpfen. 
Deshalb sollte der WLAN-Status regelmäßig geprüft werden und ggf. 
einfach ein reset() durchgeführt werden. Hilft bei mir ganz gut. 
Außerdem hab ich gemerkt, wenn die Fritzbox die Kanäle fürs WLAN ändert 
und der Kanal 1 nach oben wandert die Teile wenn sie nur weit genug weg 
sind unter Umständen keinen connect mehr hinbekommen. Und die zweite 
Sache ist bei diesen Teilen immer der limitierte Speicher. Deshalb 
verwende ich immer vorcompilierten Code (bis auf main.py), damit passt 
ne Menge Code auf die kleinen Dinger (mpy-cross compiler). Und trotz 
allem sollte man ab und an mal den Speicher putzen mit gc.collect(). 
Sonst musst du halt mal ne Konsole länger mitlaufen lassen um zu sehen 
was der sagt wenn er stirbt. Ein Raspi an USB reicht.
Nicht verzagen, die Teile sind an sich nicht tot zu kriegen, ich hab die 
locker schon seit 3-4 Jahren mit ner Menge Sensoren laufen.
Viele Grüße
Gerd

von Christian S. (somerhimson)


Lesenswert?

Stefan ⛄ F. schrieb:
>
> Wohl kaum, ohne Schaltplan und Bilder vom Aufbau. Liefere mal was zum
> angucken nach.

Hallo Stefan,
der Schaltplan ist nicht der Rede wert, die Tasten ziehen den jeweiligen 
Pin einfach nur auf Masse beim Betätigen. Die LED's sind mit 1k0 - 4k7 
zwischen Masse und jeweiligen Ausgangspin. Der 100 µF ist zwischen Masse 
und 5V-Pin.
Mehr ist da am Wemos D1 Mini nicht dran, daher habe ich auch keinen 
Schaltplan gemacht. Mit der Hardware hat es sicher nichts zu tun, denn 
die Tasten 2-4 funktionieren, nur Taste 1, die an GPIO0 hängt, halt 
nicht. Muß also was mit dem Port zu tun haben.

von Christian S. (somerhimson)


Lesenswert?

Hallo Gerd,

Gerd A. schrieb:
> Hi, also ohne den Code lange zu analysieren (puh!) ein paar kleine
> Tipps. Der ESP8266 hat immer mal wieder mit WLAN Abrüchen zu kämpfen.
> Deshalb sollte der WLAN-Status regelmäßig geprüft werden und ggf.
> einfach ein reset() durchgeführt werden. Hilft bei mir ganz gut.
> Außerdem hab ich gemerkt, wenn die Fritzbox die Kanäle fürs WLAN ändert
> und der Kanal 1 nach oben wandert die Teile wenn sie nur weit genug weg
> sind unter Umständen keinen connect mehr hinbekommen.

Das mit dem WLAN hatte ich auch schon vermutet, deshalb habe ich die 
Status-LED dann bei jedem Tastendruck reagieren lassen, egal ob im WLAN 
oder nicht. Und dabei zeigte sich, das Drücken von Taste 1 wird in den 
"komischen Phasen" gar nicht registriert. Die Status-LED reagiert gar 
nicht, was nur damit zu erklären ist, das die Funktion 
"handle_interrupt" nicht aufgerufen wird. Bei Taste 2 oder so reagiert 
sie dann aber normal, lößt sogar das gewünschte Signal aus im Netz.
Da es aber grundsätzlich funktioniert, auch für einige Tage am Stück, 
und dann eben irgendwann einfach nicht mehr, kann es meines Erachtens 
nicht grundsätzlich am Code liegen. Da aber auch nur Taste 1 gestört 
ist, würde es mich wundern, wenn es etwas mit der Spannungsqualität zu 
tun hat. Alle vier Tasten sind genau gleich beschaltet.

> Und die zweite
> Sache ist bei diesen Teilen immer der limitierte Speicher. Deshalb
> verwende ich immer vorcompilierten Code (bis auf main.py), damit passt
> ne Menge Code auf die kleinen Dinger (mpy-cross compiler).

Damit habe ich mich noch gar nicht beschäftigt, hatte es so verstanden, 
das bei (Micro-)Python das nicht nötig ist. Klar, Phython ist eher was 
zum Spielen, weil mega langsam, aber für meine Belange bin ich 
eigentlich ganz zufrieden, solange es läuft.

> Und trotz
> allem sollte man ab und an mal den Speicher putzen mit gc.collect().

Das ist eine Sache, die ich meinte mit dem Garbage Collctor. Habe ich 
noch nie was mit gemacht, werde ich mir dann jetzt mal anschauen.
Bisher dachte ich, mein kleines Progrämmchen ist so einfach und macht 
kaum was, das sollte Micropython hinbekommen mit der Speicherverwaltung. 
Dachte ich einfach mal so, wie gesagt, mein erstes Projekt in der 
Sprache und mit dem MC.

> Sonst musst du halt mal ne Konsole länger mitlaufen lassen um zu sehen
> was der sagt wenn er stirbt. Ein Raspi an USB reicht.

Das klingt grundsätzlich gut, allerdings weiß ich nicht, wie ich da am 
besten lausche. Wenn ich über Thonny starte, sind die Bedingungen ja 
deutlich anders als im Realbetrieb. Ich müßte irgendwie das USB-Terminal 
"anzapfen" können, ohne Thonny oder so, einfach nur lauschen. Mal 
schauen, ob ich da einen Weg finde, gibt es ja sicher was im Netz zu.

> Nicht verzagen, die Teile sind an sich nicht tot zu kriegen, ich hab die
> locker schon seit 3-4 Jahren mit ner Menge Sensoren laufen.
> Viele Grüße
> Gerd

Das läßt hoffen, so hatte ich mir das auch vorgestellt. Die ESP8266 in 
Sonoff und Shelly sind ja auch recht pflege leicht. ;-)

Gruß,
Christian

von Christian S. (somerhimson)


Lesenswert?

Christian S. schrieb:
>> Sonst musst du halt mal ne Konsole länger mitlaufen lassen um zu sehen
>> was der sagt wenn er stirbt. Ein Raspi an USB reicht.
>
> Das klingt grundsätzlich gut, allerdings weiß ich nicht, wie ich da am
> besten lausche. Wenn ich über Thonny starte, sind die Bedingungen ja
> deutlich anders als im Realbetrieb. Ich müßte irgendwie das USB-Terminal
> "anzapfen" können, ohne Thonny oder so, einfach nur lauschen. Mal
> schauen, ob ich da einen Weg finde, gibt es ja sicher was im Netz zu.
>

So, ist eingerichtet an einem Gerät. Nutze dazu picocom, war ja ganz 
einfach. Bin jetzt mal gespannt, was dort stehen wird.

von Christian S. (somerhimson)


Lesenswert?

Also ich habe jetzt seit dem letzten Post von mir unter screen picocom 
laufen und die Ausgabe von screen in eine Datei geschrieben.
Heute morgen sehe ich nun, die Logdatei wurde heute Nacht zwischen 01.03 
Uhr und 02.03 Uhr aufgehört zu füttern (genauer kann ich es nicht 
eingrenzen, da die regulären Meldungen nur alle Stunde kommen). Auch 
kommen aktuell keine Ausgaben mehr über picocom, als wäre die 
Schnittstelle einfach eingefroren. Der ESP scheint noch zu laufen, auf 
alle vier Tasten reagiert die Status-LED, aber nicht immer bekommt mein 
Server den Befehl mit. Letzteres könnte ja an der WLAN-Verbindung 
liegen, aber der ESP merkt es dann wohl nicht, sonst wäre das Signal der 
Status-LED anders (wenn nicht verbunden, blinkt er schnell bei 
Tastendrücken).

Also ich muß sagen, ich bin echt ratlos. Da jetzt der ESP über den 
USB-Bus eines Pi versorgt wird, gehe ich fest davon aus, die 
Versorgungsspannung ist sauber. Einen low-ESR Elko habe ich ja auch noch 
am 5 V-Pin des Wemos.
Kann es sein, dass Micropython einfach nicht langzeitstabil auf einem 
ESP8266 läuft? Muß ich vielleicht für "ernsthafte" Systeme doch lieber 
die Aduino IDE nutzen?
Sollte Micropython an sich nicht ganz sauber laufen, dann kann ich mir 
ja nen Wolf suchen und werde nie das Problem lösen, das mich jetzt doch 
langsam echt nervt. :-(

von Stefan F. (Gast)


Lesenswert?

Christian S. schrieb:
> Kann es sein, dass Micropython einfach nicht langzeitstabil auf einem
> ESP8266 läuft?

Bevor wir das auch nur erwägen möchte ich erstmal Fotos vom Aufbau 
sehen. meistens ist doch noch was mit der Stromversorgung. Kabel leiten 
nicht so gut, wie man es gerne hätte, insbesondere bei dem Muster mit 
dem der ESP Strom aufnimmt.

Bei so einem komplexen Betriebssystem kann es durchaus passieren, dass 
nur Teil-Funktionen ausfallen. Das kennt ja auch jeder von seinem 
Desktop PC. Wenn dort ein einzelnes Programm ausfällt, laufen die 
anderen meistens weiter. Der selbe Effekt kann auch innerhalb von 
Programmen mit einzelnen Threads passieren.

Der HW Watchdog kann so etwas nicht zuverlässig erkennen. Auch ist er 
nicht immer imstande, den Chip vollständig zu resetten. Insofern kann 
man sich auf den Watchdog so oder so nicht verlassen. Bei dir hat er 
offenbar nicht ausgelöst, sonst hättest du etwas über seine Ausgaben zum 
Zeitpunkt des Ausfalls geschrieben. Je nach Baudrate sieht man dann Text 
oder wenigstens ein paar Zeilen Müll.

Ich habe einen Roboter (Codey Rocky) da läuft Micropython auf einem 
ESP32, Stromversorgung via Akku. Der hängt sich selten sporadisch auf 
(kommt aber vor).

von Εrnst B. (ernst)


Lesenswert?

Ohne Micropython im Detail zu kennen:

-> Tastenauswertung per IRQ ist ansich schon zweifelhaft
-> Du hast sehr viel langlaufenden Code in deinem interrupt_handler.
Wenn Micropython während der IRQ-Abarbeitung weitere Interrupts erlaubt, 
läuft der handler nach Tasterprellen vielleicht mehrfach gleichzeitig.
Wenn nicht: WLan kann wegen der langen laufzeit abbrechen, delay, 
micros, serial output funktionieren evtl. nicht so wie erwartet.

Macht dein Hauptprogramm denn ständig irgendwas wichtiges, bei dem du es 
per IRQ unterbrechen musst? Oder könntest du die Tasten nicht genausogut 
einfach regelmäßig im Hauptprogramm abfragen?

von Christian S. (somerhimson)


Lesenswert?

Guten Morgen Stefan,

Stefan ⛄ F. schrieb:
>
> Bevor wir das auch nur erwägen möchte ich erstmal Fotos vom Aufbau
> sehen. meistens ist doch noch was mit der Stromversorgung. Kabel leiten
> nicht so gut, wie man es gerne hätte, insbesondere bei dem Muster mit
> dem der ESP Strom aufnimmt.

Das mit der Stromversorgung ist mir durchaus bewußt. Da habe ich erst 
kürzlich hier durch das Forum sehr intensive und hoch lehrreiche Hilfe 
erhalten. :-)

Ich habe, abgesehen von dem Prüfling am Pi, insgesamt vier der 4 
fach-Taster laufen und 2 der WLAN-Bewegungsmelder.

Um das Thema der Spannungsversorgung besser bewerten zu können, habe ich 
nach den ersten Ausfällen verschiedene Netzteilmodelle genommen. Die 
USB-Versorgungskabel wie auch die Netzteile habe ich alle vorher mit 
einer elektronischen Last und entsprechenden USB-Messgeräten (sagen wir 
lieber guten Schätzeisen, die aber echt erstaunlich genau im Vergleich 
zu Voltcraft DMM sind) vermessen. Da gibt es ja leider viel Müll auf dem 
Markt, habe es mir deshalb vor zwei Jahren, senibilisiert durch CC2.tv, 
angewöhnt, vor jeder Nutzung die USB-Kabel zu messen.
Auch sind die Kabel unterschiedlich lang und teils von unterschiedlichen 
Lieferanten. Weiterhin hängen die Netzteile an verschiedenen Phasen, 
unsaubere Netzspannung sollte da dann ja auch nicht so wahrscheinlich 
sein.
Ich habe bisher auch noch keinen zeitlichen Zusammenhang zwischen den 
Ausfällen der System erkennen können.

Ich sollte vielleicht dazu sagen, ich habe auch vier Pi Picos unter 
Micropython laufen, zwei davon seit März, die anderen zwei seit Juni. 
Weitere drei hatte ich zu Entwicklungszwecken über gut zwei Monate 
ebenfalls 24/7 laufen. Alle Picos nutzen gleiche Netzteile und Kabel, 
wie die ESPs und von den Picos hat noch keiner eine Fehlfunktion gehabt, 
obwohl dort die Aufbauten um ein vielfaches komplexer sind und ich noch 
nicht mal irgendwelche Kondensatoren zu Spannungsaufbereitung verbaut 
habe. (bin mit dem Pi Pico Anfang des Jahres überhaupt erst motiviert 
worden mir Microcontroller anzuschauen, vorher habe ich alles immer mit 
Pis gemacht).

Alles in Allem bin ich der Meinung, bei den insgesamt 7 ESPs ist das 
Thema Stromversorgung sehr unterschiedlich im Detail gelöst. Alle Geräte 
fallen allerdings im Schnitt gleich häufig aus bzw. zeigen eben diese 
partiellen Fehlfunktionen. Keiner hat es bisher länger als zwei Wochen 
geschafft. :-(

>
> Ich habe einen Roboter (Codey Rocky) da läuft Micropython auf einem
> ESP32, Stromversorgung via Akku. Der hängt sich selten sporadisch auf
> (kommt aber vor).

Wenn das bei Dir auch vorkommt, konntest Du dafür einen Grund ermitteln 
bzw. hast Du eine Theorie dazu? Unsaubere Versorungsspannung könnte es 
ja auch sein, wenn der Akku es ESP auch die Motoren speist. Aber auf der 
anderen Seite, ich kann mir nicht vorstellen, dass die ESP soooo 
empfindlich sind, Sonoff & Co. scheinen auf ihren Platinen auch kein 
Feuerwerk der Spannungsversorgungsgenialität abzufeuern.

von Christian S. (somerhimson)


Lesenswert?

Guten Morgen Ernst,

Εrnst B. schrieb:
> Ohne Micropython im Detail zu kennen:
>
> -> Tastenauswertung per IRQ ist ansich schon zweifelhaft
> -> Du hast sehr viel langlaufenden Code in deinem interrupt_handler.
> Wenn Micropython während der IRQ-Abarbeitung weitere Interrupts erlaubt,
> läuft der handler nach Tasterprellen vielleicht mehrfach gleichzeitig.

Das mit dem zeitgleichen IRQ-Handler habe ich mich auch schonmal 
gefragt. Tatsächlich sind die 4 fach-Taster auch die ersten digitalen 
Bauten von mir, wo ich die Taster nicht elektrisch entprelle. Ich hatte 
mich von einem Bekannten bequatschen lassen, das ich mir den Aufwand 
sparen könne, "das mache man heute nicht mehr so". Ich habe hier 
Entprellzeiten eingesetzt, wo dann ja auch praktisch nichts gemacht 
wird, außer paar lokale Variablen setzen und am Ende verwerfen. Was das 
allerdings tatsächlich bewirkt (Stichwort Kreuzbeeinflussung), weiß ich 
leider nicht. Ich hatte gehofft bzw. vorausgesetzt, dass Micropython das 
selbstständig handelt, war eventuell ein Fehler.
Allerdings gibt es bei den WLAN-Bewegungsmeldern hoffentlich keine 
Prellthematik, denn da ist ja nur ein geschalteter Ausgang des 
PIR-Moduls am GPIO dran, und der hat eine Mindestanzugsdauer von etwa 
1,5 s.

> Wenn nicht: WLan kann wegen der langen laufzeit abbrechen, delay,
> micros, serial output funktionieren evtl. nicht so wie erwartet.

Was das WLAN angeht, das habe ich recht früh im Verdacht gehabt, daher 
habe ich die Status-LED der Taster programmiert bei jeden Tastendruck 
aufzuleuchten. Dabei ist dann relevant, ob eine WLAN-Verbindung besteht 
oder nicht (zumindest ob Micropython das meint), der "Blinkcode" ist 
verschiedenen. Habe das auch während der Entwicklung mit gezielter 
Manipulation eines entsprechenden Versuchs-WLANs getestet, und es 
funktionierte in meinen Augen zuverlässig. Im "abgestürzten" Zustand 
reagiert die Status-LED allerdings gar nicht auf einen Tastendruck, was 
in meinen Augen nur passieren kann, wenn der IRQ-Handler gar nicht 
aufgerufen wird.

>
> Macht dein Hauptprogramm denn ständig irgendwas wichtiges, bei dem du es
> per IRQ unterbrechen musst? Oder könntest du die Tasten nicht genausogut
> einfach regelmäßig im Hauptprogramm abfragen?

Diese Frage ist eine absolut zentrale, über die ich zum Projektbeginn 
lange nachdachte. Ich habe mich für diese Organisation entschieden, weil 
ich Netzwerknachrichten empfangen und trotzdem die Tasten jederzeit 
nutzen möchte. Bis zu diesem Projekt habe ich alles Schleifen-basierend 
gemacht, allerdings scheint es dann für die Netzwerknachrichten nicht 
immer zu klappen. Ich habe mir extra für dieses Projekt die IRQ-Thematik 
angeschaut, es erschien mir für mich passend.

Wenn es eine andere Möglichkeit gibt zuverlässig Netzwerknachrichten zu 
empfangen und trotzdem die Taster nutzen zu können, dann mache ich das 
sehr gerne. Nachdem ich mich jetzt mit den IRQs etwas beschäftigt habe, 
sind die mir eh etwas "suspekt" geworden.

von Stefan F. (Gast)


Lesenswert?

Christian S. schrieb:
> Der hängt sich selten sporadisch auf (kommt aber vor).

> Wenn das bei Dir auch vorkommt, konntest Du dafür einen Grund ermitteln
> bzw. hast Du eine Theorie dazu?

Nein. Ich habe da allerdings auch keinen Einfluss auf die Firmware. 
Jedenfalls hat das Din an der seriellen (USB) Console keine hilfreichen 
Meldungen ausgegeben.

> Unsaubere Versorungsspannung könnte es
> ja auch sein, wenn der Akku es ESP auch die Motoren speist.

Ist ein Argument, ich hatte allerdings die meisten Tests ohne Motoren 
gemacht. In meinem Python Script habe ich übrigens keine Interrupts 
verwendet. Auch keine Call-Back Funktionen für irgendwelche Events. Es 
gab immer einfach nur eine einzige Hauptschleife. Natürlich wird der 
vorinstallierte Python Interpreter aber wohl Interrupts nutzen.

von Christian S. (somerhimson)


Lesenswert?

Ich hatte eben bei dem System am Pi den Effekt, das ein Tastendruck bei 
ihm zwar eine Nachricht im Netzwerk auslöste, aber er nicht mehr auf 
eingehende Netzwerknachrichten reagierte. Sprich jetzt gerade war nur 
der Netzwerkempfang von UDP-Paketen gestört. Also irgendwie wird es 
langsam komisch.

Die Sache mit dem Garbage Collector habe ich leider noch nicht 
rausfinden können. Ich hoffe morgen habe ich etwas mehr Zeit dafür.

von Michael S. (Gast)


Lesenswert?

Hallo Christian S.,

Dein Problem wird gc.collect() nicht lösen.

Dein Problem liegt ganz offensichtlich am Interrupthandler.

siehe ausführliche Beschreibung hier:

- https://docs.micropython.org/en/latest/reference/isr_rules.html

Ein Interrupthandler muss kurz und bündig sein, weil er das laufende
Programm unterbricht.

Und vor allem: delays sind dort absolut tabu !

ebendso print-Statements.

Und Delays würde ich grundsätzlich versuchen zu vermeiden, denn sie 
blocken
den Programmablauf.

Michael S.

von Michael S. (Gast)


Lesenswert?

Hallo Christian S.

Hier noch eine Anmerkung zu "is" und "==".
"is" prüft, ob es sich um identische Objekte handelt.
Objekte sind identisch, wenn ihre id() gleich ist.
Kann man sehen mit print(id(a), id(b))

Das gilt unten für a und b, aber nicht für a und d,
Obwohl a und d den gleichen Inhalt transportieren,
sind sie doch unterschiedliche Objekte.

>>> a = "ABC"
>>> b = "ABC"
>>> c = "ABCD"
>>> d = c[:3]
>>> print(c)
ABCD
>>> print(d)
ABC
>>> print(a is b)
True
>>> print(a is d)
False
>>> print(a, d)
ABC ABC
>>> print( a == d)
True
>>> print(id(a), id(b), id(c))
140618533736176 140618533736176 140618511470192

von Stefan F. (Gast)


Lesenswert?

Die ID von a und b ist hier aber nur deswegen gleich, weil der Optimizer 
den String "ABC" nur einmal im Speicher anlegt und beide Variablen 
darauf zeigen lässt.

Normalerweise (ohne Optimizer-Tricks) wären das zwei unterschiedliche 
Objekte an zwei unterschiedlichen Speicherplätzen.

von Christian S. (somerhimson)


Lesenswert?

Danke Euch beiden für die Hinweise.
Die Sache mit "is" und "==" hat mich schon einige Male verwirrt. Mit 
Trail-and-Error habe ich schon gemerkt, das es einige Situationen gibt, 
in denen es das eine oder das andere mir besser half. Jetzt verstehe ich 
auch warum. :-)

Die Sache mit dem Handler muß ich dann wohl nochmal grundsätzlich 
überdenken. Der UDP-Empfang ist ja mein einziger relevanter Grund, warum 
ich IRQ nutze. Wenn es eine Möglichkeit gibt, das die recht kurzen 
Nachrichten in einem Zwischenspeicher landen und ich sie dann alle 0,5 
Sekunden oder so abrufen kann, das würde mir echt helfen. Wie das geht 
habe ich bisher noch nicht gefunden, hoffe da gibt es irgendwie was.

von Michael S. (Gast)


Lesenswert?

Hallo Christian S.,

Niemand zwingt Dich, mit Interrupts zu arbeiten.

Wenn die Erkennung der Statusänderung eines Pins nicht binnen kürzester 
Zeit
(in "Echtzeit") erfolgen muss - was hier sicherlich nicht notwendig ist 
- dann
reicht es aus, die Pins in hinreichend kurzen Zeitabständen abzufragen 
und dann
ggf. zu reagieren.

Mit Interrupts zu arbeiten würde Sinn machen, wenn diese einen 
schlafenden
Prozessor wecken könnten.
Aber einerseits ist das mit den ESP8266's ja nicht so recht möglich und 
andererseits
spricht die Netzwerkanbindung dagegen.

Michael S.

von Michael S. (Gast)


Lesenswert?

Hallo Christian S.

zur Umsetzung Deines Programmes kannst Du mal schauen, wie die 
Arduino-Fraktion
(die ich nicht mag) vorgeht:

Es gibt einen "Setup" Bereich, in dem die Grundeinstellungen vorgenommen 
werden,
wie etwa die Pinkonfiguration, die Netzwerkeinrichtung ....

Wenn das erfolgreich abgeschlossen ist, dann beginnt eine "mainloop", 
die
endlos wiederholt wird.

In Python könnte das - abstrakt formuliert - so aussehen:
1
- Konfigurieren der Pins
2
- Konfigurieren der Netzwerkverbindung
3
4
while True:
5
    schauen, ob Pin_0 gedrückt:
6
        wenn ja, dann eine Meldung absetzen
7
    schauen, ob Pin_1 gedrückt:
8
        wenn ja, dann eine Meldung absetzten
9
    ....
10
    steht die Netzwerkverbindung:
11
        wenn nicht, dann ein reconnect() versuchen
Anstelle von delays kann man Counter verwenden, die von
einem Timerinterrupt decrementiert werden.
Ein Programmteil, dass eine Wartezeit benötigt, setzt einen Counter auf 
einen
geeigneten Wert.
Innerhalb der mainloop wird dann getestet, ob der Counter abgelaufen ist
1
    if counter_x == 0:
2
        counter_x = -1
3
        towas()
4
        
5
Der Iimerinterrupt prüft:
6
    if couter_y > 0:
7
        counter -= 1
Aber viele Wege führen nach Rom, manche Wege sind kurz, andere dagegen 
länger,
aber dafür landschaftlich schöner.

Michael S.

von Christian S. (somerhimson)


Lesenswert?

Michael S. schrieb:
> Hallo Christian S.,
>
> Niemand zwingt Dich, mit Interrupts zu arbeiten.
>
> Wenn die Erkennung der Statusänderung eines Pins nicht binnen kürzester
> Zeit
> (in "Echtzeit") erfolgen muss - was hier sicherlich nicht notwendig ist
> - dann
> reicht es aus, die Pins in hinreichend kurzen Zeitabständen abzufragen
> und dann
> ggf. zu reagieren.
>

Hallo Michael,

ich sehe das im Prinzip genauso und die letzten 28 Jahre habe ich auch 
alles Schleifen-, Zustands- oder Trigger-basiert programmiert.

Diese Anwendung hier ist jetzt recht viel Neuland für mich. Ich habe, um 
den ESP und µPython zu lernen, mir verschiedene Tutorials angeschaut 
bzw. gelesen. Ich habe es dort so verstanden, das, wenn ich auf einem 
Netzwerkport lauschen möchte, ich ständig damit beschäftigt bin. Ich 
mache das auch in einem dritten ESP-Projekt, das, durch den 
Verbindungsaufbau auf TCP/80 getriggert, nur einen DHT22 ausliest, auf 
einem OLED-Display die Werte anzeigt und die Werte dann auf einer 
kleinen Webseite anzeigt (davon habe ich seit vier Wochen drei laufen, 
die hängen sich auch gelegentlich auf :-( ).

Am liebsten würde ich es gerne so machen, wie Du geschrieben hast: Eine 
Schleife mit kleiner Zykluszeit laufen lassen und die Pins abfragen und 
dann handeln. Diese Counter für Pausen nutze ich auch in anderen 
Projekten, nur haben die alle nicht die Anforderung permanent auf einem 
UDP- bzw. TCP-Port zu lauschen.

Entweder schnalle ich es einfach nicht, wie es umsetzbar ist, oder es 
geht nicht, "nebenbei" im Netz zu lauschen und bei Nachrichtenempfang 
dann zu handeln.

Weiß Du, ob es geht "nebenbei" zu lauschen? Das würde mir sehr helfen.

Gruß,
Christian

von Johannes S. (Gast)


Lesenswert?

Das nenbenbei lauschen ist eventuell ein Feature das noch fehlt:
https://github.com/perbu/dgram

von Michael S. (Gast)


Lesenswert?

Hallo Christian S.

Der Hinweis von Johannes S. auf asynchio bietet einen Ansatz.

Aber asyncnio ist für den Einstieg in Python weniger geeignet.
asynhio hat eine "flache Lernkurve" - sprich, es dauert lange die
Zusammenhänge zu verstehen.

Es gibt ein Tutorial von Peter Hinch, das ich aber selbst noch nicht
durcharbeitet habe (steht aber auf der Agenda):

https://github.com/peterhinch/micropython-async

Andererseits ist Dein Problem ja nicht so kompliziert.
Das sollte auch innerhalb der mainloop lösbar sein.

Stöbere mal in der Doku zum ESP8266:

https://docs.micropython.org/en/latest/esp8266/quickref.html#networking
https://docs.micropython.org/en/latest/library/socket.html#module-socket

Ich selbst habe von Anfang an auf MQTT gesetzt, das ist schlank und 
schnell.

Anstelle einer geschwätzigen Kommunikation mit Worten werden hier nur 
wenige
Bytes versandt, das passt meines Erachtens besser zu den begrenzten 
Ressourcen
eines Mikrocontrollers.

Michael S.

von Christian S. (somerhimson)


Lesenswert?

Johannes S. schrieb:
> Das nenbenbei lauschen ist eventuell ein Feature das noch fehlt:
> https://github.com/perbu/dgram

Guten Morgen Johannes,

das ist genau mein Eindruck, den ich bisher gewonnen habe. Finde ich 
sehr schade, denn das schließt in meinen Augen eine ganze Menge 
spannender Projekte aus, insbesondere wenn die IRQ-Handler kritisch 
sind.

Ich werde mir dgram mal anschauen, brauche ich allerdings bißchen Musse 
zu, die ich diese Tage nicht haben werde. Nächste Woche hoffentlich 
aber.

von Christian S. (somerhimson)


Lesenswert?

Guten Morgen Michael,

Michael S. schrieb:
> Hallo Christian S.
>
> Der Hinweis von Johannes S. auf asynchio bietet einen Ansatz.
>
> Aber asyncnio ist für den Einstieg in Python weniger geeignet.
> asynhio hat eine "flache Lernkurve" - sprich, es dauert lange die
> Zusammenhänge zu verstehen.
>
> Es gibt ein Tutorial von Peter Hinch, das ich aber selbst noch nicht
> durcharbeitet habe (steht aber auf der Agenda):
>
> https://github.com/peterhinch/micropython-async
>

Ich werde mir das mal anschauen, brauche ich allerdings bißchen Musse
zu, die ich diese Tage leider nicht haben werde. Nächste Woche 
hoffentlich
aber.

> Andererseits ist Dein Problem ja nicht so kompliziert.
> Das sollte auch innerhalb der mainloop lösbar sein.
>
> Stöbere mal in der Doku zum ESP8266:
>
> https://docs.micropython.org/en/latest/esp8266/quickref.html#networking
> https://docs.micropython.org/en/latest/library/socket.html#module-socket
>

U.a. diese beiden Artikel hatte ich mir im Vorfeld angeschaut und dann 
mein "Konstrukt" entworfen. Entweder ich verstehe es nicht ganz, oder 
die führen zu meiner Lösung, wenn ich im Netz lauschen will und trotzdem 
lokale Tastendrücke verarbeiten möchte. :-(

Mein Smarthome-Server löst aufgrund verschiedener Ereignisse und 
Zustände gewisse Funktionen aus. Diese Funktionen können Schaltbefehle 
oder E-Mailnachrichten sein, oder auch Zustandsmeldungen an Sub- oder 
Parallelsysteme. Ich möchte, im Sinne des Edge-Computings ;-) , gewisse 
Intelligenz in einigen Subsystemen haben, daher soll zum Beispiel in 
meinem Beispielcode oben beim Druck der Taste 4 eine andere Nachricht 
verschicken, wenn mein Gartenstrom eingeschaltet ist als wenn dieser aus 
ist. Hat auch dieses Netzwerklauschen den Vorteil, ich bekomme mit der 
entsprechenden LED angezeigt, ob der Gartenstrom an ist oder nicht. Auch 
wenn ich ihn über ein anderes Device eingeschaltet habe oder das System 
es gar automatisch aus löste. Ob man das braucht steht auf einem anderen 
Blatt, aber ich möchte es halt irgendwie hinbekommen.

Lernen tue ich am besten, wenn es erstmal nicht klappt, was ich bauen 
möchte. ;-)

> Ich selbst habe von Anfang an auf MQTT gesetzt, das ist schlank und
> schnell.
>
> Anstelle einer geschwätzigen Kommunikation mit Worten werden hier nur
> wenige
> Bytes versandt, das passt meines Erachtens besser zu den begrenzten
> Ressourcen
> eines Mikrocontrollers.
>
> Michael S.

MQTT nutze ich auch für drei spezielle kommerzielle Sensoren bzw. 
Bridges, denn sonst komme ich dort nicht an meine gewünschten Signale. 
Allerdings habe ich gelegentlich den Effekt, das Signale nicht 
eingetragen werden. Ich weiß nicht, ob es an der China-Dingern liegt 
oder ein MQTT-Effekt ist.
Aber das nur so am Rande, denn mit den ESP's geht es mir neben deren 
Funktion bzw. Nutzung für mein Smarthome-System, vor allem darum zu 
Lernen.
Mein Netzwerkprotokoll, von dem das mit den ESPs abstammt, ist auch 
recht schlank und läuft mit Pis schon seit vielen Jahren an drei 
Standorten einwandfrei und sehr komplex (einfach kann ja jeder ;-) ).

Es geht hier also quasi um den landschaftlich schöneren Weg nach Rom. 
;-)

von Philipp K. (philipp_k59)


Lesenswert?

Vielleicht gibt es einen Überlauf und der esp8266 startet neu, da du den 
pullup auf gpio0 aktivierst gehe ich davon aus das der Pin keinen 
externen pullup hat.. gpio0 sollte aber einen externen Pullup beim 
booten haben.

Kommt dann drauf an welches Board verwendet wird und wie da GPIO0 
verdrahtet ist.

Man müsste zum debuggen einen anderen esp zum loggen des seriellen debug 
Outputs nutzen und dann dort nachschauen welche Fehlermeldungen es gibt. 
(Stacktrace) etc.

Der ESP bringt wenn er abstürzt einen seriellen Debug Hinweis wie das 
Zustande gekommen ist.

von Christian S. (somerhimson)


Lesenswert?

Philipp K. schrieb:
> Vielleicht gibt es einen Überlauf und der esp8266 startet neu, da du den
> pullup auf gpio0 aktivierst gehe ich davon aus das der Pin keinen
> externen pullup hat.. gpio0 sollte aber einen externen Pullup beim
> booten haben.
>
> Kommt dann drauf an welches Board verwendet wird und wie da GPIO0
> verdrahtet ist.
>

Hallo Philipp,

ich nutze ausschließlich das D1 Mini von Wemos. Und vergurkte Neustarts 
konnte ich bisher nicht feststellen. Jeder Neustart würde entweder zum 
Verlöschen der LEDs führen (oder sagen wir mal einem "nur noch 
Glimmen"), und wenn er ordnungsgemäß bootet gibt es eine "Anmeldung" an 
meinem Server. Schlägt die Fehl, stimmen die LED-Anzeigen nicht. Das ist 
alles nicht der Fall, daher denke ich, Neustarts kann ich ausschließen.

Im Gegenteil sogar, wenn ich absichtlich einen Reboot bzw. Reset per 
Befehl auslöse, z.B. weil die WLAN-Verbindung nicht sauber hochkommt, 
booten die Boards nicht. Ich scheine da wohl einen falschen Befehl zu 
nutzen, das muß ich mir auch noch anschauen. Nur, da mich die ESP jetzt 
sehr ärgern mit deren blödem Hängenbleiben, mache ich da erstmal nix, 
bis die stabil laufen.

> Man müsste zum debuggen einen anderen esp zum loggen des seriellen debug
> Outputs nutzen und dann dort nachschauen welche Fehlermeldungen es gibt.
> (Stacktrace) etc.
>
> Der ESP bringt wenn er abstürzt einen seriellen Debug Hinweis wie das
> Zustande gekommen ist.

Per USB und Picocom habe ich schon versucht der Sache auf die Spur zu 
kommen, aber entweder mein Pi 3b mag es nicht bzw. dessen Picocom läuft 
nicht stabil, oder der ESP mag keine langfristigen Terminalausgaben. 
Nach einigen Tagen ist die Kommunikation einfach tot, Picocom empfängt 
nichts mehr, bis ich den ESP neu starte.

von Stefan F. (Gast)


Lesenswert?

Nach meiner Erfahrung erkennt der Watchdog nur einen Bruchteil der real 
auftretenden Fehler (finde ich nicht überraschend). Wenn er einen reset 
auslöst, hat der Chip sofort danach manchmal trotzdem noch erhebliche 
Fehlfunktionen. Ein Reset-Impuls von außen funktionierte in meinen 
Fällen jedoch immer einwandfrei.

von Christian S. (somerhimson)


Lesenswert?

Stefan ⛄ F. schrieb:
> Nach meiner Erfahrung erkennt der Watchdog nur einen Bruchteil der real
> auftretenden Fehler (finde ich nicht überraschend). Wenn er einen reset
> auslöst, hat der Chip sofort danach manchmal trotzdem noch erhebliche
> Fehlfunktionen. Ein Reset-Impuls von außen funktionierte in meinen
> Fällen jedoch immer einwandfrei.

Hallo Stefan,

verstehe ich das richtig, Du nutzt einen GPIO um den Hardwarereset 
auszulösen?

Ich möchte gerne gezielt einen Reset zuverlässig auslösen können, wenn 
ich eine Fehlfunktion detektiere.

von Stefan F. (Gast)


Lesenswert?

Christian S. schrieb:
> verstehe ich das richtig, Du nutzt einen GPIO um den Hardwarereset
> auszulösen?

Nein ich nutze einen externen zweiten Mikrocontroller, der 
Fehlfunktionen erkennt und ggf. einen Impuls am Reset-Eingang des ESP 
erzeugt.

Siehe http://stefanfrings.de/wlan_io/index.html

Habe ich mal für eine Alarmanlage gemacht, wo selten jemand vor Ort ist. 
Normalerweise laufen die Module allerdings stabil - zumindest mit dem 
Arduino Core 2.3.0.

Mit Python habe ich sie noch nicht verwendet.

von Christian S. (somerhimson)


Lesenswert?

Stefan ⛄ F. schrieb:
> Nein ich nutze einen externen zweiten Mikrocontroller, der
> Fehlfunktionen erkennt und ggf. einen Impuls am Reset-Eingang des ESP
> erzeugt.

Na das ist mal voll nach meinem Geschmack. ;-)
Mein großes Bewässerungsprojekt mit den Pi Picos habe ich auch so 
gestaltet. Ein Pi Zero steuert zwei Picos und erkennt Fehlfunktionen. 
Mein Server erkennt per LAN dann Fehlfunktionen des Zero, klappt richtig 
gut (gibt allerdings praktisch keine Fehlfunktionen :-) ). :-)

Allerdings kommt es bei den zwei fraglichen ESP-Projekten sehr auf den 
Bauraum an. Wenn ich da jetzt noch einen Watchdog-Controller dazu bauen 
muß, wäre das relativ viel Extraplatz.

Ich fürchte die Arduino IDE muß ich mir wohl doch noch anschauen, 
Micropython scheint mir immer deutlicher nicht so ganz rund zu laufen 
auf den ESP8266. :-(

von Christian S. (somerhimson)


Lesenswert?

Ist bißchen Zeit ins Land gegangen und ich habe verschiedene Dinge 
probiert.
Ich habe auf zwei verschiedenen Gerätetypen jetzt ein Programm ganz ohne 
Log-Ausgabe geschrieben. Das schien zwar zunächst die Situation zu 
verbessern und insgesamt habe ich den Eindruck, die beiden Geräte laufen 
länger am Stück ohne Problem, aber da ich es nie direkt mitbekomme, wann 
das Problem auftaucht ist es mehr ein Gefühl, ich weiß nicht, wie ich es 
messen könnte.

Das Thema mit dem Messen ist eh so eine Sache, denn auf der Suche nach 
einer Messmöglichkeit, habe ich herausgefunden, dass ein scheinbar 
abgestürztes Gerät nur auf den jeweiligen GPIO nicht mehr reagiert. So 
als wenn nur dieser eine GPIO einfriert und sonst nichts passiert. Die 
Geräte sind im "eingefrorenen" Zustand per WLAN einwandfrei erreichbar 
und reagieren ganz normal.

Ich denke, mit dieser Beobachtung ist dann auch die Stromversorgung 
recht unwahrscheinlich. Zum einen trifft es ja jedes ESP8266-Gerät, das 
ich bisher von diesen Typen gebaut habe, und zum anderen würde ich 
erwarten, dass entweder die Stromspitzen das ganze Programm abschießen, 
oder zumindest einen beliebigen Fehler auslösen, und nicht immer genau 
das gleiche Verhalten.

Ich frage mich jetzt, was muß passieren, das nur ein einzelner GPIO 
einfriert, bzw. kein IRQ mehr ausgelöst wird, ohne das Programm zu 
ändern.

von c-hater (Gast)


Lesenswert?

Christian S. schrieb:
> if befehlhier is not "nix":

Das vergleich übrigens Identität, statt Gleichheit.
Wahrscheinlich nicht das, was du willst.

von Christian S. (somerhimson)


Lesenswert?

c-hater schrieb:
> Das vergleich übrigens Identität, statt Gleichheit.
> Wahrscheinlich nicht das, was du willst.

Danke für den Hinweis.

Der Unterschied war mir damals tatsächlich nicht klar.
In der Zwischenzeit hat es diverse Anpassungen und Veränderungen im 
Rahmen der Fehlersuche gegeben. Die jüngsten Erkenntnisse sind die 
meines letzten Beitrages.

von Christian S. (somerhimson)


Lesenswert?

Mir ist an einem der Systeme aufgefallen, dass trotz des Problems mit 
dem Taster, es per Netzwerk ansprechbar war und sogar korrekt auf 
Anfragen antwortete, inkl. Berechnung von Werten.

Das veranlasste mich mal einen Zähler für das Auslösen des Interrupts zu 
einzubauen, den ich per Netzwerk abfragen kann. Habe das bei einem der 
Bewegungsmelder gemacht, weil der am meisten auslöst und sich auch am 
häufigsten "aufhängt".

Interessant ist, der Zähler zählt hoch, also muß die Interrupt-Routine 
ausgelöst werden. Komisch ist dabei, warum zählt der Zähler hoch, der 
einzig in dieser Interrupt-Routine erhöht wird, aber andere Funktionen 
reagieren nicht. Das betrifft lokale, wie das blinken einer LED, als 
auch Netzwerkfunktionen, wie das Absetzen von UDP-Nachrichten.

Hat vielleicht jemand eine Idee, wo ich da suchen könnte?

von mIstA (Gast)


Lesenswert?

Christian S. schrieb:
> Das veranlasste mich mal einen Zähler für das Auslösen des
> Interrupts zu einzubauen, den ich per Netzwerk abfragen kann.

Christian S. schrieb:
> Interessant ist, der Zähler zählt hoch, also muß die
> Interrupt-Routine ausgelöst werden.

Das ist doch schon mal ein guter Anfang. Hast Du schon mal ermittelt, 
wie schnell der Zähler hochzählt? Da Du den Zähler übers Netz abfragen 
kannst, sollte das ja recht einfach sein - eine grobe Einschätzung der 
Größenordnung reicht für den Anfang schon: zählt er alle paar Sekunden 
(oder seltener), 'n paarmal pro Sekunde oder vielleicht ein paar tausend 
oder gar Millionen mal pro Sekunde?


Christian S. schrieb:
> Komisch ist dabei, warum zählt der Zähler hoch, der
> einzig in dieser Interrupt-Routine erhöht wird, aber andere
> Funktionen reagieren nicht. Das betrifft lokale, wie das
> blinken einer LED, als auch Netzwerkfunktionen, wie das
> Absetzen von UDP-Nachrichten.

Also falls das letzte der obigen Zähltempo-Beispiele Deiner Realität am 
nächsten kommt, dann wäre die Antwort hierauf ja mehr als 
offensichtlich: der Arme zählt & zählt & zählt noch schneller, daß ihm 
für sonst nix mehr Zeit bleibt. (Die naheliegendste Erklärung für ein 
derart absurdes Zähltempo wäre dann wohl ein unbeschalteter Input-Pin 
der an einem Radiosender gefallen gefunden hat.)

Aber auch extremes Prellen, bei dem er (nur) ein paar hundert 
Flankenwechsel abkriegt, die aber in Bruchteilen einer Sekunde…
also da hielte ich es schon für denkbar, daß, während er beschäftigt ist 
die hunderten Interrupts abzuarbeiten, für andere Aufgaben nicht mehr 
genug Zeit bleibt.


Christian S. schrieb:
> Netzwerkfunktionen, wie das Absetzen von UDP-Nachrichten.

Aber die Abfrage des Zählers übers Netz klappt auch in diesen Momenten 
problemlos?

von Christian S. (somerhimson)


Lesenswert?

mIstA schrieb:
> zählt er alle paar Sekunden
> (oder seltener), 'n paarmal pro Sekunde oder vielleicht ein paar tausend
> oder gar Millionen mal pro Sekunde?

Es gibt zwei Konstellationen. Einmal meine "DIYT", eine 
Dash-Button-Ertsatz mit vier einfachen, nicht entprellten Tasten durch 
bewusstes Drücken bedient werden. Die andere Variante, in der ich jetzt 
auch den Eventzähler eingebaut habe, nenne ich "PIR" und es ist ein 
Bewegungsmelder, der das PIR-Modul AZDelivery HC-SR501 (also das 
Wald-und-Wiesen-Teil) nutzt. Hier zieht der Ausgang bei Auslösen für > 1 
Sekunde mindestens an, wenn die Bewegung länger ist, dann auch länger. 
Ich habe absichtlich das an einem PIR probiert, weil zum einen dort mehr 
Ereignisse passieren und zum anderen ich davon ausgehen, der 
PIR-Modul-Ausgang prellt nicht. Wenn ich meinen Zähler anschaue, dann 
sind dort am Tag, in dem der Raum normal stark frequentiert wird, so 
etwa 1200 Ereignisse. Wenn niemand im Raum ist, zählt mein Zähler auch 
nicht hoch. Ich habe es bei Abwesenheit auch an einem Server, der alles 
protokolliert, und ich muß sagen, ich hatte noch nie eine Fehlauslösung.

Eine Sache vielleicht noch ergänzend:
Ich habe die Programme (DIYT und PIR) auf Python auf einem Pi Zero 
(beide Funktionen auf einem einzigen Pi, natürlich mit etwas angepasster 
Hardware) portiert, da muß man ja kaum Anpassungen machen. Dort läuft es 
seit fast zwei Jahren ohne eine Fehlfunktion. In der Zeit ist der Pi nur 
dreimal neugestartet und dessen Raum ist sogar noch stärker 
frequentiert. Daher hatte ich bisher meinen Programmcode ansich auch 
ausgeschlossen, aber auf der anderen Seite ist der Pi natürlich auch 
deutlich leistungsfähiger.

Was die UDP-Nachrichten angeht, die werden in dem "eingefrorenen" 
Zustand nicht mehr über die Interrupt-Routine abgesetzt, sonst würde 
mein Server das mitbekommen. Wenn ich jedoch eine Abfrage mache (auf 
einem UDP-Port wird dauerhaft gelauscht und dann die empfangene 
Nachricht verarbeitet, das ist auch der Grund für die Interruptnutzung), 
dann reagiert der ESP prompt und korrekt.

: Bearbeitet durch User
von Christian S. (somerhimson)


Lesenswert?

Falls jemand über diesen Fred stoplert:

Mittlerweile habe ich die Thematik für mich im Griff.

Zum einen bin ich durch den Pi Pico W nicht mehr auf den ESP angewiesen 
(und der Pico läuft ja einwandfrei) und zum anderen habe ich einen 
täglichen Reboot der ESPs im Server etabliert. Da die Netzwerkreaktionen 
ja immer einwandfrei waren und ich durch den Einzelkern des ESP leider 
keine Schleife laufen lassen kann, habe ich mich entschieden einen 
Reboot-Befehl über UDP zu triggern. Seitdem hatte ich keinen Aussetzer 
mehr, alle ESP-Devices laufen einwandfrei.


Ich habe noch eine Beobachtung gemacht: Schon länger hatte ich ein 
Problem von MicroPython auf dem ESP bzw. das der ESP ein Problem mit der 
Umgebung hat, vermutet. Dies hat sich in meinen Augen erhärtet, denn ich 
habe, beflügelt durch die jetzt "saubere" Funktionsweise, mein 
DIYT-Programm feingeschliffen und sicherer gegenüber Fehlinformationen 
gemacht. Dazu mußte ich natürlich mehr Tests einbauen, und das führte 
dazu, dass Thonny mir meldete, der RAM sei voll. Ich habe versucht durch 
gezieltes Entfernen und Hinzufügen von Funktionen und sogar einzelnen 
Variablen und Variablentypen ein Prinzip zu finden, wieviel der RAM 
verkraftet, bzw. was wieviel RAM benötigt. Es ist mir trotz sehr vieler 
Stunden und jeglicher Tests, die mir einfielen, nicht gelungen. 
Teilweise schien es einen Zusammenhang zwischen Funktionsaufrufen und 
RAM-Last zu geben, und dann kurz drauf in meinen Augen eine 
vergleichbare Funktion bzw. Konstellation brachte andere RAM-Last (sie 
steig laut Thonny vereinzelt sogar, als ich Dinge entfernte). Was mich 
dann vor allem wunderte, als ich zur Laufzeit den RAM auslesen ließ, war 
immer weniger als 1/3 belegt (egal ob als "main.py" eigenständig 
gestartet oder über Thonny).
Also ich denke, da stimmt was nicht mit der MicroPython-Implementierung 
auf dem ESP8266. Das fällt wahrscheinlich nicht ins Gewicht, wenn man 
nur so einfache kleine Dinge schreibt, aber bei komplexeren 
Konstellationen passt es dann offensichtlich nicht mehr.

Ich bin mir auch deshalb so sicher dabei, denn ich habe den Code 1:1 auf 
einen Pi Pico W gepackt und mußte da nur den Funktionsaufruf ".duty" in 
".dutyu16" für die Nutzung von PWM-GPIOs umschreiben und die 
PWM-Zahlenwerte anpassen (ESP 0=an & 1023=aus; Pico 0=aus & 65025=an). 
Der Rest ist buchstabengetreu absolut identisch, und läuft einwandfrei. 
Sprich, auch wenn ich mit den IRQs etwas viel Code ausführen lasse, so 
stört das scheinbar nur den ESP8266, den Pi Pico nicht.

Und noch was habe ich über mehrere Monate getestet: Ich habe ein DIYT in 
der ursprünglichen Hardware mit dem ESP8266 laufenlassen und absichtlich 
nicht einen der Tasten berührt, womit in meinem Verständnis es 
ausgeschlossen ist, das einer meiner IRQ-Handler ausgelöst wurde. Und 
trotzdem lief der Prüfling nie länger als 1,5 Wochen sauber. Die Tasten 
froren dann doch ein, per Netzwerk war er normal zu erreichen. Das ist 
in meinen Augen der letzte Beweis, dass die Programmierung des 
IRQ-Handlers nicht das Problem sein kann, es muß etwas anderes, von 
MicroPython selbst sein, das da nach einiger Zeit aus dem Ruder läuft.

Das nun vorerst als letzte Nachricht von mir in der Angelegenheit.
Sollte ich irgendwann das Rätsel weiter entschlüsseln, werde ich es hier 
auch posten.

Allerdings ist mein Fazit: ESP8266 und MicroPython ist keine gute 
Kombination, lieber einen Pi Pico W nehmen, der kostet auch nicht sooo 
viel mehr und läuft granatenmäßig stabil.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.