环境准备
电脑操作系统:win10
打开蓝牙和其他设备,添加蓝牙或其他设备,添加设备,发现有BLE和SPP两种;
蓝牙协议分为两种,SPP协议和BLE(Bluetooth low energy)
- BLE:web bluetooth api能扫描到,本文以BLE协议传输数据
- SPP:蓝牙串口,需要输入PIN码
Web Bluetooth入门
WebBluetooth 是一种已在 Chrome 和三星 Internet中实施的新规范,它允许我们从浏览器直接与蓝牙低功耗设备进行通信。渐进式 Web 应用程序与 WebBluetooth 相结合,提供 Web 应用程序的安全性和便利性,并具有直接与设备对话的能力。
当我们谈论 WebBluetooth 时,我们谈论的是蓝牙规范的一个特定部分,称为 Generic Attribute Profile,它有一个非常明显的缩写 GATT。(显然,GAP 已经被采用了。)
在 GATT 的上下文中,我们不再谈论中央设备和外围设备,而是客户端和服务器。你的灯泡是服务器。这可能看起来违反直觉,但如果你仔细想想,它实际上是有道理的。灯泡提供服务,即光。就像浏览器连接到 Internet 上的服务器一样,您的手机或计算机是一个客户端,连接到灯泡中的 GATT 服务器。
每台服务器都提供一项或多项服务。每个服务都有一个或多个特征。每个特征都有一个可以读取或写入的值。与对象的属性不同,服务和特征不是由字符串标识的。每个服务和特性都有一个唯一的 UUID。
Chrome浏览器地址栏输入:chrome://bluetooth-internals
,可查看蓝牙设备
使用WebBluetooth API
通过使用WebBluetooth API,我们只需要几行JavaScript就可以和蓝牙设备进行沟通。
1. 连接设备
let device = await navigator.bluetooth.requestDevice({
filters: [{
namePrefix: 'JDY',
}],
//acceptAllDevices: true,
optionalServices: [coyoteService]
});
当我们调用此函数时,会弹出一个窗口,其中包含符合我们指定过滤器的设备列表。现在我们必须手动选择要连接的设备。
访问设备后,我们可以通过调用设备属性上的connect()函数连接到 GATT 服务器gatt并等待结果。
const server = await device.gatt.connect();
一旦我们有了服务器,我们就可以getPrimaryService()使用我们想要使用的服务的 UUID 作为参数调用服务器并等待结果。
const service = await server.getPrimaryService(coyoteService);
然后getCharacteristic()以特征的 UUID 作为参数调用服务并再次等待结果。现在有了可以用来写入和读取数据的特征:
const config = await service.getCharacteristic(configCharacteristic);
2. 写入数据
var hex = document.getElementById('battery_level_text').value;
var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function(h){
return parseInt(h,16)
}));
log(typedArray);
config.writeValue(typedArray);
3. 数据返回
监听数据改变:
config.addEventListener('characteristicvaluechanged', handleCharacteristicValueChanged);
function handleCharacteristicValueChanged(event) {
const valueDataView = event.target.value;
const hexString = [...new Uint8Array(valueDataView.buffer)].map(b => {
return b.toString(16).padStart(2, '0');
}).join(' ');
log(
'\n (Hex) ' + hexString
);
}
广播:
await config.startNotifications();
3. 断开连接
await device.gatt.disconnect();
完整代码
<button id="connect">连接蓝牙</button>
<button id="disconnect">断开蓝牙</button>
<form>
<fieldset>
<legend>Status</legend>
<input id="battery_level_text" />
</fieldset>
</form>
<button id="pair">发送指令</button>
<script>
var ChromeSamples = {
log: function () {
var line = Array.prototype.slice.call(arguments).map(function (argument) {
return typeof argument === 'string' ? argument : JSON.stringify(argument);
}).join(' ');
document.querySelector('#log').textContent += line + '\n';
const elem = document.getElementById('log');
elem.scrollTop = elem.scrollHeight;
},
clearLog: function () {
document.querySelector('#log').textContent = '';
},
setStatus: function (status) {
document.querySelector('#status').textContent = status;
},
setContent: function (newContent) {
var content = document.querySelector('#content');
while (content.hasChildNodes()) {
content.removeChild(content.lastChild);
}
content.appendChild(newContent);
}
};
</script>
<h3>Live Output</h3>
<div id="output" class="output">
<div id="content"></div>
<div id="status"></div>
<pre id="log"></pre>
</div>
<script>
if (/Chrome\/(\d+\.\d+.\d+.\d+)/.test(navigator.userAgent)) {
// Let's log a warning if the sample is not supposed to execute on this
// version of Chrome.
if (55 > parseInt(RegExp.$1)) {
ChromeSamples.setStatus('Warning! Keep in mind this sample has been tested with Chrome ' + 55 + '.');
}
}
</script>
<script>
const coyoteService = "0000ffe0-0000-1000-8000-00805f9b34fb";
const configCharacteristic = "0000ffe1-0000-1000-8000-00805f9b34fb";
let hasAcceptedWarning = false;
let device = null;
document.querySelector('button#pair').addEventListener('click', () => {
if (isWebBluetoothEnabled()) {
onButtonClick();
}
});
document.querySelector('button#connect').addEventListener('click', () => {
if (isWebBluetoothEnabled()) {
ChromeSamples.clearLog();
onButtonConnect();
}
});
document.querySelector('button#disconnect').addEventListener('click', () => {
if (isWebBluetoothEnabled()) {
disconnect();
}
});
async function onButtonConnect() {
try {
log('Requesting Bluetooth Device...');
device = await navigator.bluetooth.requestDevice({
filters: [{
namePrefix: 'JDY',
}],
//acceptAllDevices: true,
optionalServices: [coyoteService]
});
log(device.name);
log('Connecting to GATT Server...');
const server = await device.gatt.connect();
log('Getting Coyote Service...');
const service = await server.getPrimaryService(coyoteService);
log('Getting Config Characteristic...');
const config = await service.getCharacteristic(configCharacteristic);
config.addEventListener('characteristicvaluechanged', handleCharacteristicValueChanged);
} catch (error) {
log('Argh! ' + error);
throw error;
}
}
async function onButtonClick() {
try {
log('Connecting to GATT Server...');
const server = await device.gatt.connect();
log('Getting Coyote Service...');
const service = await server.getPrimaryService(coyoteService);
log('Getting Config Characteristic...');
const config = await service.getCharacteristic(configCharacteristic);
var hex = document.getElementById('battery_level_text').value;
var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function(h){
return parseInt(h,16)
}));
log(typedArray);
config.writeValue(typedArray);
await config.startNotifications();
log('notifications have been started');
} catch (error) {
log('Argh! ' + error);
throw error;
}
}
function handleCharacteristicValueChanged(event) {
const valueDataView = event.target.value;
const hexString = [...new Uint8Array(valueDataView.buffer)].map(b => {
return b.toString(16).padStart(2, '0');
}).join(' ');
log(
'\n (Hex) ' + hexString
);
}
async function disconnect() {
try {
await device.gatt.disconnect();
log('断开连接');
} catch {}
device = null;
}
</script>
<script>
log = ChromeSamples.log;
function isWebBluetoothEnabled() {
if (navigator.bluetooth) {
return true;
} else {
ChromeSamples.setStatus('Web Bluetooth API is not available.\n' +
'Please make sure the "Experimental Web Platform features" flag is enabled.');
return false;
}
}
</script>
测试
1、开启蓝牙设备,点击连接蓝牙按钮,选择蓝牙,配对;
2、输入指令:ff5508000208090441ca09,打开像素灯;
3、输入指令:ff55050002080901,关闭像素灯。
4、点击断开蓝牙,蓝牙连接断开。