Fix MicroPython coroutine startup detection

This commit is contained in:
Franz Rolfsvaag 2026-08-28 18:43:29 +02:00
parent 0a87fa71f1
commit efdb8ec3fe
3 changed files with 17 additions and 7 deletions

View File

@ -42,9 +42,9 @@ UART_RX_GPIO=21
# ---------- Read-only development probe ---------- # ---------- Read-only development probe ----------
# Keep disabled until a safe, conditioned front-panel signal is connected. # Keep disabled until a safe, conditioned front-panel signal is connected.
PROBE_ENABLED=false PROBE_ENABLED=false
# Required when PROBE_ENABLED=true. GPIO3 is a candidate on the C3 Super Mini, # Required when PROBE_ENABLED=true. GPIO3 is the chosen candidate on the
# but confirm the board routing and electrical interface before using it. # ESP32-C3 Super Mini; confirm the electrical interface before using it.
PROBE_GPIO= PROBE_GPIO=3
# state | frequency | pulse | watch # state | frequency | pulse | watch
PROBE_MODE=frequency PROBE_MODE=frequency
PROBE_INTERVAL_SECONDS=3 PROBE_INTERVAL_SECONDS=3

View File

@ -197,6 +197,16 @@ def epoch_is_valid():
return False return False
def is_awaitable(value):
"""Support CPython and MicroPython coroutine objects.
On the ESP32 MicroPython port, native coroutine objects expose ``send``
but not ``__await__``. Checking both lets application hooks be either
synchronous functions or ``async def`` coroutines.
"""
return hasattr(value, "__await__") or hasattr(value, "send")
class ActivityTracker: class ActivityTracker:
"""Tracks idleness and protected/busy operations for safe OTA timing.""" """Tracks idleness and protected/busy operations for safe OTA timing."""
@ -816,7 +826,7 @@ async def run_async():
# restore the previous launcher/app files. # restore the previous launcher/app files.
if hasattr(app, "setup"): if hasattr(app, "setup"):
result = app.setup(ctx) result = app.setup(ctx)
if hasattr(result, "__await__"): if is_awaitable(result):
await result await result
else: else:
system.ready() system.ready()
@ -825,7 +835,7 @@ async def run_async():
asyncio.create_task(updater.service()) asyncio.create_task(updater.service())
result = app.main(ctx) result = app.main(ctx)
if hasattr(result, "__await__"): if is_awaitable(result):
await result await result
else: else:
log("synchronous main() returned; async main() is recommended") log("synchronous main() returned; async main() is recommended")

View File

@ -1,11 +1,11 @@
{ {
"schema": 1, "schema": 1,
"release": "0.1.2-probe.2", "release": "0.1.3-probe.3",
"files": [ "files": [
{ {
"source": "firmware/launcher.py", "source": "firmware/launcher.py",
"target": "/launcher.py", "target": "/launcher.py",
"sha256": "f8ef1bba8e298877b39427870a10ea4784db33a943a5e10040bf652b4866cd2f" "sha256": "e668276d99c5e78238fe9c4eb77acb5c055a4f0deabf272112ed4e0f2c1320ef"
}, },
{ {
"source": "firmware/app/__init__.py", "source": "firmware/app/__init__.py",