자바스크립트를 통해 블루투스 기기와 통신하기

Web Bluetooth API를 사용하면 웹사이트에서 블루투스 기기와 통신할 수 있습니다.

François Beaufort
François Beaufort

웹사이트가 근처의 블루투스 기기와 통신할 수 있다고 말하면 어떻게 해야 할까요? 어떻게 활용할 수 있을까요? 이렇게 하면 심박수를 측정하고, 노래를 부르고, 심지어 전구, 심지어 거북이도 웹사이트와 직접 상호작용할 수 있습니다.

지금까지는 블루투스 기기와 상호작용하는 기능이 가능했습니다. 할 수 있습니다. Web Bluetooth API는 웹 브라우저에서도 사용할 수 있습니다.

시작하기 전에

이 문서에서는 Bluetooth Low 페이지의 작동 방식에 대한 기본 지식이 에너지 (BLE)와 일반 속성 프로필이 작동합니다.

Web Bluetooth API 사양은 아직 확정되지 않았지만 개발자들은 이 API를 사용해 볼 열정적인 개발자들을 적극적으로 찾고 있으며 사양에 대한 의견구현에 대한 의견을 제공합니다.

웹 블루투스 API의 하위 집합은 ChromeOS, Android용 Chrome에서 사용할 수 있습니다. 6.0, Mac (Chrome 56), Windows 10 (Chrome 70)에서만 지원됩니다. 즉, 사용자는 주변의 저전력 블루투스 기기에 요청하고 연결합니다. 블루투스 특성 읽기/쓰기, GATT 알림 수신, 파악 블루투스 기기가 연결 해제되고 심지어 블루투스 설명자. 자세한 내용은 MDN의 브라우저 호환성 표를 참고하세요. 확인할 수 있습니다

Linux 및 이전 버전의 Windows에서는 about://flags#experimental-web-platform-features 플래그.

오리진 트라이얼에 사용 가능

웹 앱을 사용하는 개발자들로부터 가능한 한 많은 피드백을 얻기 위해 Bluetooth API를 현장에서 사용할 수 있지만, Chrome은 이전에 이 기능을 Chrome에 추가했습니다. 53을 ChromeOS, Android, Mac용 오리진 트라이얼으로 사용해 보세요.

무료 체험판은 2017년 1월에 종료되었습니다.

보안 요구사항

보안의 장단점을 알아보려면 웹 블루투스 보안 Chrome팀의 소프트웨어 엔지니어인 제프리 야스킨의 모델 게시물입니다. 웹 블루투스 API 사양에서 작업 중입니다.

HTTPS 전용

이 실험용 API는 웹에 추가된 강력한 새 기능이므로 보안 컨텍스트에만 사용할 수 있습니다. 즉, 빌드 시 컨테이너 이미지를 TLS를 고려해야 합니다

사용자 동작 필요

보안 기능으로 navigator.bluetooth.requestDevice는 다음과 같은 사용자 동작으로 트리거되어야 합니다. 마우스 클릭 또는 터치와 같은 형태가 됩니다. 이제 중요한 것은 pointerup, click, touchend 이벤트

button.addEventListener('pointerup', function(event) {
  // Call navigator.bluetooth.requestDevice
});

코드 들어가기

Web Bluetooth API는 JavaScript 프로미스에 크게 의존합니다. 그렇지 않은 경우 프로미스 튜토리얼을 확인해 보세요. 한 가지 더 알려드릴 사항이 있습니다. () => {}는 ECMAScript 2015 화살표 함수입니다.

블루투스 기기 요청

이 버전의 Web Bluetooth API 사양은 BLE 연결을 통해 원격 GATT 서버에 연결하는 중앙 역할입니다. 그것은 Bluetooth 4.0 이상을 구현하는 장치 간 통신을 지원합니다.

웹사이트에서 근처 기기에 대한 액세스를 요청할 때 navigator.bluetooth.requestDevice: 브라우저가 사용자에게 기기 사용 메시지를 표시합니다. 사용자가 하나의 기기를 선택하거나 요청을 취소할 수 있는 선택기입니다.

블루투스 기기 사용자 메시지.

navigator.bluetooth.requestDevice() 함수는 는 필터를 정의합니다. 이 필터는 검색어와 일치하는 기기만 반환하는 데 사용됩니다. 광고 블루투스 GATT 서비스 및/또는 기기 이름을 사용할 수 없습니다.

서비스 필터

예를 들어, 블루투스 GATT를 광고하는 블루투스 기기를 요청하는 경우 배터리 서비스:

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });

블루투스 GATT 서비스가 표준화된 블루투스 목록에 없는 경우 GATT 서비스의 경우 전체 블루투스 UUID 또는 짧은 16비트 또는 32비트 형식.

