Skip to content

net/webrepl: Support LAN interfaces and fix AttributeError on ports without WLAN#1116

Open
AsinoEsel wants to merge 1 commit into
micropython:masterfrom
AsinoEsel:fix/webrepl-wlan-attributeerror
Open

net/webrepl: Support LAN interfaces and fix AttributeError on ports without WLAN#1116
AsinoEsel wants to merge 1 commit into
micropython:masterfrom
AsinoEsel:fix/webrepl-wlan-attributeerror

Conversation

@AsinoEsel

Copy link
Copy Markdown

WebREPL currently does not support LAN interfaces, and raises an AttributeError on webrepl.start() on boards without network.WLAN, such as the ESP32-P4 port. The exception is raised in setup_conn() in line 105:

    for i in (network.WLAN.IF_AP, network.WLAN.IF_STA):

Steps to reproduce:

  1. Flash the latest firmware for the ESP32-P4 port
  2. Inside the REPL, configure WebREPL using import webrepl_setup
  3. If configured to enable on startup, it will immediately raise:
  File "<stdin>", line 1, in <module>
  File "webrepl.py", line 1, in start
  File "webrepl.py", line 1, in setup_conn
AttributeError: 'module' object has no attribute 'WLAN'

This PR adds

  1. a try-except block for the existing WLAN logic, to catch this AttributeError.
  2. support for LAN interfaces, with a try-except block to catch errors (such as a TypeError in the event that the LAN interface has not yet been initialized).
  3. A fallback for when neither type of interface has been found.

I have tested this on an ESP32-P4-ETH board, and a generic ESP32 board. Works as intended.

This issue was raised before in #920 by @Romaric-RILLET, but that attempted fix failed to cover the network.WLAN AttributeError (as it happens outside the try-except block), making it impossible for ethernet-only boards to use WebREPL.

On ports without network.WLAN (such as the ESP32-P4 port), webrepl
crashes on webrepl.start() because network.WLAN is accessed
unconditionally in setup_conn().

Add LAN interface support, add try/except around LAN and WLAN access,
and add fallback to 0.0.0.0:<port> if no active interface is found.

Based on micropython#920 by @Romaric-RILLET.

Signed-off-by: AsinoEsel <lerefff@gmail.com>
@agatti

agatti commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR!

If I read the code correctly, if you have a board that has both LAN and WiFi interfaces available the REPL will bind to the first LAN interface and will leave WiFi interfaces alone. Same thing for WiFi, the old code would bind to all available interfaces, yours stops whenever the first viable interface is found.

Maybe that's what somebody may want, but I reckon there ought to be some sort of control on the binding behaviour. How about having an additional optional parameter that indicates which interfaces are enumerated? For now I guess it could be something as simple as this (only for WLAN in this case - completely untested!):

diff --git i/micropython/net/webrepl/webrepl.py w/micropython/net/webrepl/webrepl.py
index 00da815..07f9b50 100644
--- i/micropython/net/webrepl/webrepl.py
+++ w/micropython/net/webrepl/webrepl.py
@@ -90,7 +90,11 @@ HTTP/1.0 200 OK\r
     cl.close()
 
 
-def setup_conn(port, accept_handler):
+BIND_WLAN = const(1)
+BIND_LAN = const(2)
+
+
+def setup_conn(port, accept_handler, bind):
     global listen_s
     listen_s = socket.socket()
     listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -103,6 +107,8 @@ def setup_conn(port, accept_handler):
     if accept_handler:
         listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler)
     for i in (network.WLAN.IF_AP, network.WLAN.IF_STA):
+        if bind & BIND_WLAN == 0:
+            continue
         iface = network.WLAN(i)
         if iface.active():
             print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port))
@@ -146,7 +152,7 @@ def stop():
         listen_s.close()
 
 
-def start(port=8266, password=None, accept_handler=accept_conn):
+def start(port=8266, password=None, accept_handler=accept_conn, bind=BIND_WLAN | BIND_LAN):
     global static_host
     stop()
     webrepl_pass = password
@@ -161,7 +167,7 @@ def start(port=8266, password=None, accept_handler=accept_conn):
             print("WebREPL is not configured, run 'import webrepl_setup'")
 
     _webrepl.password(webrepl_pass)
-    s = setup_conn(port, accept_handler)
+    s = setup_conn(port, accept_handler, (BIND_WLAN | BIND_LAN) if not bind else bind)
 
     if accept_handler is None:
         print("Starting webrepl in foreground mode")

although things should be optimised to reduce the final size.

This also exposes a shortcoming on MicroPython's core side, namely a way to know how many LAN interfaces are available. Technically this could also apply to WiFi if you can have an IP address on 2.4GHz and another on 5GHz. So far there's only one known supported MCU with multi-mode WiFi (ESP32C5) but I bet you can only have one single IP address.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants