通过蓝牙连接RaspberryPi与Android并传输WiFi配置文件的技术咨询
树莓派蓝牙传输WiFi配置解决方案(适配你的三个约束)
一、树莓派端:一次性SSH脚本完成全配置
因为最终仅能通过SSH执行一次脚本,且后续无网络,脚本需包含所有依赖安装、蓝牙配置、接收服务部署:
- 安装蓝牙依赖(初始联网时完成,脚本执行时自动处理):
sudo apt update && sudo apt install -y bluez bluez-tools python3-bluez - 持久化蓝牙可发现/可配对:
修改蓝牙配置文件,确保树莓派始终处于可被安卓发现的状态:sudo sed -i 's/#DiscoverableTimeout = 0/DiscoverableTimeout = 0/' /etc/bluetooth/main.conf sudo sed -i 's/#PairableTimeout = 0/PairableTimeout = 0/' /etc/bluetooth/main.conf sudo systemctl restart bluetooth - 部署WiFi配置接收服务:
脚本内嵌Python监听逻辑,接收安卓发来的WiFi配置并写入系统文件:- 先写入接收脚本到树莓派:
cat << 'EOF' > /home/pi/wifi_config_receiver.py import bluetooth import subprocess import json server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) server_sock.bind(("", bluetooth.PORT_ANY)) server_sock.listen(1) port = server_sock.getsockname()[1] uuid = "00001101-0000-1000-8000-00805F9B34FB" bluetooth.advertise_service(server_sock, "WiFiConfigServer", service_id=uuid) print(f"Waiting for Android connection on RFCOMM port {port}") try: client_sock, client_info = server_sock.accept() print(f"Connected to {client_info}") data = client_sock.recv(1024).decode('utf-8') if not data: raise ValueError("Empty config data received") config = json.loads(data) ssid = config.get('ssid') password = config.get('password') if not ssid or not password: raise ValueError("Invalid WiFi config") # 写入WiFi配置文件 config_entry = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n}}' with open('/etc/wpa_supplicant/wpa_supplicant.conf', 'a') as f: f.write(config_entry) # 重启网络服务生效 subprocess.run(["sudo", "systemctl", "restart", "wpa_supplicant"], check=True) print("WiFi config applied successfully") except Exception as e: print(f"Error: {str(e)}") finally: if 'client_sock' in locals(): client_sock.close() server_sock.close() print("Socket closed") EOF- 设置开机自启,确保树莓派重启后自动监听:
sudo cat << EOF > /etc/systemd/system/wifi-config-bt.service [Unit] Description=Bluetooth WiFi Config Receiver After=bluetooth.service [Service] ExecStart=/usr/bin/python3 /home/pi/wifi_config_receiver.py User=pi Restart=always [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable wifi-config-bt.service - 将以上所有命令整合成一个脚本,通过SSH一次性执行,执行后树莓派无需网络即可运行蓝牙监听服务。
二、安卓端:应用实现蓝牙发起连接与配置传输
安卓应用需完成蓝牙扫描、配对、RFCOMM连接、配置发送四个核心步骤:
- 权限配置(AndroidManifest.xml):
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> - 核心逻辑(Kotlin示例):
- 扫描树莓派设备:
private fun scanBluetoothDevices() { val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() if (!bluetoothAdapter.isEnabled) { // 提示用户开启蓝牙 return } val scanner = bluetoothAdapter.bluetoothLeScanner scanner.startScan(object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult?) { result?.device?.let { device -> if (device.name == "raspberrypi") { // 过滤树莓派设备 scanner.stopScan(this) connectToDevice(device) } } } }) }- 连接并发送配置:
private fun connectToDevice(device: BluetoothDevice, ssid: String, password: String) { val uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") val socket = device.createRfcommSocketToServiceRecord(uuid) try { socket.connect() val outputStream = socket.outputStream val configJson = """{"ssid":"$ssid","password":"$password"}""" outputStream.write(configJson.toByteArray(Charsets.UTF_8)) outputStream.flush() // 提示用户发送成功 } catch (e: IOException) { // 处理连接/发送失败 } finally { socket.close() } } - 注意事项:处理蓝牙配对请求(安卓端会弹出配对提示,用户确认后即可连接),添加网络权限适配不同安卓版本。
三、验证流程
- 树莓派执行一次性SSH脚本,完成所有配置后重启
- 安卓应用开启蓝牙,扫描并配对树莓派
- 输入WiFi SSID和密码,发送配置
- 树莓派自动写入配置并重启网络,完成联网
内容的提问来源于stack exchange,提问作者Nihon
相关产品推荐
相关产品推荐

