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
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.
mhadaily
chrome://flags
"Experimental Web Platform Features"
"Web NFC"
Your Mobile should support NFC
await navigator.nfc.watch(
async function(message) {
if (message.records[0].recordType === 'empty') {
writeToTag();
}
processMessage(message);
},
{ mode: 'any' }
);
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'
})
)
}
]
}
);
mhadaily
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
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.