AgentDevicePLC.py 5.94 KB
#!/usr/bin/env python3

import sys,os

pwd = os.environ['PROJECT_ROOT_PATH']
if pwd not in sys.path:
    sys.path.append(pwd)
from src.core.pyros_django.agent.Agent import Agent, build_agent, log, parse_args

from src.core.pyros_django.devices.PLC import PLCController
from src.core.pyros_django.monitoring.plc_checker import PlcChecker
from common.models import *
from config.pyros.config_pyros import ConfigPyros


class AgentDevicePLC(Agent):


    # FOR TEST ONLY
    # Run this agent in simulator mode
    TEST_MODE = False
    # Run the assertion tests at the end
    TEST_WITH_FINAL_TEST = True
    TEST_MAX_DURATION_SEC = None
    #TEST_MAX_DURATION_SEC = 120

    plcController = PLCController()
    print ("AGENT ENV: config PLC is (ip={}, port={})".format(plcController.ip, plcController.port))
    plc_checker = PlcChecker()

    log.debug("PLC instanciated")
    time_history_minutes = 4

    # new config (obsconfig)
    def __init__(self, name:str=None, simulated_computer=None):
        if name is None:
            name = self.__class__.__name__
        super().__init__(simulated_computer=simulated_computer)
        self.device_name = self.get_config().get_device_for_agent(self.get_config().unit_name, self.name).get("name")
        self.serial_number = self.get_config().get_device_for_agent(self.get_config().unit_name, self.name).get("device_config").get("sn")
        self.output_data = self.get_config().get_output_data_device(self.device_name)
    # @override
    def _init(self):
        super()._init()
       
        log.debug("end init()")
        # --- Set the mode according the startmode value
        ##agent_alias = self.__class__.__name__
        ##self.set_mode_from_config(agent_alias)

    # @override
    def do_log(self):
        super().do_log()


    # @override
    # previous name of function : routine_process
    # Note : in Agent.py, routine_process_body seems to be the main function of routine of the agent
    # We need to override routine_process_body and not routine_process
        
    def _routine_process_iter_end_body(self):
        log.debug("in routine_process_body()")
        log.info("routine process iter end body")
        log.info(self.plcController)
        status_plc = self.plcController.getStatus()
        if self.parseNewStatus(status_plc):
            self.saveSensors()
            #self.saveInternalMonitoring()

    def parseNewStatus(self,status_plc):
        # """ PM 20181009 parse new status for config
        # Find return string "plc_status" positin within status_plc
        if status_plc.find('PLC_STATUS') >= 0:
            self.plc_checker.chk_config(status_plc)
            return True
        
        return False

    def saveSensors(self):
        log.info("Saving sensors data")
        latest_entry_of_history = Sensors_data.objects.all().order_by("-created").first()
        datetimenow = datetime.now(timezone.utc)
        sensor_data_dict = {}
        for sensor in self.output_data:
            for entity in self.output_data[sensor]:
                sensor_monitoring_name = self.output_data[sensor].get(entity).get("monitoring_name")
                if sensor_monitoring_name in self.plc_checker.monitoring_names.keys() and self.plc_checker.monitoring_names[sensor_monitoring_name] is not None:
                    value = self.plc_checker.get_sensor(sensor_monitoring_name)
                    try:
                        sensor_db = Sensors_data_last_value.objects.get(key=entity,serial_number=self.serial_number)
                    except Sensors_data_last_value.DoesNotExist:
                        sensor_db = Sensors_data_last_value.objects.create(
                            value=value,
                            key=entity,
                            model=self.device_name,
                            serial_number=self.serial_number,
                            monitoring_name=sensor_monitoring_name
                        )
                    sensor_db.value=value
                    sensor_db.key=entity 
                    sensor_db.model=self.device_name
                    sensor_db.serial_number=self.serial_number
                    sensor_db.monitoring_name=sensor_monitoring_name
                    sensor_db.save()
                    sensor_data_dict[entity] = {
                        "value":value,
                        "model":self.device_name,
                        "serial_number":self.serial_number,
                        "monitoring_name":sensor_monitoring_name
                    }
                    # Check error_code & if error, save it in database
        if latest_entry_of_history == None:
            self.save_history(sensor_data_dict)
            # We don't have an history for sensor_data

        else:
            time_between_history_and_latest_entry = datetimenow - latest_entry_of_history.created  
            sec_diff = time_between_history_and_latest_entry.total_seconds() / 60
            # if diff between last entry of history and current time if greater than x then we save a new entry in history
            if int(sec_diff) > self.time_history_minutes:
                self.save_history(sensor_data_dict)
        log.debug("saved weather")

    def save_history(self, sensor_data_dict):
        for key in sensor_data_dict:
            sensor_data = Sensors_data.objects.create(
                value=sensor_data_dict[key]["value"],
                key=key,
                model=sensor_data_dict[key]["model"],
                serial_number=sensor_data_dict[key]["serial_number"],
                monitoring_name=sensor_data_dict[key]["monitoring_name"]
            )
        sensor_data.save()

if __name__ == "__main__":

    # with thread
    RUN_IN_THREAD=True
    # with process
    #RUN_IN_THREAD=False
    args =  parse_args(sys.argv[1:])    
    agent = build_agent(AgentDevicePLC,param_constr=args)
    '''
    TEST_MODE, configfile = extract_parameters()
    agent = AgentM("AgentM", configfile, RUN_IN_THREAD)
    agent.setSimulatorMode(TEST_MODE)
    '''
    print(agent)
    agent.run()