diff --git a/CHANGELOG b/CHANGELOG index cf95a25..1fe66b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +05-12-2022 (AKo): v0.6.15.1 + - Update AgentM (protected attributes/functions) + 02-12-2022 (AKo): v0.6.15.1 - Fix initial_fixture with new path of models - Fix routine_manager tests diff --git a/privatedev/plugin/agent/AgentM.py b/privatedev/plugin/agent/AgentM.py new file mode 100755 index 0000000..aeb6c16 --- /dev/null +++ b/privatedev/plugin/agent/AgentM.py @@ -0,0 +1,279 @@ +#!/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.agent.Agent import Agent, build_agent, log + +# PM 20190416 recycle code +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 + + + +##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 + + # PM 20190416 fucking config path starting: /home/patrick/Dev/PYROS/start_agent.py agentM + ##_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() + + + + """ + ================================================================= + FUNCTIONS RUN INSIDE A SUB-THREAD (OR A PROCESS) (thread_*()) + ================================================================= + """ + + # Define your own command step(s) here + def cmd_step1(self, step:int): + cmd = self._current_specific_cmd + cmd.result = f"in step #{step}/{self._thread_total_steps_number}" + cmd.save() + """ + if self.RUN_IN_THREAD: + print("(save from thread)") + cmd.save() + else: + #@transaction.atomic + print("(save from process)") + with transaction.atomic(): + cmd.save() + #Command.objects.select_for_update() + """ + + def cmd_step2(self, step:int): + self.cmd_step1(step) + def cmd_step3(self, step:int): + self.cmd_step1(step) + def cmd_step4(self, step:int): + self.cmd_step1(step) + + """ + # @override + def thread_exec_specific_cmd_step(self, step:int, sleep_time:float=1.0): + self.thread_stop_if_asked() + cmd = self._current_specific_cmd + print(f">>>>> Thread (cmd {cmd.name}): step #{step}/5") + self.sleep(sleep_time) + """ + + ''' + # @override + def exec_specific_cmd_start(self, cmd:Command, from_thread=True): + super().exec_specific_cmd_start(cmd, from_thread) + ''' + + # @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()") + print("TODO: we recycle code") + status_plc = self.plcController.getStatus() + if self.parseNewStatus(status_plc): + self.saveWeather() + #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 saveWeather(self): + outside = WeatherWatch() + inside = SiteWatch() + datetimenow = datetime.now(timezone.utc) + latest_entry_of_history = WeatherWatchHistory.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 = WeatherWatch.objects.get(id=latest_entry_of_history.weather.id) + outside_attributes_values = {} + for sensor in self.plc_checker.monitoring_names.keys(): + if sensor in self.plc_checker.inside_sensors: + value = self.plc_checker.get_sensor(sensor) + inside.setAttribute(sensor,value) + else: + value = self.plc_checker.get_sensor(sensor) + outside.setAttribute(sensor, value) + outside_attributes_values[sensor] = value + 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 isInsideMonitoring(self,key): + print(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 + + agent = build_agent(AgentM) + ''' + TEST_MODE, configfile = extract_parameters() + agent = AgentM("AgentM", configfile, RUN_IN_THREAD) + agent.setSimulatorMode(TEST_MODE) + ''' + print(agent) + agent.run() diff --git a/src/core/pyros_django/monitoring/AgentM.py b/src/core/pyros_django/monitoring/AgentM.py index 6054db0..aeb6c16 100755 --- a/src/core/pyros_django/monitoring/AgentM.py +++ b/src/core/pyros_django/monitoring/AgentM.py @@ -8,8 +8,11 @@ import sys #from django.db import transaction #from common.models import Command -sys.path.append("..") -sys.path.append("../../../..") +import 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 # PM 20190416 recycle code @@ -167,7 +170,7 @@ class AgentM(Agent): # 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_body(self): + def _routine_process_iter_end_body(self): log.debug("in routine_process_body()") print("TODO: we recycle code") status_plc = self.plcController.getStatus() -- libgit2 0.21.2