UNPKG

npm-polymer-elements

Version:

Polymer Elements package for npm

420 lines (389 loc) 14.2 kB
<!-- @license Copyright (c) 2015 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt --> <link rel="import" href="../polymer/polymer.html"> <script> (function() { 'use strict'; // This allows us to use BluetoothDevice related attributes type in // browsers where it is not defined. if (!('BluetoothDevice' in window)) { window.BluetoothDevice = {}; } // This allows us to use BluetoothGATTRemoteServer related attributes type // in browsers where it is not defined. if (!('BluetoothGATTRemoteServer' in window)) { window.BluetoothGATTRemoteServer = {}; } // This allows us to use BluetoothGATTService related attributes type in // browsers where it is not defined. if (!('BluetoothGATTService' in window)) { window.BluetoothGATTService = {}; } // This allows us to use BluetoothGATTCharacteristic related attributes // type in browsers where it is not defined. if (!('BluetoothGATTCharacteristic' in window)) { window.BluetoothGATTCharacteristic = {}; } /** * The `<platinum-bluetooth-characteristic>` element allows you to [read * and write characteristics on nearby bluetooth devices][1] thanks to the * young [Web Bluetooth API][2]. It is currently only partially implemented * in Chrome OS 45 behind the experimental flag * `chrome://flags/#enable-web-bluetooth`. * * `<platinum-bluetooth-characteristic>` needs to be a child of a * `<platinum-bluetooth-device>` element. * * For instance, here's how to read battery level from a nearby bluetooth * device advertising Battery service: * * ```html * <platinum-bluetooth-device services-filter='["battery_service"]'> * <platinum-bluetooth-characteristic * service='battery_service' * characteristic='battery_level'> * </platinum-bluetooth-characteristic> * </platinum-bluetooth-device> * ``` * ```js * var bluetoothDevice = document.querySelector('platinum-bluetooth-device'); * var batteryLevel = document.querySelector('platinum-bluetooth-characteristic'); * * button.addEventListener('click', function() { * bluetoothDevice.request().then(function() { * return batteryLevel.read().then(function(value) { * var data = new DataView(value); * console.log('Battery Level is ' + data.getUint8(0) + '%'); * }); * }) * .catch(function(error) { }); * }); * ``` * * Here's another example on how to reset energy expended on nearby * bluetooth device advertising Heart Rate service: * * ```html * <platinum-bluetooth-device services-filter='["heart_rate"]'> * <platinum-bluetooth-characteristic * service='heart_rate' * characteristic='heart_rate_control_point'> * </platinum-bluetooth-characteristic> * </platinum-bluetooth-device> * ``` * ```js * var bluetoothDevice = document.querySelector('platinum-bluetooth-device'); * var heartRateCtrlPoint = document.querySelector('platinum-bluetooth-characteristic'); * * button.addEventListener('click', function() { * bluetoothDevice.request().then(function() { * // Writing 1 is the signal to reset energy expended. * var resetEnergyExpended = new Uint8Array([1]); * return heartRateCtrlPoint.write(resetEnergyExpended).then(function() { * console.log('Energy expended has been reset'); * }); * }) * .catch(function(error) { }); * }); * ``` * * It is also possible for `<platinum-bluetooth-characteristic>` to fill in * a data-bound field in response to a read. * * ```html * <platinum-bluetooth-device services-filter='["heart_rate"]'> * <platinum-bluetooth-characteristic * service='heart_rate' * characteristic='body_sensor_location' * value={{bodySensorLocation}}> * </platinum-bluetooth-characteristic> * </platinum-bluetooth-device> * ... * <span>{{bodySensorLocation}}</span> * ``` * ```js * var bluetoothDevice = document.querySelector('platinum-bluetooth-device'); * var bodySensorLocation = document.querySelector('platinum-bluetooth-characteristic'); * * button.addEventListener('click', function() { * bluetoothDevice.request().then(function() { * return bodySensorLocation.read() * }) * .catch(function(error) { }); * }); * ``` * * You can also use changes in `value` to drive characteristic writes when * `auto-write` property is set to true. * * ```html * <platinum-bluetooth-device services-filter='["heart_rate"]'> * <platinum-bluetooth-characteristic * service='heart_rate' * characteristic='heart_rate_control_point' * auto-write> * </platinum-bluetooth-characteristic> * </platinum-bluetooth-device> * ``` * ```js * var bluetoothDevice = document.querySelector('platinum-bluetooth-device'); * var heartRateCtrlPoint = document.querySelector('platinum-bluetooth-characteristic'); * * button.addEventListener('click', function() { * bluetoothDevice.request().then(function() { * // Writing 1 is the signal to reset energy expended. * heartRateCtrlPoint.value = new Uint8Array([1]); * }) * .catch(function(error) { }); * }); * * heartRateCtrlPoint.addEventListener('platinum-bluetooth-auto-write-error', * function(event) { * // Handle error... * }); * ``` * * [1]: https://developers.google.com/web/updates/2015/07/interact-with-ble-devices-on-the-web * [2]: https://github.com/WebBluetoothCG/web-bluetooth * * @hero hero.svg * @demo demo/ */ Polymer({ is: 'platinum-bluetooth-characteristic', properties: { /** * Required Bluetooth GATT primary service. You may provide either the * full Bluetooth UUID as a string or a short 16- or 32-bit form as * integers like 0x180d. */ service: { type: String, observer: '_serviceChanged' }, /** * Required Bluetooth GATT characteristic for read and write operations. * You may provide either the full Bluetooth UUID as a string or a * short 16- or 32-bit form as integers like 0x2A19. */ characteristic: { type: String, observer: '_characteristicChanged' }, /** * Value gets populated with the characteristic value when it's read. */ value: { type: ArrayBuffer, observer: '_valueChanged', notify: true }, /** * If true, automatically perform a write `value` on the characteristic * when `value` changes. */ autoWrite: { type: Boolean, reflectToAttribute: true, value: false }, /** * Internal variable used that represents the Bluetooth device. */ _device: { type: BluetoothDevice }, /** * Internal variable used to cache Bluetooth GATT remote server. */ _server: { readOnly: true, type: BluetoothGATTRemoteServer }, /** * Internal variable used to cache Bluetooth GATT primary service. */ _service: { readOnly: true, type: BluetoothGATTService }, /** * Internal variable used to cache Bluetooth GATT characteristic. */ _characteristic: { readOnly: true, type: BluetoothGATTCharacteristic }, }, /** * Fired when an error occurs while writing automatically to a characteristic. * * @event platinum-bluetooth-auto-write-error * @param {String} The error message */ /** * Returns a promise that will resolve when bluetooth device picked by * user is connected. * * @return {Promise<BluetoothGATTRemoteServer>} */ _connectToDevice: function() { if (this._server) { // Resolve promise if device is already connected. return Promise.resolve(this._server); } if (!this._device) { return Promise.reject(new Error('Bluetooth device is not connected.')); } var self = this; return this._device.connectGATT() .then(function(server) { self._set_server(server); return self._server; }); }, /** * Returns a promise that will resolve when Bluetooth GATT Primary * Service is discovered. * * @return {Promise<BluetoothGATTService>} */ _getPrimaryService: function() { if (this._service && this._service.uuid === BluetoothUUID.getService(this.service)) { // Resolve promise if primary service is already discovered. return Promise.resolve(this._service); } if (!this._server || !this._server.connected) { return Promise.reject(new Error('Bluetooth GATT Remote server is not connected.')); } if (!this.service) { return Promise.reject(new Error('Bluetooth GATT Primary Service is mandatory.')); } var self = this; return this._server.getPrimaryService(this.service) .then(function(service) { if (!service) { throw new Error('Bluetooth GATT Primary Service not found.'); } self._set_service(service); return self._service; }); }, /** * Returns a promise that will resolve when Bluetooth GATT Characteristic * is discovered. * * @return {Promise<BluetoothGATTCharacteristic>} */ _getCharacteristic: function() { if (this._characteristic && this._characteristic.uuid === BluetoothUUID.getCharacteristic(this.characteristic)) { // Resolve promise if characteristic is already _. return Promise.resolve(this._characteristic); } if (!this._service) { return Promise.reject(new Error('Bluetooth GATT Primary Service is not connected.')); } if (!this.characteristic) { return Promise.reject(new Error('Bluetooth GATT Characteristic is mandatory.')); } var self = this; return this._service.getCharacteristic(this.characteristic) .then(function(characteristic) { self._set_characteristic(characteristic); return self._characteristic; }); }, /** * Returns a promise that will resolve when Bluetooth GATT Characteristic * is read. * * @return {Promise<ArrayBuffer>} */ _readCharacteristic: function() { if (!this._characteristic) { return Promise.reject(new Error('Bluetooth GATT Characteristic is not connected.')); } var self = this; return this._characteristic.readValue() .then(function(value) { self.value = value; return self.value; }); }, /** * Returns a promise that will resolve when Bluetooth GATT Characteristic * is written. * * @param value {BufferSource (ArrayBufferView|ArrayBuffer)} * @return {Promise<void>} */ _writeCharacteristic: function(value) { if (!this._characteristic) { return Promise.reject(new Error('Bluetooth GATT Characteristic is not connected.')); } return this._characteristic.writeValue(value); }, /** * Reset internal cache when service property is changed. */ _serviceChanged: function() { this._set_service(null); this._set_characteristic(null); }, /** * Reset internal cache when characteristic property is changed. */ _characteristicChanged: function() { this._set_characteristic(null); }, /** * Automatically write value when auto-write property is true and value * changed. */ _valueChanged: function() { if (this.autoWrite) { var self = this; this.write(this.value).catch(function(error) { self.fire('platinum-bluetooth-auto-write-error', error.message || error); }); } }, /** * Returns a promise that will resolve when Bluetooth GATT Characteristic * is read. * * @return {Promise<ArrayBuffer>} The value of this Bluetooth GATT Characteristic. */ read: function() { var self = this; return this._connectToDevice() .then(function() { return self._getPrimaryService() }) .then(function() { return self._getCharacteristic() }) .then(function() { return self._readCharacteristic() }) }, /** * Returns a promise that will resolve when Bluetooth GATT Characteristic * is written. * * @param {(ArrayBufferView|ArrayBuffer)} value The value to write. * @return {Promise} */ write: function(value) { var self = this; return this._connectToDevice() .then(function() { return self._getPrimaryService() }) .then(function() { return self._getCharacteristic() }) .then(function() { return self._writeCharacteristic(value) }) }, }); })(); </script>