You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android/iOS应用蓝牙向Pi Pico W传WiFi配置的技术求助

问题描述

我有个项目需求:通过蓝牙让Android/iOS应用和Pi Pico W连接,把WiFi配置信息传给Pico,Pico本地存储这些信息后连接指定WiFi热点。

我已经用Jetpack Compose(Kotlin)开发了安卓应用,目前能搜索并连接蓝牙设备。

我的Raspberry Pi Pico W运行MicroPython,这部分遇到了困难:用aioble库实现了设备广播与连接,但不知道怎么接收数据并处理成JSON文件。

现有代码(来自YouTube教程):

import sys
import aioble
import bluetooth
import machine
import uasyncio as asyncio
from micropython import const

def uuid():
    return "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}".format(
        *machine.unique_id()
    )

MANUFACTURER_ID = const(0x02A29)
MODEL_NUMBER_ID = const(0x2A24)
SERIAL_NUMBER_ID = const(0x2A25)
HARDWARE_REVISION_ID = const(0x2A26)
BLE_VERSION_ID = const(0x2A28)

led = machine.Pin("LED", machine.Pin.OUT)

_GENERIC = bluetooth.UUID(0x1848)
_BLE_APPEARANCE = const(960)

ADV_INTERVAL_MS = 250_000

device_info = aioble.Service(_GENERIC)

connection = None

#Characteristics for device info
aioble.Characteristic(device_info, bluetooth.UUID(MANUFACTURER_ID), read=True, initial="AuraByte")
aioble.Characteristic(device_info, bluetooth.UUID(MODEL_NUMBER_ID), read=True, initial="1.0")
aioble.Characteristic(device_info, bluetooth.UUID(SERIAL_NUMBER_ID), read=True, initial=uuid())
aioble.Characteristic(device_info, bluetooth.UUID(HARDWARE_REVISION_ID), read=True, initial=sys.version)
aioble.Characteristic(device_info, bluetooth.UUID(BLE_VERSION_ID), read=True, initial="1.0")

async def peripheral_task():
    print('peripheral task started')
    global connected, connection
    while True:
        connected = False
        async with await aioble.advertise(
            ADV_INTERVAL_MS, 
            name="AuraByteGateModule", 
            appearance=_BLE_APPEARANCE, 
            services=[_GENERIC]
        ) as connection:
            print("Connection from", connection.device)
            connected = True
            print(f"connected: {connected}")
            await connection.disconnected()
            print(f'disconnected')
        

async def blink_task():
    print('blink task started')
    toggle = True
    while True:
        led.value(toggle)
        toggle = not toggle
        blink = 1000
        if connected:
            blink = 1000
        else:
            blink = 250
        await asyncio.sleep_ms(blink)

async def main():
    tasks = [
        asyncio.create_task(peripheral_task()),
        asyncio.create_task(blink_task())
    ]
    await asyncio.gather(*tasks)

asyncio.run(main())
解决方案

1. 添加可写BLE特征接收数据

要接收手机端的WiFi配置,需新增一个支持写入的BLE特征,让手机能把JSON格式的配置数据写入该特征。在现有设备信息特征后添加:

# 自定义UUID用于WiFi配置传输(可自行更换为任意合法UUID)
WIFI_CONFIG_UUID = bluetooth.UUID("0000ffb2-0000-1000-8000-00805f9b34fb")

# 创建可写特征,支持手机写入数据
wifi_config_char = aioble.Characteristic(
    device_info,
    WIFI_CONFIG_UUID,
    write=True,
    notify=False,  # 若需给手机回传连接结果,可设为True
    max_len=256  # 根据JSON大小调整,默认足够存储WiFi账号密码
)

2. 监听写入事件并解析JSON

新增异步任务监听特征写入事件,解析传入的JSON数据并执行后续操作:

import ujson  # MicroPython自带JSON解析库

async def handle_wifi_config_task():
    while True:
        # 等待数据写入wifi_config_char
        conn, data = await wifi_config_char.written()
        raw_data = data.decode('utf-8')
        print(f"收到WiFi配置: {raw_data}")
        
        try:
            # 解析JSON(手机需传入{"ssid":"热点名称","password":"热点密码"}格式)
            wifi_config = ujson.loads(raw_data)
            ssid = wifi_config.get("ssid")
            password = wifi_config.get("password")
            
            if not ssid or not password:
                print("配置不完整:缺少ssid或password")
                continue
            
            # 存储配置到本地文件
            save_wifi_config(wifi_config)
            # 尝试连接WiFi
            await connect_to_wifi(ssid, password)
            
        except ValueError as e:
            print(f"JSON解析失败: {e}")
        except Exception as e:
            print(f"处理配置出错: {e}")

3. 实现本地JSON存储

添加函数将配置写入Pico文件系统:

def save_wifi_config(config):
    try:
        with open("wifi_config.json", "w") as f:
            ujson.dump(config, f)
        print("WiFi配置已保存到wifi_config.json")
    except OSError as e:
        print(f"保存文件失败: {e}")

4. 实现WiFi连接逻辑

添加函数连接指定WiFi热点:

import network

async def connect_to_wifi(ssid, password):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    
    if wlan.isconnected():
        print(f"已连接WiFi: {wlan.ifconfig()}")
        return
    
    print(f"正在连接WiFi: {ssid}")
    wlan.connect(ssid, password)
    
    # 最多等待10秒连接
    timeout = 10
    while timeout > 0:
        if wlan.isconnected():
            print(f"连接成功!IP: {wlan.ifconfig()[0]}")
            return
        timeout -= 1
        await asyncio.sleep(1)
    
    print("WiFi连接超时失败")

5. 整合所有任务到主函数

修改main函数,加入新的配置处理任务:

async def main():
    tasks = [
        asyncio.create_task(peripheral_task()),
        asyncio.create_task(blink_task()),
        asyncio.create_task(handle_wifi_config_task())  # 新增任务
    ]
    await asyncio.gather(*tasks)

额外优化:开机自动连接WiFi

在代码开头添加逻辑,启动时读取已保存的配置并自动连接:

# 开机尝试读取已保存的配置并连接WiFi
def load_and_connect_wifi():
    try:
        with open("wifi_config.json", "r") as f:
            config = ujson.load(f)
        asyncio.create_task(connect_to_wifi(config["ssid"], config["password"]))
    except OSError:
        print("未找到已保存的WiFi配置")

# 在启动主任务前调用
load_and_connect_wifi()

注意事项

  • 手机端需对应写入上述自定义UUID的特征,数据必须是严格的JSON字符串
  • 若需给手机回传连接结果,可将特征notify设为True,用wifi_config_char.notify(conn, b"success")发送通知
  • Pico文件系统默认可写,若出现权限问题需检查固件设置

内容的提问来源于stack exchange,提问作者quinzyamg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:59:54