Majid Hajian
mhadaily
import HelloWorld from "@/components/HelloWorld.component";
export default {
name: "whoAmI",
data: {
me: {
name: "Majid Hajian",
location: "Oslo, Norway",
description: ```
Passionate Software engineer,
Community Leader, Author and international Speaker
```,
main: "Web, Javascripter, Flutter/Dart, IoT",
homepage: "https://www.majidhajian.com",
socials: {
twitter: "https://www.twitter.com/mhadaily",
github: "https://www.github.com/mhadaily"
},
books: {
"Progressive Web App with Angular": {
version: "1.0.0",
publishedBy: "Apress",
foundOn: "www.pwawithangular.com",
}
},
author: {
packtpub: "PWA development, 7 hours video course",
Udemy: "PWA development, 7 hours video course"
}
founder: "Softiware As (www.Softiware.com)"
devDependencies: {
tea: "green", mac: "10.14+",
},
engines: {
VueJsOslo: "Orginizer", MobileEraConference: "Orginizer",
ngVikingsConference: "Orginizer",
MobileMeetupOslo:"Co-Orginizer",AngularOslo: "Co-Orginizer",
FlutterDartOslo: "Co-Orginizer",Framsia: "Co-Orginizer",
}};}
};
To show beyond the web and unleash the power of hardware connectivity and internet of things on the progressive web
mhadaily
WebBluetooth
WebUSB
WebNFC
Progressive Web Apps
Internt of Things (WebThings)
mhadaily
Reliable
Fast
Engaging
Reliable
Linkable
Engaging
Secure
Progressive by nature
Native-like User Experince
mhadaily
Responsiveness
Fast
Discoverable
mhadaily
mhadaily
mhadaily
Delicious if prepared correctly, deadly if not
mhadaily
mhadaily
mhadaily
The Web of Things connects real-world objects to the World Wide Web.
Classic Bluetooth
Bluetooth Smart
Bluetooth Low Energy Bluetooth4, 5
BLE, Bluetooth LE
sucks
mhadaily
Central
Peripheral
mhadaily
Central
mhadaily
GATT
mhadaily
Central
Peripheral
Client
Server
mhadaily
Server
mhadaily
Server
Service
Service
mhadaily
Server
Service
Service
Characteristic
Characteristic
Characteristic
Characteristic
mhadaily
Server
Service
Service
Characteristic
properties
Value
Characteristic
properties
Value
Characteristic
properties
Value
Characteristic
properties
Value
mhadaily
Server
Service
Service
Characteristic
properties
Value
Characteristic
properties
Value
Characteristic
properties
Value
Characteristic
properties
Value
Services and characteristics are identified by 16 or 128 bit UUIDs.
characteristics have different properties such as read, write, write without response, notify, indicate and ...
Values are just an array of bytes
mhadaily
mhadaily
requestHTMLButton.addEventListener('click', async function() {
// Logic
});
mhadaily
const options = {
filters: [
{ namePrefix: 'Polar' }
],
};
const device = await navigator.bluetooth.requestDevice(options);
const server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE);
const character = await service.getCharacteristic(CHARACTERISTIC);
character.oncharacteristicvaluechanged = () => {
const value = event.target.value;
const currentHeartRate = parseHeartRate(value);
// Update UI or do your logic
};
await character.startNotifications();
Request the device
mhadaily
const options = {
filters: [
{ namePrefix: 'Polar' }
],
};
const device = await navigator.bluetooth.requestDevice(options);
const server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE);
const character = await service.getCharacteristic(CHARACTERISTIC);
character.oncharacteristicvaluechanged = () => {
const value = event.target.value;
const currentHeartRate = parseHeartRate(value);
// Update UI or do your logic
};
await character.startNotifications();
Request the device
mhadaily
const options = {
filters: [
{ namePrefix: 'Polar' }
],
};
const device = await navigator.bluetooth.requestDevice(options);
const server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE);
const character = await service.getCharacteristic(CHARACTERISTIC);
character.oncharacteristicvaluechanged = () => {
const value = event.target.value;
const currentHeartRate = parseHeartRate(value);
// Update UI or do your logic
};
await character.startNotifications();
Connect to Gatt
mhadaily
const options = {
filters: [
{ namePrefix: 'Polar' }
],
};
const device = await navigator.bluetooth.requestDevice(options);
const server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE);
const character = await service.getCharacteristic(CHARACTERISTIC);
character.oncharacteristicvaluechanged = () => {
const value = event.target.value;
const currentHeartRate = parseHeartRate(value);
// Update UI or do your logic
};
await character.startNotifications();
Get a Service
mhadaily
const options = {
filters: [
{ namePrefix: 'Polar' }
],
};
const device = await navigator.bluetooth.requestDevice(options);
const server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE);
const character = await service.getCharacteristic(CHARACTERISTIC);
character.oncharacteristicvaluechanged = () => {
const value = event.target.value;
const currentHeartRate = parseHeartRate(value);
// Update UI or do your logic
};
await character.startNotifications();
Get a Characteristic
mhadaily
const options = {
filters: [
{ namePrefix: 'Polar' }
],
};
const device = await navigator.bluetooth.requestDevice(options);
const server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE);
const character = await service.getCharacteristic(CHARACTERISTIC);
character.oncharacteristicvaluechanged = () => {
const value = event.target.value;
const currentHeartRate = parseHeartRate(value);
// Update UI or do your logic
};
await character.startNotifications();
Start Notifying
Listen to value change and read value
mhadaily
const characteristic = await service.getCharacteristic(`heart_rate_control_point`);
console.log('Writing Heart Rate Control Point Characteristic...');
// Writing 1 is the signal to reset energy expended.
const resetEnergyExpended = Uint8Array.of(1);
await characteristic.writeValue(resetEnergyExpended);
const characteristic = await service.getCharacteristic(`battery_level`);
const value = await characteristic.readValue();
let batteryLevel = value.getUint8(0);
console.log('> Battery Level is ' + batteryLevel + '%');
mhadaily
// Discovery options match any devices advertising:
// . The standard heart rate service.
// . Both 16-bit service IDs 0x1802 and 0x1803.
// . A proprietary 128-bit UUID service c48e6067-5295-48d3-8d5c-0395f61792b1.
// . Devices with name "ExampleName".
// . Devices with name starting with "Prefix".
//
// And enables access to the battery service if devices
// include it, even if devices do not advertise that service.
const options = {
filters: [
{services: ['heart_rate']},
{services: [0x1802, 0x1803]},
{services: ['c48e6067-5295-48d3-8d5c-0395f61792b1']},
{name: 'Polar H7'},
{namePrefix: 'Polar'}
],
optionalServices: ['battery_service']
}
const options2 = {
acceptAllDevices: true,
}
mhadaily
mhadaily
PWA
Setup Gateway
WebThings Gateway
+
BluetoothWiFi
Manager
Connect Via WebBluetooth
Check List of Wifi SSIDs
Connect to Wifi
Go to WebThings PWA
mhadaily
mhadaily
The WebUSB API provides a way to safely expose USB device services to the web.
- webUSB spec
mhadaily
It provides an API familiar to developers who have used existing native USB libraries and exposes the device interfaces defined by existing specifications.
- webUSB spec
mhadaily
Cross-platform Javascript SDKs
Hot patch easily
rapidly prototype
Combine with other web tech
Fast to Make
mhadaily
HTTPS only
No Native Code Needed
User Gesture required
mhadaily
Device Descriptor
mhadaily
Device Descriptor
Config Descriptor
Config Descriptor
mhadaily
Device Descriptor
Config Descriptor
Config Descriptor
Interface Descriptor
Interface Descriptor
Interface Descriptor
Interface Descriptor
mhadaily
Device Descriptor
Config Descriptor
Config Descriptor
Interface Descriptor
Interface Descriptor
Interface Descriptor
Interface Descriptor
Endpoint Descriptor
Endpoint Descriptor
Endpoint Descriptor
Endpoint Descriptor
Endpoint Descriptor
Endpoint Descriptor
Endpoint Descriptor
Endpoint Descriptor
mhadaily
requestHTMLButton.addEventListener('click', async function() {
// Logic
});
mhadaily
const options = {
filters: [{ vendorId: 0x22b8, productId: 0x2e76 }]
};
const _device = await navigator.usb.requestDevice(options);
const device = await _device.open();
await device.selectConfiguration(0);
await device.claimInterface(0);
// Transfer Out ->
// Transfer In <-
mhadaily
const options = {
filters: [{ vendorId: 0x22b8, productId: 0x2e76 }]
};
const _device = await navigator.usb.requestDevice(options);
const device = await _device.open();
await device.selectConfiguration(0);
await device.claimInterface(0);
// Transfer Out ->
// Transfer In <-
mhadaily
const options = {
filters: [{ vendorId: 0x22b8, productId: 0x2e76 }]
};
const _device = await navigator.usb.requestDevice(options);
const device = await _device.open();
await device.selectConfiguration(0);
await device.claimInterface(0);
// Transfer Out ->
// Transfer In <-
mhadaily
const options = {
filters: [{ vendorId: 0x22b8, productId: 0x2e76 }]
};
const _device = await navigator.usb.requestDevice(options);
const device = await _device.open();
await device.selectConfiguration(0);
await device.claimInterface(0);
// Transfer Out ->
// Transfer In <-
mhadaily
/*
vendorId
productId
classCode
subclassCode
protocolCode
serialNumber
*/
const options = {
filters: [
{
vendorId: 0x22b8,
productId: 0x2e76,
serialNumber: 'ZY223SD2TP'
}
]
};
mhadaily
INTERRUPT
CONTROL
IN
OUT
Non-periodic, small,
device "initiated communication
-> small amount of time sensitive data
mhadaily
// Out
const endpointNumber = 1;
const data = 'VueJs';
await device.transferOut(endpointNumber, data);
// In
const length = 8;
await device.trasnferIn(endpointNumber, length);
mhadaily
INTERRUPT
CONTROL
IN
OUT
Non-periodic, small,
device "initiated communication
-> small amount of time sensitive data
Good for small configuration commands
mhadaily
const data = 'VueJs';
const length = 64;
const setup = {
requestType: 'class', // standard, vendor
recipient: 'interface', // device, endpoint, other
request: 0x22, // vendor-specefic command
value: 0x01, // vendor-specefic request
index: 0x02 // endpoint
};
// out
await device.controlTransferOut(setup, data);
// in
await device.controlTransferIn(setup, length);
mhadaily
INTERRUPT
CONTROL
ISOCHRONOUS
IN
OUT
Good for small configuration commands
Non-periodic, small,
device "initiated communication
-> small amount of time sensitive data
used for streams of data like video and sound
mhadaily
// Isochronous transfer
const _data = ArrayBuffer(8);
const endpointNumber = 1;
const length = 64;
const packetLength = 8;
// out
await device.isochronousTransferOut(endpointNumber, _data, length);
// in
await device.isochronousTransferIn(endpointNumber, packetLength);
mhadaily
System information / Chrome device info
mhadaily
mhadaily
kenneth christiansen
The hardware standard is defined in NFC Forum Technical Specifications
As of 6 Nov 2019, The current scope of the specification is NDEF
An NFC tag is a passive NFC device.
The NFC tag is powered by magnetic induction when an active NFC device is in proximity range. An NFC tag contains a single NDEF message.
An NFC peer is an active, powered device,
which can interact with other devices in order to exchange data using NFC.
NFC device
The NFC Data Exchange Format (NDEF) is a standardized data format that can be used to exchange information between any compatible NFC device and another NFC device or tag.
The data format consists of NDEF Messages and NDEF Records.
chrome://flags
"Experimental Web Platform Features"
"Web NFC"
Your Mobile should support NFC
mhadaily
const writer = new NDEFWriter();
const encoder = new TextEncoder();
await writer.push(
{
records: [
{
id: '/pwathing/web-nfc',
recordType: 'mime',
mediaType: 'application/json',
data: encoder.encode(
JSON.stringify({
id: '12345678900987654321',
name: 'Majid',
role: 'Cashier'
})
)
},
{ recordType: 'url', data: 'https://w3c.github.io/web-nfc/' },
{ recordType: 'text', data: 'Hello World' },
{
id: '/pwathing/web-nfc',
recordType: 'mime',
mediaType: 'application/json',
data: encoder.encode(
JSON.stringify({
id: '12345678900987654322',
name: 'John',
role: 'Unknown'
})
)
}
]
}
);
if (typeof NDEFReader !== 'undefined' || typeof NDEFWriter !== 'undefined') {
const reader = new NDEFReader();
reader.onreading = ({ message }: any) => {
if (message.records.length == 0 || message.records[0].recordType == 'empty') {
return;
}
const decoder = new TextDecoder();
for (let record of message.records) {
console.log('RecordType', record.recordType, record);
if (record.recordType === 'mime') {
if (record.mediaType === 'application/json') {
const _record = JSON.parse(decoder.decode(record.data));
console.log(_record);
}
}
}
};
reader.scan({
mediaType: 'application/json'
// recordType: "w3.org:webnfc",
// id: "https://mygame.com/mypath/mygame",
});
}
mhadaily
WebBluetooth
WebUSB
WebNFC
Progressive Web Apps
Internt of Things (WebThings)
mhadaily
RESOURCES
Chromium https://goo.gle/fugu-api-tracker
https://github.com/SamsungInternet/SamsungBluetoothWiFiManager
Deep dive into the Service worker, Majid Hajian, https://vimeo.com/273475511
Slides and link to source code
bit.ly/pwa-things-jsfest2019
mhadaily
Majid Hajian
mhadaily