1. ¿De qué se trata?
En este codelab ilustrado, aprenderás a controlar una vela LED sin llamas LED de PLAYBULB solo con JavaScript gracias a la API de Web Bluetooth. También podrás probar funciones de JavaScript ES2015, como clases, funciones de flecha, Map y promesas.
Qué aprenderás
- Cómo interactuar con un dispositivo Bluetooth cercano en JavaScript
- Cómo usar clases, funciones de flecha, mapas y promesas de ES2015
Requisitos
- Conocimientos básicos sobre el desarrollo web
- Conocimientos básicos de Bluetooth de bajo consumo (BLE) y el perfil de atributos genéricos (GATT)
- El editor de texto que prefieras
- Una Mac, una Chromebook o un dispositivo Android M con la aplicación del navegador Chrome y un cable USB micro a USB.
2. Reproducir primero
Te recomendamos consultar la versión final de la app que estás por crear en https://googlecodelabs.github.io/candle-bluetooth y jugar con el dispositivo Bluetooth PLAYBULB que tienes a tu disposición antes de sumergirte en este codelab.
También puedes ver cómo cambia de color en https://www.youtube.com/watch?v=fBCPA9gIxlU
3. Prepárate
Descarga el código de muestra
Para obtener el código de muestra de este código, descarga el zip aquí:
o clonando este repositorio de Git:
git clone https://github.com/googlecodelabs/candle-bluetooth.git
Si descargaste la fuente como un ZIP, cuando lo descomprimas deberías obtener una carpeta raíz candle-bluetooth-master
.
Instala y verifica el servidor web
Aunque puedes usar tu propio servidor web, este codelab está diseñado para funcionar bien con Chrome Web Server. Si aún no tienes esa app instalada, puedes instalarla desde Chrome Web Store.
Después de instalar la app Web Server for Chrome, haz clic en el acceso directo de Apps en la barra de favoritos:
En la ventana subsiguiente, haz clic en el ícono de Web Server:
A continuación, verás este diálogo, que te permite configurar tu servidor web local:
Haz clic en el botón Choose folder y selecciona la raíz del repositorio clonado (o desarchivado). Esto te permitirá entregar el trabajo en curso a través de la URL destacada en el diálogo del servidor web (en la sección Web Server URL(s)).
En Opciones, marca la casilla junto a "Automatically show index.html", como se muestra a continuación:
Ahora visita tu sitio en tu navegador web (haciendo clic en la URL destacada de Web Server) y deberías ver una página como la siguiente:
Si quieres saber cómo se ve esta app en tu teléfono Android, deberás habilitar la Depuración remota en Android y configurar la redirección de puertos (el número de puerto predeterminado es 8887). Luego, puedes abrir una nueva pestaña de Chrome en http://localhost:8887 en tu teléfono Android.
Cuál es el próximo paso
En este punto, esta app web no hace mucho. Comencemos a agregar compatibilidad con Bluetooth.
4. Descubre la vela
Empezaremos escribiendo una biblioteca que use una clase JavaScript ES2015 para el dispositivo Bluetooth PLAYBULB Candle.
Mantén la calma. La sintaxis de la clase no presentará un nuevo modelo de herencia orientado a objetos en JavaScript. Simplemente, proporciona una sintaxis mucho más clara para crear objetos y lidiar con la herencia, como puedes leer a continuación.
Primero, definiremos una clase PlaybulbCandle
en playbulbCandle.js
y crearemos una instancia de playbulbCandle
que estará disponible más adelante en el archivo app.js
.
playbulbCandle.js
(function() {
'use strict';
class PlaybulbCandle {
constructor() {
this.device = null;
}
}
window.playbulbCandle = new PlaybulbCandle();
})();
Para solicitar acceso a un dispositivo Bluetooth cercano, debemos llamar a navigator.bluetooth.requestDevice
. Dado que el dispositivo PLAYBULB Candle anuncia de manera continua (si aún no está vinculado) un UUID de servicio GATT de Bluetooth constante conocido como 0xFF02
, podemos definir una constante y agregarla al parámetro de servicios de filtros en un nuevo método público connect
de la clase PlaybulbCandle
.
También realizaremos un seguimiento interno del objeto BluetoothDevice
para poder acceder a él más tarde si es necesario. Como navigator.bluetooth.requestDevice
muestra una promesa de JavaScript ES2015, lo haremos en el método then
.
playbulbCandle.js
(function() {
'use strict';
const CANDLE_SERVICE_UUID = 0xFF02;
class PlaybulbCandle {
constructor() {
this.device = null;
}
connect() {
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}]};
return navigator.bluetooth.requestDevice(options)
.then(function(device) {
this.device = device;
}.bind(this));
}
}
window.playbulbCandle = new PlaybulbCandle();
})();
Como función de seguridad, la detección de dispositivos Bluetooth cercanos con navigator.bluetooth.requestDevice
se debe llamar con un gesto del usuario, como un toque o un clic del mouse. Por eso, llamaremos al método connect
cuando el usuario haga clic en "Conectar". en el archivo app.js
:
app.js
document.querySelector('#connect').addEventListener('click', function(event) {
document.querySelector('#state').classList.add('connecting');
playbulbCandle.connect()
.then(function() {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
})
.catch(function(error) {
console.error('Argh!', error);
});
});
Ejecuta la app
En este punto, visita tu sitio en tu navegador web (haciendo clic en la URL del servidor web destacada en la app del servidor web) o simplemente actualiza la página existente. Haz clic en el botón verde "Conectar". elige el dispositivo del selector y abre tu consola favorita de Herramientas para desarrolladores con la combinación de teclas Ctrl + Mayúsculas + J y observa que se registró el objeto BluetoothDevice
.
Es posible que se produzca un error si el Bluetooth está desactivado o si el dispositivo Bluetooth PLAYBULB Candle está desactivado. En ese caso, actívalo y vuelve a continuar.
Bonificación obligatoria
No sé qué te parece, pero ya veo demasiados function() {}
en este código. En su lugar, cambiemos a las funciones de flecha de JavaScript ES2015 de () => {}
. Son absolutamente salvadores: Toda la belleza de las funciones anónimas, sin la tristeza de las vinculaciones.
playbulbCandle.js
(function() {
'use strict';
const CANDLE_SERVICE_UUID = 0xFF02;
class PlaybulbCandle {
constructor() {
this.device = null;
}
connect() {
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}]};
return navigator.bluetooth.requestDevice(options)
.then(device => {
this.device = device;
});
}
}
window.playbulbCandle = new PlaybulbCandle();
})();
app.js
document.querySelector('#connect').addEventListener('click', event => {
playbulbCandle.connect()
.then(() => {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
})
.catch(error => {
console.error('Argh!', error);
});
});
Cuál es el próximo paso
- Bien... ¿Puedo hablarle a esta vela o qué?
- Por supuesto... continúa con el siguiente paso
Preguntas frecuentes
5. Leer algo
¿Qué haces ahora que se muestra un BluetoothDevice
de la promesa de navigator.bluetooth.requestDevice
? Conectémonos al GATT Server remoto con Bluetooth que contiene el servicio Bluetooth y las definiciones de características llamando a device.gatt.connect()
:
playbulbCandle.js
class PlaybulbCandle {
constructor() {
this.device = null;
}
connect() {
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}]};
return navigator.bluetooth.requestDevice(options)
.then(device => {
this.device = device;
return device.gatt.connect();
});
}
}
Lee el nombre del dispositivo
Aquí estamos conectados al servidor GATT del dispositivo Bluetooth PLAYBULB Candle. Ahora queremos obtener el servicio GATT principal (que antes se anunciaba como 0xFF02
) y leer la característica del nombre del dispositivo (0xFFFF
) que pertenece a este servicio. Esto se puede lograr fácilmente agregando un nuevo método getDeviceName
a la clase PlaybulbCandle
y usando device.gatt.getPrimaryService
y service.getCharacteristic
. El método characteristic.readValue
en realidad mostrará un DataView
que simplemente decodificaremos con TextDecoder
.
playbulbCandle.js
const CANDLE_DEVICE_NAME_UUID = 0xFFFF;
...
getDeviceName() {
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_DEVICE_NAME_UUID))
.then(characteristic => characteristic.readValue())
.then(data => {
let decoder = new TextDecoder('utf-8');
return decoder.decode(data);
});
}
Agreguemos esto a app.js
llamando a playbulbCandle.getDeviceName
una vez que nos conectemos y mostremos el nombre del dispositivo.
app.js
document.querySelector('#connect').addEventListener('click', event => {
playbulbCandle.connect()
.then(() => {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
return playbulbCandle.getDeviceName().then(handleDeviceName);
})
.catch(error => {
console.error('Argh!', error);
});
});
function handleDeviceName(deviceName) {
document.querySelector('#deviceName').value = deviceName;
}
En este punto, visita tu sitio en tu navegador web (haciendo clic en la URL del servidor web destacada en la app del servidor web) o simplemente actualiza la página existente. Asegúrate de que la vela PLAYBULB esté encendida y haz clic en "Conectar" de la página y deberías ver el nombre del dispositivo debajo del selector de color.
Consultar el nivel de batería
También hay una característica estándar de Bluetooth a nivel de batería disponible en el dispositivo PLAYBULB Candle Bluetooth que contiene el nivel de batería del dispositivo. Esto significa que podemos usar nombres estándar como battery_service
para el UUID del servicio GATT de Bluetooth y battery_level
para el UUID de característica GATT de Bluetooth.
Agreguemos un nuevo método getBatteryLevel
a la clase PlaybulbCandle
y analicemos el nivel de batería en porcentaje.
playbulbCandle.js
getBatteryLevel() {
return this.device.gatt.getPrimaryService('battery_service')
.then(service => service.getCharacteristic('battery_level'))
.then(characteristic => characteristic.readValue())
.then(data => data.getUint8(0));
}
También necesitamos actualizar el objeto de JavaScript options
para incluir el servicio de batería en la clave optionalServices
, ya que no lo anuncia el dispositivo Bluetooth PLAYBULB Candle, pero sigue siendo obligatorio para acceder a él.
playbulbCandle.js
let options = {filters:[{services:[ CANDLE_SERVICE_UUID ]}],
optionalServices: ['battery_service']};
return navigator.bluetooth.requestDevice(options)
Como antes, conectaremos esto a app.js
llamando a playbulbCandle.getBatteryLevel
una vez que tengamos el nombre del dispositivo y mostremos el nivel de batería.
app.js
document.querySelector('#connect').addEventListener('click', event => {
playbulbCandle.connect()
.then(() => {
console.log(playbulbCandle.device);
document.querySelector('#state').classList.remove('connecting');
document.querySelector('#state').classList.add('connected');
return playbulbCandle.getDeviceName().then(handleDeviceName)
.then(() => playbulbCandle.getBatteryLevel().then(handleBatteryLevel));
})
.catch(error => {
console.error('Argh!', error);
});
});
function handleDeviceName(deviceName) {
document.querySelector('#deviceName').value = deviceName;
}
function handleBatteryLevel(batteryLevel) {
document.querySelector('#batteryLevel').textContent = batteryLevel + '%';
}
En este punto, visita tu sitio en tu navegador web (haciendo clic en la URL del servidor web destacada en la app del servidor web) o simplemente actualiza la página existente. Haz clic en el botón “Conectar” de la página. Allí deberías ver el nombre del dispositivo y el nivel de batería.
Cuál es el próximo paso
- ¿Cómo puedo cambiar el color de esta bombilla? Por eso estoy aquí.
- Te prometo que estás tan cerca...
Preguntas frecuentes
6. Cambiar el color
Cambiar el color es tan fácil como escribir un conjunto específico de comandos en una característica de Bluetooth (0xFFFC
) en el servicio GATT principal anunciado como 0xFF02
. Por ejemplo, si cambias la vela PLAYBULB a rojo, estaría escribiendo un array de números enteros sin signo de 8 bits iguales a [0x00, 255, 0, 0]
, donde 0x00
es la saturación de blancos y 255, 0, 0
son, respectivamente, los valores de rojo, verde y azul .
Usaremos characteristic.writeValue
para escribir algunos datos en la característica de Bluetooth en el nuevo método público setColor
de la clase PlaybulbCandle
. También mostraremos los valores reales de rojo, verde y azul cuando se cumpla la promesa para que podamos usarlos en app.js
más adelante:
playbulbCandle.js
const CANDLE_COLOR_UUID = 0xFFFC;
...
setColor(r, g, b) {
let data = new Uint8Array([0x00, r, g, b]);
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_COLOR_UUID))
.then(characteristic => characteristic.writeValue(data))
.then(() => [r,g,b]);
}
Actualicemos la función changeColor
en app.js
para llamar a playbulbCandle.setColor
cuando se muestre el resultado "Sin efecto" el botón de selección esté marcado. Las variables de color r, g, b
globales ya están configuradas cuando el usuario hace clic en el lienzo del selector de color.
app.js
function changeColor() {
var effect = document.querySelector('[name="effectSwitch"]:checked').id;
if (effect === 'noEffect') {
playbulbCandle.setColor(r, g, b).then(onColorChanged);
}
}
En este punto, visita tu sitio en tu navegador web (haciendo clic en la URL del servidor web destacada en la app del servidor web) o simplemente actualiza la página existente. Haz clic en el botón “Conectar” de la página y haz clic en el selector de color para cambiar el color de la vela de PLAYBULB tantas veces como desees.
Efectos de velas moradas
Si ya has encendido una vela antes, sabrás que la luz no es estática. Por suerte para nosotros, hay otra característica Bluetooth (0xFFFB
) en el servicio principal GATT, anunciada como 0xFF02
, que le permite al usuario configurar algunos efectos de vela.
Configurar un “efecto de vela” Por ejemplo, se puede lograr escribiendo [0x00, r, g, b, 0x04, 0x00, 0x01, 0x00]
. También puedes establecer el "efecto de flash" con [0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00]
.
Agreguemos los métodos setCandleEffectColor
y setFlashingColor
a la clase PlaybulbCandle
.
playbulbCandle.js
const CANDLE_EFFECT_UUID = 0xFFFB;
...
setCandleEffectColor(r, g, b) {
let data = new Uint8Array([0x00, r, g, b, 0x04, 0x00, 0x01, 0x00]);
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_EFFECT_UUID))
.then(characteristic => characteristic.writeValue(data))
.then(() => [r,g,b]);
}
setFlashingColor(r, g, b) {
let data = new Uint8Array([0x00, r, g, b, 0x00, 0x00, 0x1F, 0x00]);
return this.device.gatt.getPrimaryService(CANDLE_SERVICE_UUID)
.then(service => service.getCharacteristic(CANDLE_EFFECT_UUID))
.then(characteristic => characteristic.writeValue(data))
.then(() => [r,g,b]);
}
Actualicemos la función changeColor
en app.js
para llamar a playbulbCandle.setCandleEffectColor
cuando el "Efecto de vela" el botón de selección está marcado y playbulbCandle.setFlashingColor
cuando el ícono "Intermitente" está marcado el botón de selección esté marcado. Esta vez, usaremos switch
si te parece bien.
app.js
function changeColor() {
var effect = document.querySelector('[name="effectSwitch"]:checked').id;
switch(effect) {
case 'noEffect':
playbulbCandle.setColor(r, g, b).then(onColorChanged);
break;
case 'candleEffect':
playbulbCandle.setCandleEffectColor(r, g, b).then(onColorChanged);
break;
case 'flashing':
playbulbCandle.setFlashingColor(r, g, b).then(onColorChanged);
break;
}
}
En este punto, visita tu sitio en tu navegador web (haciendo clic en la URL del servidor web destacada en la app del servidor web) o simplemente actualiza la página existente. Haz clic en el botón “Conectar” de la página y juega con velas y efectos de flash.
Cuál es el próximo paso
- ¿Eso es todo? ¿3 efectos de velas malos? ¿Es por eso que estoy aquí?
- Hay más, pero trabajarás por tu cuenta esta vez.
7. Haz un esfuerzo adicional
¡Aquí estamos! Tal vez pienses que está por el final, pero la app aún no termina. Veamos si entendiste lo que copiaste y pegaste durante este codelab. Esto es lo que quieres hacer por tu cuenta para que esta app se destaque.
Agregar los efectos que faltan
A continuación, se muestran los datos de los efectos faltantes:
- Pulso:
[0x00, r, g, b, 0x01, 0x00, 0x09, 0x00]
(es posible que desees ajustar los valores der, g, b
allí) - Arcoíris:
[0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00]
(Las personas epilépticas quieren evitar este) - Atenuación de arcoíris:
[0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x00]
Básicamente, esto significa agregar nuevos métodos setPulseColor
, setRainbow
y setRainbowFade
a la clase PlaybulbCandle
y llamarlos en changeColor
.
Cómo corregir la configuración “sin efecto”
Como habrás notado, la expresión "sin efecto" no restablece ningún efecto en curso. Esto es menor, pero igual. Tiene una solución. En el método setColor
, primero deberás verificar si hay un efecto en curso a través de una nueva variable de clase _isEffectSet
y, si es true
, desactivar el efecto antes de configurar un nuevo color con estos datos: [0x00, r, g, b, 0x05, 0x00, 0x01, 0x00]
.
Escribir nombre del dispositivo
Esto es fácil. Escribir un nombre de dispositivo personalizado es tan simple como escribir en la característica de nombre del dispositivo Bluetooth anterior. Te recomendamos que uses el método TextEncoder
encode
para obtener un Uint8Array
que contenga el nombre del dispositivo.
Luego, agrego una "entrada" eventListener
a document.querySelector('#deviceName')
y llama a playbulbCandle.setDeviceName
para simplificar el proceso.
Personalmente, le llamé a la mía PLAY💡 VENTAJA.
8. Eso es todo.
Qué aprendiste
- Cómo interactuar con un dispositivo Bluetooth cercano en JavaScript
- Cómo usar clases, funciones de flecha, mapas y promesas de ES2015
Próximos pasos
- Obtén más información sobre la API de Web Bluetooth
- Explora los ejemplos y las demostraciones oficiales de Bluetooth web.
- Echa un vistazo al gato gruñón volador