ble_peripheral
BLE 外设广播模式。
BLE 外设模式:让本机作为蓝牙外设广播,供其他设备(中心端)扫描连接。
边界:与 bluetooth 中心端(扫描/连接)互补——本模块做外设广播。需要蓝牙硬件开启;模拟器通常不可用。广播和update_value()放在按钮回调,不要在body()中自动启动。
#模块概览
| 项 | 说明 |
|---|---|
| 导入 | import ble_peripheral |
| 适合做什么 | 传感器数据广播、简易 BLE 信标、与自定义中心 App 配对 |
| 调用时机 | 用户点击后开始 start_advertising(),离开页面时 stop_advertising() |
| 推荐顺序 | start_advertising() → status() 确认 → update_value() 推送数据 |
| UUID | service_uuid 必填;characteristic_uuid 省略时默认与 service 相同 |
#快速开始
下面脚本启动广播、查看状态并停止:
已复制
import ble_peripheral
SERVICE = "12345678-1234-1234-1234-123456789ABC"
try:
ble_peripheral.start_advertising(
"PyMiniApp",
SERVICE,
initial_value="hello",
)
print(ble_peripheral.status())
ble_peripheral.update_value("ping")
print(ble_peripheral.status())
finally:
ble_peripheral.stop_advertising()
#AppUI 示例
开始/停止广播放在按钮回调;用 try/except 处理蓝牙未开启。
已复制
import appui
import ble_peripheral
SERVICE = "12345678-1234-1234-1234-123456789ABC"
DEVICE_NAME = "PyMiniApp"
state = appui.State(
advertising=False,
name="—",
service="—",
payload="hello",
status="点击开始广播",
)
def refresh_status():
try:
st = ble_peripheral.status() or {}
state.batch_update(
advertising=bool(st.get("advertising")),
name=st.get("name") or "—",
service=st.get("service_uuid") or "—",
)
except ble_peripheral.BlePeripheralError as exc:
state.status = f"状态查询失败: {exc}"
def start_adv():
try:
ble_peripheral.start_advertising(
DEVICE_NAME,
SERVICE,
initial_value=state.payload,
)
refresh_status()
state.status = "正在广播"
except ble_peripheral.BlePeripheralError as exc:
state.status = f"无法开始: {exc}(请开启蓝牙)"
def stop_adv():
try:
ble_peripheral.stop_advertising()
state.batch_update(
advertising=False,
name="—",
service="—",
status="已停止广播",
)
except ble_peripheral.BlePeripheralError as exc:
state.status = f"停止失败: {exc}"
def push_value():
if not state.advertising:
state.status = "请先开始广播"
return
try:
ble_peripheral.update_value(state.payload)
state.status = f"已推送: {state.payload}"
except ble_peripheral.BlePeripheralError as exc:
state.status = f"推送失败: {exc}"
def body():
label = "停止广播" if state.advertising else "开始广播"
return appui.NavigationStack(
appui.Form([
appui.Section("外设状态", [
appui.LabeledContent("广播中", value="是" if state.advertising else "否"),
appui.LabeledContent("名称", value=state.name),
appui.LabeledContent("服务 UUID", value=state.service),
]),
appui.Section("数据", [
appui.TextField("特征值", text=state.payload),
appui.Button("推送特征值", action=push_value),
]),
appui.Section("操作", [
appui.Button(label, action=stop_adv if state.advertising else start_adv)
.button_style("bordered_prominent"),
appui.Text(state.status).foreground_color("secondaryLabel"),
], footer="真机 + 蓝牙开启;中心端用 bluetooth 模块扫描连接。"),
]).navigation_title("BLE 外设")
)
appui.run(body, state=state)
#API 参考
#速查
| API | 作用 |
|---|---|
start_advertising(name, service_uuid, ...) | 开始 BLE 广播 |
stop_advertising() | 停止广播并清理服务 |
status() | {advertising, name, service_uuid} |
update_value(value) | 更新特征值并通知订阅方 |
BlePeripheralError | 操作失败时抛出 |
#start_advertising
start_advertising(name, service_uuid, characteristic_uuid=None, initial_value=None)
已复制
ble_peripheral.start_advertising(
"SensorHub",
"12345678-1234-1234-1234-123456789ABC",
characteristic_uuid="ABCDEF00-0000-0000-0000-000000000001",
initial_value="42",
)
| 参数 | 说明 |
|---|---|
name | 广播本地名称 |
service_uuid | 服务 UUID |
characteristic_uuid | 特征 UUID;省略时用 service UUID |
initial_value | 初始特征值(UTF-8 文本) |
特征支持 read / write / notify。
#status
status() 返回:
| 字段 | 说明 |
|---|---|
advertising | 是否正在广播 |
name | 当前广播名称 |
service_uuid | 服务 UUID |
#update_value
update_value(value) — 更新特征值(UTF-8 字符串),并向已订阅的中心端发送通知。须先 start_advertising()。
#异常
code | 含义 |
|---|---|
unavailable | 蓝牙未开启 |
invalid_input | 缺少 name / service_uuid |
invalid_state | 未广播时调用 update_value |
#常见错误
| 错误写法 | 后果 | 修正 |
|---|---|---|
在 body() 里 start_advertising() | 刷新时重复广播 | 放进按钮回调 |
| 模拟器测试 | 蓝牙不可用 | 用真机 |
| 与 bluetooth 中心模式混淆 | 调错 API | 扫描连接用 bluetooth,广播用本模块 |
页面离开不 stop_advertising() | 持续耗电 | 停止按钮或生命周期回调里清理 |
#相关文档
| 文档 | 用途 |
|---|---|
| bluetooth | BLE 中心端扫描/连接/读写 |
| permission | 蓝牙权限状态查询 |
| 原生能力入口 | MiniApp 场景配方 |
#预期效果
运行示例后,界面应出现文档描述的目标结果;若与预期不符,先看「失败路径」并按返回值或日志排查。