Device listens to telemetry state changed
This guide describes the concept and syntax when a device listens to the changes of telemetry state from its Virtual Twin.
Below telemetry state schema with a state name of smart_plug_state will be used throughout this guide.
{
"electricity": {
"power": 0,
"votage": 0
},
"switch": {
"toggle": false,
"led": {
"front": false,
"back": true
}
}
}
Code below shows several examples when listening to changes and invoke functions associated to the changes.
import {
Device,
DeviceIdentifier,
DeviceIdentifierStore,
CertificateStore,
ConnectionStore
} from "@neukolabs/device-sdk-js";
import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'fs';
import path from 'path';
class deviceIdentifier extends DeviceIdentifierStore {
// ... some content inside
}
class deviceCertificate extends CertificateStore {
// ... some content inside
}
class deviceConnection extends ConnectionStore {
// ... some content inside
}
// Example 1
// this function will be invoked whenever any attribute in the telemetry state changed
async function logAttributeChanged(data) {
console.log(`${data.deviceIdentifier} ${data.stateName} ${data.attributeTree}, ${data.value}`);
return true;
}
// Example 2
// this function will be invoked a "swtich.toggle" changed
async function onChangedSwitchToggle(data) {
if (data.value) {
some_hardware_function_to_switch(true);
} else {
some_hardware_function_to_switch(false);
}
return true;
}
// Example 3
// this function will be invoked a "switch.led.*" changed
async function onLedChangedRequest(data) {
// data.attributeTree will have value like switch.led.front or switch.led.back
const location = data.attributeTree.replace("switch.led.", "");
some_hardware_function_to_switch_led(location, data.value);
return true;
}
async function main() {
const device: Device = new Device();
device.identifierStore = new deviceIdentifier();
device.connectionStore = new deviceConnection();
device.certificateStore = new deviceCertificate();
// register listeners
device.useEffects(this, "smart_plug_state", "*", logAttributeChanged); // example 1
device.useEffects(this, "smart_plug_state", "switch.toggle", onChangedSwitchToggle); // example 2
device.useEffects(this, "smart_plug_state", "switch.led.front", onLedChangedRequest); // example 3
device.useEffects(this, "smart_plug_state", "switch.led.back", onLedChangedRequest); // example 3
// start the device
await device.start();
}
async function exit() {
// stop the device
await device.stop();
}
import sys
import asyncio
import concurrent.futures
from neuko.device.identifierStore import DeviceIdentifierStore
from neuko.connection.certificateStore import CertificateStore
from neuko.connection.connectionStore import ConnectionStore
from neuko.device.model import DeviceIdentifier, TelemetricStateChangeParameter
from neuko.device.device import Device, DeviceState
class deviceIdentifier(DeviceIdentifierStore):
# ... some content here
class deviceCertificate(CertificateStore):
# ... some content here
class deviceConnection(ConnectionStore):
# ... some content here
class MyDevice:
def __init__(self) -> None:
self.device = None
self.RUNNING = False
self._ready = False
# Example 1 - this function will be invoked in another thread whenever any attribute in the telemetry state changed
def logAttributeChanged(self, params: TelemetricStateChangeParameter):
print(f'{params.deviceIdentifier}, {params.stateName}, {params.attributeTree}, {params.value}')
return true
# Example 2 - this function will be invoked in another thread whenever a "swtich.toggle" changed
def onChangedSwitchToggle(self, params: TelemetricStateChangeParameter):
some_hard_function_to_switch_toggle(params.value)
return true
# Example 3 - this function will be invoked in another thread whenever a "switch.led.*" changed
def onLedChangedRequest(self, params: TelemetricStateChangeParameter):
location = params.attributeTree.replace("switch.led.", "")
some_hard_function_to_switch_led(location, params.value)
return true
def init(self):
self.device = Device(deviceIdentifier(), deviceConnection(), deviceCertificate())
self.useEffect(self, self.logAttributeChanged, "smart_plug_state", "*") # example 1
self.useEffect(self, self.onChangedSwitchToggle, "smart_plug_state", "switch.toggle") # example 2
self.useEffect(self, self.onLedChangedRequest, "smart_plug_state", "switch.led.front") # example 3
self.useEffect(self, self.onLedChangedRequest, "smart_plug_state", "switch.led.back") # example 3
self.device.start_threadsafe()
async def start(self):
self.RUNNING = True
while self.RUNNING:
if (self._ready == False):
if (self.gateway.state == DeviceState.READY):
self._ready = True
self._initalizeDevices()
await asyncio.sleep(1)
async def stop(self):
self.RUNNING = False
await self.gateway.stop()
async def forever():
mydevice = MyDevice()
mydevice.init()
await mydevice.start()
def main():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(forever())
if __name__ == "__main__":
main()
Telemetry state lifecycles
When an active device connected to the platform, Neuko Device SDK requests the latest telemetry state from its Virtual Twin and copy it into local variable.
Once it has copied, it will invoked each of the listeners registered using useEffect() function. As the result, you should know that this can be used to initialize the device at the time of connecting.