Skip to content

PIOT-CDA-09-005-A: Add DELETE functionality to AsyncCoapClientConnector #216

@labbenchstudios

Description

@labbenchstudios

Description

  • Update the Python module named CoapClientConnector with support for DELETE 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 DELETE request method

  • Implement the public sendDeleteRequest() 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
      • timeout (int): The timeout value to pass to the CoAP client infrastructure
  • A general implementation may look like the following:
	def sendDeleteRequest(self, resource: ResourceNameEnum = None, name: str = None, enableCON: bool = False, timeout: int = IRequestResponseClient.DEFAULT_TIMEOUT) -> bool:
		if resource or name:
			resourcePath = self._createResourcePath(resource, name)
			
			logging.info(f"Issuing Async DELETE to path: {resourcePath}")
			
			future = asyncio.run_coroutine_threadsafe(
				self._handleDeleteRequest(resourcePath, enableCON),
				self._eventLoopThread
			)

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

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

  • Implement the internal _handleDeleteRequest() and _onDeleteResponse() 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.
    • _handleDeleteRequest() will take the following arguments:
      • resourcePath (str): This will be the full resource path used for the request
      • enableCON (bool): If True, use a CONFIRMABLE request; else, use NONCONFIRMABLE
  • A general implementation may look like the following:
	async def _handleDeleteRequest(self, resourcePath: str = None, enableCON: bool = False):
		try:
			uriAndResourcePath = self.uriPath + resourcePath
	
			msgType = NON
			
			if enableCON:
				msgType = CON
				
			msg = Message(mtype = msgType, code = Code.DELETE, uri = uriAndResourcePath)

			responseData = await self.clientContext.request(request_message = msg).response
			
			self._onDeleteResponse(responseData)
  • The _onDeleteResponse() method is rather simple - it decodes the incoming payload and logs it to the console.
	def _onDeleteResponse(self, response):
		if not response:
			logging.warning("Async DELETE response invalid. Ignoring.")
			return
		
		logging.info("Async DELETE 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, create a two tests to issue a SensorData delete request to 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 testDeleteSensorMessageCon(self):
	self.coapClient.sendDeleteRequest( \
		resource = ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE, enableCON = True, timeout = 5)

@unittest.skip("Ignore for now.")
def testDeleteSensorMessageNon(self):
	self.coapClient.sendDeleteRequest( \
		resource = ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE, enableCON = False, 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 DELETE tests
    • Run both testDeleteSensorMessage...() 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 - and be sure to notice the WARNING message at the end:

About the WARNING message

  • Recall that the GDA CoAP server implementation for handling CDA SensorData messages (via the UpdateTelemetryResourceHandler only implements the PUT request, and NOT DELETE (or POST or GET).
    • You can choose to add the DELETE handler within UpdateTelemetryResourceHandler, which will then generate log output similar to that of the PUT functionality.

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