Skip to content

PIOT-CDA-08-002-A: Create resource handlers to process updates from the client #209

@labbenchstudios

Description

@labbenchstudios

Description

Create two new Python modules with like-named classes named AsyncGetSystemPerformanceResourceHandler and AsyncGetTelemetryResourceHandler.

  • Both of these will allow the CDA to (eventually) notify the GDA of new SensorData and SystemPerformanceData payloads available via the CoAP OBSERVE specification. You can find templates for their non-Async definitions in the programmingtheiot.cda.connection.handlers package.
  • NOTE: These instructions make use of the following CoAP library:
    • The aiocoap open source CoAP library, located at: aiocoap. Reference: Amsüss, Christian and Wasilak, Maciej. aiocoap: Python CoAP Library. Energy Harvesting Solutions, 2013–. http://github.com/chrysn/aiocoap/.

Review the README

  • Please see README.md for further information on, and use of, this content.
  • License for embedded documentation and source codes: PIOT-DOC-LIC

Estimated effort may vary greatly

  • The estimated level of effort for this exercise shown in the 'Estimate' section below is a very rough approximation. The actual level of effort may vary greatly depending on your development and test environment, experience with the requisite technologies, and many other factors.

Actions

Step 1: Create the module, class, and import statements for AsyncGetSystemPerformanceResourceHandler.py

  • Within the programmingtheiot.cda.connection.handlers package, create the new resource handler class as described above: AsyncGetSystemPerformanceResourceHandler
    • This class provides a simple implementation of a CoAP resource that will support automatic updates to the GDA from the CDA after the initial GDA GET request specific to retrieving SystemPerformanceData from the CDA by the GDA.
    • Make sure the import statements for each class include the appropriate module and class references for the library you're using.
  • Here are the import statements you'll need:
import logging

import aiocoap

from aiocoap.resource import ObservableResource

import programmingtheiot.common.ConfigConst as ConfigConst

from programmingtheiot.common.ConfigUtil import ConfigUtil
from programmingtheiot.common.IDataMessageListener import IDataMessageListener
from programmingtheiot.common.ISystemPerformanceDataListener import ISystemPerformanceDataListener 
from programmingtheiot.common.ITelemetryDataListener import ITelemetryDataListener

from programmingtheiot.data.DataUtil import DataUtil

from programmingtheiot.data.SystemPerformanceData import SystemPerformanceData
  • Here's a sample class implementation for AsyncGetSystemPerformanceResourceHandler
class AsyncGetSystemPerformanceResourceHandler(ObservableResource, ISystemPerformanceDataListener):
	def __init__(self):
		super().__init__()

		self.pollCycles = \
			ConfigUtil().getInteger( \
				section = ConfigConst.CONSTRAINED_DEVICE, \
				key = ConfigConst.POLL_CYCLES_KEY, \
				defaultVal = ConfigConst.DEFAULT_POLL_CYCLES)
		
		self.dataUtil = DataUtil()
		self.sysPerfData = None
		
		# for testing
		self.payload = "GetSysPerfData"
		
	async def render_get(self, request):
		responseCode = aiocoap.Code.CONTENT
		
		if not self.sysPerfData:
			self.sysPerfData = SystemPerformanceData()
			responseCode = aiocoap.Code.CONTENT
			
		jsonData = self.dataUtil.systemPerformanceDataToJson(self.sysPerfData)
		
		logging.info('Returning latest SystemPerformanceData: ' + jsonData)
		
		return aiocoap.Message(code = responseCode, payload = jsonData.encode('ascii'))

	def onSystemPerformanceDataUpdate(self, data: SystemPerformanceData) -> bool:
		pass
  • NOTE: The type ISystemPerformanceDataListener should already exist within your CDA repository as part of the programmingtheiot.common package, and should not need any modifications.
    • While Python doesn't support interfaces, this provides a base class with method definitions that should make it easier to invoke the callback onSystemPerformanceDataUpdate(SystemPerformanceData)

Step 2: Create the module, class, and import statements for AsyncGetTelemetryResourceHandler.py

  • Within the programmingtheiot.cda.connection.handlers package, create the new resource handler class as described above: AsyncGetTelemetryResourceHandler
    • This class provides a simple implementation of a CoAP resource that will support automatic updates to the GDA from the CDA after the initial GDA GET request specific to retrieving SensorData from the CDA by the GDA.
    • Make sure the import statements for each class include the appropriate module and class references for the library you're using.
  • Here are the import statements you'll need:
