Majid Hajian
Majid Hajian is a passionate software developer with years of developing and architecting complex web and mobile applications. He is passionate about web platform especially flutter, IoT, PWAs, and performance.
Majid Hajian
on
mhadaily
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",
}};}
};
@mhadaily
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
Secure
Progressively
Enhancement
Native-like
User Experince
mhadaily
mhadaily
mhadaily
Delicious if prepared correctly, deadly if not
mhadaily
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
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 = 'Cool';
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
low-level API allowing Web applications to access and exchange the data with the Near-Field Communication devices, such as NFC tags.
chrome://flags
"Experimental Web Platform Features"
"Web NFC"
Your Mobile should support NFC
mhadaily
const reader = new NFCReader();
reader.onreading = event => {
for (let record of event.message.records) {
// ...
}
};
const ctr = new AbortController;
reader.scan({ signal: ctr.signal });
This api has changed as of November 8, 2019, Check out my recent Presentation to find out more
const reader = new NFCReader();
reader.onreading = event => {
for (let record of event.message.records) {
if (record.recordType === "json") {
console.log(`JSON: ${record.toJSON().myProperty}`);
}
if (record.recordType === "opaque" && record.mediaType.startsWith('image/')) {
const blob = new Blob([record.toArrayBuffer()], {type: record.mediaType});
const img = document.createElement("img");
img.src = URL.createObjectURL(blob);
img.onload = () => window.URL.revokeObjectURL(this.src);
document.body.appendChild(img);
}
}
}
};
const ctr = new AbortController;
reader.scan({ signal: ctr.signal });
This API has changed as of November 8, 2019, Check out my recent presentation to find out more
const writer = new NFCWriter();
writer.push({
records: [
{
recordType: "json",
mediaType: "application/json",
data: {
name: "Benny Jensen",
title: "Banker"
}
},
{
recordType: "json",
mediaType: "application/json",
data: {
name: "Zoey Braun",
title: "Engineer"
}
}]
}, {target: "tag", ignoreRead: false});
This API has changed as of November 8, 2019, Check out my recent presentation to find out more
mhadaily
RESOURCES
Chromium https://goo.gle/fugu-api-tracker
https://github.com/SamsungInternet/SamsungBluetoothWiFiManager
Slides and link to source code
bit.ly/hw-pwa
Majid Hajian
mhadaily
By Majid Hajian
In daily basis where billions of billion devices are connected to the internet, browsers can actually take control Things like lightbulbs, robots, printers, NFC tags, toys, drones, and many more Things via web standard APIs such as WebBluetooth, WebUSB, WebNFC, Shape Detection API and etc. How about connecting to IoT gateway which supports Wifi via BLE ?! On the other hand, Progressive web apps open a new era to build web apps that work offline and resemble native apps. PWAs are installable too, therefore, your solution to controlling Things in the real world can be written once for web and reuse everywhere. In this session, I am going through some of the web capabilities to connect devices into a progressive web app and demonstrate how the web, eventually, could go beyond the browsers. There will be lots of demos such as Connect to IoT gateway via BLE over Wifi, Drone controller, NFC reader, Android ADB connector to Web and more.
Majid Hajian is a passionate software developer with years of developing and architecting complex web and mobile applications. He is passionate about web platform especially flutter, IoT, PWAs, and performance.