def testStartAndStopManagerWithMqtt(self):
        """
		NOTE: Be sure to enable CoAP by setting the following flag to True
		within PiotConfig.props
		enableMqttClient = True
		enableCoapClient = False
		
		"""
        ddMgr = DeviceDataManager()
        ddMgr.startManager()

        mqttClient = MqttClientConnector()
        mqttClient.connectClient()

        ad = ActuatorData()
        ad.setCommand(1)

        adJson = DataUtil().actuatorDataToJson(ad)

        mqttClient.publishMessage(ResourceNameEnum.CDA_ACTUATOR_CMD_RESOURCE,
                                  msg=adJson,
                                  qos=1)

        sleep(10)

        mqttClient.disconnectClient()
        ddMgr.stopManager()
Beispiel #2
0
class MqttClientConnectorTest(unittest.TestCase):
    """
	This test case class contains very basic unit tests for
	MqttClientConnector. It should not be considered complete,
	but serve as a starting point for the student implementing
	additional functionality within their Programming the IoT
	environment.
	"""
    @classmethod
    def setUpClass(self):
        logging.basicConfig(
            format='%(asctime)s:%(module)s:%(levelname)s:%(message)s',
            level=logging.DEBUG)
        logging.info("Testing MqttClientConnector class...")

        self.cfg = ConfigUtil()
        self.mcc = MqttClientConnector()

    def setUp(self):
        pass

    def tearDown(self):
        pass

    @unittest.skip("Ignore for now.")
    def testConnectAndDisconnect(self):
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)

        self.mcc.connectClient()

        sleep(delay + 5)

        self.mcc.disconnectClient()

    @unittest.skip("Ignore for now.")
    def testConnectAndCDAManagementStatusPubSub(self):
        qos = 1
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)

        self.mcc.connectClient()
        self.mcc.subscribeToTopic(
            resource=ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE, qos=qos)
        sleep(5)

        self.mcc.publishMessage(
            resource=ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE,
            msg="TEST: This is the CDA message payload.",
            qos=qos)
        sleep(5)

        self.mcc.unsubscribeFromTopic(
            resource=ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE)
        sleep(5)

        sleep(delay)

        self.mcc.disconnectClient()

    @unittest.skip("Ignore for now.")
    def testActuatorCmdPubSub(self):
        qos = 0
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)

        actuatorData = ActuatorData()
        actuatorData.setCommand(7)

        self.mcc.setDataMessageListener(DefaultDataMessageListener())

        payload = DataUtil().actuatorDataToJson(actuatorData)

        self.mcc.connectClient()

        sleep(5)

        self.mcc.publishMessage(
            resource=ResourceNameEnum.CDA_ACTUATOR_CMD_RESOURCE,
            msg=payload,
            qos=qos)

        sleep(delay + 5)

        self.mcc.disconnectClient()

    @unittest.skip("Ignore for now.")
    def testCDAManagementStatusSubscribe(self):
        qos = 1
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)

        self.mcc.connectClient()
        self.mcc.subscribeToTopic(
            resource=ResourceNameEnum.CDA_MGMT_STATUS_CMD_RESOURCE, qos=qos)

        sleep(delay)

        self.mcc.disconnectClient()

    @unittest.skip("Ignore for now.")
    def testCDAManagementStatusPublish(self):
        """
		Uncomment this test when integration between the GDA and CDA using MQTT.
		
		"""
        qos = 1
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)

        self.mcc.connectClient()
        self.mcc.publishMessage(
            resource=ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE,
            msg="TEST: This is the CDA message payload.",
            qos=qos)

        sleep(delay)

        self.mcc.disconnectClient()
Beispiel #3
0
class MqttClientConnectorTest(unittest.TestCase):
    """
	This test case class contains very basic unit tests for
	MqttClientConnector. It should not be considered complete,
	but serve as a starting point for the student implementing
	additional functionality within their Programming the IoT
	environment.
	"""
    NS_IN_MILLIS = 1000000
    MAX_TEST_RUNS = 100000

    @classmethod
    def setUpClass(self):
        logging.basicConfig(
            format='%(asctime)s:%(module)s:%(levelname)s:%(message)s',
            level=logging.DEBUG)

    def setUp(self):
        self.mqttClient = MqttClientConnector(
            clientID='CDAMqttClientPerformanceTest001')
        pass

    def tearDown(self):
        pass

    #@unittest.skip("Ignore for now.")
    def testConnectAndDisconnect(self):
        startTime = time.time_ns()

        self.assertTrue(self.mqttClient.connectClient())
        self.assertTrue(self.mqttClient.disconnectClient())

        endTime = time.time_ns()
        elapsedMillis = (endTime - startTime) / self.NS_IN_MILLIS

        logging.info("Connect and Disconnect: " + str(elapsedMillis) + " ms")

    #@unittest.skip("Ignore for now.")
    def testPublishQoS0(self):
        self._execTestPublish(self.MAX_TEST_RUNS, 0)

    #@unittest.skip("Ignore for now.")
    def testPublishQoS1(self):
        self._execTestPublish(self.MAX_TEST_RUNS, 1)

    #@unittest.skip("Ignore for now.")
    def testPublishQoS2(self):
        self._execTestPublish(self.MAX_TEST_RUNS, 2)

    def _execTestPublish(self, maxTestRuns: int, qos: int):
        self.assertTrue(self.mqttClient.connectClient())

        sensorData = SensorData()
        payload = DataUtil().sensorDataToJson(sensorData)

        startTime = time.time_ns()

        for seqNo in range(0, maxTestRuns):
            self.mqttClient.publishMessage(
                resource=ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE,
                msg=payload,
                qos=qos)

        endTime = time.time_ns()
        elapsedMillis = (endTime - startTime) / self.NS_IN_MILLIS

        self.assertTrue(self.mqttClient.disconnectClient())

        logging.info("Publish message - QoS " + str(qos) + " [" +
                     str(maxTestRuns) + "]: " + str(elapsedMillis) + " ms")
class MqttClientConnectorTest(unittest.TestCase):
    """
	This test case class contains very basic unit tests for
	MqttClientConnector. It should not be considered complete,
	but serve as a starting point for the student implementing
	additional functionality within their Programming the IoT
	environment.
	"""
    @classmethod
    def setUpClass(self):
        logging.basicConfig(
            format='%(asctime)s:%(module)s:%(levelname)s:%(message)s',
            level=logging.DEBUG)
        logging.info("Testing MqttClientConnector class...")

        self.cfg = ConfigUtil()
        self.mcc = MqttClientConnector(
            clientID='CDAMqttClientConnectorTest001')

    def setUp(self):
        pass

    def tearDown(self):
        pass

    @unittest.skip("Ignore for now.")
    def testConnectAndDisconnect(self):
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)

        self.mcc.connect()

        sleep(delay + 5)

        self.mcc.disconnect()

    @unittest.skip("Ignore for now.")
    def testConnectAndPublish(self):
        qos = 1
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)
        listener = DefaultDataMessageListener()

        self.mcc.connect()
        self.mcc.subscribeToTopic(
            ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE, qos)

        sleep(5)

        self.mcc.publishMessage(ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE,
                                "TEST: This is the CDA message payload.", qos)
        sleep(5)

        self.mcc.unsubscribeFromTopic(
            ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE)
        sleep(5)

        sleep(delay)

        self.mcc.disconnect()

    @unittest.skip("Ignore for now.")
    def testIntegrateWithGdaSubscribeCdaCmdTopic(self):
        qos = 1
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)
        listener = DefaultDataMessageListener()

        self.mcc.connect()
        self.mcc.subscribeToTopic(
            ResourceNameEnum.CDA_MGMT_STATUS_CMD_RESOURCE, qos)

        sleep(delay)

        self.mcc.disconnect()

    @unittest.skip("Ignore for now.")
    def testIntegrateWithGdaPublishCdaMgmtTopic(self):
        qos = 1
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)
        listener = DefaultDataMessageListener()

        self.mcc.connect()
        self.mcc.publishMessage(ResourceNameEnum.CDA_MGMT_STATUS_MSG_RESOURCE,
                                "TEST: This is the CDA message payload.", qos)

        sleep(5)

        self.mcc.disconnect()

    def testActuatorCmdPubSub(self):
        qos = 1
        # NOTE: delay can be anything you'd like - the sleep() calls are simply to slow things down a bit for observation
        delay = self.cfg.getInteger(ConfigConst.MQTT_GATEWAY_SERVICE,
                                    ConfigConst.KEEP_ALIVE_KEY,
                                    ConfigConst.DEFAULT_KEEP_ALIVE)
        actuatorData = ActuatorData()
        payload = DataUtil().actuatorDataToJson(actuatorData)
        self.mcc.connectClient()
        sleep(3)
        self.mcc.publishMessage(
            resource=ResourceNameEnum.CDA_ACTUATOR_CMD_RESOURCE,
            msg=payload,
            qos=qos)
        sleep(3)
        self.mcc.disconnectClient()
