Skip to content

PIOT-CDA-09-003-A: Add PUT functionality to AsyncCoapClientConnector #214

@labbenchstudios

Description

@labbenchstudios

Description

  • Update the Python module named AsyncCoapClientConnector with support for PUT requests, using the existing method definitions within IRequestResponseHandler to support this request type.
    • 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 and implement a callable PUT request method

  • Implement the public sendPutRequest() method
    • This method will take the following arguments:
      • resource (ResourceNameEnum): Used to create the general request URL
      • name (str): Used to extend the general request URL with further detail (if warranted)
      • enableCON (bool): If True, use a CONFIRMABLE request; else, use NONCONFIRMABLE
      • payload (str): The payload to send to the server
      • timeout (int): The timeout value to pass to the CoAP client infrastructure
  • A general implementation may look like the following:
	def sendPutRequest(self, resource: ResourceNameEnum = None, name: str = None, enableCON: bool = False, payload: str = None, timeout: int = IRequestResponseClient.DEFAULT_TIMEOUT) -> bool:
		if resource or name:
			resourcePath = self._createResourcePath(resource, name)
			
			logging.info(f"Issuing Async PUT to path: {resourcePath}")
			
			future = asyncio.run_coroutine_threadsafe(
				self._handlePutRequest(resourcePath, payload, enableCON),
				self._eventLoopThread
			)

			return future.result()
		else:
			logging.warning("Can't issue Async PUT - no path provided.")

Step 2: Create and implement the internal PUT request callback method and response handler

  • Implement the internal _handlePutRequest() and _onPutResponse() methods
    • These methods will process the incoming response from the CoAP server, parse the payload, determine which data type is part of the payload, and react accordingly.
    • _handlePutRequest() will take the following arguments:
      • resourcePath (str): This will be the full resource path used for the request
      • payload (str): The payload to send to the CoAP server
      • enableCON (bool): If True, use a CONFIRMABLE request; else, use NONCONFIRMABLE
  • A general implementation may look like the following:
	async def _handlePutRequest(self, resourcePath: str = None, payload: str = None, enableCON: bool = False):
		try:
			uriAndResourcePath = self.uriPath + resourcePath
	
			msgType = NON
			
			if enableCON:
				msgType = CON
				
			msg = Message(mtype = msgType, payload = payload.encode("utf-8"), code = Code.PUT, uri = uriAndResourcePath)

			responseData = await self.clientContext.request(request_message = msg).response
			
			self._onPutResponse(responseData)
  • The _onPutResponse() method is rather simple - it decodes the incoming payload and logs it to the console.
	def _onPutResponse(self, response):
		if not response:
			logging.warning("Async PUT response invalid. Ignoring.")
			return
		
		logging.info("Async PUT response received.")
		
		responseData = response.payload.decode("utf-8")
		
		logging.info(f"Response data received. Payload: {responseData}")

Estimate

  • Small

Tests

  • Edit / add test cases
    • Update the test_CoapAsyncClientConnectorTest.py module (containing the CoapAsyncClientConnectorTest class) in CDA_HOME/tests/integration/connection as indicated below.
      • If not already done for you within the code, disable the existing tests by UNCOMMENTING the skip test annotation before each test case (change #@unittest.skip("Ignore for now.") to @unittest.skip("Ignore for now.")).
      • If not already done for you within the code, add two tests to store a test SensorData instance on the CoAP server using both CON and NON requests.
      • The code for each should look similar to the following:
#@unittest.skip("Ignore for now.")
def testPutSensorMessageCon(self):
	data = SensorData()
	jsonData = DataUtil().sensorDataToJson(data = data)
	
	self.coapClient.sendPutRequest( \
		resource = ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE, enableCON = True, payload = jsonData, timeout = 5)

#@unittest.skip("Ignore for now.")
def testPutSensorMessageNon(self):
	data = SensorData()
	jsonData = DataUtil().sensorDataToJson(data = data)
	
	self.coapClient.sendPutRequest( \
		resource = ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE, enableCON = False, payload = jsonData, timeout = 5)
  • Setup
    • Start Wireshark, and ensure it's watching the loopback adapter.
      • You can filter on 'coap' to track only CoAP messages, which is recommended for this test.
    • Start your GDA application with the CoAP server enabled. Make sure it runs for a couple of minutes - long enough for you to run the integration tests listed below.
      • To run your GDA from the command line, you just need to do the following from a shell (assuming you're starting from the parent directory containing your java-components, and that the path is named 'piot-java-components':
        • NOTE: Be sure to run your GDA Java app for a few minutes so you have time to run the tests!!
cd piot-java-components
mvn clean install -DskipTests
java -jar target/gateway-device-app-0.0.1-jar-with-dependencies.jar
  • Run the PUT tests
    • Run both testPutSensorMessage...() test cases and watch the output in the console for the client as well as within Wireshark.
      • NOTE: If you're a student in the Connected Devices course, be sure to follow the instructions in PIOT-INF-09-003.
    • Your output will contain log content similar to the following:


Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Lab Module 09 - CoAP Clients

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions