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()
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()
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")
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)
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) """