class MqttClientPerformanceTest(unittest.TestCase):
    """
	This test case class contains very basic unit tests for
	Mqtt Client Perfomance.
	"""

    NS_IN_MILLIS = 1000000

    # NOTE: We'll use only 10,000 requests for MQTT
    MAX_TEST_RUNS = 20

    @classmethod
    def setUpClass(self):
        logging.basicConfig(
            format='%(asctime)s:%(module)s:%(levelname)s:%(message)s',
            level=logging.DEBUG)

    def setUp(self):
        self.mqttClient = MqttClientConnector(
            clientID='CDAMqttClientPerformanceTest001')
        pass

    def tearDown(self):
        pass

    # @unittest.skip("Ignore for now.")
    def testConnectAndDisconnect(self):
        startTime = time.time_ns()

        self.assertTrue(self.mqttClient.connectClient())
        self.assertTrue(self.mqttClient.disconnectClient())

        endTime = time.time_ns()
        elapsedMillis = (endTime - startTime) / self.NS_IN_MILLIS

        logging.info("Connect and Disconnect: " + str(elapsedMillis) + " ms")

    # @unittest.skip("Ignore for now.")
    def testPublishQoS0(self):
        self._execTestPublish(self.MAX_TEST_RUNS, 0)

    # @unittest.skip("Ignore for now.")
    def testPublishQoS1(self):
        self._execTestPublish(self.MAX_TEST_RUNS, 1)

    # @unittest.skip("Ignore for now.")
    def testPublishQoS2(self):
        self._execTestPublish(self.MAX_TEST_RUNS, 2)

    def _execTestPublish(self, maxTestRuns: int, qos: int):
        self.assertTrue(self.mqttClient.connectClient())

        sensorData = SensorData()
        payload = DataUtil().sensorDataToJson(sensorData)

        startTime = time.time_ns()

        for seqNo in range(0, maxTestRuns):
            self.mqttClient.publishMessage(
                resource=ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE,
                msg=payload,
                qos=qos)

        endTime = time.time_ns()
        elapsedMillis = (endTime - startTime) / self.NS_IN_MILLIS

        self.assertTrue(self.mqttClient.disconnectClient())

        logging.info("Publish message - QoS " + str(qos) + " [" +
                     str(maxTestRuns) + "]: " + str(elapsedMillis) + " ms")
