Skip to content

Allow use on network interfaces other than WIFI. #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 71 additions & 49 deletions mqtt_as/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,29 @@ def __init__(self, config):
if self.server is None:
raise ValueError("no server specified.")
self._sock = None
self._sta_if = network.WLAN(network.STA_IF)
self._sta_if.active(True)
if config["gateway"]: # Called from gateway (hence ESP32).
import aioespnow # Set up ESPNOW

while not (sta := self._sta_if).active():
time.sleep(0.1)
sta.config(pm=sta.PM_NONE) # No power management
sta.active(True)
self._espnow = aioespnow.AIOESPNow() # Returns AIOESPNow enhanced with async support
self._espnow.active(True)
try:
self._net_if = network.WLAN(network.STA_IF)
self._net_if.active(True)
self._quick = config.get("quick", False)
if config["gateway"]: # Called from gateway (hence ESP32).
import aioespnow # Set up ESPNOW

while not (sta := self._net_if).active():
time.sleep(0.1)
sta.config(pm=sta.PM_NONE) # No power management
sta.active(True)
self._espnow = aioespnow.AIOESPNow() # Returns AIOESPNow enhanced with async support
self._espnow.active(True)

except AttributeError:
self._net_if = None
# No WLAN interface, find a different network interface to use
self._quick = config.get("quick", True)
for iface in network.__dict__.values():
if isinstance(iface, type) and hasattr(iface, "isconnected"):
self._net_if = iface()
if self._net_if is None:
raise ValueError("No network interface found")

self.newpid = pid_gen()
self.rcv_pids = set() # PUBACK and SUBACK pids awaiting ACK response
Expand Down Expand Up @@ -455,11 +467,14 @@ def _close(self):

def close(self): # API. See https://github.com/peterhinch/micropython-mqtt/issues/60
self._close()
try:
self._sta_if.disconnect() # Disconnect Wi-Fi to avoid errors
except OSError:
self.dprint("Wi-Fi not started, unable to disconnect interface")
self._sta_if.active(False)
if self._net_if:
try:
self._net_if.disconnect() # Disconnect Wi-Fi to avoid errors
except OSError:
self.dprint("Wi-Fi not started, unable to disconnect interface")
except AttributeError:
pass # no disconnection needed
self._net_if.active(False)

async def _await_pid(self, pid):
t = ticks_ms()
Expand Down Expand Up @@ -585,7 +600,7 @@ async def wait_msg(self):
if res is None:
return
if res == b"":
raise OSError(-1, "Empty response")
return

if res == b"\xd0": # PINGRESP
await self._as_read(1) # Update .last_rx time
Expand Down Expand Up @@ -725,7 +740,7 @@ def __init__(self, config):
esp.sleep_type(0) # Improve connection integrity at cost of power consumption.

async def wifi_connect(self, quick=False):
s = self._sta_if
s = self._net_if
if ESP8266:
if s.isconnected(): # 1st attempt, already connected.
return
Expand All @@ -747,38 +762,43 @@ async def wifi_connect(self, quick=False):
await asyncio.sleep(1)
else:
s.active(True)
if RP2: # Disable auto-sleep.
# https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf
# para 3.6.3
s.config(pm=0xA11140)
s.connect(self._ssid, self._wifi_pw)
for _ in range(60): # Break out on fail or success. Check once per sec.
await asyncio.sleep(1)
# Loop while connecting or no IP
if s.isconnected():
break
if ESP32:
# Status values >= STAT_IDLE can occur during connect:
# STAT_IDLE 1000, STAT_CONNECTING 1001, STAT_GOT_IP 1010
# Error statuses are in range 200..204
if s.status() < network.STAT_IDLE:
# pause as workaround to avoid persistent reconnect failures
# see https://github.com/peterhinch/micropython-mqtt/issues/132 for details
await asyncio.sleep(1)
break
elif PYBOARD: # No symbolic constants in network
if not 1 <= s.status() <= 2:
break
elif RP2: # 1 is STAT_CONNECTING. 2 reported by user (No IP?)
if not 1 <= s.status() <= 2:
if RP2: # Disable auto-sleep for wifi.
try:
# https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf
# para 3.6.3
s.config(pm=0xA11140)
except (AttributeError, ValueError):
pass
try:
s.connect(self._ssid, self._wifi_pw)
for _ in range(60): # Break out on fail or success. Check once per sec.
await asyncio.sleep(1)
# Loop while connecting or no IP
if s.isconnected():
break
else: # Timeout: still in connecting state
s.disconnect()
await asyncio.sleep(1)

if ESP32:
# Status values >= STAT_IDLE can occur during connect:
# STAT_IDLE 1000, STAT_CONNECTING 1001, STAT_GOT_IP 1010
# Error statuses are in range 200..204
if s.status() < network.STAT_IDLE:
# pause as workaround to avoid persistent reconnect failures
# see https://github.com/peterhinch/micropython-mqtt/issues/132 for details
await asyncio.sleep(1)
break
elif PYBOARD: # No symbolic constants in network
if not 1 <= s.status() <= 2:
break
elif RP2: # 1 is STAT_CONNECTING. 2 reported by user (No IP?)
if not 1 <= s.status() <= 2:
break
else: # Timeout: still in connecting state
s.disconnect()
await asyncio.sleep(1)
except AttributeError:
pass # no connect process needed
if not s.isconnected(): # Timed out
raise OSError("Wi-Fi connect timed out")
if not quick: # Skip on first connection only if power saving
if not (quick or self._quick): # Skip on first connection only if power saving
# Ensure connection stays up for a few secs.
self.dprint("Checking WiFi integrity.")
for _ in range(5):
Expand Down Expand Up @@ -883,7 +903,7 @@ def isconnected(self):
if self._in_connect: # Disable low-level check during .connect()
return True

if self._isconnected and not self._sta_if.isconnected(): # It's going down.
if self._isconnected and not self._net_if.isconnected(): # It's going down.
self._reconnect()
return self._isconnected

Expand All @@ -910,9 +930,11 @@ async def _keep_connected(self):
gc.collect()
else: # Link is down, socket is closed, tasks are killed
try:
self._sta_if.disconnect()
self._net_if.disconnect()
except OSError:
self.dprint("Wi-Fi not started, unable to disconnect interface")
except AttributeError:
pass # no disconnection needed
await asyncio.sleep(1)
try:
await self.wifi_connect()
Expand Down