class SensorAdapterManagerTest(unittest.TestCase):
    """
	This test case class contains very basic unit tests for
	SensorAdapterManager. 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 SensorAdapterManager class...")
        self.configUtil = ConfigUtil()
        self.enableEmulator = self.configUtil.getBoolean(
            ConfigConst.CONSTRAINED_DEVICE, ConfigConst.ENABLE_EMULATOR_KEY)
        self.defaultMsgListener = DefaultDataMessageListener()
        self.sensorAdapterMgr = SensorAdapterManager(
            useEmulator=self.enableEmulator)
        self.sensorAdapterMgr.setDataMessageListener(self.defaultMsgListener)

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testStartAndStopManager(self):
        self.sensorAdapterMgr.startManager()

        sleep(20)

        self.sensorAdapterMgr.stopManager()
Exemplo n.º 2
0
class SensorEmulatorManagerTest(unittest.TestCase):
    """
	This test case class contains very basic unit tests for
	ActuatorSimAdapterManager. It should not be considered complete,
	but serve as a starting point for the student implementing
	additional functionality within their Programming the IoT
	environment.
	
	NOTE: This test requires the sense_emu_gui to be running
	and must have access to the underlying libraries that
	support the pisense module. On Windows, one way to do
	this is by installing pisense and sense-emu within the
	Bash on Ubuntu on Windows environment and then execute this
	test case from the command line, as it will likely fail
	if run within an IDE in native Windows.
	
	"""
    @classmethod
    def setUpClass(self):
        logging.basicConfig(
            format='%(asctime)s:%(module)s:%(levelname)s:%(message)s',
            level=logging.DEBUG)
        logging.info(
            "Testing SensorAdapterManager class [using SenseHAT emulator]...")

        self.defaultMsgListener = DefaultDataMessageListener()
        self.sensorAdapterMgr = SensorAdapterManager(useEmulator=True)
        self.sensorAdapterMgr.setDataMessageListener(self.defaultMsgListener)

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testRunAllSimulators(self):
        self.sensorAdapterMgr.startManager()

        sleep(60)

        self.sensorAdapterMgr.stopManager()
class DeviceDataManager(IDataMessageListener):
    """
	Shell representation of class for student implementation.
	
	"""
    def __init__(self, enableMqtt: bool = True, enableCoap: bool = False):
        self.sysPerfManager = SystemPerformanceManager()
        self.sensorAdapterManager = SensorAdapterManager()
        self.actuatorAdapterManager = ActuatorAdapterManager()
        self.configUtil = ConfigUtil()
        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)

    def handleActuatorCommandResponse(self, data: ActuatorData) -> bool:
        logging("handleActuatorCommandResponse method is called...")
        self._handleUpstreamTransmission(
            ResourceNameEnum.CDA_ACTUATOR_RESPONSE_RESOURCE,
            DataUtil.actuatorDataToJson(self, data))
        pass

    def handleIncomingMessage(self, resourceEnum: ResourceNameEnum,
                              msg: str) -> bool:
        logging("handleIncomingMessage method is called...")
        self._handleIncomingDataAnalysis(DataUtil.jsonToActuatorData(
            self, msg))
        pass

    def handleSensorMessage(self, data: SensorData) -> bool:
        logging("handleSensorMessage method is called...")
        self._handleUpstreamTransmission(
            ResourceNameEnum.CDA_SENSOR_MSG_RESOURCE,
            DataUtil.sensorDataToJson(self, data))
        pass

    def handleSystemPerformanceMessage(self,
                                       data: SystemPerformanceData) -> bool:
        logging("handleSystemPerformanceMessage method is called...")
        self._handleUpstreamTransmission(
            ResourceNameEnum.CDA_SYSTEM_PERF_MSG_RESOURCE,
            DataUtil.systemPerformanceDataToJson(self, data))
        pass

    def startManager(self):
        logging.info("Started DeviceDataManager.")
        self.sysPerfManager.startManager()
        self.sensorAdapterManager.startManager()
        pass

    def stopManager(self):
        logging.info("Stopped DeviceDataManager.")
        self.sysPerfManager.stopManager()
        self.sensorAdapterManager.stopManager()
        pass

    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("_handleIncomingDataAnalysis method is called...")
        self.actuatorAdapterManager.sendActuatorCommand(
            DataUtil.jsonToActuatorData(self, msg))
        pass

    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("_handleSensorDataAnalysis method is called...")
        if (self.enableHandleTempChangeOnDevice == True):
            self.actuatorData = ActuatorData()
            self.actuatorData.actuator_type = ActuatorData.HVAC_ACTUATOR_TYPE
            self.actuatorData.COMMAND_ON
            self.actuatorAdapterManager.sendActuatorCommand(self.actuatorData)
            pass

    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("_handleUpstreamTransmission method is called...")
        pass
Exemplo n.º 4
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)
Exemplo n.º 5
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)
        """