0.0.1 • Published 3 years ago

@neukolabs/neuko-js-device-sdk v0.0.1

Weekly downloads
-
License
ISC
Repository
github
Last release
3 years ago

js-device-sdk

This device SDK will be a starting point to build Neuko SDK for device.

The main idea in using the SDK is based on state management as what we have in React. You may think of this as a react-redux but for IoT device.

Every device typically works by watching, executing and updating its own state. For instance, if you take a Raspberry PI, the each of the pin on the board can be represented as the state. For example,

{
    "digital_input": {
        "pin1": true,
        "pin2": false
    }
}

Or lets use Maevi Smart Plug. We can define the plug state as below:

{
    "information": {
        "ieee": "123",
        "ep": 1,
        "netDeviceStatus": 256,
        "name": "Room 1 General Socket"
    },
    "electricity": {
        "switchgear": "on",
        "consumption": {
            "active_power": 1.3,
            "cumulative_energy": 12.9,
            "active_power_unit": "kW",
            "cumulative_energy_unit": "kWh"
        }
    }
}

With above state definition, this SDK will group the state into 2 states: 1. information 2. electricity

Following the methods exposed by the Device class, you can actually update, watch and execute the state when there is a request to change or being changed between actual device and cloud.

This SDK exposed Device class in which you can use ES2015 inheritance style or creating new instance as object.

Installation

Should be (I don't know yet)

yarn add https://github.com/neukolabs/js-device-sdk

Usage ES2015

    const { Device } = require("js-device-sdk"); // maybe. Aku xpernah try pon cmni

    class SmartPlug extends Device {
        constructor(deviceId, deviceAttributes, connectionOptions) {
            super(deviceId, deviceAttributes, connectionOptions)
        }

        ...
    }

Usage as Object

    const { Device } = require("js-device-sdk"); // maybe. Aku xpernah try pon cmni

    let smartPlug = new Device(deviceId, deviceAttributes, connectionOptions);

ConnectionOptions

ConnectionOptions defines parameters required to connect to MQTT Broker and HTTP Server.

  • ConnectionnOptions
    • deviceId - Unique identifier for device in context. If this is null, a random ID will be created
    • brokerEndpoint - Endpoint to IoT platform. OMIT protocol value. e.g. iot.endpoint.com
    • tlsOptions
      • ca - Certificate Authority
      • key - Private key certificate
      • cert - Public certificate
    • recycleClients - If this is null, new clients will be created and populated. If you provide value, the connection will be reused instead of new connection

example

    const ConnectionOptions = require("../clients/connection-options");

    const connectionOptios = new ConnectionOptions(
        "js-device-sdk-test-demojs", 
        "a3ubgz3tzfk7uk-ats.iot.ap-southeast-1.amazonaws.com", 
        {
            ca: fs.readFileSync(CA_PATH),
            key: fs.readFileSync(KEY_PATH),
            cert: fs.readFileSync(CERT_PATH)
        }
    )
    
    let myDevice = new MyDevice(deviceId, deviceAttributes, connectionOptios);

Device State

Device's state defined with state's name and its value. The value MUST NOT EXCEED 5 tiers.

Format

{
    "StateName1": {
        "Key1": Value
        "Key2": [],
        "Key3": {
            "Key31": {
                "Key32": {
                    "Key33": {
                        "Key34": {
                            "Key35": Value
                        }
                    }
                }
            }
        }
    },
    ...
}

Example

Sample below shows 2 different states.

{
    "electricity": {
        "switchgear": "on",
        "consumption": {
            "power": 1.2,
            "energy": 33.2,
            "power_unit": "kW",
            "energy_unit": "kWh"
        }
    },
    "information": {
        "firmware_version": "version1.2.3",
        "link_status": true
    }
}

Device State Changed Request Payload

Payload provided when state changed request.

  • deviceId - Device unique identifier
  • stateName - State's name with changes
  • payload
    • state - An object with state attribute's name and value

Example

{
    "deviceId": "device_id",
    "stateName": "state_name",
    "payload": {
        "state": {
            "key1": false
        }
    }
}

or

{
    "deviceId": "device_id",
    "stateName": "state_name",
    "payload": {
        "state": {
            "key1.key2": 123
        }
    }
}

Device Methods

initialize()

Initializing the object class and set the default state to the cloud.

    let device = new Device(...args);

    device.initialize({
        stateA: {
            attrA: false
        },
        stateB: {
            attr1: 44122
        }
    })

registerStateChangedFunction(context, stateName, listener, filterAttribute)

This function register the listener to be invoked when any watched state changed.

Parameters

  • context - Caller context
  • stateName - State name to be watched
  • listener - Function callback to be invoked
  • filterAttribbute - Optional. You can watch towards specific attribute in the state using dot path. If you omit this parameter, any attribute changed will invoke the listener.

Notes

The listener function will be passed with 2 arguments 1. context - the context when registered 2. data - object with below information

The data has a structure in such

{
    "deviceId": "<deviceId",
    "stateName": "stateName",
    "changeState": {
        "path.to.attribute": "value"
    }
}

Example

e.g One of the state named plug

{
    "plug": {
        "pin_d01": true,
        "digital_input": {
            "pin_d32": false
        }
    }
}

And you want to watch pin_d32, so

    function onPinD32Changed(context, data) {
        // ... do something
    }

    // register the function
    device.registerStateChangedFunction(this, "plug", this.onPinD32Changed, "digital_input.pin_d32");

synchronizeState()

This function will synchronize the state as per request by executing the function registered to the state or/and attribute.

:warning Make sure you have registered functions (using registerStateChangedFunction()) to be invoked when state changed request before calling synchronizeState().

Example

    // above code already initialize and register several function

    // sync the state cloud vs actual
    await device.synchronizeState();

updateOrCreateState(stateName, state)

This will update or create a new state with state value if not existed yet. You can update whole state's attributes or partial attribute.

This method usually being called when the actual device changed its state and your function being invoked because of that, in which, you want to state at the cloud.

Notes. This function handles the interval to update the cloud. Which means, although you may update at fast interval, it will be the one that actually decide to update the cloud or not. If the state is being configured (at cloud level) to be stored as timestream data such as power data, it will automatically handles for you.

Also it will publish at certain topic when there is client watches the device. (Still in development)

Parameters

  • stateName - State name to be watched
  • state - JSON object of the state. You can pass full object or partial object. They will be merged in the cloud.

Example

    await device.updateOrCreateState("plug", {
        "pin_d01": false
    })

stateChangeRequestCompleted(stateName, newState)

This function needs to be called when the actual device already fullfilled the state request changed.

Parameters

  • stateName - State name to be watched
  • state - JSON object of the state. You can pass full object or partial object. They will be merged in the cloud.

Example

    async function onPinD32Changed(context, data) {
        // ... do something to the actual device
        // once success update the cloud
        super.stateChangeRequestCompleted(data.stateName, {
            "digital_input": {
                "pin_d32": true // new value from false
            }
        })
    }

Usage Example

Refer to example folder. There are 2 examples. 1. simple.js - A simple skeleton to show on how the Device class can be use directly as an object. 2. extends.js - Using inheritence that extend Device functionality to your class.