当前位置: 首页 > news >正文

基于微信小程序蓝牙信标 (Beacon)的室内导航实例

这个例子模拟了在商场中,当用户靠近某个店铺(由Beacon信标代表)时,小程序自动识别位置并提示用户已到达目的地。

📁 项目结构

beacon-navigation/
├── pages/
│   └── index/
│       ├── index.js
│       ├── index.wxml
│       ├── index.wxss
│       └── index.json
├── utils/
│   └── beaconService.js
└── app.js

1. pages/index/index.wxml - 页面结构

<view class="container"><view class="status-box"><text>蓝牙状态:{{bluetoothStatus}}</text></view><view class="target-store"><text>目标店铺:3楼 - 星巴克 (Beacon UUID: FDA50693-A4E2-4FB1-AFCF-C6EB07647825)</text></view><view class="navigation-info"><!-- 根据距离显示不同提示 --><block wx:if="{{currentDistance === null}}"><text class="tip">请打开蓝牙,靠近目标区域...</text></block><block wx:elif="{{currentDistance <= 1}}"><text class="arrived">🎉 恭喜!您已到达星巴克门店!</text></block><block wx:elif="{{currentDistance <= 5}}"><text class="close">接近目标:距离约 {{currentDistance.toFixed(1)}} 米</text></block><block wx:else><text class="far">寻找目标:距离较远 ({{currentDistance.toFixed(1)}} 米)</text></block></view><!-- 显示最近探测到的Beacon设备信息 --><view class="beacon-info" wx:if="{{nearestBeacon}}"><text>当前信号最强设备:</text><text>UUID: {{nearestBeacon.uuid}}</text><text>RSSI: {{nearestBeacon.rssi}} dBm</text><text>距离估算: {{nearestBeacon.distance.toFixed(2)}} 米</text></view><button bindtap="startSearch" disabled="{{isSearching}}">开始搜索Beacon</button><button bindtap="stopSearch" disabled="{{!isSearching}}">停止搜索</button>
</view>

2. pages/index/index.js - 页面逻辑

// 引入Beacon服务工具
import BeaconService from '../../utils/beaconService.js';Page({data: {bluetoothStatus: '初始化中...',isSearching: false,currentDistance: null, // 当前与目标Beacon的距离nearestBeacon: null,   // 最近的Beacon设备},// 页面加载onLoad() {this.beaconService = new BeaconService();// 监听蓝牙状态和Beacon事件this.beaconService.on('stateChange', (state) => {this.setData({ bluetoothStatus: state });});this.beaconService.on('found', (beacons) => {this.handleBeaconFound(beacons);});this.beaconService.on('updated', (beacons) => {this.handleBeaconFound(beacons); // 更新时也处理});// 初始化蓝牙this.beaconService.init();},// 处理发现的Beacon设备handleBeaconFound(beacons) {if (!Array.isArray(beacons) || beacons.length === 0) return;// 过滤出目标店铺的Beacon (假设我们知道其UUID)const TARGET_UUID = 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825'.toLowerCase();const targetBeacons = beacons.filter(b => b.uuid.toLowerCase() === TARGET_UUID && b.distance !== undefined);if (targetBeacons.length > 0) {// 找到信号最强(距离最近)的目标Beaconconst nearest = targetBeacons.reduce((a, b) => a.distance < b.distance ? a : b);this.setData({nearestBeacon: nearest,currentDistance: nearest.distance});} else {// 如果没有找到目标,显示最近的任意Beacon作为参考const nearest = beacons.reduce((a, b) => a.rssi > b.rssi ? a : b);this.setData({nearestBeacon: nearest,currentDistance: nearest.distance || null});}},// 开始搜索startSearch() {this.beaconService.startSearch().then(() => {this.setData({ isSearching: true });}).catch(err => {wx.showToast({ title: '启动失败', icon: 'error' });console.error(err);});},// 停止搜索stopSearch() {this.beaconService.stopSearch();this.setData({ isSearching: false });},// 页面卸载时清理onUnload() {this.stopSearch();this.beaconService.destroy();}
});

3. utils/beaconService.js - Beacon服务工具类

class BeaconService {constructor() {this.eventCallbacks = {};this.isInitialized = false;}// 注册事件监听on(event, callback) {if (!this.eventCallbacks[event]) {this.eventCallbacks[event] = [];}this.eventCallbacks[event].push(callback);}// 触发事件emit(event, data) {if (this.eventCallbacks[event]) {this.eventCallbacks[event].forEach(cb => cb(data));}}// 初始化蓝牙init() {wx.openBluetoothAdapter({success: () => {this.emit('stateChange', '蓝牙适配器已开启');this.isInitialized = true;// 监听蓝牙状态变化wx.onBluetoothAdapterStateChange((res) => {this.emit('stateChange', res.available ? '蓝牙可用' : '蓝牙不可用');});},fail: (err) => {this.emit('stateChange', '蓝牙初始化失败,请检查权限');console.error('蓝牙初始化失败', err);}});}// 开始搜索BeaconstartSearch() {return new Promise((resolve, reject) => {if (!this.isInitialized) {reject(new Error('蓝牙未初始化'));return;}wx.startBeaconDiscovery({uuids: ['FDA50693-A4E2-4FB1-AFCF-C6EB07647825'], // 可以指定目标UUID提高效率ignoreBluetoothAvailable: true,success: () => {this.bindBeaconEvents();resolve();},fail: (err) => {reject(err);}});});}// 绑定Beacon事件bindBeaconEvents() {// 发现Beaconwx.onBeaconServiceChange((res) => {if (res.available) {wx.getBeacons({success: (beaconRes) => {if (beaconRes.beacons && beaconRes.beacons.length > 0) {const processedBeacons = this.processBeacons(beaconRes.beacons);this.emit('found', processedBeacons);}}});}});// 更新Beacon信号wx.onBeaconUpdate((res) => {const processedBeacons = this.processBeacons(res.beacons);this.emit('updated', processedBeacons);});}// 停止搜索stopSearch() {wx.stopBeaconDiscovery();}// 销毁资源destroy() {this.stopSearch();wx.closeBluetoothAdapter();}// 处理原始Beacon数据,估算距离processBeacons(rawBeacons) {return rawBeacons.map(beacon => {// 简单的距离估算公式(实际应用需校准)// 使用 RSSI 和 measuredPower (通常为-59dBm @1m) 计算const txPower = beacon.measuredPower || -59; // 发射功率if (beacon.rssi >= txPower) {beacon.distance = 1.0; // 距离小于1米} else {// 对数距离路径损耗模型简化版const ratio = beacon.rssi * 1.0 / txPower;if (ratio < 1.0) {beacon.distance = Math.pow(ratio, 10);} else {beacon.distance = 0.89976 * Math.pow(ratio, 7.7095) + 0.111;}}return beacon;});}
}module.exports = BeaconService;

4. pages/index/index.wxss - 样式文件(可选)

.container {padding: 20rpx;font-size: 28rpx;
}.status-box {background: #f0f0f0;padding: 20rpx;margin-bottom: 20rpx;border-radius: 8rpx;
}.target-store {background: #e8f4ff;padding: 20rpx;margin-bottom: 30rpx;border-left: 4px solid #007aff;
}.navigation-info {text-align: center;margin: 40rpx 0;
}.tip { color: #666; }
.far { color: #ff9900; }
.close { color: #00aa00; font-weight: bold; }
.arrived { color: #ff0000; font-size: 36rpx; font-weight: bold; }.beacon-info {background: #f9f9f9;padding: 20rpx;margin: 20rpx 0;border-radius: 8rpx;font-size: 24rpx;
}button {margin: 15rpx 0;
}

⚠️ 注意事项

  1. 硬件要求:需要真实部署支持 iBeacon 协议的蓝牙信标(如 Estimote、Gimbal 等),并配置好 UUID、Major、Minor。
  2. 权限:用户需授权蓝牙权限,且手机蓝牙必须开启。
  3. 距离估算:代码中的距离估算是简化的模型,实际精度受环境干扰、信号遮挡等影响较大,需现场校准。
  4. 性能优化:真实项目中应加入防抖、多点定位(三角定位)、地图渲染等功能。
  5. 兼容性:部分安卓机型对Beacon支持不完善,建议在iOS上测试效果更佳。
http://www.dtcms.com/a/389984.html

相关文章:

  • 用Comate Zulu开发一款微信小程序
  • 触觉智能Purple Pi OH2开发板配置参数
  • 鸿蒙Next应用文件管理全攻略:从基础操作到高级实践
  • 云手机对《黑神话:悟空》的作用都有哪些?
  • Leetcode 994. 腐烂的橘子 多源 BFS
  • 微硕WSP4982双N沟MOSFET,赋能汽车智能座椅通风系统
  • BMP280 气压计驱动
  • 速通ACM省铜第八天 赋源码(1709)
  • InnoDB索引结构与排序构建机制详解
  • mmpose可视化出错,图像与关键点对不上
  • Flutter 基本开发环境配置环境搭建
  • 【数控系统】第七章 NURBS插补
  • 某养老数字化协同办公平台网络方案解析
  • docker 容器终止时都做了什么?怎么优雅退出?
  • 苹果10月还有发布会?多款新品预曝光
  • wincc
  • 获取公网IP的方法
  • 苦瓜叶片病害检测数据集:2w+图像,9类,yolo标注
  • LlamaIndex入门
  • 基于RK3576+FPGA的无人机飞控系统设计
  • Redisson原理
  • PyQt6之日期与时间控件应用案例
  • css | 总结一下flex布局
  • c#里面的catch (Exception e)
  • 浅谈 CDN
  • 125、【OS】【Nuttx】【周边】效果呈现方案解析:分号与换行
  • CBB21-MPP电子元器件 RC容钏 金属化聚丙烯薄膜电容器 电子元器件技术解析
  • Day02 递归 | 46. 全排列、226. 翻转二叉树
  • [Spring Cloud][6] Eureka Server 搭建详解,与 Zookeeper 的区别
  • 前端性能优化完全指南:从入门到实战