142a621066
MicroPython fuehrt main.py nach jedem Reset selbst aus -- nach Stromausfall oder Watchdog-Neustart laeuft die Anzeige damit ohne Notebook wieder an. Bisher gab es die Datei bewusst nicht, weil am Aufbau gearbeitet wurde. **Das Abbruchfenster ist kein Komfort, sondern die Notbremse.** Ohne es waere ein Geraet, dessen Programm beim Start haengt, nur noch durch Neuflashen erreichbar: Die Endlosschleife belegt die REPL sofort nach dem Reset. main.py wartet deshalb erst AUTOSTART_DELAY (3 s), in denen Ctrl-C zurueck an die REPL fuehrt -- dann laeuft auch kein Watchdog. Watchdog (WDT_TIMEOUT = 120 s): startet das Geraet neu, wenn die Poll-Schleife stehenbleibt. Gefuettert wird zu Beginn *jedes* Durchlaufs, auch nach einem Fehler -- "KEIN LINK" ist kein Stillstand, die Schleife laeuft ja weiter. Der Wert muss ueber allem liegen, was regulaer blockieren darf (WLAN 20 s, Montierung 3 s, dazu ein MQTT-Versuch); knapper waere er eine Neustart-Schleife. Ein gestarteter Watchdog laesst sich nicht mehr abschalten. Deshalb legt ihn nur main.py an -- im Handbetrieb ueber die REPL startete das Geraet sonst neu, waehrend man nachdenkt. Weiteres: - Nach einem Watchdog-Neustart meldet main.py das beim Start (machine.reset_cause()), sonst saehe er aus wie ein Stromausfall. - Eine Ausnahme faengt main.py ab und startet nach RESTART_DELAY (10 s) neu, statt in die REPL zu fallen und die Anzeige einzufrieren. Die Pause verhindert eine Neustart-Schleife im Sekundentakt. - Autostart faehrt mit Helligkeitsregelung (with_ldr=True, Nutzerentscheidung). Am Geraet bestaetigt: Autostart nach Reset laeuft durch (Watchdog aktiv, WLAN, MQTT), ein absichtlich herbeigefuehrter Stillstand loest den Watchdog aus und das Geraet kommt von allein wieder hoch -- mit der Meldung "Vorheriger Lauf wurde vom Watchdog beendet". Ctrl-C im Startfenster gibt die REPL frei. Beim Geraetetest aufgefallen: make_watchdog wurde ohne log aufgerufen, im Startprotokoll stand also nichts vom Watchdog. Behoben und durch einen Test festgehalten. 178 Tests gruen (neu: test_main.py). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
88 lines
2.9 KiB
Python
88 lines
2.9 KiB
Python
"""Autostart auf dem ESP32-C3.
|
|
|
|
MicroPython fuehrt diese Datei nach boot.py bei jedem Reset selbst aus. Damit
|
|
laeuft die Anzeige nach Stromausfall oder Watchdog-Neustart von allein wieder an,
|
|
ohne dass jemand ein Notebook anschliessen muss.
|
|
|
|
**Das Abbruchfenster ist kein Komfort, sondern die Notbremse.** Ohne es waere ein
|
|
Geraet, dessen Programm beim Start haengt oder abstuerzt, nur noch durch
|
|
Neuflashen erreichbar -- die Endlosschleife belegt die REPL sofort nach dem
|
|
Reset. Deshalb wartet main.py erst config.AUTOSTART_DELAY Sekunden, in denen
|
|
Ctrl-C zurueck an die REPL fuehrt:
|
|
|
|
mpremote repl dann Ctrl-C druecken, solange "startet in ..." steht
|
|
|
|
Danach:
|
|
- Der **Watchdog** startet das Geraet neu, wenn die Poll-Schleife stehenbleibt
|
|
(siehe run_esp32.make_watchdog). Das faengt Haenger, die keine Ausnahme werfen.
|
|
- Eine **Ausnahme** faengt der Block unten ab und startet nach
|
|
config.RESTART_DELAY neu, statt in die REPL zu fallen und die Anzeige
|
|
einzufrieren.
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
|
|
import config
|
|
|
|
|
|
def _startbar():
|
|
"""Wartet das Abbruchfenster ab. False, wenn abgebrochen wurde."""
|
|
print("Grossanzeige startet in %.0f s -- Ctrl-C bricht ab."
|
|
% config.AUTOSTART_DELAY)
|
|
try:
|
|
time.sleep(config.AUTOSTART_DELAY)
|
|
except KeyboardInterrupt:
|
|
print("Autostart abgebrochen, REPL ist frei.")
|
|
return False
|
|
return True
|
|
|
|
|
|
def _neustart(grund):
|
|
"""Nach einem Absturz neu starten -- mit Pause und Abbruchmoeglichkeit."""
|
|
print("%s -- Neustart in %.0f s (Ctrl-C bricht ab)"
|
|
% (grund, config.RESTART_DELAY))
|
|
try:
|
|
time.sleep(config.RESTART_DELAY)
|
|
except KeyboardInterrupt:
|
|
print("Neustart abgebrochen, REPL ist frei.")
|
|
return
|
|
try:
|
|
import machine
|
|
machine.reset()
|
|
except ImportError:
|
|
sys.exit()
|
|
|
|
|
|
def start():
|
|
if not _startbar():
|
|
return
|
|
|
|
import run_esp32
|
|
|
|
# Nach einem Watchdog-Neustart ist das der einzige Hinweis darauf, dass
|
|
# ueberhaupt etwas gehangen hat -- ohne ihn sieht ein Neustart aus wie ein
|
|
# gewoehnlicher Stromausfall.
|
|
try:
|
|
import machine
|
|
if machine.reset_cause() == machine.WDT_RESET:
|
|
print("Vorheriger Lauf wurde vom Watchdog beendet.")
|
|
except (ImportError, AttributeError):
|
|
pass
|
|
|
|
# log=print, damit im Startprotokoll steht, dass der Watchdog laeuft --
|
|
# sonst bliebe unsichtbar, ob er ueberhaupt angelegt wurde.
|
|
feed = run_esp32.make_watchdog(log=print)
|
|
try:
|
|
run_esp32.main(with_ldr=True, feed=feed)
|
|
except KeyboardInterrupt:
|
|
# Von Hand beendet: nicht neu starten, sondern die REPL freigeben.
|
|
# Der Watchdog laeuft allerdings weiter und startet das Geraet in
|
|
# config.WDT_TIMEOUT Sekunden neu -- er laesst sich nicht abschalten.
|
|
print("\nbeendet (Watchdog startet in %.0f s neu)" % config.WDT_TIMEOUT)
|
|
except Exception as e:
|
|
_neustart("Absturz: %s" % e)
|
|
|
|
|
|
start()
|