Majid Hajian

Things in

 

 

Era

mhadaily

<ME />

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

The Talk's Aim

To show beyond the web and unleash the power of hardware connectivity and internet of things on the progressive web

mhadaily

SIMPLIFIED

What will be explored

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

Service Worker 

Web App Manifest

mhadaily

mhadaily

Project Fugu

Delicious if prepared correctly, deadly if not

 

mhadaily

mhadaily

 Gartner says that by 2020

there will be

over 26 billion connected devices

mhadaily

Web of Things

The Web of Things connects real-world objects to the World Wide Web.

Yesssss,

The web is capable of doing that

Web Bluetooth

Classic Bluetooth

Bluetooth Smart

Bluetooth Low Energy
Bluetooth4, 5

BLE, Bluetooth LE

sucks

mhadaily

Central

Peripheral

mhadaily

Central

mhadaily

Generic attribute profile

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

Before going forward...

mhadaily

requestHTMLButton.addEventListener('click', async function() {

    // Logic
  
});

User Interaction

HTTPS Only

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

USB

WEB

The WebUSB API provides a way to safely expose USB device services to the web.

 

 

- webUSB spec

https://wicg.github.io/webusb/

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

https://wicg.github.io/webusb/

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

FACTS

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
  
});

User Interaction

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 <-

Device Descriptor 

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 <-

Device Descriptor 

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 <-

Device Descriptor 

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 <-

Device Descriptor 

mhadaily

    /*
        vendorId
        productId
        classCode
        subclassCode
        protocolCode
        serialNumber
    */

 const options = {
    filters: [
       { 
            vendorId: 0x22b8, 
            productId: 0x2e76, 
            serialNumber: 'ZY223SD2TP' 
       }
    ]
  };

mhadaily

Transfer Types

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);

Interrupt transfer

mhadaily

Transfer Types

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);

Control transfer

mhadaily

Transfer Types

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);

Isochronous transfer

mhadaily

System information / Chrome device info 

mhadaily

mhadaily

Web NFC

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

Web NFC

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

NDEF (NFC Data Exchange Format)

 

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

Chrome

Android

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

What we have learned

WebBluetooth
WebUSB
WebNFC
Progressive Web Apps
Internt of Things (WebThings)

mhadaily

Slides and link to source code

bit.ly/pwa-things-jsfest2019

mhadaily

Majid Hajian

mhadaily