import logging

import aiocoap

from aiocoap.resource import ObservableResource

import programmingtheiot.common.ConfigConst as ConfigConst

from programmingtheiot.common.ConfigUtil import ConfigUtil
from programmingtheiot.common.IDataMessageListener import IDataMessageListener
from programmingtheiot.common.ISystemPerformanceDataListener import ISystemPerformanceDataListener 
from programmingtheiot.common.ITelemetryDataListener import ITelemetryDataListener

from programmingtheiot.data.DataUtil import DataUtil

from programmingtheiot.data.SensorData import SensorData
  • Here's a sample class implementation for AsyncGetTelemetryResourceHandler
class AsyncGetTelemetryResourceHandler(ObservableResource, ITelemetryDataListener):
	def __init__(self):
		super().__init__()
		
		self.pollCycles = \
			ConfigUtil().getInteger( \
				section = ConfigConst.CONSTRAINED_DEVICE, \
				key = ConfigConst.POLL_CYCLES_KEY, \
				defaultVal = ConfigConst.DEFAULT_POLL_CYCLES)
		
		self.dataUtil = DataUtil()
		self.sensorData = None
		
		# for testing
		self.payload = "GetSensorData"
		
	async def render_get(self, request):
		responseCode = aiocoap.Code.CONTENT
		
		if not self.sensorData:
			self.sensorData = SensorData()
			responseCode = aiocoap.Code.CONTENT
			
		jsonData = self.dataUtil.sensorDataToJson(self.sensorData)
		
		logging.info('Returning latest SensorData: ' + jsonData)
		
		return aiocoap.Message(code = responseCode, payload = jsonData.encode('ascii'))

	def onSensorDataUpdate(self, data: SensorData = None) -> bool:
		pass
  • NOTE: The type ITelemetryDataListener should already exist within your CDA repository as part of the programmingtheiot.common package, and should not need any modifications.
    • While Python doesn't support interfaces, this provides a base class with method definitions that should make it easier to invoke the callback onSensorDataUpdate(SensorData)

Estimate (Small = < 2 hrs; Medium = 4 hrs; Large = 8 hrs)

  • Medium

Tests

  • You can use the Californium client described in PIOT-CFG-08-001 to test your CoAP server running within the CDA.

Configure the CDA to run with CoAP server enabled

  • Make sure your CDA's configuration file is updated to enable the CoAP server
    • Update the config file and start the CDA in a separate terminal (or within your IDE)
    • NOTE: The config info below is JUST AN EXAMPLE
#
# CoAP client configuration information
#
[Coap.GatewayService]
credFile       = ./cred/PiotCoapCred.props
certFile       = ./cert/PiotCoapLocalCertFile.pem
host           = localhost
port           = 5683
securePort     = 5684
enableAuth     = False
enableCrypt    = False

#
# CDA specific configuration information
#
[ConstrainedDevice]
deviceLocationID = constraineddevice001
enableSimulator  = True
enableEmulator   = False
enableSenseHAT   = False
enableMqttClient = False
enableCoapServer = True
enableCoapClient = False
enableSystemPerformance = True
enableSensing    = True
enableLogging    = True
pollCycleSecs    = 5
testGdaDataPath  = /tmp/gda-data
testCdaDataPath  = /tmp/cda-data
testEmptyApp     = False
runForever       = True

Configure and run the Californium Client

  • Open a separate terminal window on your system to run the Californium client.
    • Change directory to the Californium Tools path (INSTALL_PATH/californium.tools)
    • Run cf-client with a simple discover or get request

CoAP GET Example

cd cf-client/target
java -jar cf-client-3.10.0-SNAPSHOT.jar -m GET coap://localhost:5683

CoAP DISCOVER Example

cd cf-client/target
java -jar cf-client-3.10.0-SNAPSHOT.jar -m GET coap://localhost:5683/.well-known/core

Californium client help

  • For a list of supported client parameters, use the following:
java -jar cf-client-3.10.0-SNAPSHOT.jar --help

Results (Initial)

  • You should see something similar to the following, depending on how the server is configured:
    • NOTE: The following is an example response from a DISCOVER request

Results (Upon Full Lab Module Completion)

  • Once you've completed all the exercises in this lab module, you should see an output that looks similar to the following, depending on how the server is configured:
    • NOTE: The following is an example response from a DISCOVER request when using the aiocoap library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Lab Module 08 - CoAP Servers

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions