各位靓仔靓女们,今天老司机带大家飙一趟蓝牙,目标:用JavaScript驯服那些藏在身边的蓝牙小可爱们!准备好了吗?系好安全带,Let’s go!
Web Bluetooth API:让浏览器也能玩转蓝牙
以前我们想让网页和蓝牙设备勾搭上,那简直比登天还难。要么装插件,要么用原生应用绕弯路。现在好了,有了Web Bluetooth API,浏览器可以直接跟蓝牙设备眉来眼去,是不是感觉瞬间打开了新世界的大门?
理论先行:先搞清楚蓝牙的那些事儿
要玩转Web Bluetooth,咱们得先了解一些蓝牙的基本概念,不然就像拿着机关枪打蚊子,费力不讨好。
- UUID (Universally Unique Identifier): 蓝牙设备上的每一个服务和特征都有一个UUID,相当于它们的身份证号码。有了UUID,我们才能找到特定的服务和特征。这玩意长得有点吓人,比如:
0000ffe0-0000-1000-8000-00805f9b34fb
。别怕,复制粘贴大法好! - Service (服务): 服务就像一个蓝牙设备的某个功能模块,比如心率监测、电量显示等等。一个设备可以有多个服务。
- Characteristic (特征): 特征是服务内部的具体数据,比如心率的数值、电量的百分比等等。我们可以读取特征的值,也可以向特征写入值,从而控制设备。
准备工作:浏览器和蓝牙设备都要到位
首先,你的浏览器必须支持Web Bluetooth API。目前主流的Chrome、Edge等都支持,但Safari比较傲娇,暂时还不支持。
其次,你需要一个支持蓝牙的设备,并且这个设备要支持GATT (Generic Attribute Profile)。GATT是蓝牙通信的一种协议,Web Bluetooth API就是基于GATT的。常见的蓝牙设备,比如智能手表、心率带、蓝牙音箱等等,都支持GATT。
代码实战:一步一步征服蓝牙
好了,理论知识武装完毕,现在开始撸代码!
第一步:请求蓝牙设备
首先,我们要让浏览器弹出一个对话框,让用户选择要连接的蓝牙设备。
navigator.bluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }] // 筛选只显示心率设备
})
.then(device => {
console.log('Device name:', device.name);
//device.gatt.connect(); // 连接设备,移到 connectGATT() 中
return device.gatt.connect(); // 返回 GATT Server 对象
})
.then(server => {
console.log('GATT server:', server);
// 获取心率服务,移到 getPrimaryService() 中
return server.getPrimaryService('heart_rate');
})
.then(service => {
console.log('Service:', service);
// 获取心率测量特征,移到 getCharacteristic() 中
return service.getCharacteristic('heart_rate_measurement');
})
.then(characteristic => {
console.log('Characteristic:', characteristic);
// 开始监听心率值的变化,移到 startNotifications() 中
return characteristic.startNotifications();
})
.then(characteristic => {
console.log('Notifications started');
// 监听心率值的变化
characteristic.addEventListener('characteristicvaluechanged', handleHeartRate);
})
.catch(error => {
console.log('Error:', error);
});
function handleHeartRate(event) {
const value = event.target.value;
const heartRate = value.getUint8(1); // 获取心率值,通常在第二个字节
console.log('Heart Rate:', heartRate);
}
这段代码做了什么?
navigator.bluetooth.requestDevice()
:弹出设备选择对话框。filters
选项可以用来筛选设备,只显示特定的服务。这里我们只显示支持心率服务的设备。.then(device => ...)
:当用户选择了一个设备后,这个回调函数会被执行。我们可以在这里获取设备的信息,比如设备名称。device.gatt.connect()
:连接到设备的GATT服务器。.then(server => ...)
:连接成功后,这个回调函数会被执行。我们可以在这里获取GATT服务器对象。server.getPrimaryService('heart_rate')
:获取心率服务。.then(service => ...)
:获取服务成功后,这个回调函数会被执行。我们可以在这里获取服务对象。service.getCharacteristic('heart_rate_measurement')
:获取心率测量特征。.then(characteristic => ...)
:获取特征成功后,这个回调函数会被执行。我们可以在这里获取特征对象。characteristic.startNotifications()
:开始监听心率值的变化。.then(characteristic => ...)
:开启通知后,此回调函数执行,监听 characteristicvaluechanged 事件。characteristic.addEventListener('characteristicvaluechanged', handleHeartRate)
:监听心率值的变化。当心率值发生变化时,handleHeartRate
函数会被执行。handleHeartRate(event)
:处理心率值变化的函数。我们可以在这里获取心率值,并进行处理。
第二步:读取特征的值
除了监听特征值的变化,我们也可以直接读取特征的值。
// 在获取 characteristic 对象后,添加如下代码:
characteristic.readValue()
.then(value => {
const heartRate = value.getUint8(1);
console.log('Initial Heart Rate:', heartRate);
});
这段代码会在连接成功后,立即读取一次心率值。
第三步:写入特征的值
有些特征是可写的,我们可以通过写入值来控制设备。
// 假设我们有一个控制 LED 灯的特征,UUID 为 '0000ffe1-0000-1000-8000-00805f9b34fb'
service.getCharacteristic('0000ffe1-0000-1000-8000-00805f9b34fb')
.then(characteristic => {
const value = new Uint8Array([1]); // 1 表示打开 LED 灯,0 表示关闭
return characteristic.writeValue(value);
})
.then(() => {
console.log('LED turned on');
})
.catch(error => {
console.log('Error writing value:', error);
});
这段代码会向 LED 灯的特征写入一个值,打开 LED 灯。
进阶技巧:优雅地处理蓝牙连接
蓝牙连接可能会因为各种原因断开,比如设备关机、超出范围等等。我们需要优雅地处理这些情况,给用户一个友好的提示。
device.addEventListener('gattserverdisconnected', () => {
console.log('Bluetooth Device disconnected');
// 重新连接设备
connectDevice(); // 需要重新定义 connectDevice() 函数
});
function connectDevice() {
navigator.bluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }]
})
.then(device => {
// ... (连接设备的逻辑)
})
.catch(error => {
console.log('Error:', error);
});
}
这段代码监听了 gattserverdisconnected
事件,当蓝牙连接断开时,会重新连接设备。
实战案例:控制智能灯泡
为了让大家更直观地了解Web Bluetooth API的用法,我们来一个实战案例:控制智能灯泡。
假设我们有一个智能灯泡,它有一个服务用来控制灯泡的亮度,UUID 为 0000ffe0-0000-1000-8000-00805f9b34fb
,这个服务有一个特征用来设置亮度值,UUID 为 0000ffe1-0000-1000-8000-00805f9b34fb
。亮度值的范围是 0-255。
<!DOCTYPE html>
<html>
<head>
<title>Smart Bulb Control</title>
</head>
<body>
<h1>Smart Bulb Control</h1>
<input type="range" id="brightness" min="0" max="255" value="0">
<button id="connect">Connect</button>
<script>
const connectButton = document.getElementById('connect');
const brightnessInput = document.getElementById('brightness');
let bulbCharacteristic;
connectButton.addEventListener('click', () => {
navigator.bluetooth.requestDevice({
filters: [{ services: ['0000ffe0-0000-1000-8000-00805f9b34fb'] }]
})
.then(device => {
return device.gatt.connect();
})
.then(server => {
return server.getPrimaryService('0000ffe0-0000-1000-8000-00805f9b34fb');
})
.then(service => {
return service.getCharacteristic('0000ffe1-0000-1000-8000-00805f9b34fb');
})
.then(characteristic => {
bulbCharacteristic = characteristic;
console.log('Connected to bulb');
})
.catch(error => {
console.log('Error:', error);
});
});
brightnessInput.addEventListener('input', () => {
const brightness = parseInt(brightnessInput.value);
const value = new Uint8Array([brightness]);
if (bulbCharacteristic) {
bulbCharacteristic.writeValue(value)
.then(() => {
console.log('Brightness set to:', brightness);
})
.catch(error => {
console.log('Error writing value:', error);
});
} else {
console.log('Not connected to bulb');
}
});
</script>
</body>
</html>
这个代码实现了一个简单的智能灯泡控制页面。页面上有一个滑动条和一个连接按钮。点击连接按钮后,会弹出设备选择对话框,选择智能灯泡后,就可以通过滑动条来调节灯泡的亮度。
Web Bluetooth API 的优势与局限
- 优势:
- 无需插件: 摆脱了插件的束缚,直接在浏览器中使用。
- 跨平台: 可以在任何支持Web Bluetooth API的浏览器中使用。
- 安全性: 浏览器会提示用户授权,保护用户的隐私。
- 局限:
- 兼容性: 目前只有部分浏览器支持。
- 蓝牙权限: 某些蓝牙设备可能需要配对才能使用。
- 距离限制: 蓝牙的有效距离有限。
常见问题与解决方案
- 设备无法连接:
- 检查蓝牙设备是否开启。
- 检查浏览器是否开启蓝牙。
- 检查设备是否支持GATT协议。
- 尝试重新启动浏览器和蓝牙设备。
- 无法读取特征的值:
- 检查特征是否可读。
- 检查是否已经连接到设备。
- 无法写入特征的值:
- 检查特征是否可写。
- 检查写入的值是否符合要求。
总结:拥抱蓝牙的未来
Web Bluetooth API 的出现,让网页与蓝牙设备的交互变得更加简单便捷。虽然目前还存在一些局限性,但随着技术的不断发展,相信Web Bluetooth API 会在物联网、智能家居等领域发挥越来越重要的作用。
今天的蓝牙之旅就到这里。希望大家通过今天的学习,能够掌握Web Bluetooth API的基本用法,并能够用它来开发出各种有趣的蓝牙应用。记住,编程的乐趣在于不断探索和创新,大胆尝试,你也能成为蓝牙大师!
附录:一些常用的蓝牙 UUID
服务名称 | UUID | 说明 |
---|---|---|
心率服务 | 0000180D-0000-1000-8000-00805f9b34fb |
用于测量心率 |
电量服务 | 0000180F-0000-1000-8000-00805f9b34fb |
用于获取电量信息 |
设备信息服务 | 0000180A-0000-1000-8000-00805f9b34fb |
用于获取设备制造商、型号等信息 |
环境感知服务 | 0000181A-0000-1000-8000-00805f9b34fb |
用于测量温度、湿度等环境参数 |
血氧饱和度服务 | 00001810-0000-1000-8000-00805f9b34fb |
用于测量血氧饱和度 |
这些UUID可以帮助你快速找到常用的蓝牙服务。当然,不同的设备可能会使用不同的UUID,你需要根据设备的文档来确定。
好了,今天的讲座就到这里,祝大家编码愉快!记住,遇到问题不要怕,Google一下,Stack Overflow一下,总能找到答案的!下次再见!