2

Creating A Web IoT Javascript Package: NFC, Bluetooth, Web Serial, Web USB

 1 year ago
source link: https://jyroneparker.com/2023/02/28/creating-a-web-iot-javascript-package-nfc-bluetooth-web-serial-web-usb/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

The Source Code

Init The Project

Creating a new project and running the npm create script

mkdir web-iot && cd web-iot
npm init

The package.json looks like this:

{
  "name": "@mastashake08/web-iot",
  "version": "1.0.0",
  "description": "Connect to your IoT devices via usb, serial, NFC or Bluetooth",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/mastashake08/web-iot.git"
  },
  "keywords": [
    "iot",
    "webserial",
    "bluetooth",
    "webusb",
    "nfc"
  ],
  "author": "Mastashake",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/mastashake08/web-iot/issues"
  },
  "homepage": "https://github.com/mastashake08/web-iot#readme"
}

The index.js file

This is the entry point for the package and it simply exports our classes

import { WebIOT } from './classes/WebIOT'
import { NFCManager } from './classes/NFCManager'
import { BluetoothManager } from './classes/BluetoothManager'
import { SerialManager } from './classes/SerialManager'
import { USBManager } from './classes/USBManager'
export {
  WebIOT,
  NFCManager,
  BluetoothManager,
  SerialManager,
  USBManager
}

The WebIOT Class

This is the base class for all our managers. It contains some functions for sending data to a remote server, a functionality that’s usually needed when dealing with IoT devices.

export class WebIOT {
  debug = false
  constructor(debug = false) {
    this.debug = debug
  }
  sendData (url, options = {}, type='fetch') {
      try {
        switch (type) {
          case 'fetch':
            return this.sendFetch(url, options)
            break;
          case 'beacon':
            return this.sendBeacon(url, options)
            break;
          default:
            return this.sendFetch(url, options)
        }
      } catch (e) {
        this.handleError(e)
      }
  }

  sendBeacon (url, data) {
    try {
      navigator.sendBeacon(url, data)
    } catch (e) {
      this.handleError(e)
    }
  }

  async sendFetch(url, options) {
    try {
      const res = await fetch(url, options)
      if (res.status != 200) {
        throw new Error(`HTTP error! Status: ${res.status}`)
      } else {
        return res
      }
    } catch (e) {
      this.handleError(e)
    }
  }

  handleError (e) {
    if(this.debug) {
      alert(e.message)
      console.log(e.message)
    } else {
      throw e
    }
  }
}

The USBManager

The USBManager is responsible for working with USB devices.

import { WebIOT } from './WebIOT'
export class USBManager extends WebIOT{
  #devices = {}
  #selectedDevice = {}
  constructor (debug = false) {
    super(debug)
  }

  async getDevices () {
    this.devices = await navigator.usb.getDevices()
    return this.devices
  }

  async requestDevice(options = {}) {
    this.selectedDevice = this.selectedDevice = await navigator.usb.requestDevice(options)
    return this.selectedDevice
  }

  async openDevice() {
    await this.connectDevice()
  }

  async closeDevice(options) {
    await this.selectedDevice.close()
  }

  async connectDevice() {
    await this.selectedDevice.open();
    if (this.selectedDevice.configuration === null)
      await this.selectedDevice.selectConfiguration(1);
    await this.selectedDevice.claimInterface(0);
    return this.selectedDevice

  }

  async writeData(endpointNumber, data) {
    return await this.selectedDevice.transferOut(endpointNumber, data)
  }
  async readData(endpointNumber, data) {
    return await this.selectedDevice.transferIn(endpointNumber, data)
  }
}

}

The SerialManager

The SerialManager class manages serial connections.

import { WebIOT } from './WebIOT'
export class SerialManager extends WebIOT {
  #ports = {}
  #selectedPort = {}
  constructor (debug = false) {
    super(debug)
  }

  async getPorts () {
    this.ports = await navigator.serial.getPorts()
    return this.ports
  }

  async requestPort(options = {}) {
    this.selectedPort = this.selectedPort = await navigator.serial.requestPort(options)
    return this.selectedPort
  }

  async openPort(options) {
    await this.selectedPort.open(options)
  }

  async closePort(options) {
    await this.selectedPort.close()
  }

  async getInfo() {
    await this.selectedPort.getInfo()
  }

  async setSignals(options) {
    await this.selectedPort.setSignals(options)
  }

  async getSignals() {
    return await this.selectedPort.getSignals()
  }

  async readData () {
    const reader = this.selectedPort.readable.getReader();

    // Listen to data coming from the serial device.
    while (true) {
      const { value, done } = await reader.read();
      if (done) {
        // Allow the serial port to be closed later.
        reader.releaseLock();
        break;
      }
      // value is a Uint8Array.
      return value
    }
  }

  async writeData(data) {
    const writer = port.writable.getWriter();

    await writer.write(data);
    // Allow the serial port to be closed later.
    writer.releaseLock();
  }
}

The BluetoothManager

The BluetoothManager is responsible for managing Bluetooth devices

import { WebIOT } from './WebIOT'
export class BluetoothManager extends WebIOT {
  #bluetooth = {}
  #device = {}
  #server = {}
  #selectedService = {}
  #services = {}
  #characteristic = {}
  #currentValue = null
  constructor (debug = false) {
    super(debug)
    navigator.bluetooth.getAvailability().then((available) => {
      if (available) {
        this.bluetooth = navigator.bluetooth
      } else {
        alert("Doh! Bluetooth is not supported");
      }
    });

  }

  async getDevices (options = {acceptAllDevices: true}) {
    return await this.requestDevice(options)
  }

  async requestDevice (options) {
    try {
      this.device = await navigator.bluetooth.requestDevice(options)
      return this.device
    } catch(e) {
      alert(e.message)
    }
  }

  async connectToServer () {
    this.server = await this.device.gatt.connect()
  }

  async getService (service) {
    this.selectedService = await this.server.getPrimaryService(service)
    return this.selectedService
  }

  async getServices () {
    this.services = await this.server.getPrimaryServices()
    return this.services
  }

  async getCharacteristic (char) {
    this.characteristic = await this.selectedService.getCharacteristic(char)
    return this.characteristic
  }

  async getCharacteristics () {
    return await this.selectedService.getCharacteristics()
  }

  async getValue () {
    this.currentValue = await this.characteristic.readValue()
    return this.currentValue
  }

  async writeValue(data) {
    await this.characteristic.writeValue(data)
  }
}

The NFCManager

Work with NFC tags with the NFCManager

import { WebIOT } from './WebIOT'
export class NFCManager extends WebIOT {
  #nfc = {}
  constructor (debug = false) {
    super(debug)
    if ('NDEFReader' in window) { /* Scan and write NFC tags */
      this.nfc = new NDEFReader()
    } else {
      alert('NFC is not supported in your browser')
    }

  }

  startNFC () {

    this.nfc = new NDEFReader()
  }
  async readNFCData (readCb, errorCb = (event) => console.log(event)) {
    this.nfc.onreading = readCb()
    await this.nfc.scan()
  }
  async writeNFCData (records, errorCb = (event) => console.log(event)) {
    try {
      await this.nfc.write(records)
    } catch (e) {
      errorCb(e)
    }
  }
  async lockNFCTag(errorCb = (event) => console.log(event)) {
    try {
      await this.nfc.makeReadOnly()
    } catch(e) {
      errorCb(e)
    }
  }
  static generateNFC () {
    return new NDEFReader()
  }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK