@neukolabs/device-sdk-js
v1.2.0
Published
Neuko device SDK for NodeJS hardware
Downloads
4
Readme
Device SDK for NodeJS
This document provides information about the Neuko SDK that can be installed as a dependency in an IoT device.
Pre-requisites
- Neuko account (sign up here)
- Defined device type schema (refer documentation)
- Bootstrap certificates that can downloaded after define a device type schema (step 2)
Device State
Device state is the condition of the hardware at any moment. Typically, the state will be watched, executed and updated under certain circumstances. You can imagine the state of a digital board as below:
{
"digital_input": {
"pin_0": true,
"pin_1": false
},
"digital_output": {
"pin_0": true,
"pin_1": true
}
}
The above example tells us that the digital board has 2 states:
- digital input
- digital output
Also, each state has 2 attributes - pin 0 and pin 1.
The Neuko Javascript SDK works by managing the state's attributes of the device between actual physical and its virtual representation in cloud.
Prior to that, the SDK supports provisioning of a new device during 1st time connection.
Installation
Checking minimum requirement
The SDK requires Node v14 and above.
node --version
Installation
npm install --save @neukolabs/device-sdk-js
Usage
Import package
const {Device, DeviceIdentifierStore, ConnectionStore, CertificateStore } = require("@neukolabs/device-sdk-js");
Extend DeviceIdentifierStore class
class myDeviceId extends DeviceIdentifierStore {
constructor() {
super();
}
getAccountId() {
return "<Neuko Account Id>";
}
getProjectId() {
return "<Neuko Project Id>";
}
getDeviceId() {
return "<Device Serial Number / Id>";
}
getDeviceSchemaId() {
return "<Neuko Device Type Schema Id>";
}
}
Extend ConnectionStore class
class myDeviceConnStore extends ConnectionStore {
constructor() {
super();
}
dir = './tmp';
perpetualSettingPath = path.join(dir, "mydevice-perpetual-settings.json");
getPerpetualConnectionSettings(deviceIdentifier) {
return readFileSync(perpetualSettingPath).toString();
}
savePerpetualConnectionSettings(deviceIdentifier, settings) {
const dir = './tmp';
if (!existsSync(dir)){
mkdirSync(dir);
}
writeFileSync(perpetualSettingPath, settings);
}
deletePerpetualConnectionSettings(deviceIdentifier) {
return unlinkSync(perpetualSettingPath);
}
isPerpetualConnectionSettingsExists(deviceIdentifier) {
return existsSync(perpetualSettingPath);
}
}
Extend CertificateStore class
class myDeviceCertStore extends CertificateStore {
BOOTSTRAP_CA_PATH = "./security/bootstrap/root_ca.pem";
BOOTSTRAP_KEY_PATH = "./security/bootstrap/private_key.pem";
BOOTSTRAP_CERT_PATH = "./security/bootstrap/certificate.pem";
PERPETUAL_CA_PATH = "./security/perpetual/root_ca.pem";
PERPETUAL_KEY_PATH = "./security/perpetual/private_key.pem";
PERPETUAL_CERT_PATH = "./security/perpetual/certificate.pem";
getBootstrapCertificateAuthority(deviceIdentifier) {
return readFileSync(this.BOOTSTRAP_CA_PATH);
}
getBootstrapChainCertificate(deviceIdentifier) {
return readFileSync(this.BOOTSTRAP_CERT_PATH);
}
getBootstrapPrivateKey(deviceIdentifier) {
return readFileSync(this.BOOTSTRAP_KEY_PATH);
}
getPerpetualCertificateAuthority(deviceIdentifier) {
return readFileSync(this.PERPETUAL_CA_PATH);
}
getPerpetualChainCertificate(deviceIdentifier) {
return readFileSync(this.PERPETUAL_CERT_PATH);
}
getPerpetualPrivateKey(deviceIdentifier) {
return readFileSync(this.PERPETUAL_KEY_PATH);
}
savePerpetualCertificateAuthority(deviceIdentifier, certificate) {
writeFileSync(this.PERPETUAL_CA_PATH, certificate);
}
savePerpetualChainCertificate(deviceIdentifier, certificate) {
writeFileSync(this.PERPETUAL_CERT_PATH, certificate);
}
savePerpetualPrivateKey(deviceIdentifier, certificate) {
writeFileSync(this.PERPETUAL_CERT_PATH, certificate);
}
}
Create Device class instance
const device = new Device();
device.identifierStore = new myDeviceId();
device.connectionStore = new myDeviceConnStore();
device.certificateStore = new myDeviceCertStore();
await device.start();
Methods
start()
This function start the SDK or in other words starts the virtual/twin of the device. The function also provisions the device with Neuko registry if it is yet to be registered. A provisioned device will stay in its perpetual state.
Important Only called this function after you have registered (by useEffect method) the handler to be invoked when any of the telemetric state has any changed request.
useEffect(context: any, stateName: string, attributeTree: string = "*", listener: Function, listenerSignature?: string)
Use effect attaches a listener or function handler to any state's attributes. The parameters details are as below:
context - Class or any object of context. (eg. this)
stateName - the name of the state.
attributeTree - Dot notation representing state attribute. For example, if you have state as below
{
"state_name_1": {
"attr_0": true,
"attr_1": {
"deep_attr_0": false
}
}
}
The deep_attr_0 tree is attr_1.deep_attr_0
- Function that will be invoked when the value of interest attribute changed. The function must return true if the process success. Otherwise return false.
Example
function logWhenAttributeChanged(payload) {
console.log(payload);
return true;
}
device.useEffect(this, "digital_input", "pin_0", logWhenAttributeChanged);
device.useEffect(this, "digital_input", "pin_1", logWhenAttributeChanged);
// or use wildcard to invoke the listener for any attribute
device.useEffect(this, "digital_input", "*", logWhenAttributeChanged);
updateState(stateName: string, stateObject: object)
Call this function when the state of actual device changed. The function will synchronize with its virtual/twin on cloud.
Example
await device.updateState("digital_output", {
"pin_0": false,
"pin_1": false,
})