Beispiel #6
0
class DeviceDataManager(IDataMessageListener):
    """
    Shell representation of class for student implementation.
    
    """

    def __init__(self, enableMqtt: bool = True, enableCoap: bool = False):
        # set enable connection
        self.enableMqtt = enableMqtt
        self.enableCoap = enableCoap
        # load config
        self.configUtil = ConfigUtil()
        self.enableEmulator = self.configUtil.getBoolean(ConfigConst.CONSTRAINED_DEVICE,
                                                         ConfigConst.ENABLE_EMULATOR_KEY)
        self.stepmotor = StepMotorAdapterTask()
        # create system Perf manager
        self.sysPerfManager = SystemPerformanceManager()
        # set sensor config
        self.sam = SensorAdapterManager(useEmulator=self.enableEmulator)
        #set actuator config
        self.aam = ActuatorAdapterManager(useEmulator=self.enableEmulator)
        #set data generation config
        self.enableHandleTempChangeOnDevice = self.configUtil.getBoolean(ConfigConst.CONSTRAINED_DEVICE,
                                                                         ConfigConst.ENABLE_HANDLE_TEMP_CHANGE_ON_DEVICE_KEY)

        self.triggerHvacTempFloor = self.configUtil.getFloat(ConfigConst.CONSTRAINED_DEVICE,
                                                             ConfigConst.TRIGGER_HVAC_TEMP_FLOOR_KEY);

        self.triggerHvacTempCeiling = self.configUtil.getFloat(ConfigConst.CONSTRAINED_DEVICE,
                                                               ConfigConst.TRIGGER_HVAC_TEMP_CEILING_KEY);
        #self.stepmotor.moveTo(-40,-40,True)
        # set Mqtt client
        if enableMqtt is True:
            self.mqttClient = MqttClientConnector()
            #self.mqttClient.subscribeToTopic(ResourceNameEnum.CDA_ACTUATOR_RESPONSE_RESOURCE.value)
            #self.mqttClient.subscribeToTopic(ResourceNameEnum.CDA_ACTUATOR_CMD_RESOURCE.value)
            self.mqttClient.subscribeToTopic("ProgrammingIoT/StepMotor/Instruction")
            #self.mqttClient.mc.message_callback_add(callback=self.actuatorCallBack, sub=ResourceNameEnum.CDA_ACTUATOR_CMD_RESOURCE.value)
            self.mqttClient.mc.message_callback_add(callback=self.stepMotorCallBack, sub="ProgrammingIoT/StepMotor/Instruction")

    def actuatorCallBack(self,client, userdata, message):
        logging.info("MQTT CallBack:%s,%s" % (message.topic, message.payload))
        self._handleIncomingDataAnalysis(message)
    
    def stepMotorCallBack(self,client, userdata, message):
        logging.info("MQTT CallBack:%s,%s" % (message.topic, message.payload))
        point = str(message.payload.decode()).split(",")
        if len(point) == 2:
            self.stepmotor.moveTo(int(point[0]),int(point[1]),True)

    def handleActuatorCommandResponse(self, data: ActuatorData) -> bool:
        logging.info("handleActuatorCommandResponse called")
        #pass data to handler
        super().handleActuatorCommandResponse(data)
        #translate data to json and set updstream
        du = DataUtil()
        self._handleUpstreamTransmission(ResourceNameEnum.CDA_ACTUATOR_RESPONSE_RESOURCE.value, du.actuatorDataToJson(data))

    def handleIncomingMessage(self, resourceEnum: ResourceNameEnum, msg: str) -> bool:
        logging.info("handleIncommingMessage called")
        #translate json to object and pass it to analysis
        du = DataUtil()
        du.jsonToActuatorData(msg)
        self._handleIncomingDataAnalysis(msg)

    def handleSensorMessage(self, data: SensorData) -> bool:
        logging.info("handleSensorMessage called")
        super().handleSensorMessage(data)
        # translate sensor data to json and handle it
        du = DataUtil()
        self._handleUpstreamTransmission(ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE.value, du.sensorDataToJson(data))
        self._handleSensorDataAnalysis(data)

    def handleSystemPerformanceMessage(self, data: SystemPerformanceData) -> bool:
        logging.info("handleSystemPerformanceMessage called")
        #translate sys perf data to json and set upstream
        du = DataUtil()
        self._handleUpstreamTransmission(ResourceNameEnum.CDA_SYSTEM_PERF_MSG_RESOURC.value, du.systemPerformanceDataToJson(data))

    def startManager(self):
        #start manager
        self.sysPerfManager.startManager()
        self.sam.startManager()
        self.sam.setDataMessageListener(self)
        self.mqttClient.connectClient()

    def stopManager(self):
        #stop manager
        self.sysPerfManager.stopManager()
        self.sam.stopManager()
        self.mqttClient.disconnectClient()

    def _handleIncomingDataAnalysis(self, msg: str):
        """
        Call this from handleIncomeMessage() to determine if there's
        any action to take on the message. Steps to take:
        1) Validate msg: Most will be ActuatorData, but you may pass other info as well.
        2) Convert msg: Use DataUtil to convert if appropriate.
        3) Act on msg: Determine what - if any - action is required, and execute.
        """
        logging.info("_handleIncomingDataAnalysis called,msg:"+str(msg))
        #du = DataUtil()
        #self.aam.sendActuatorCommand(du.jsonToActuatorData(msg))

    def _handleSensorDataAnalysis(self, data: SensorData):
        """
        Call this from handleSensorMessage() to determine if there's
        any action to take on the message. Steps to take:
        1) Check config: Is there a rule or flag that requires immediate processing of data?
        2) Act on data: If # 1 is true, determine what - if any - action is required, and execute.
        """
        logging.info("_handleSensorDataAnalysis called,msg:"+str(data))
        if self.enableHandleTempChangeOnDevice is True:
            hvac = ActuatorData(ActuatorData.HVAC_ACTUATOR_TYPE)
            if data.getValue() < self.triggerHvacTempCeiling and data.getValue() > self.triggerHvacTempFloor:
                # start hvac when in trigger range
                hvac.setCommand(ActuatorData.COMMAND_ON)
            else:
                # stop hvac when not in range
                hvac.setCommand(ActuatorData.COMMAND_OFF)
            # send command
            self.aam.sendActuatorCommand(hvac)

    def handleActuatorCommandMessage(self, data: ActuatorData) -> bool:
        if data:
            logging.info("Processing actuator command message.")

            # TODO: add further validation before sending the command
            self.aam.sendActuatorCommand(data)
            return True
        else:
            logging.warning("Received invalid ActuatorData command message. Ignoring.")
            return False

    def _handleUpstreamTransmission(self, resourceName: ResourceNameEnum, msg: str):
        """
        Call this from handleActuatorCommandResponse(), handlesensorMessage(), and handleSystemPerformanceMessage()
        to determine if the message should be sent upstream. Steps to take:
        1) Check connection: Is there a client connection configured (and valid) to a remote MQTT or CoAP server?
        2) Act on msg: If # 1 is true, send message upstream using one (or both) client connections.
        """
        logging.info("_handleUpstreamTransmission called")
        # send message to mqtt broker
        if self.enableMqtt is True:
            self.mqttClient.publishMessage(resourceName, msg)
