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.