HTML та JavaScript мінімальний дослідник Bluetooth/BLE Service за допомогою navigator.bluetooth
Цей самодостатній приклад на HTML та JavaScript демонструє, як використовувати Web Bluetooth API для підключення до Bluetooth-пристрою, виявлення його сервісів та характеристик, а також читання/запису значень.
ble_service_explorer.html
<!doctype html>
<html lang="uk">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Дослідник характеристик BLE-сервісу</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; padding: 1rem; }
button { margin: 0.25rem; }
.characteristic { margin: 0.5rem 0; padding: 0.5rem; border: 1px solid #ddd; border-radius: 6px; }
.props { font-size: 0.9rem; color: #444; }
pre { background:#f7f7f7; padding:0.5rem; border-radius:4px; overflow:auto }
</style>
</head>
<body>
<h1>Дослідник характеристик BLE-сервісу</h1>
<p>UUID сервісу: <code id="serviceUuidDisplay">42355f23-e1c4-8481-4282-5add5f9e85aa</code></p>
<p>
<button id="connectBtn">Підключитися та вивести характеристики</button>
<button id="disconnectBtn" disabled>Відключитися</button>
</p>
<div id="status">Очікування</div>
<h2>Характеристики</h2>
<div id="characteristics"></div>
<script>
// TODO Змініть це на ваш UUID сервісу
const SERVICE_UUID = '42355f23-e1c4-8481-4282-5add5f9e85aa';
const connectBtn = document.getElementById('connectBtn');
const disconnectBtn = document.getElementById('disconnectBtn');
const statusEl = document.getElementById('status');
const charContainer = document.getElementById('characteristics');
document.getElementById('serviceUuidDisplay').textContent = SERVICE_UUID;
let device = null;
let server = null;
let service = null;
function setStatus(text) {
statusEl.textContent = text;
}
function formatProps(props) {
return Object.keys(props).filter(k => props[k]).join(', ') || 'none';
}
async function listCharacteristics() {
try {
setStatus('Виявлення характеристик...');
const characteristics = await service.getCharacteristics();
charContainer.innerHTML = '';
if (characteristics.length === 0) {
charContainer.textContent = 'Для цього сервісу характеристик не знайдено.';
return;
}
for (const ch of characteristics) {
const el = document.createElement('div');
el.className = 'characteristic';
const title = document.createElement('div');
title.innerHTML = `<strong>UUID:</strong> <code>${ch.uuid}</code>`;
el.appendChild(title);
const props = document.createElement('div');
props.className = 'props';
props.textContent = 'Властивості: ' + formatProps(ch.properties);
el.appendChild(props);
const actions = document.createElement('div');
// Кнопка читання
if (ch.properties.read) {
const readBtn = document.createElement('button');
readBtn.textContent = 'Читати';
readBtn.addEventListener('click', async () => {
try {
setStatus(`Читання ${ch.uuid}...`);
const value = await ch.readValue();
const bytes = new Uint8Array(value.buffer);
const hex = Array.from(bytes).map(b => b.toString(16).padStart(2,'0')).join(' ');
showValue(el, hex, bytesToString(bytes));
setStatus('Читання виконано');
} catch (err) {
setStatus('Помилка читання: ' + err);
}
});
actions.appendChild(readBtn);
}
// Перемикач сповіщень
if (ch.properties.notify || ch.properties.indicate) {
const notifyBtn = document.createElement('button');
notifyBtn.textContent = 'Увімкнути сповіщення';
let notifying = false;
async function handleNotification(e) {
const v = e.target.value;
const bytes = new Uint8Array(v.buffer);
const hex = Array.from(bytes).map(b => b.toString(16).padStart(2,'0')).join(' ');
showValue(el, hex, bytesToString(bytes), true);
}
notifyBtn.addEventListener('click', async () => {
try {
if (!notifying) {
await ch.startNotifications();
ch.addEventListener('characteristicvaluechanged', handleNotification);
notifyBtn.textContent = 'Вимкнути сповіщення';
notifying = true;
setStatus('Сповіщення розпочато для ' + ch.uuid);
} else {
ch.removeEventListener('characteristicvaluechanged', handleNotification);
await ch.stopNotifications();
notifyBtn.textContent = 'Увімкнути сповіщення';
notifying = false;
setStatus('Сповіщення зупинено для ' + ch.uuid);
}
} catch (err) {
setStatus('Помилка сповіщень: ' + err);
}
});
actions.appendChild(notifyBtn);
}
el.appendChild(actions);
charContainer.appendChild(el);
}
setStatus('Характеристики виведено.');
} catch (err) {
setStatus('Помилка виведення характеристик: ' + err);
}
}
function showValue(parentEl, hex, text, append=false) {
let pre = parentEl.querySelector('pre');
if (!pre) {
pre = document.createElement('pre');
parentEl.appendChild(pre);
}
const now = new Date().toISOString();
const s = `${now} hex: ${hex}\ntext: ${text}\n`;
if (append)
pre.textContent = pre.textContent + '\n' + s;
else
pre.textContent = s;
}
function bytesToString(bytes) {
try { return new TextDecoder().decode(bytes); } catch { return '<бінарні дані>'; }
}
connectBtn.addEventListener('click', async () => {
try {
setStatus('Запит пристрою...');
device = await navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: [SERVICE_UUID]
});
device.addEventListener('gattserverdisconnected', () => {
setStatus('Пристрій відключено');
disconnectBtn.disabled = true;
connectBtn.disabled = false;
});
setStatus('Підключення до GATT-сервера...');
server = await device.gatt.connect();
setStatus('Отримання сервісу...');
service = await server.getPrimaryService(SERVICE_UUID);
setStatus('Сервіс знайдено: ' + SERVICE_UUID);
connectBtn.disabled = true;
disconnectBtn.disabled = false;
await listCharacteristics();
} catch (err) {
setStatus('Помилка підключення: ' + err);
}
});
disconnectBtn.addEventListener('click', async () => {
if (!device) return;
try {
if (device.gatt.connected) device.gatt.disconnect();
setStatus('Відключено');
disconnectBtn.disabled = true;
connectBtn.disabled = false;
} catch (err) {
setStatus('Помилка відключення: ' + err);
}
});
</script>
</body>
</html>
Дивіться схожі статті за категоріями:
Javascript, Bluetooth
Якщо ця стаття допомогла вам, будь ласка, подумайте про те, щоб купити мені каву або зробити пожертву через PayPal на підтримку досліджень та публікації нових статей на TechOverflow