Majid Hajian

Hardware Connectivity

on

mhadaily

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

Secure

Progressively

Enhancement

Native-like

User Experince

mhadaily

mhadaily

Service Worker 

Web App Manifest

mhadaily

Project Fugu

Delicious if prepared correctly, deadly if not

 

mhadaily

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.

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

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 = 'Cool';
  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

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

Chrome

Android

mhadaily

const reader = new NFCReader();

reader.onreading = event => {
  for (let record of event.message.records) {
    // ...    
  }
};

const ctr = new AbortController;
reader.scan({ signal: ctr.signal });

New Proposed API

 

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

Slides and link to source code

bit.ly/hw-pwa

 

Majid Hajian

mhadaily

Made with Slides.com