npm-polymer-elements
Version:
Polymer Elements package for npm
420 lines (389 loc) • 14.2 kB
HTML
<!--
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>
Copyright (c)