navigator.bluetooth.requestDevice({
  filters: [{
    services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
  }]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

이름 필터

광고 중인 기기 이름에 따라 블루투스 기기를 요청할 수도 있습니다. name 필터 키가 있는 경우 또는 이 이름의 프리픽스를 namePrefix 필터 키를 누릅니다. 이 경우 optionalServices 키를 사용하여 서비스 필터 그러지 않으면 나중에 액세스하려고 할 때 오류가 표시됩니다. 있습니다.

navigator.bluetooth.requestDevice({
  filters: [{
    name: 'Francois robot'
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

제조업체 데이터 필터

제조업체별로 블루투스 기기를 요청할 수도 있습니다. manufacturerData 필터 키로 광고되는 특정 데이터 이 키 는이라는 필수 블루투스 회사 식별자 키가 있는 객체의 배열입니다. companyIdentifier입니다. 또한 피처스토어를 필터링하는 제조업체 데이터를 수집합니다. 참고: 모든 서비스에 액세스하려면 optionalServices 키도 정의해야 합니다. 서비스 필터에 포함되지 않습니다. 그러지 않으면 나중에 액세스를 시도하고 있습니다.

// Filter Bluetooth devices from Google company with manufacturer data bytes
// that start with [0x01, 0x02].
navigator.bluetooth.requestDevice({
  filters: [{
    manufacturerData: [{
      companyIdentifier: 0x00e0,
      dataPrefix: new Uint8Array([0x01, 0x02])
    }]
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

마스크를 데이터 접두사와 함께 사용하여 제조업체 데이터 자세히 알아보려면 블루투스 데이터 필터 설명을 확인하세요. 자세히 알아보세요.

제외 필터

navigator.bluetooth.requestDevice()exclusionFilters 옵션을 사용하면 브라우저 선택 도구에서 일부 기기를 제외합니다. 특정 광고 단위를 더 넓은 필터와 일치하지만 지원되지 않는 기기

// Request access to a bluetooth device whose name starts with "Created by".
// The device named "Created by Francois" has been reported as unsupported.
navigator.bluetooth.requestDevice({
  filters: [{
    namePrefix: "Created by"
  }],
  exclusionFilters: [{
    name: "Created by Francois"
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

필터 사용하지 않기

마지막으로 filters 대신 acceptAllDevices 키를 사용하여 근처 블루투스 기기입니다. optionalServices도 정의해야 합니다. 일부 서비스에 액세스할 수 있어야 합니다. 그러지 않으면 나중에 오류가 발생합니다. 문제가 있을 수 있습니다.

navigator.bluetooth.requestDevice({
  acceptAllDevices: true,
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

블루투스 기기에 연결

이제 BluetoothDevice가 있으므로 어떻게 해야 할까요? 서비스 및 특성을 보유하는 블루투스 원격 GATT 서버입니다. 정의할 수 있습니다

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => {
  // Human-readable name of the device.
  console.log(device.name);

  // Attempts to connect to remote GATT Server.
  return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });

블루투스 특성 읽기

여기서 원격 블루투스 장치의 GATT 서버에 연결합니다. 이제 기본 GATT 서비스를 받고 1)에 속하는 특성을 읽기를 원하는 경우 사용할 수 있습니다 예를 들어 Nest × Yale 도어락의 현재 충전 수준을 배터리 수명을 연장할 수 있습니다.

다음 예에서 battery_level표준화된 배터리 수준입니다. 특성.

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => device.gatt.connect())
.then(server => {
  // Getting Battery Service…
  return server.getPrimaryService('battery_service');
})
.then(service => {
  // Getting Battery Level Characteristic…
  return service.getCharacteristic('battery_level');
})
.then(characteristic => {
  // Reading Battery Level…
  return characteristic.readValue();
})
.then(value => {
  console.log(`Battery percentage is ${value.getUint8(0)}`);
})
.catch(error => { console.error(error); });

맞춤형 블루투스 GATT 특성을 사용하는 경우 전체 블루투스 UUID 또는 짧은 16비트 또는 32비트 형식으로 service.getCharacteristic

characteristicvaluechanged 이벤트 리스너를 특성 값을 사용하여 값 읽기를 처리합니다. 자세한 내용은 읽기 특성 값이 변경된 샘플을 참고하여 예정된 GATT를 선택적으로 처리하는 방법을 알아보세요. 알림을 받을 수도 있습니다

…
.then(characteristic => {
  // Set up event listener for when characteristic value changes.
  characteristic.addEventListener('characteristicvaluechanged',
                                  handleBatteryLevelChanged);
  // Reading Battery Level…
  return characteristic.readValue();
})
.catch(error => { console.error(error); });

function handleBatteryLevelChanged(event) {
  const batteryLevel = event.target.value.getUint8(0);
  console.log('Battery percentage is ' + batteryLevel);
}

블루투스 특성에 쓰기

블루투스 GATT 특성에 쓰는 것은 읽는 것만큼 쉽습니다. 이번에는 심박수 컨트롤 포인트를 사용하여 에너지 소비량 값을 재설정해 보세요. 필드를 0으로 설정합니다.

진짜 마법 같은 건 없다고 장담해요. 자세한 내용은 심박수 조절 포인트 특성 페이지를 참고하세요.

navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_control_point'))
.then(characteristic => {
  // Writing 1 is the signal to reset energy expended.
  const resetEnergyExpended = Uint8Array.of(1);
  return characteristic.writeValue(resetEnergyExpended);
})
.then(_ => {
  console.log('Energy expended has been reset.');
})
.catch(error => { console.error(error); });

GATT 알림 수신

이제 심박수 측정이 시작될 때 알림을 받는 방법을 알아보겠습니다. 특성 변화를 나타냅니다.

navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_measurement'))
.then(characteristic => characteristic.startNotifications())
.then(characteristic => {
  characteristic.addEventListener('characteristicvaluechanged',
                                  handleCharacteristicValueChanged);
  console.log('Notifications have been started.');
})
.catch(error => { console.error(error); });

function handleCharacteristicValueChanged(event) {
  const value = event.target.value;
  console.log('Received ' + value);
  // TODO: Parse Heart Rate Measurement value.
  // See https://github.com/WebBluetoothCG/demos/blob/gh-pages/heart-rate-sensor/heartRateSensor.js
}

알림 샘플에서는 다음을 사용하여 알림을 중지하는 방법을 보여줍니다. stopNotifications()하고 추가된 characteristicvaluechanged를 적절하게 삭제합니다. 이벤트 리스너를 추가합니다.

블루투스 기기에서 연결 해제

더 나은 사용자 환경을 제공하려면 연결 끊김 이벤트를 수신 대기하는 것이 좋습니다. 사용자를 다시 연결하도록 초대합니다.

navigator.bluetooth.requestDevice({ filters: [{ name: 'Francois robot' }] })
.then(device => {
  // Set up event listener for when device gets disconnected.
  device.addEventListener('gattserverdisconnected', onDisconnected);

  // Attempts to connect to remote GATT Server.
  return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });

function onDisconnected(event) {
  const device = event.target;
  console.log(`Device ${device.name} is disconnected.`);
}

device.gatt.disconnect()를 호출하여 웹 앱을 블루투스 기기 기존 gattserverdisconnected 이벤트가 트리거됩니다. 리스너입니다. 다른 기기가 연결되어도 블루투스 기기 통신은 중지되지 않습니다. 이미 블루투스 기기와 통신 중입니다. 기기 연결 해제 샘플자동 재연결 샘플을 통해 자세히 알아보세요.

블루투스 설명자 읽기 및 쓰기

블루투스 GATT 설명자는 특성 값을 설명하는 속성입니다. 블루투스 GATT와 비슷한 방식으로 읽고 쓸 수 있습니다. 특성에 따라 다릅니다

예를 들어 측정에 대한 사용자 설명을 읽는 방법을 살펴보겠습니다. 간격을 유지합니다.

아래 예에서 health_thermometer건강 온도계 서비스입니다. measurement_interval 측정 간격 특성 gatt.characteristic_user_description 특징 사용자 설명 설명자.

navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => descriptor.readValue())
.then(value => {
  const decoder = new TextDecoder('utf-8');
  console.log(`User Description: ${decoder.decode(value)}`);
})
.catch(error => { console.error(error); });

이제 측정 간격에 대한 사용자 설명을 읽었으므로 업데이트하는 방법을 알아보겠습니다. 값에 사용합니다.

navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => {
  const encoder = new TextEncoder('utf-8');
  const userDescription = encoder.encode('Defines the time between measurements.');
  return descriptor.writeValue(userDescription);
})
.catch(error => { console.error(error); });

샘플, 데모, Codelab

아래의 모든 웹 블루투스 샘플은 성공적으로 테스트되었습니다. 다음 기능을 이용하려면 최대한 활용하려면 [BLE 주변기기 시뮬레이터]를 Android 앱] - 배터리 서비스, 심박수를 사용하여 BLE 주변기기를 시뮬레이션합니다. 서비스 또는 건강 온도계 서비스.

초급

  • Device Info: BLE 기기에서 기본 기기 정보를 검색합니다.
  • 배터리 수준: 배터리 정보를 광고하는 BLE 기기에서 배터리 정보를 검색합니다.
  • 에너지 재설정 - 심박수를 광고하는 BLE 기기에서 소모된 에너지를 재설정합니다.
  • 특성 속성 - BLE 기기에서 특정 특성의 모든 속성을 표시합니다.
  • 알림 - BLE 기기에서 특성 알림을 시작하고 중지합니다.
  • 기기 연결 해제 - 연결 후 BLE 기기의 연결을 해제하고 연결 해제되면 알림을 받습니다.
  • Get Characteristics - BLE 기기에서 광고되는 서비스의 모든 특성을 가져옵니다.
  • Get Descriptors(설명자 가져오기) - 모든 특성 가져오기 BLE 기기에서 광고된 서비스의 설명어를 제공합니다.
  • Manufacturer Data Filter: BLE 기기에서 제조업체 데이터와 일치하는 기본 기기 정보를 검색합니다.
  • 제외 필터 - 기본 제외 필터가 특징인 BLE 기기에서 기본 기기 정보를 검색합니다.

여러 작업 결합

  • GAP 특성 - BLE 기기의 모든 GAP 특성을 가져옵니다.
  • Device Information Characteristics - BLE 기기의 모든 기기 정보 특성을 가져옵니다.
  • 링크 손실 - BLE 기기의 알림 수준 특성을 설정합니다 (readValue 및 writeValue).
  • 서비스 및 특성 - BLE 기기에서 액세스 가능한 모든 기본 서비스와 그 특성을 알아봅니다.
  • 자동 다시 연결 - 지수 백오프 알고리즘을 사용하여 연결 해제된 BLE 기기에 다시 연결합니다.
  • Read Characteristic Value Changed(읽기 특성 값이 변경됨) - 배터리 수준을 읽고 BLE 기기의 변경사항에 관해 알림을 받습니다.
  • Read Descriptors: BLE 기기에서 서비스의 모든 특성 설명어를 읽습니다.
  • Write Descriptor: 'Characteristic User Description'의 설명어에 작성합니다. 연결되어야 합니다.

선별된 웹 블루투스 데모공식 웹 블루투스 Codelab도 확인하세요.

라이브러리

  • web-bluetooth-utils는 몇 가지 편의 함수를 추가하는 npm 모듈입니다. 생성합니다.
  • Web Bluetooth API shim은 가장 인기 있는 Node.js BLE인 noble에서 사용할 수 있습니다. 중앙 모듈에서 제공됩니다 이를 통해 별도의 설정 없이도 noble을 webpack/browserify할 수 있습니다. 사용할 수 있습니다.
  • angular-web-bluetoothAngular 모듈입니다. 웹 블루투스 API를 구성하는 데 필요한 상용구입니다.

도구

  • 웹 블루투스 시작하기는 간단한 웹 앱으로 JavaScript 상용구 코드를 사용하여 블루투스 기기와 상호작용을 시작합니다. 기기 이름, 서비스, 특성을 입력하고 속성을 정의합니다. 이제 가도 됩니다
  • 이미 블루투스 개발자인 경우 웹 블루투스 개발자 스튜디오 또한 플러그인은 앱에 사용할 웹 블루투스 자바스크립트 코드를 생성합니다. 블루투스 기기

블루투스 내부 페이지는 Chrome에서 사용할 수 있습니다. about://bluetooth-internals 주변 정보를 모두 검사할 수 있습니다. 블루투스 기기: 상태, 서비스, 특성 및 설명어

Chrome에서 블루투스를 디버그하는 내부 페이지의 스크린샷
블루투스 기기 디버깅을 위한 Chrome 내부 페이지

또한 공식 웹 블루투스 버그 신고 방법을 확인하시기 바랍니다. 페이지를 디버깅하는 것이 어려울 수 있습니다.

다음 단계

먼저 브라우저 및 플랫폼 구현 상태를 확인하여 어떤 부분이 있는지 확인하세요. 현재 구현되고 있습니다.

아직 완성되지 않았지만 가까운 시일 내에 기대할 수 있는 사항은 다음과 같습니다. 향후:

  • 주변 BLE 광고 검색 navigator.bluetooth.requestLEScan()와 함께 진행됩니다.
  • serviceadded 이벤트는 새로 발견된 블루투스 GATT 서비스를 추적합니다. serviceremoved 이벤트는 삭제된 항목을 추적합니다. 새로운 servicechanged 이벤트는 특성 또는 설명어가 추가되거나 블루투스 GATT 서비스에서 제거되었습니다.

API 지원 표시

Web Bluetooth API를 사용할 계획이신가요? 여러분의 공개적 지원은 Chrome팀에 도움이 됩니다 기능의 우선순위를 지정하고 해당 기능을 지원하는 것이 얼마나 중요한지 다른 브라우저 공급업체에 보여줍니다.

해시태그를 사용하여 @ChromiumDev에 트윗을 보냅니다. #WebBluetooth 어디서 어떻게 사용하는지 알려주세요.

리소스

감사의 말씀

이 도움말을 검토해 주신 Kayce Basques님께 감사드립니다. 히어로 이미지: 미국 볼더의 SparkFun Electronics