AgentM.py 9.5 KB
#!/usr/bin/env python3

import sys
##import utils.Logger as L
#import threading #, multiprocessing, os
#import time

#from django.db import transaction
#from common.models import Command

import os
pwd = os.environ['PROJECT_ROOT_PATH']
if pwd not in sys.path:
    sys.path.append(pwd)

from src.core.pyros_django.majordome.agent.Agent import Agent, build_agent, log, parse_args

# PM 20190416 recycle code
from src.core.pyros_django.devices.PLC import PLCController
from src.core.pyros_django.env_monitor.plc_checker import PlcChecker
from common.models import *
from config.general.config_pyros import ConfigPyros



##log = L.setupLogger("AgentXTaskLogger", "AgentX")



class AgentM(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

    ##_path_data = 'config'
    _path_data = 'config/old_config'
    # PM 20190416 recycle code
    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


    '''
    # Who should I send commands to ?
    #TEST_COMMANDS_DEST = "myself"
    TEST_COMMANDS_DEST = "AgentA"
    # Scenario to be executed
    TEST_COMMANDS_LIST = [
        "go_active",
        "go_idle",
        "go_active",
        "go_idle",
        "go_active",
        "go_idle",
        "exit",
    ]
    '''

    """
    =================================================================
        FUNCTIONS RUN INSIDE MAIN THREAD
    =================================================================
    """
    # old config
    # @override
    #def __init__(self, name:str=None, config_filename=None, RUN_IN_THREAD=True):
    # def __init__(self, config_filename=None, RUN_IN_THREAD=True):
    #     ##if name is None: name = self.__class__.__name__
    #     super().__init__(config_filename, RUN_IN_THREAD)

    # new config (obsconfig)
    def __init__(self, name:str=None):
        if name is None:
            name = self.__class__.__name__
        super().__init__()
        PYROS_CONFIG_FILE = os.environ.get("pyros_config_file")
        if PYROS_CONFIG_FILE:
            CONFIG_PYROS =  ConfigPyros(PYROS_CONFIG_FILE).pyros_config
            self.time_history_minutes = int(CONFIG_PYROS.get("ENV").get("time_history"))
            log.info(f"time_history_minutes set to {int(self.time_history_minutes)}")
    # @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 load_config(self):
        super().load_config()
    '''

    '''
    # @override
    def update_survey(self):
        super().update_survey()
    '''

    '''
    # @override
    def get_next_command(self):
        return super().get_next_command()
    '''

    # @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()")
        status_plc = self.plcController.getStatus()
        print("Save weather")
        self.saveWeather()

    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 saveWeather(self):
        print(("saving weather")
        sensors_data = Sensors_data_last_value().objects.all()
        datetimenow = datetime.now(timezone.utc)
        # get sensor config to read quality and take the device with the best quality value
        monitoring_devices = self.get_config().get_monitoring_devices()
        devices = self.get_config().get_devices()
        sensors_data_with_qualities = {}
        for device in monitoring_devices:
            capabilities = devices[device].get("device_config").get("CAPABILITIES")
            for capability in capabilities:
                output_data = capabilities[capability].get("output_data")
                for sensor in output_data:
                    key = output_data[sensor].get("key")
                    sensor_data = Sensors_data_last_value.get(key=key)
                    quality =  output_data[sensor].get("quality")
                    monitoring_name = output_data[sensor].get("monitoring_name")
                    if sensors_data_with_qualities[monitoring_name] is None:
                        sensors_data_with_qualities[monitoring_name] = [(key,quality)]
                    else:
                        sensors_data_with_qualities[monitoring_name].append((key,quality))
        for monitoring_name in sensors_data_with_qualities:
            max_quality = 0
            associated_key = ""
            for sensor_data in sensors_data_with_qualities[monitoring_name]:
                key = sensors_data[0]
                quality = float(sensor_data[1])
                if quality > max_quality:
                    max_quality = quality
                    associated_key = key
            print(Sensors_data.objects.get(key=associated_key)
            env.objects.create(monitoring_name=monitoring_name,value = Sensors_data.objects.get(key=associated_key).value)

        # Loop into each monitoring and set global status -> issue : describe which monitoring name to survey and make a global status with them...
        latest_entry_of_history = Sensors_data.objects.all().order_by("-datetime").first()
        if latest_entry_of_history != None:
            # Get last entry of WeatherWatchHistory as WeatherWatch
            latest_entry_of_history_as_weather = Sensors_data.objects.get(id=latest_entry_of_history.weather.id)
        # outside.setGlobalStatus()
        # outside.save()
        #inside.save()
        # We don't have an history for weatherwatch
        # if latest_entry_of_history == None:
        #     weather_history = WeatherWatchHistory()
        #     weather_history.weather = outside
        #     for sensor in outside_attributes_values.keys():
        #         weather_history.setAttribute(sensor,outside_attributes_values.get(sensor))
        #     # save also sensors 
        #     weather_history.save()
        # else:
        #     time_between_history_and_latest_entry = datetimenow - latest_entry_of_history_as_weather.updated  
        #     sec_diff = time_between_history_and_latest_entry.total_seconds() / 60
        #     # if diff between last entry of history and current time if greather than x then we save a new entry in history
        #     if int(sec_diff) > self.time_history_minutes:
        #         weather_history = WeatherWatchHistory()
        #         weather_history.weather = outside
        #         for sensor in outside_attributes_values.keys():
        #             weather_history.setAttribute(sensor,outside_attributes_values.get(sensor))
        #         weather_history.save()
        # log.debug("saved weather")

    def setGlobalStatus(self):
        self.global_status = ""
        if self.doors and self.doors.find("open") != -1:
            self.global_status += "DOOR_OPEN "
        if self.lights and self.lights == "on":
            self.global_status += "LIGHTS_ON "
        if self.temperature and float(self.temperature) > 40:
            self.global_status += "TOO_HOT "
        if self.humidity and float(self.humidity) > 80:
            self.global_status += "HUMIDITY_TOO_HIGH "
        if self.global_status == "":
            self.global_status = "OK"
        return 0

    def isInsideMonitoring(self,key):
        if key in ("Power_input","Roof_state"):
            return True
        else:
            return False
    # @override
    def thread_exec_specific_cmd_main(self):
        # This is optional
        self.thread_set_total_steps_number(5)

        # HERE, write your own scenario

        # scenario OK
        self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1)
        self.thread_exec_specific_cmd_step(2, self.cmd_step2, 3)
        self.thread_exec_specific_cmd_step(3, self.cmd_step1, 5)
        self.thread_exec_specific_cmd_step(4, self.cmd_step3, 10)
        self.thread_exec_specific_cmd_step(5, self.cmd_step1, 4)
        # ... as many as you need

        """ autre scenario
        self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1)
        self.thread_exec_specific_cmd_step(2, self.cmd_step2, 2)
        self.thread_exec_specific_cmd_step(3, self.cmd_step1, 2)
        self.thread_exec_specific_cmd_step(4, self.cmd_step3, 2)
        self.thread_exec_specific_cmd_step(5, self.cmd_step1, 3)
        """

    '''
    # @override
    def exec_specific_cmd_end(self, cmd:Command, from_thread=True):
        super().exec_specific_cmd_end(cmd, from_thread)
    '''


if __name__ == "__main__":

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