Beispiel #7
0
class DeviceDataManager(IDataMessageListener):
    """
	Shell representation of class for student implementation.
	
	"""
    def __init__(self, enableMqtt: bool = True, enableCoap: bool = False):
        """
		Initialization of class.
		Create an instance of DeviceDataManager
		"""

        self.configUtil = ConfigUtil()

        self.enableEmulator = self.configUtil.getBoolean(
            ConfigConst.CONSTRAINED_DEVICE, ConfigConst.ENABLE_EMULATOR_KEY)

        self.enableRedis = False

        self.sysPerfManager = SystemPerformanceManager()
        self.sysPerfManager.setDataMessageListener(self)
        self.sensorAdapterManager = SensorAdapterManager(
            useEmulator=self.enableEmulator)
        self.sensorAdapterManager.setDataMessageListener(self)
        self.actuatorAdapterManager = ActuatorAdapterManager(
            useEmulator=self.enableEmulator)
        self.actuatorAdapterManager.setDataMessageListener(self)
        ##add by miaoyao @10/30/2020
        if self.enableRedis:
            self.redisClient = RedisPersistenceAdapter()

        self.enableHandleTempChangeOnDevice = self.configUtil.getBoolean(
            ConfigConst.CONSTRAINED_DEVICE,
            ConfigConst.ENABLE_HANDLE_TEMP_CHANGE_ON_DEVICE_KEY)

        self.triggerHvacTempFloor = self.configUtil.getFloat(
            ConfigConst.CONSTRAINED_DEVICE,
            ConfigConst.TRIGGER_HVAC_TEMP_FLOOR_KEY)

        self.triggerHvacTempCeiling = self.configUtil.getFloat(
            ConfigConst.CONSTRAINED_DEVICE,
            ConfigConst.TRIGGER_HVAC_TEMP_CEILING_KEY)
        ##add by miaoyao for final project

        self.enableHandleSoilHumidityChangeOnDevice = self.configUtil.getBoolean(
            ConfigConst.CONSTRAINED_DEVICE,
            ConfigConst.ENABLE_HANDLE_SOIL_HUMIDITY_CHANGE_ON_DEVICE_KEY)

        self.triggerWaterDeviceHumiFloor = self.configUtil.getFloat(
            ConfigConst.CONSTRAINED_DEVICE,
            ConfigConst.TRIGGER_WATER_SOIL_HUMI_FLOOR_KEY)

        self.triggerWaterDeviceHumiCeiling = self.configUtil.getFloat(
            ConfigConst.CONSTRAINED_DEVICE,
            ConfigConst.TRIGGER_WATER_SOIL_HUMI_CEILING_KEY)

        ##add by miaoyao @11/02/2020
        ##self.enableMqtt = self.configUtil.getBoolean(ConfigConst.CONSTRAINED_DEVICE, ConfigConst.ENABLE_MQTT_KEY)
        self.enableMqtt = enableMqtt
        self.enableCoap = enableCoap

        if self.enableMqtt:
            self.mqttClient = MqttClientConnector()
            self.mqttClient.setDataMessageListener(self)
        if self.enableCoap:
            self.coapClient = CoapClientConnector()
            self.coapClient.setDataMessageListener(self)

    def handleActuatorCommandResponse(self, data: ActuatorData) -> bool:
        """
		handle the ActuatorCommandResponse
		
		@return bool
		"""

        # Use the DataUtil class to convert the ActuatorData to JSON.
        logging.info(
            "[CDA_CALLBACK]----->>>The handleActuatorCommandResponse method is being called"
        )
        adJson = DataUtil.actuatorDataToJson(self, data)
        self._handleUpstreamTransmission(
            ResourceNameEnum.CDA_ACTUATOR_RESPONSE_RESOURCE, adJson)

    def handleActuatorCommandMessage(self, data: ActuatorData) -> bool:
        """
		handle the handleActuatorCommandMessage
		
		@return bool
		"""
        logging.info(
            "[CDA_CALLBACK]----->>>The handleActuatorCommandMessage method is being called"
        )
        if data:
            logging.info("Processing actuator command message.")

            # TODO: add further validation before sending the command
            self.actuatorAdapterManager.sendActuatorCommand(data)
            return True
        else:
            logging.warning(
                "Received invalid ActuatorData command message. Ignoring.")
            return False

    def handleIncomingMessage(self, resourceEnum: ResourceNameEnum,
                              msg: str) -> bool:
        """
		handle the IncomingMessage
		
		@return bool
		"""
        logging.info(
            "[CDA_CALLBACK]----->>>The handleIncomingMessage method is being called"
        )
        # Use the DataUtil class to convert the msg content (which should be JSON) to an ActuatorData instance
        ad = DataUtil.jsonToActuatorData(self, msg)
        self._handleIncomingDataAnalysis(msg)

    def handleSensorMessage(self, data: SensorData) -> bool:
        """
		handle the SensorMessage
		
		@return bool
		"""
        logging.info(
            "[CDA_CALLBACK]----->>>The handleSensorMessage method is being called"
        )
        # Use the DataUtil class to convert the SensorData to JSON
        sdJosn = DataUtil.sensorDataToJson(self, data)
        self._handleUpstreamTransmission(
            ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE, sdJosn)
        self._handleSensorDataAnalysis(data)

        if self.enableRedis:
            self.redisClient.storeData(
                ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE, data)

    def handleSystemPerformanceMessage(self,
                                       data: SystemPerformanceData) -> bool:
        """
		handle the SystemPerformanceMessage
		
		@return bool
		"""
        logging.info(
            "[CDA_CALLBACK]----->>>The handleSystemPerformanceMessage method is being called"
        )
        spmJson = DataUtil.systemPerformanceDataToJson(self, data)
        self._handleUpstreamTransmission(
            ResourceNameEnum.CDA_SYSTEM_PERF_MSG_RESOURCE, spmJson)

    def startManager(self):
        """
		Start the DeviceDataManager. 
		Calls startManager() on the sysPerfManager instance.
		Calls startManager() on the sensorAdapterManager instance.
		
		"""
        logging.info("----->>>The DeviceDataManager will be started")
        self.sysPerfManager.startManager()
        self.sensorAdapterManager.startManager()
        if self.enableRedis:
            self.redisClient.connectClient()

        if self.enableMqtt:
            self.mqttClient.connectClient()

    def stopManager(self):
        """
		Stop the DeviceDataManager. 
		Calls stopManager() on the sysPerfManager instance.
		Calls stopManager() on the sensorAdapterManager instance.
		
		"""
        self.sysPerfManager.stopManager()
        self.sensorAdapterManager.stopManager()

        if self.enableRedis:
            self.redisClient.disconnectClient()
        if self.enableMqtt:
            self.mqttClient.disconnectClient()

        logging.info("----->>>The DeviceDataManager stopped")

    def _handleIncomingDataAnalysis(self, msg: str):
        """
		Call this from handleIncomeMessage() to determine if there's
		any action to take on the message. Steps to take:
		1) Validate msg: Most will be ActuatorData, but you may pass other info as well.
		2) Convert msg: Use DataUtil to convert if appropriate.
		3) Act on msg: Determine what - if any - action is required, and execute.
		"""
        logging.info(
            "[CDA_CALLBACK]----->>>The _handleIncomingDataAnalysis method is being called"
        )
        ad = DataUtil.jsonToActuatorData(self, msg)
        self.actuatorAdapterManager.sendActuatorCommand(ad)

    def _handleSensorDataAnalysis(self, data: SensorData):
        """
		Call this from handleSensorMessage() to determine if there's
		any action to take on the message. Steps to take:
		1) Check config: Is there a rule or flag that requires immediate processing of data?
		2) Act on data: If # 1 is true, determine what - if any - action is required, and execute.
		"""
        logging.info(
            "[CDA_CALLBACK]----->>>The _handleSensorDataAnalysis method is being called"
        )
        """
		"""
        if self.enableHandleTempChangeOnDevice and data.getSensorType(
        ) == SensorData.TEMP_SENSOR_TYPE:

            ad = ActuatorData(actuatorType=ActuatorData.HVAC_ACTUATOR_TYPE)
            value = data.getValue()
            if value >= self.triggerHvacTempFloor and value <= self.triggerHvacTempCeiling:
                ad.setCommand(ActuatorData.COMMAND_OFF)
            else:
                ad.setCommand(ActuatorData.COMMAND_ON)

            self.actuatorAdapterManager.sendActuatorCommand(ad)
        """
		"""
        if self.enableHandleSoilHumidityChangeOnDevice and data.getSensorType(
        ) == SensorData.SOIL_HUMIDITY_SENSOR_TYPE:

            ad = ActuatorData(
                actuatorType=ActuatorData.SPRINKLER_ACTUATOR_TYPE)
            value = data.getValue()
            if value >= self.triggerWaterDeviceHumiCeiling:
                ad.setCommand(ActuatorData.COMMAND_OFF)
                self.actuatorAdapterManager.sendActuatorCommand(ad)
            elif value <= self.triggerWaterDeviceHumiFloor:
                ad.setCommand(ActuatorData.COMMAND_ON)
                self.actuatorAdapterManager.sendActuatorCommand(ad)
                self.coapClient.sendGetRequest(
                    ResourceNameEnum.CDA_ACTUATOR_CMD_RESOURCE, False, 5)
            else:
                self.coapClient.sendGetRequest(
                    ResourceNameEnum.CDA_CLOUD_ACTUATOR_CMD_RESOURCE, False, 5)

    def _handleUpstreamTransmission(self, resourceName: ResourceNameEnum,
                                    msg: str):
        """
		Call this from handleActuatorCommandResponse(), handlesensorMessage(), and handleSystemPerformanceMessage()
		to determine if the message should be sent upstream. Steps to take:
		1) Check connection: Is there a client connection configured (and valid) to a remote MQTT or CoAP server?
		2) Act on msg: If # 1 is true, send message upstream using one (or both) client connections.
		"""
        logging.info(
            "[callback]----->>>The _handleUpstreamTransmission method is being called"
        )
        if self.enableMqtt:
            self.mqttClient.publishMessage(resourceName, msg)
        """