我们在用ESP32做开发时,由于初始化配网的需要,往往是需要工作在AP模式,但是也要能使用STA模式的扫描功能,列出周围可用的wifi热点列表,方便用户通过选择的方式输入热点名。这就需要进入STA和AP的混合模式。
但是,在micropython的标准文档中,wifi的模式只有STA和AP两种模式,似乎没有混合模式。并且STA模式和AP模式的切换很容易出现扫描不到周围的wifi热点、wifi模块报unknown error 0x0102错误导致wifi模块失效等问题。
为此,笔者经过研究发现,micropython可以通过以下代码方法(注意代码中的注释)稳妥操作wifi模块进入STA与AP的混合模式,充当AP的同时,可以扫描出周围的wifi热点供配网使用。
具体场景是这样的:
1.ESP32启动时,尝试读取设备上保存的wifi热点配置文件。如果找不到配置文件,或者连接不上配置文件中的热点,就进入AP模式,启动web服务,等待用户登录web进行热点信息配置(所谓配网)。
wifi热点配置文件wificonfig.json内容如下:
{"wifiname": "YourRouterName", "wifipassword": "YourRouterPassword"}
该文件的自动生成和WEB服务配网部分代码不是此文重点,不在此叙述,需要的可以私信我。测试后述代码时,人工生成一个wificonfig.json在根目录即可。
2.ESP32启动时,如果能顺利连接到配置文件中的热点,就直接进入STA正常模式,不开启AP功能。该模式也就是完成了配网之后设备的正常运行模式,该模式下也应该通过WEB提供热点信息的修改功能,以方便用户修改。
以下为代码。
class myWifiSet:
def __init__(self) :
self.Mode =""
self.APList ={}#保存热点扫描结果
#先尝试进入STA模式,连接热点,如果出错,就进入STA和AP混合模式
if self.StaMode()==False:
self.APMode()
print("连接热点失败,进入STA&AP混合模式...")
self.Mode="Hybrid"
else:
print("已进入STA模式,连接热点成功!")
self.Mode="STA"
def scanAP(self):
#此方法只能在本类实例化后才能调用,即wifi变量已存在
import utime,ujson
#try:
# self.wifi.scan()#先尝试一次扫描
#except:
# pass
print("now in %s mode"%self.Mode)
#self.wifi.active(False)#启停一次,确保扫描成功
#utime.sleep(0.5)
#self.wifi.active(True)
#utime.sleep(0.5)
#有时模块会读不出来信号弱的路由器名,因此写一段把名字为空的热点全部干掉!
try:
self.APList=self.wifi.scan()
print("扫描AP结束,列表如下:")
print(self.APList)
f=open("/wifiAPList.json","w")
#print(APList_json)
for item in self.APList:
print(item)
if item[0]==b'':
print("one item deleted!")
self.APList.remove(item)
for item in self.APList:
print(item)
if item[0]==b'':
print("one item deleted!")
self.APList.remove(item)
APList_json=ujson.dumps(self.APList)
f.write(APList_json)
f.flush()
f.close()
except Exception as e:
print("扫描AP错误:%s"%str(e))
def StaMode(self):
import json,utime,network
try:
with open('/wificonfig.json','r') as f:
config = json.loads(f.read())
# 若初次运行,则将进入excpet
except:
print('WIFI配置文件错误!')
return False
#以下为正常的WIFI连接流程
self.wifi = network.WLAN(network.STA_IF)
self.wifi.active(True)
utime.sleep(0.5)
if not self.wifi.isconnected():
print('正在连接到热点%s...'%config['wifiname'])
self.wifi.active(True)
self.wifi.connect(config['wifiname'], config['wifipassword'])
import utime
for i in range(10):
print('第{}次尝试连接WIFI热点'.format(i+1))
if self.wifi.isconnected():
break
utime.sleep(2) #一般睡个5-10秒,应该绰绰有余
if not self.wifi.isconnected():
return False
else:
print('network config:',self.wifi.ifconfig())
return True
else:
print('network config:', self.wifi.ifconfig())
return True
def APMode(self):
#此方法为重点
import utime,network
try:
if self.wifi.status()==network.STAT_CONNECTING:
#变量wifi不存在的话,也会进入except
print("强制退出STAT_CONNECTING状态...")
#要想进入混合模式,就先进STA模式。
#进入STA模式后,如果连接路由器失败,会一直停留在STA_CONNECTING状态
#因此,先active(False)强制退出STA_CONNECTING状态,再active(True)回到STA初始状态
#这样会避免后面scan()出现STA_CONNECTING状态禁止扫描的问题,同时也能进入混合模式
self.wifi.active(False)
self.wifi.active(True)
except:
pass
self.wifi=network.WLAN(network.AP_IF)
self.wifi.active(False)
self.wifi.active(True)
#以下为测试代码
if __name__ == "__main__":
import network
#初始化时直接尝试进入STA模式连接热点,连接出错时进入STA与AP混合模式
x=myWifiSet()
if x.Mode=="STA":
print("11111")
elif x.Mode=="Hybrid":
print("22222")
#尝试扫描AP。不管在STA还是STA与AP混合模式,均可用以下方法正确扫描周围的AP列表
x.scanAP()
print(x.APList)
以上代码可以单独存为一个.py文件,由main.py通过import方式调用即可。
注意:
1.不要尝试直接去单独调用STAMode()和APMode()两个方法,在初始化时,操作wifi的步骤已经隐含在内了(先STA后AP),操作流程错误可能导致wifi模块出错。
2.不管x=myWifiSet()的结果是进入了STA模式还是AP与STA混合模式,都可在你的配网部分代码中随时调用x.scanAP()来动态扫描周围的热点。