Commit 514e3287b5a145ca753bb7761fc0dfd5b458eb87
1 parent
43d8ca44
Exists in
dev
Update AgentM (protected attributes/functions)
Showing
3 changed files
with
288 additions
and
3 deletions
Show diff stats
CHANGELOG
1 | +05-12-2022 (AKo): v0.6.15.1 | ||
2 | + - Update AgentM (protected attributes/functions) | ||
3 | + | ||
1 | 02-12-2022 (AKo): v0.6.15.1 | 4 | 02-12-2022 (AKo): v0.6.15.1 |
2 | - Fix initial_fixture with new path of models | 5 | - Fix initial_fixture with new path of models |
3 | - Fix routine_manager tests | 6 | - Fix routine_manager tests |
@@ -0,0 +1,279 @@ | @@ -0,0 +1,279 @@ | ||
1 | +#!/usr/bin/env python3 | ||
2 | + | ||
3 | +import sys | ||
4 | +##import utils.Logger as L | ||
5 | +#import threading #, multiprocessing, os | ||
6 | +#import time | ||
7 | + | ||
8 | +#from django.db import transaction | ||
9 | +#from common.models import Command | ||
10 | + | ||
11 | +import os | ||
12 | +pwd = os.environ['PROJECT_ROOT_PATH'] | ||
13 | +if pwd not in sys.path: | ||
14 | + sys.path.append(pwd) | ||
15 | + | ||
16 | +from src.core.pyros_django.agent.Agent import Agent, build_agent, log | ||
17 | + | ||
18 | +# PM 20190416 recycle code | ||
19 | +from src.core.pyros_django.devices.PLC import PLCController | ||
20 | +from src.core.pyros_django.monitoring.plc_checker import PlcChecker | ||
21 | +from common.models import * | ||
22 | +from config.pyros.config_pyros import ConfigPyros | ||
23 | + | ||
24 | + | ||
25 | + | ||
26 | +##log = L.setupLogger("AgentXTaskLogger", "AgentX") | ||
27 | + | ||
28 | + | ||
29 | + | ||
30 | +class AgentM(Agent): | ||
31 | + | ||
32 | + | ||
33 | + # FOR TEST ONLY | ||
34 | + # Run this agent in simulator mode | ||
35 | + TEST_MODE = False | ||
36 | + # Run the assertion tests at the end | ||
37 | + TEST_WITH_FINAL_TEST = True | ||
38 | + TEST_MAX_DURATION_SEC = None | ||
39 | + #TEST_MAX_DURATION_SEC = 120 | ||
40 | + | ||
41 | + # PM 20190416 fucking config path starting: /home/patrick/Dev/PYROS/start_agent.py agentM | ||
42 | + ##_path_data = 'config' | ||
43 | + _path_data = 'config/old_config' | ||
44 | + # PM 20190416 recycle code | ||
45 | + plcController = PLCController() | ||
46 | + print ("AGENT ENV: config PLC is (ip={}, port={})".format(plcController.ip, plcController.port)) | ||
47 | + plc_checker = PlcChecker() | ||
48 | + | ||
49 | + log.debug("PLC instanciated") | ||
50 | + time_history_minutes = 4 | ||
51 | + | ||
52 | + | ||
53 | + ''' | ||
54 | + # Who should I send commands to ? | ||
55 | + #TEST_COMMANDS_DEST = "myself" | ||
56 | + TEST_COMMANDS_DEST = "AgentA" | ||
57 | + # Scenario to be executed | ||
58 | + TEST_COMMANDS_LIST = [ | ||
59 | + "go_active", | ||
60 | + "go_idle", | ||
61 | + "go_active", | ||
62 | + "go_idle", | ||
63 | + "go_active", | ||
64 | + "go_idle", | ||
65 | + "exit", | ||
66 | + ] | ||
67 | + ''' | ||
68 | + | ||
69 | + """ | ||
70 | + ================================================================= | ||
71 | + FUNCTIONS RUN INSIDE MAIN THREAD | ||
72 | + ================================================================= | ||
73 | + """ | ||
74 | + # old config | ||
75 | + # @override | ||
76 | + #def __init__(self, name:str=None, config_filename=None, RUN_IN_THREAD=True): | ||
77 | + # def __init__(self, config_filename=None, RUN_IN_THREAD=True): | ||
78 | + # ##if name is None: name = self.__class__.__name__ | ||
79 | + # super().__init__(config_filename, RUN_IN_THREAD) | ||
80 | + | ||
81 | + # new config (obsconfig) | ||
82 | + def __init__(self, name:str=None): | ||
83 | + if name is None: | ||
84 | + name = self.__class__.__name__ | ||
85 | + super().__init__() | ||
86 | + PYROS_CONFIG_FILE = os.environ.get("pyros_config_file") | ||
87 | + if PYROS_CONFIG_FILE: | ||
88 | + CONFIG_PYROS = ConfigPyros(PYROS_CONFIG_FILE).pyros_config | ||
89 | + self.time_history_minutes = int(CONFIG_PYROS.get("ENV").get("time_history")) | ||
90 | + log.info(f"time_history_minutes set to {int(self.time_history_minutes)}") | ||
91 | + # @override | ||
92 | + def _init(self): | ||
93 | + super()._init() | ||
94 | + | ||
95 | + log.debug("end init()") | ||
96 | + # --- Set the mode according the startmode value | ||
97 | + ##agent_alias = self.__class__.__name__ | ||
98 | + ##self.set_mode_from_config(agent_alias) | ||
99 | + | ||
100 | + ''' | ||
101 | + # @override | ||
102 | + def load_config(self): | ||
103 | + super().load_config() | ||
104 | + ''' | ||
105 | + | ||
106 | + ''' | ||
107 | + # @override | ||
108 | + def update_survey(self): | ||
109 | + super().update_survey() | ||
110 | + ''' | ||
111 | + | ||
112 | + ''' | ||
113 | + # @override | ||
114 | + def get_next_command(self): | ||
115 | + return super().get_next_command() | ||
116 | + ''' | ||
117 | + | ||
118 | + # @override | ||
119 | + def do_log(self): | ||
120 | + super().do_log() | ||
121 | + | ||
122 | + | ||
123 | + | ||
124 | + """ | ||
125 | + ================================================================= | ||
126 | + FUNCTIONS RUN INSIDE A SUB-THREAD (OR A PROCESS) (thread_*()) | ||
127 | + ================================================================= | ||
128 | + """ | ||
129 | + | ||
130 | + # Define your own command step(s) here | ||
131 | + def cmd_step1(self, step:int): | ||
132 | + cmd = self._current_specific_cmd | ||
133 | + cmd.result = f"in step #{step}/{self._thread_total_steps_number}" | ||
134 | + cmd.save() | ||
135 | + """ | ||
136 | + if self.RUN_IN_THREAD: | ||
137 | + print("(save from thread)") | ||
138 | + cmd.save() | ||
139 | + else: | ||
140 | + #@transaction.atomic | ||
141 | + print("(save from process)") | ||
142 | + with transaction.atomic(): | ||
143 | + cmd.save() | ||
144 | + #Command.objects.select_for_update() | ||
145 | + """ | ||
146 | + | ||
147 | + def cmd_step2(self, step:int): | ||
148 | + self.cmd_step1(step) | ||
149 | + def cmd_step3(self, step:int): | ||
150 | + self.cmd_step1(step) | ||
151 | + def cmd_step4(self, step:int): | ||
152 | + self.cmd_step1(step) | ||
153 | + | ||
154 | + """ | ||
155 | + # @override | ||
156 | + def thread_exec_specific_cmd_step(self, step:int, sleep_time:float=1.0): | ||
157 | + self.thread_stop_if_asked() | ||
158 | + cmd = self._current_specific_cmd | ||
159 | + print(f">>>>> Thread (cmd {cmd.name}): step #{step}/5") | ||
160 | + self.sleep(sleep_time) | ||
161 | + """ | ||
162 | + | ||
163 | + ''' | ||
164 | + # @override | ||
165 | + def exec_specific_cmd_start(self, cmd:Command, from_thread=True): | ||
166 | + super().exec_specific_cmd_start(cmd, from_thread) | ||
167 | + ''' | ||
168 | + | ||
169 | + # @override | ||
170 | + # previous name of function : routine_process | ||
171 | + # Note : in Agent.py, routine_process_body seems to be the main function of routine of the agent | ||
172 | + # We need to override routine_process_body and not routine_process | ||
173 | + def _routine_process_iter_end_body(self): | ||
174 | + log.debug("in routine_process_body()") | ||
175 | + print("TODO: we recycle code") | ||
176 | + status_plc = self.plcController.getStatus() | ||
177 | + if self.parseNewStatus(status_plc): | ||
178 | + self.saveWeather() | ||
179 | + #self.saveInternalMonitoring() | ||
180 | + | ||
181 | + def parseNewStatus(self,status_plc): | ||
182 | + # """ PM 20181009 parse new status for config | ||
183 | + # Find return string "plc_status" positin within status_plc | ||
184 | + if status_plc.find('PLC_STATUS') >= 0: | ||
185 | + self.plc_checker.chk_config(status_plc) | ||
186 | + return True | ||
187 | + return False | ||
188 | + | ||
189 | + def saveWeather(self): | ||
190 | + outside = WeatherWatch() | ||
191 | + inside = SiteWatch() | ||
192 | + datetimenow = datetime.now(timezone.utc) | ||
193 | + latest_entry_of_history = WeatherWatchHistory.objects.all().order_by("-datetime").first() | ||
194 | + if latest_entry_of_history != None: | ||
195 | + # Get last entry of WeatherWatchHistory as WeatherWatch | ||
196 | + latest_entry_of_history_as_weather = WeatherWatch.objects.get(id=latest_entry_of_history.weather.id) | ||
197 | + outside_attributes_values = {} | ||
198 | + for sensor in self.plc_checker.monitoring_names.keys(): | ||
199 | + if sensor in self.plc_checker.inside_sensors: | ||
200 | + value = self.plc_checker.get_sensor(sensor) | ||
201 | + inside.setAttribute(sensor,value) | ||
202 | + else: | ||
203 | + value = self.plc_checker.get_sensor(sensor) | ||
204 | + outside.setAttribute(sensor, value) | ||
205 | + outside_attributes_values[sensor] = value | ||
206 | + outside.setGlobalStatus() | ||
207 | + outside.save() | ||
208 | + #inside.save() | ||
209 | + # We don't have an history for weatherwatch | ||
210 | + if latest_entry_of_history == None: | ||
211 | + weather_history = WeatherWatchHistory() | ||
212 | + weather_history.weather = outside | ||
213 | + for sensor in outside_attributes_values.keys(): | ||
214 | + weather_history.setAttribute(sensor,outside_attributes_values.get(sensor)) | ||
215 | + # save also sensors | ||
216 | + weather_history.save() | ||
217 | + else: | ||
218 | + time_between_history_and_latest_entry = datetimenow - latest_entry_of_history_as_weather.updated | ||
219 | + sec_diff = time_between_history_and_latest_entry.total_seconds() / 60 | ||
220 | + # if diff between last entry of history and current time if greather than x then we save a new entry in history | ||
221 | + if int(sec_diff) > self.time_history_minutes: | ||
222 | + weather_history = WeatherWatchHistory() | ||
223 | + weather_history.weather = outside | ||
224 | + for sensor in outside_attributes_values.keys(): | ||
225 | + weather_history.setAttribute(sensor,outside_attributes_values.get(sensor)) | ||
226 | + weather_history.save() | ||
227 | + log.debug("saved weather") | ||
228 | + | ||
229 | + def isInsideMonitoring(self,key): | ||
230 | + print(key) | ||
231 | + if key in ("Power_input","Roof_state"): | ||
232 | + return True | ||
233 | + else: | ||
234 | + return False | ||
235 | + # @override | ||
236 | + def thread_exec_specific_cmd_main(self): | ||
237 | + # This is optional | ||
238 | + self.thread_set_total_steps_number(5) | ||
239 | + | ||
240 | + # HERE, write your own scenario | ||
241 | + | ||
242 | + # scenario OK | ||
243 | + self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1) | ||
244 | + self.thread_exec_specific_cmd_step(2, self.cmd_step2, 3) | ||
245 | + self.thread_exec_specific_cmd_step(3, self.cmd_step1, 5) | ||
246 | + self.thread_exec_specific_cmd_step(4, self.cmd_step3, 10) | ||
247 | + self.thread_exec_specific_cmd_step(5, self.cmd_step1, 4) | ||
248 | + # ... as many as you need | ||
249 | + | ||
250 | + """ autre scenario | ||
251 | + self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1) | ||
252 | + self.thread_exec_specific_cmd_step(2, self.cmd_step2, 2) | ||
253 | + self.thread_exec_specific_cmd_step(3, self.cmd_step1, 2) | ||
254 | + self.thread_exec_specific_cmd_step(4, self.cmd_step3, 2) | ||
255 | + self.thread_exec_specific_cmd_step(5, self.cmd_step1, 3) | ||
256 | + """ | ||
257 | + | ||
258 | + ''' | ||
259 | + # @override | ||
260 | + def exec_specific_cmd_end(self, cmd:Command, from_thread=True): | ||
261 | + super().exec_specific_cmd_end(cmd, from_thread) | ||
262 | + ''' | ||
263 | + | ||
264 | + | ||
265 | +if __name__ == "__main__": | ||
266 | + | ||
267 | + # with thread | ||
268 | + RUN_IN_THREAD=True | ||
269 | + # with process | ||
270 | + #RUN_IN_THREAD=False | ||
271 | + | ||
272 | + agent = build_agent(AgentM) | ||
273 | + ''' | ||
274 | + TEST_MODE, configfile = extract_parameters() | ||
275 | + agent = AgentM("AgentM", configfile, RUN_IN_THREAD) | ||
276 | + agent.setSimulatorMode(TEST_MODE) | ||
277 | + ''' | ||
278 | + print(agent) | ||
279 | + agent.run() |
src/core/pyros_django/monitoring/AgentM.py
@@ -8,8 +8,11 @@ import sys | @@ -8,8 +8,11 @@ import sys | ||
8 | #from django.db import transaction | 8 | #from django.db import transaction |
9 | #from common.models import Command | 9 | #from common.models import Command |
10 | 10 | ||
11 | -sys.path.append("..") | ||
12 | -sys.path.append("../../../..") | 11 | +import os |
12 | +pwd = os.environ['PROJECT_ROOT_PATH'] | ||
13 | +if pwd not in sys.path: | ||
14 | + sys.path.append(pwd) | ||
15 | + | ||
13 | from src.core.pyros_django.agent.Agent import Agent, build_agent, log | 16 | from src.core.pyros_django.agent.Agent import Agent, build_agent, log |
14 | 17 | ||
15 | # PM 20190416 recycle code | 18 | # PM 20190416 recycle code |
@@ -167,7 +170,7 @@ class AgentM(Agent): | @@ -167,7 +170,7 @@ class AgentM(Agent): | ||
167 | # previous name of function : routine_process | 170 | # previous name of function : routine_process |
168 | # Note : in Agent.py, routine_process_body seems to be the main function of routine of the agent | 171 | # Note : in Agent.py, routine_process_body seems to be the main function of routine of the agent |
169 | # We need to override routine_process_body and not routine_process | 172 | # We need to override routine_process_body and not routine_process |
170 | - def routine_process_body(self): | 173 | + def _routine_process_iter_end_body(self): |
171 | log.debug("in routine_process_body()") | 174 | log.debug("in routine_process_body()") |
172 | print("TODO: we recycle code") | 175 | print("TODO: we recycle code") |
173 | status_plc = self.plcController.getStatus() | 176 | status_plc = self.plcController.getStatus() |