Commit 0ca00ebdacc4277fc306d840f85630fc9672cfa2
1 parent
4078466e
Exists in
dev
refactorized and improved majordome
Showing
3 changed files
with
144 additions
and
66 deletions
Show diff stats
src/common/models.py
@@ -843,7 +843,11 @@ class Config(models.Model): | @@ -843,7 +843,11 @@ class Config(models.Model): | ||
843 | telescope_ip_address = models.CharField(max_length=45, default="127.0.0.1") | 843 | telescope_ip_address = models.CharField(max_length=45, default="127.0.0.1") |
844 | camera_ip_address = models.CharField(max_length=45, default="127.0.0.1") | 844 | camera_ip_address = models.CharField(max_length=45, default="127.0.0.1") |
845 | plc_ip_address = models.CharField(max_length=45, default="127.0.0.1") | 845 | plc_ip_address = models.CharField(max_length=45, default="127.0.0.1") |
846 | + | ||
847 | + # TODO: changer ça, c'est pas clair du tout... | ||
848 | + # True = mode Scheduler-standby, False = mode Remote !!!! | ||
846 | global_mode = models.BooleanField(default='True') | 849 | global_mode = models.BooleanField(default='True') |
850 | + | ||
847 | ack = models.BooleanField(default='False') | 851 | ack = models.BooleanField(default='False') |
848 | bypass = models.BooleanField(default='True') | 852 | bypass = models.BooleanField(default='True') |
849 | lock = models.BooleanField(default='False') | 853 | lock = models.BooleanField(default='False') |
src/dashboard/views.py
@@ -85,6 +85,7 @@ def retrieve_env_navbar(request): | @@ -85,6 +85,7 @@ def retrieve_env_navbar(request): | ||
85 | plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds | 85 | plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds |
86 | timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds() | 86 | timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds() |
87 | weather[0]['max_sunelev'] = SUN_ELEV_DAY_THRESHOLD | 87 | weather[0]['max_sunelev'] = SUN_ELEV_DAY_THRESHOLD |
88 | + #weather[0]['sunelev'] = 10 | ||
88 | weather[0]['sunelev'] = get_sunelev() | 89 | weather[0]['sunelev'] = get_sunelev() |
89 | weather[0]["plc_mode"] = plc_mode | 90 | weather[0]["plc_mode"] = plc_mode |
90 | weather[0]["is_safe"] = is_safe | 91 | weather[0]["is_safe"] = is_safe |
src/majordome/tasks.py
@@ -57,11 +57,15 @@ class Majordome(Task): | @@ -57,11 +57,15 @@ class Majordome(Task): | ||
57 | 57 | ||
58 | config = None | 58 | config = None |
59 | plc_status = None | 59 | plc_status = None |
60 | - current_state = "Passive" | 60 | + current_state = "Starting" |
61 | 61 | ||
62 | # OCS-RESTART, OCS-SHUTDOWN, or NONE (default) | 62 | # OCS-RESTART, OCS-SHUTDOWN, or NONE (default) |
63 | closing_mode = "NONE" | 63 | closing_mode = "NONE" |
64 | 64 | ||
65 | + NEED_TO_CLOSE = False | ||
66 | + PLC_IS_SAFE = False | ||
67 | + | ||
68 | + | ||
65 | ''' | 69 | ''' |
66 | OLD //// Function called by celery task | 70 | OLD //// Function called by celery task |
67 | Behavior: | 71 | Behavior: |
@@ -85,8 +89,7 @@ class Majordome(Task): | @@ -85,8 +89,7 @@ class Majordome(Task): | ||
85 | #self.loop() | 89 | #self.loop() |
86 | 90 | ||
87 | 91 | ||
88 | - RESTART = True | ||
89 | - while RESTART: | 92 | + while True: |
90 | 93 | ||
91 | # SETUP | 94 | # SETUP |
92 | try : | 95 | try : |
@@ -94,7 +97,7 @@ class Majordome(Task): | @@ -94,7 +97,7 @@ class Majordome(Task): | ||
94 | except Config.ObjectDoesNotExist: | 97 | except Config.ObjectDoesNotExist: |
95 | return -1 | 98 | return -1 |
96 | 99 | ||
97 | - self.config.ntc = False | 100 | + #self.config.ntc = False |
98 | 101 | ||
99 | # Set STATE to STARTING | 102 | # Set STATE to STARTING |
100 | self.changeState("STARTING") | 103 | self.changeState("STARTING") |
@@ -118,46 +121,60 @@ class Majordome(Task): | @@ -118,46 +121,60 @@ class Majordome(Task): | ||
118 | 121 | ||
119 | # MAIN LOOP: iterate on current state | 122 | # MAIN LOOP: iterate on current state |
120 | #while self.plc_is_connected() != False and self.closing_mode == "RUNNING" : | 123 | #while self.plc_is_connected() != False and self.closing_mode == "RUNNING" : |
121 | - while self.plc_is_connected() and not self.is_closing_or_restarting(): | 124 | + while self.plc_is_connected() and not self.is_shuttingdown_or_restarting(): |
122 | # Call behavior for the current state and set new current state (can stay the same if no state change) | 125 | # Call behavior for the current state and set new current state (can stay the same if no state change) |
123 | #self.behavior[self.current_state](self) | 126 | #self.behavior[self.current_state](self) |
124 | self.current_state = self.behavior[self.current_state](self) | 127 | self.current_state = self.behavior[self.current_state](self) |
125 | time.sleep(2) | 128 | time.sleep(2) |
126 | ''' | 129 | ''' |
127 | while True: | 130 | while True: |
128 | - if self.is_closing_or_restarting(): break | 131 | + if self.current_state in ['STARTING', 'PASSIVE_NO_PLC', 'PASSIVE']: |
132 | + if self.is_shuttingdown_or_restarting() and not self.NEED_TO_CLOSE: break | ||
133 | + ''' | ||
129 | if self.current_state not in ['STARTING', 'PASSIVE_NO_PLC']: | 134 | if self.current_state not in ['STARTING', 'PASSIVE_NO_PLC']: |
130 | - if not self.plc_is_connected(): | ||
131 | - self.changeState("PASSIVE") | 135 | + if self.plc_is_not_auto(): self.changeState("PASSIVE") |
136 | + ''' | ||
132 | self.current_state = self.do_behavior_for_state(self.current_state) | 137 | self.current_state = self.do_behavior_for_state(self.current_state) |
133 | 138 | ||
134 | - | ||
135 | - # EXIT | 139 | + |
140 | + ''' | ||
136 | # Shutdown options change by the main program | 141 | # Shutdown options change by the main program |
137 | if self.closing_mode == "OCS-SHUTDOWN": | 142 | if self.closing_mode == "OCS-SHUTDOWN": |
143 | + self.shutdown() | ||
138 | #self.closeBehaviour(self) | 144 | #self.closeBehaviour(self) |
139 | - self.behavior_closing() | ||
140 | - #TODO: self.kill_all_agents() | ||
141 | - RESTART = False | 145 | + #self.sub_behavior_closing() |
146 | + break | ||
147 | + ''' | ||
142 | 148 | ||
143 | - elif self.closing_mode == "OCS-RESTART": | 149 | + if self.closing_mode == "OCS-RESTART": |
144 | self.config.majordome_restarted = True | 150 | self.config.majordome_restarted = True |
145 | self.config.save() | 151 | self.config.save() |
146 | #TODO: self.kill_all_agents() | 152 | #TODO: self.kill_all_agents() |
147 | - self.send_alarm_if_not_closed() | 153 | + #self.send_alarm_if_not_closed() |
148 | #self.run() | 154 | #self.run() |
149 | - | ||
150 | - #TODO: rester dans la main loop ??? | ||
151 | - #elif self.closing_mode == "RUNNING" and self.plc_is_connected() == False: | 155 | + |
156 | + ''' | ||
152 | elif not self.plc_is_connected(): | 157 | elif not self.plc_is_connected(): |
153 | #self.config.majordome_restarted = True | 158 | #self.config.majordome_restarted = True |
154 | #self.config.save() | 159 | #self.config.save() |
155 | self.changeState("Passive No PLC") | 160 | self.changeState("Passive No PLC") |
156 | self.send_alarm_if_not_closed() | 161 | self.send_alarm_if_not_closed() |
157 | #self.run() | 162 | #self.run() |
163 | + ''' | ||
164 | + | ||
165 | + self.shutdown() | ||
166 | + | ||
158 | 167 | ||
159 | 168 | ||
160 | - def is_closing_or_restarting(self): | 169 | + def shutdown(self): |
170 | + #TODO: write shutdown code (kill agents...) | ||
171 | + print("OCS SHUTDOWN") | ||
172 | + | ||
173 | + def is_restarting(self): | ||
174 | + return self.closing_mode == "OCS-RESTART" | ||
175 | + def is_shuttingdown(self): | ||
176 | + return self.closing_mode == "OCS-SHUTDOWN" | ||
177 | + def is_shuttingdown_or_restarting(self): | ||
161 | return self.closing_mode != "NONE" | 178 | return self.closing_mode != "NONE" |
162 | 179 | ||
163 | 180 | ||
@@ -172,14 +189,31 @@ class Majordome(Task): | @@ -172,14 +189,31 @@ class Majordome(Task): | ||
172 | self.config.pyros_state = state | 189 | self.config.pyros_state = state |
173 | self.config.save() | 190 | self.config.save() |
174 | 191 | ||
192 | + def _plc_is_not_auto(self): | ||
193 | + if not self.plc_is_connected(): return True; | ||
194 | + # now, self.plc_status has been updated, so check it: | ||
195 | + return self.plc_status.plc_mode != "AUTO" | ||
196 | + def plc_is_auto(self): | ||
197 | + return not self._plc_is_not_auto() | ||
198 | + | ||
199 | + def plc_is_safe(self): | ||
200 | + if not self.plc_is_connected(): return False; | ||
201 | + # now, self.plc_status has been updated, so check it: | ||
202 | + return self.plc_status.is_safe | ||
203 | + | ||
204 | + | ||
205 | + def is_night(self): | ||
206 | + return get_sunelev() < -10 | ||
175 | 207 | ||
208 | + | ||
176 | ''' | 209 | ''' |
177 | Each function with behavior describes the behavior of a state, | 210 | Each function with behavior describes the behavior of a state, |
178 | they are all contained in a dictionary called in run() | 211 | they are all contained in a dictionary called in run() |
179 | ''' | 212 | ''' |
213 | + | ||
180 | def behavior_starting(self): | 214 | def behavior_starting(self): |
181 | #print("STARTING") | 215 | #print("STARTING") |
182 | - #if self.is_closing_or_restarting(): return | 216 | + #if self.is_shuttingdown_or_restarting(): return |
183 | if not self.config.majordome_restarted: | 217 | if not self.config.majordome_restarted: |
184 | #TODO: Do setup things... (start agents...) | 218 | #TODO: Do setup things... (start agents...) |
185 | time.sleep(2) | 219 | time.sleep(2) |
@@ -194,90 +228,125 @@ class Majordome(Task): | @@ -194,90 +228,125 @@ class Majordome(Task): | ||
194 | self.changeState("PASSIVE_NO_PLC") | 228 | self.changeState("PASSIVE_NO_PLC") |
195 | #return self.current_state | 229 | #return self.current_state |
196 | 230 | ||
231 | + | ||
197 | def behavior_passive_no_plc(self): | 232 | def behavior_passive_no_plc(self): |
198 | #print("PASSIVE_NO_PLC") | 233 | #print("PASSIVE_NO_PLC") |
199 | - #if self.is_closing_or_restarting(): return | 234 | + #if self.is_shuttingdown_or_restarting(): return |
200 | #self.changeState("Passive No PLC") | 235 | #self.changeState("Passive No PLC") |
201 | print("Waiting for PLC connection") | 236 | print("Waiting for PLC connection") |
202 | # Wait until PCL is connected | 237 | # Wait until PCL is connected |
203 | while not self.plc_is_connected(): | 238 | while not self.plc_is_connected(): |
204 | - if self.is_closing_or_restarting(): return | 239 | + time.sleep(2) |
240 | + ''' | ||
241 | + if self.is_restarting(): | ||
242 | + self.changeState("STARTING") | ||
243 | + return | ||
244 | + ''' | ||
245 | + if self.is_shuttingdown_or_restarting(): return | ||
205 | print("PLC is connected") | 246 | print("PLC is connected") |
206 | # Set STATE to PASSIVE (with PLC) | 247 | # Set STATE to PASSIVE (with PLC) |
207 | self.changeState("Passive") | 248 | self.changeState("Passive") |
208 | #return self.current_state | 249 | #return self.current_state |
209 | 250 | ||
251 | + | ||
210 | def behavior_passive(self): | 252 | def behavior_passive(self): |
211 | #print("Passive") | 253 | #print("Passive") |
212 | - #if self.is_closing_or_restarting(): return | ||
213 | - if self.plc_status.plc_mode == "AUTO": | ||
214 | - if not self.config.majordome_restarted: self.config.ntc = True | 254 | + #if self.is_shuttingdown_or_restarting(): return |
255 | + #if self.plc_status.plc_mode == "AUTO": | ||
256 | + if not self.plc_is_connected(): | ||
257 | + self.changeState("PASSIVE_NO_PLC") | ||
258 | + return | ||
259 | + | ||
260 | + if self.plc_is_auto(): | ||
261 | + #if not self.config.majordome_restarted: self.config.ntc = True | ||
262 | + if not self.config.majordome_restarted: self.NEED_TO_CLOSE=True | ||
215 | self.changeState("Standby") | 263 | self.changeState("Standby") |
216 | #return self.current_state | 264 | #return self.current_state |
217 | 265 | ||
266 | + | ||
218 | def behavior_standby(self): | 267 | def behavior_standby(self): |
219 | #print("Standby") | 268 | #print("Standby") |
220 | - if self.config.ntc: | 269 | + #if self.config.ntc: |
270 | + if self.is_shuttingdown() and not self.NEED_TO_CLOSE: | ||
271 | + self.NEED_TO_CLOSE = True | ||
272 | + | ||
273 | + if self.NEED_TO_CLOSE: | ||
221 | self.changeState("Closing") | 274 | self.changeState("Closing") |
222 | - elif self.plc_status.plc_mode != "AUTO" or self.is_closing_or_restarting(): | 275 | + #self.sub_behavior_closing() |
276 | + self.do_behavior_for_state("Closing") | ||
277 | + self.changeState("Standby") | ||
278 | + | ||
279 | + #elif self.plc_status.plc_mode != "AUTO" or self.is_shuttingdown_or_restarting(): | ||
280 | + if not self.plc_is_auto() or self.is_shuttingdown_or_restarting(): | ||
223 | self.changeState("Passive") | 281 | self.changeState("Passive") |
224 | - elif self.config.global_mode == False and self.config.lock == False: | 282 | + elif not self.config.global_mode and not self.config.lock: |
225 | self.changeState("Remote") | 283 | self.changeState("Remote") |
226 | - elif get_sunelev() < -10 and self.plc_status.is_safe == True and self.config.ack == True and self.config.lock == False : | 284 | + |
285 | + elif self.is_night() and self.plc_is_safe() and self.config.ack and not self.config.lock : | ||
227 | self.changeState("Startup") | 286 | self.changeState("Startup") |
228 | #return self.current_state | 287 | #return self.current_state |
229 | 288 | ||
289 | + | ||
230 | def behavior_remote(self): | 290 | def behavior_remote(self): |
231 | #print("Remote") | 291 | #print("Remote") |
232 | - if self.config.global_mode: | ||
233 | - self.changeState("Standby") | ||
234 | - elif self.config.lock: | ||
235 | - self.config.ntc == True | 292 | + if self.config.global_mode or self.is_shuttingdown_or_restarting() or not self.plc_is_auto() or self.config.lock: |
293 | + if not self.plc_is_auto() or self.config.lock or self.is_shuttingdown(): | ||
294 | + self.NEED_TO_CLOSE=True | ||
236 | self.changeState("Standby") | 295 | self.changeState("Standby") |
237 | - #TODO: get shutter from db status (then while until close/open) | ||
238 | - #elif not self.plc_status.is_safe: | ||
239 | - # response = TelescopeRemoteControlDefault("DOME SHUTTER CLOSE", expert_mode=True).exec_command() | ||
240 | - #elif self.plc_status.is_safe == True: | ||
241 | - # response = TelescopeRemoteControlDefault("DOME SHUTTER OPEN", expert_mode=True).exec_command() | ||
242 | - elif self.plc_status.plc_mode != "AUTO": | ||
243 | - self.changeState("Passive") | 296 | + return |
297 | + | ||
298 | + #TODO: get shutter state from db status (then wait until close/open) | ||
299 | + if not self.plc_is_safe() and self.PLC_IS_SAFE: | ||
300 | + PLC_IS_SAFE = False | ||
301 | + response = TelescopeRemoteControlDefault("DOME SHUTTER CLOSE", expert_mode=True).exec_command() | ||
302 | + if self.plc_is_safe() and not self.PLC_IS_SAFE: | ||
303 | + PLC_IS_SAFE = True | ||
304 | + response = TelescopeRemoteControlDefault("DOME SHUTTER OPEN", expert_mode=True).exec_command() | ||
244 | #return self.current_state | 305 | #return self.current_state |
245 | 306 | ||
307 | + | ||
246 | def behavior_startup(self): | 308 | def behavior_startup(self): |
247 | - #TODO: get shutter and telescope from db status | ||
248 | - #if dome_shutter == Open and telescope == Ready | ||
249 | - #TelescopeRemoteControlDefault("DO DOME SHUTTER OPEN", expert_mode=True).exec_command() | ||
250 | - #TelescopeRemoteControlDefault("DO START", expert_mode=True).exec_command() | ||
251 | #print("Startup") | 309 | #print("Startup") |
252 | - if self.config.lock: | ||
253 | - self.config.ntc = True | 310 | + if self.config.lock or not self.plc_is_auto(): |
311 | + self.NEED_TO_CLOSE=True | ||
254 | self.changeState("Standby") | 312 | self.changeState("Standby") |
255 | - else: | ||
256 | - self.changeState("Scheduler") | 313 | + return |
314 | + | ||
315 | + #TODO: get shutter and telescope from db status | ||
316 | + time.sleep(5) | ||
317 | + ''' | ||
318 | + if not (dome_shutter == Open and telescope == Ready) | ||
319 | + TelescopeRemoteControlDefault("DO DOME SHUTTER OPEN", expert_mode=True).exec_command() | ||
320 | + TelescopeRemoteControlDefault("DO START", expert_mode=True).exec_command() | ||
321 | + ''' | ||
322 | + self.changeState("Scheduler") | ||
257 | #return self.current_state | 323 | #return self.current_state |
258 | 324 | ||
259 | 325 | ||
260 | def behavior_scheduler(self): | 326 | def behavior_scheduler(self): |
261 | #print("Scheduler") | 327 | #print("Scheduler") |
262 | - if get_sunelev() > -10 or self.plc_status.is_safe is False or self.config.lock is True : | ||
263 | - self.config.ntc = True | ||
264 | - self.changeState("Standby") | ||
265 | - elif self.config.global_mode == False or self.plc_status.plc_mode != "AUTO": | 328 | + if not self.is_night() or not self.plc_status.is_safe or self.config.lock or not self.plc_is_auto() or not self.config.global_mode or self.is_shuttingdown_or_restarting(): |
329 | + if not ( not self.config.global_mode or self.is_restarting() ): self.NEED_TO_CLOSE = True | ||
266 | self.changeState("Standby") | 330 | self.changeState("Standby") |
267 | #return self.current_state | 331 | #return self.current_state |
268 | 332 | ||
269 | - def behavior_closing(self): | 333 | + |
334 | + def sub_behavior_closing(self): | ||
335 | + #print("CURRENT OCS (MAJORDOME) STATE: "+ self.current_state) | ||
270 | #print("Closing") | 336 | #print("Closing") |
271 | - self.config.ntc = False | ||
272 | - self.config.save() | ||
273 | - response = TelescopeRemoteControlDefault("DO DOME SHUTTER CLOSE", expert_mode=True).exec_command() | ||
274 | - response = TelescopeRemoteControlDefault("DO DOME PARK", expert_mode=True).exec_command() | ||
275 | - response = TelescopeRemoteControlDefault("DO TELESCOPE PARK", expert_mode=True).exec_command() | ||
276 | - if self.plc_status.plc_mode != "AUTO": | ||
277 | - self.changeState("Standby") | ||
278 | - self.changeState("Standby") | ||
279 | - # TODO: elif dome == Parked and dome_shutter == Close and telescospe == Parked | ||
280 | - #self.changeState("Standby") | 337 | + #self.config.save() |
338 | + if not self.plc_is_auto(): | ||
339 | + # PLC not AUTO => we can do nothing, so only send email if dome not closed... | ||
340 | + self.send_alarm_if_not_closed() | ||
341 | + else: | ||
342 | + # These commands should do nothing if instruments are already closed/parked... | ||
343 | + response = TelescopeRemoteControlDefault("DO DOME SHUTTER CLOSE", expert_mode=True).exec_command() | ||
344 | + response = TelescopeRemoteControlDefault("DO DOME PARK", expert_mode=True).exec_command() | ||
345 | + response = TelescopeRemoteControlDefault("DO TELESCOPE PARK", expert_mode=True).exec_command() | ||
346 | + | ||
347 | + self.NEED_TO_CLOSE = False | ||
348 | + | ||
349 | + #self.changeState("Standby") | ||
281 | #return self.current_state | 350 | #return self.current_state |
282 | 351 | ||
283 | behavior = { | 352 | behavior = { |
@@ -288,17 +357,21 @@ class Majordome(Task): | @@ -288,17 +357,21 @@ class Majordome(Task): | ||
288 | "Remote": behavior_remote, | 357 | "Remote": behavior_remote, |
289 | "Startup": behavior_startup, | 358 | "Startup": behavior_startup, |
290 | "Scheduler": behavior_scheduler, | 359 | "Scheduler": behavior_scheduler, |
291 | - "Closing": behavior_closing, | 360 | + #"Closing": sub_behavior_closing, |
292 | } | 361 | } |
293 | def do_behavior_for_state(self, current_state:str) -> str: | 362 | def do_behavior_for_state(self, current_state:str) -> str: |
294 | print("CURRENT OCS (MAJORDOME) STATE: "+current_state) | 363 | print("CURRENT OCS (MAJORDOME) STATE: "+current_state) |
364 | + time.sleep(2) | ||
295 | # EXIT if PLC not connected | 365 | # EXIT if PLC not connected |
296 | #if not self.plc_is_connected(): return | 366 | #if not self.plc_is_connected(): return |
297 | # EXIT if closing or restarting | 367 | # EXIT if closing or restarting |
298 | - #if self.is_closing_or_restarting(): return | 368 | + #if self.is_shuttingdown_or_restarting(): return |
299 | # run behavior for this state | 369 | # run behavior for this state |
300 | #self.behavior[current_state](self) | 370 | #self.behavior[current_state](self) |
301 | - self.behavior[current_state](self) | 371 | + if current_state == "Closing": |
372 | + self.sub_behavior_closing() | ||
373 | + else: | ||
374 | + self.behavior[current_state](self) | ||
302 | return self.current_state | 375 | return self.current_state |
303 | 376 | ||
304 | 377 |