# Device SDK for Python
This document provides information about the Neuko SDK that can be installed as a dependency in an IoT device.
## Pre-requisites
1. Neuko account (sign up [here](https://auth.neuko.io/signup?client_id=30qirvopvpabg1njrdp4mt54tl&response_type=code&scope=email+openid+profile&redirect_uri=https://app.neuko.io/oauth))
2. Defined device type schema (refer [documentation](https://neuko.io/docs/schema/))
3. 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:
```json
{
"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:
1. digital input
2. digital output
Also, each state has 2 attributes - pin 0 and pin 1.
The Neuko Python 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 Python 3.6 and above.
```python
python --version
```
### Installation
```python
pip install neuko-device-sdk
```
## Usage
### Import package
```python
from neuko.device.device import Device
from neuko.iot.bootstrap import BootstrapClient
from neuko.iot.neuko import NeukoClient
```
### Extend DeviceIdentifierStore class
```python
class DeviceIdentifierStoreObject(DeviceIdentifierStore):
def getAccountId(self) -> str:
return "<Neuko Account Id>"
def getProjectId(self) -> str:
return "<Neuko Project Id>"
def getDeviceSchemaId(self) -> str:
return "<Device Serial Number / Id>"
def getDeviceId(self) -> str:
return "<Neuko Device Type Schema Id>"
```
### Extend ConnectionStore class
```python
class ConnectionStoreObject(ConnectionStore):
async def getPerpetualConnectionSettings(self, deviceIdentifier: DeviceIdentifier) -> str:
fd = open("./my-secure-directory/neuko-device-connection-settings.json", mode="r")
raw = json.load(fd)
fd.close()
return raw
async def savePerpetualConnectionSettings(self, deviceIdentifier: DeviceIdentifier, settings: str) -> bool:
fd = open("./my-secure-directory/neuko-device-connection-settings.json", mode="w")
json.dump(settings, fd)
fd.close()
return True
async def deletePerpetualConnectionSettings(self, deviceIdentifier: DeviceIdentifier) -> bool:
return True
async def isPerpetualConnectionSettingsExists(self, deviceIdentifier: DeviceIdentifier) -> bool:
return False
}
```
### Extend CertificateStore class
```python
class CertificateStoreObject(CertificateStore):
async def getBootstrapCertificateAuthority(self, deviceIdentifier: DeviceIdentifier) -> str:
return "./my-secure-directory/certificates/cert.ca.pem"
async def getBootstrapChainCertificate(self, deviceIdentifier: DeviceIdentifier) -> str:
return "./my-secure-directory/certificates/bootstrap-certificate.pem.crt"
async def getBootstrapPrivateKey(self, deviceIdentifier: DeviceIdentifier) -> str:
return "./my-secure-directory/certificates/bootstrap-private.pem.key"
async def getPerpetualCertificateAuthority(self, deviceIdentifier: DeviceIdentifier) -> str:
fd = open("./my-secure-directory/certificates/cert.ca.pem", mode="r")
raw = fd.read()
fd.close()
return raw
async def getPerpetualChainCertificate(self, deviceIdentifier: DeviceIdentifier) -> str:
fd = open("./my-secure-directory/certificates/certificate.pem.crt", mode="r")
raw = fd.read()
fd.close()
return raw
async def getPerpetualPrivateKey(self, deviceIdentifier: DeviceIdentifier) -> str:
fd = open("./my-secure-directory/certificates/cert.ca.pem", mode="r")
raw = fd.read()
fd.close()
return raw
async def savePerpetualCertificateAuthority(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None:
fd = open("./my-secure-directory/certificates/cert.ca.pem", mode="w")
fd.write(certificate)
fd.close()
async def savePerpetualChainCertificate(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None:
fd = open("./my-secure-directory/certificates/certificate.pem.crt"", mode="w")
fd.write(certificate)
fd.close()
async def savePerpetualPrivateKey(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None:
fd = open("./my-secure-directory/certificates/cert.ca.pem", mode="w")
fd.write(certificate)
fd.close()
```
### Create Device class instance
```python
device = Device(DeviceIdentifierStoreObject(), ConnectionStoreObject(), CertificateStoreObject())
device.start_threadsafe()
```
## 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, listener, stateName: str, attributeTree: str = "*")
Use effect attaches a listener or function handler to any state's attributes. The parameters details are as below:
1. context - Class or any object of context. (eg. this)
2. Function that will be invoked when the value of interest attribute changed. The function must return true if the process success. Otherwise return false.
3. stateName - the name of the state.
4. attributeTree - Dot notation representing state attribute. For example, if you have state as below
```json
{
"state_name_1": {
"attr_0": true,
"attr_1": {
"deep_attr_0": false
}
}
}
```
The *deep_attr_0* tree is **attr_1.deep_attr_0**
Example
```python
def callback(data: TelemetricStateChangeParameter):
logging.debug(f'data: {data}')
return True
device.useEffect(self, callback, "digital_input", "pin_0")
device.useEffect(self, callback, "digital_input", "pin_1")
// or use wildcard to invoke the listener for any attribute
device.useEffect(self, callback, "digital_input", "*");
```
### updateTelemetricState(stateName: string, value: object)
Call this function when the state of actual device changed. The function will synchronize with its virtual/twin on cloud.
Example
```python
device.updateTelemetricState("digital_output", {
"pin_0": false,
"pin_1": false,
})
```
Raw data
{
"_id": null,
"home_page": "",
"name": "neuko-device-sdk",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "iot,device,thing,cloud,mqtt,development,neuko",
"author": "neuko.io",
"author_email": "hello@neuko.io",
"download_url": "https://files.pythonhosted.org/packages/9c/34/b2be5ed5ad0c4b4f3f18778d7dd9b83709f08205e1481c33ef8c52896551/neuko-device-sdk-1.1.2.tar.gz",
"platform": null,
"description": "# Device SDK for Python\n\nThis document provides information about the Neuko SDK that can be installed as a dependency in an IoT device.\n\n## Pre-requisites\n\n1. Neuko account (sign up [here](https://auth.neuko.io/signup?client_id=30qirvopvpabg1njrdp4mt54tl&response_type=code&scope=email+openid+profile&redirect_uri=https://app.neuko.io/oauth))\n2. Defined device type schema (refer [documentation](https://neuko.io/docs/schema/))\n3. Bootstrap certificates that can downloaded after define a device type schema (step 2)\n\n\n## Device State\n\nDevice 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:\n\n```json\n{\n \"digital_input\": {\n \"pin_0\": true,\n \"pin_1\": false\n },\n \"digital_output\": {\n \"pin_0\": true,\n \"pin_1\": true\n }\n}\n```\n\nThe above example tells us that the digital board has 2 states:\n1. digital input\n2. digital output\n\nAlso, each state has 2 attributes - pin 0 and pin 1.\n\nThe Neuko Python SDK works by managing the state's attributes of the device between actual physical and its virtual representation in cloud. \n\nPrior to that, the SDK supports provisioning of a new device during 1st time connection.\n\n\n## Installation\n\n### Checking minimum requirement\nThe SDK requires Python 3.6 and above.\n\n```python\npython --version\n```\n\n### Installation\n\n```python\npip install neuko-device-sdk\n```\n\n## Usage\n\n### Import package\n\n```python\nfrom neuko.device.device import Device\nfrom neuko.iot.bootstrap import BootstrapClient\nfrom neuko.iot.neuko import NeukoClient\n```\n\n### Extend DeviceIdentifierStore class\n\n```python\nclass DeviceIdentifierStoreObject(DeviceIdentifierStore):\n def getAccountId(self) -> str:\n return \"<Neuko Account Id>\"\n\n def getProjectId(self) -> str:\n return \"<Neuko Project Id>\"\n\n def getDeviceSchemaId(self) -> str:\n return \"<Device Serial Number / Id>\"\n\n def getDeviceId(self) -> str:\n return \"<Neuko Device Type Schema Id>\"\n```\n\n### Extend ConnectionStore class\n\n```python\nclass ConnectionStoreObject(ConnectionStore):\n async def getPerpetualConnectionSettings(self, deviceIdentifier: DeviceIdentifier) -> str:\n fd = open(\"./my-secure-directory/neuko-device-connection-settings.json\", mode=\"r\")\n raw = json.load(fd)\n fd.close()\n return raw\n\n async def savePerpetualConnectionSettings(self, deviceIdentifier: DeviceIdentifier, settings: str) -> bool:\n fd = open(\"./my-secure-directory/neuko-device-connection-settings.json\", mode=\"w\")\n json.dump(settings, fd)\n fd.close()\n return True\n\n async def deletePerpetualConnectionSettings(self, deviceIdentifier: DeviceIdentifier) -> bool:\n return True\n\n async def isPerpetualConnectionSettingsExists(self, deviceIdentifier: DeviceIdentifier) -> bool:\n return False\n}\n```\n\n### Extend CertificateStore class\n\n```python\nclass CertificateStoreObject(CertificateStore):\n\n async def getBootstrapCertificateAuthority(self, deviceIdentifier: DeviceIdentifier) -> str:\n return \"./my-secure-directory/certificates/cert.ca.pem\"\n\n async def getBootstrapChainCertificate(self, deviceIdentifier: DeviceIdentifier) -> str:\n return \"./my-secure-directory/certificates/bootstrap-certificate.pem.crt\"\n\n async def getBootstrapPrivateKey(self, deviceIdentifier: DeviceIdentifier) -> str:\n return \"./my-secure-directory/certificates/bootstrap-private.pem.key\"\n\n async def getPerpetualCertificateAuthority(self, deviceIdentifier: DeviceIdentifier) -> str:\n fd = open(\"./my-secure-directory/certificates/cert.ca.pem\", mode=\"r\")\n raw = fd.read()\n fd.close()\n return raw\n\n async def getPerpetualChainCertificate(self, deviceIdentifier: DeviceIdentifier) -> str:\n fd = open(\"./my-secure-directory/certificates/certificate.pem.crt\", mode=\"r\")\n raw = fd.read()\n fd.close()\n return raw\n\n async def getPerpetualPrivateKey(self, deviceIdentifier: DeviceIdentifier) -> str:\n fd = open(\"./my-secure-directory/certificates/cert.ca.pem\", mode=\"r\")\n raw = fd.read()\n fd.close()\n return raw\n\n async def savePerpetualCertificateAuthority(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None:\n fd = open(\"./my-secure-directory/certificates/cert.ca.pem\", mode=\"w\")\n fd.write(certificate)\n fd.close()\n\n async def savePerpetualChainCertificate(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None:\n fd = open(\"./my-secure-directory/certificates/certificate.pem.crt\"\", mode=\"w\")\n fd.write(certificate)\n fd.close()\n\n async def savePerpetualPrivateKey(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None:\n fd = open(\"./my-secure-directory/certificates/cert.ca.pem\", mode=\"w\")\n fd.write(certificate)\n fd.close()\n```\n\n### Create Device class instance\n\n```python\ndevice = Device(DeviceIdentifierStoreObject(), ConnectionStoreObject(), CertificateStoreObject())\ndevice.start_threadsafe()\n```\n\n## Methods\n\n### start()\nThis 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.\nA provisioned device will stay in its perpetual state.\n\n**Important**\nOnly 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.\n\n### useEffect(context, listener, stateName: str, attributeTree: str = \"*\")\nUse effect attaches a listener or function handler to any state's attributes. The parameters details are as below:\n\n1. context - Class or any object of context. (eg. this)\n\n2. Function that will be invoked when the value of interest attribute changed. The function must return true if the process success. Otherwise return false.\n\n3. stateName - the name of the state.\n\n4. attributeTree - Dot notation representing state attribute. For example, if you have state as below\n\n```json\n{\n \"state_name_1\": {\n \"attr_0\": true,\n \"attr_1\": {\n \"deep_attr_0\": false\n }\n }\n}\n```\n\nThe *deep_attr_0* tree is **attr_1.deep_attr_0**\n\n\nExample\n\n```python\ndef callback(data: TelemetricStateChangeParameter):\n logging.debug(f'data: {data}')\n return True\n\ndevice.useEffect(self, callback, \"digital_input\", \"pin_0\")\ndevice.useEffect(self, callback, \"digital_input\", \"pin_1\")\n\n// or use wildcard to invoke the listener for any attribute\ndevice.useEffect(self, callback, \"digital_input\", \"*\");\n```\n\n### updateTelemetricState(stateName: string, value: object)\nCall this function when the state of actual device changed. The function will synchronize with its virtual/twin on cloud.\n\nExample\n\n```python\ndevice.updateTelemetricState(\"digital_output\", {\n \"pin_0\": false,\n \"pin_1\": false,\n})\n```\n\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Neuko device SDK for Python hardware",
"version": "1.1.2",
"project_urls": null,
"split_keywords": [
"iot",
"device",
"thing",
"cloud",
"mqtt",
"development",
"neuko"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "ebc82d760b56552f1608c31014151fde7428e646acef6dbec8f2513cc8af9f24",
"md5": "5249f21618ab47c7199290223be67142",
"sha256": "372245775aeda303bd31b2f0fab9f427c143bd640b93fbcc792966127cd653e5"
},
"downloads": -1,
"filename": "neuko_device_sdk-1.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5249f21618ab47c7199290223be67142",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 34818,
"upload_time": "2023-05-13T05:22:35",
"upload_time_iso_8601": "2023-05-13T05:22:35.221792Z",
"url": "https://files.pythonhosted.org/packages/eb/c8/2d760b56552f1608c31014151fde7428e646acef6dbec8f2513cc8af9f24/neuko_device_sdk-1.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "9c34b2be5ed5ad0c4b4f3f18778d7dd9b83709f08205e1481c33ef8c52896551",
"md5": "aed143539a603993761de468370cf8af",
"sha256": "1f0dec0876bcc785ea6ce400d6a505c6d03e432979ca0d53fd5a6cdbb59d66a0"
},
"downloads": -1,
"filename": "neuko-device-sdk-1.1.2.tar.gz",
"has_sig": false,
"md5_digest": "aed143539a603993761de468370cf8af",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 38058,
"upload_time": "2023-05-13T05:22:38",
"upload_time_iso_8601": "2023-05-13T05:22:38.096782Z",
"url": "https://files.pythonhosted.org/packages/9c/34/b2be5ed5ad0c4b4f3f18778d7dd9b83709f08205e1481c33ef8c52896551/neuko-device-sdk-1.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-05-13 05:22:38",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "neuko-device-sdk"
}