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 | 843 | telescope_ip_address = models.CharField(max_length=45, default="127.0.0.1") |
844 | 844 | camera_ip_address = models.CharField(max_length=45, default="127.0.0.1") |
845 | 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 | 849 | global_mode = models.BooleanField(default='True') |
850 | + | |
847 | 851 | ack = models.BooleanField(default='False') |
848 | 852 | bypass = models.BooleanField(default='True') |
849 | 853 | lock = models.BooleanField(default='False') | ... | ... |
src/dashboard/views.py
... | ... | @@ -85,6 +85,7 @@ def retrieve_env_navbar(request): |
85 | 85 | plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds |
86 | 86 | timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds() |
87 | 87 | weather[0]['max_sunelev'] = SUN_ELEV_DAY_THRESHOLD |
88 | + #weather[0]['sunelev'] = 10 | |
88 | 89 | weather[0]['sunelev'] = get_sunelev() |
89 | 90 | weather[0]["plc_mode"] = plc_mode |
90 | 91 | weather[0]["is_safe"] = is_safe | ... | ... |
src/majordome/tasks.py
... | ... | @@ -57,11 +57,15 @@ class Majordome(Task): |
57 | 57 | |
58 | 58 | config = None |
59 | 59 | plc_status = None |
60 | - current_state = "Passive" | |
60 | + current_state = "Starting" | |
61 | 61 | |
62 | 62 | # OCS-RESTART, OCS-SHUTDOWN, or NONE (default) |
63 | 63 | closing_mode = "NONE" |
64 | 64 | |
65 | + NEED_TO_CLOSE = False | |
66 | + PLC_IS_SAFE = False | |
67 | + | |
68 | + | |
65 | 69 | ''' |
66 | 70 | OLD //// Function called by celery task |
67 | 71 | Behavior: |
... | ... | @@ -85,8 +89,7 @@ class Majordome(Task): |
85 | 89 | #self.loop() |
86 | 90 | |
87 | 91 | |
88 | - RESTART = True | |
89 | - while RESTART: | |
92 | + while True: | |
90 | 93 | |
91 | 94 | # SETUP |
92 | 95 | try : |
... | ... | @@ -94,7 +97,7 @@ class Majordome(Task): |
94 | 97 | except Config.ObjectDoesNotExist: |
95 | 98 | return -1 |
96 | 99 | |
97 | - self.config.ntc = False | |
100 | + #self.config.ntc = False | |
98 | 101 | |
99 | 102 | # Set STATE to STARTING |
100 | 103 | self.changeState("STARTING") |
... | ... | @@ -118,46 +121,60 @@ class Majordome(Task): |
118 | 121 | |
119 | 122 | # MAIN LOOP: iterate on current state |
120 | 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 | 125 | # Call behavior for the current state and set new current state (can stay the same if no state change) |
123 | 126 | #self.behavior[self.current_state](self) |
124 | 127 | self.current_state = self.behavior[self.current_state](self) |
125 | 128 | time.sleep(2) |
126 | 129 | ''' |
127 | 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 | 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 | 137 | self.current_state = self.do_behavior_for_state(self.current_state) |
133 | 138 | |
134 | - | |
135 | - # EXIT | |
139 | + | |
140 | + ''' | |
136 | 141 | # Shutdown options change by the main program |
137 | 142 | if self.closing_mode == "OCS-SHUTDOWN": |
143 | + self.shutdown() | |
138 | 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 | 150 | self.config.majordome_restarted = True |
145 | 151 | self.config.save() |
146 | 152 | #TODO: self.kill_all_agents() |
147 | - self.send_alarm_if_not_closed() | |
153 | + #self.send_alarm_if_not_closed() | |
148 | 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 | 157 | elif not self.plc_is_connected(): |
153 | 158 | #self.config.majordome_restarted = True |
154 | 159 | #self.config.save() |
155 | 160 | self.changeState("Passive No PLC") |
156 | 161 | self.send_alarm_if_not_closed() |
157 | 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 | 178 | return self.closing_mode != "NONE" |
162 | 179 | |
163 | 180 | |
... | ... | @@ -172,14 +189,31 @@ class Majordome(Task): |
172 | 189 | self.config.pyros_state = state |
173 | 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 | 210 | Each function with behavior describes the behavior of a state, |
178 | 211 | they are all contained in a dictionary called in run() |
179 | 212 | ''' |
213 | + | |
180 | 214 | def behavior_starting(self): |
181 | 215 | #print("STARTING") |
182 | - #if self.is_closing_or_restarting(): return | |
216 | + #if self.is_shuttingdown_or_restarting(): return | |
183 | 217 | if not self.config.majordome_restarted: |
184 | 218 | #TODO: Do setup things... (start agents...) |
185 | 219 | time.sleep(2) |
... | ... | @@ -194,90 +228,125 @@ class Majordome(Task): |
194 | 228 | self.changeState("PASSIVE_NO_PLC") |
195 | 229 | #return self.current_state |
196 | 230 | |
231 | + | |
197 | 232 | def behavior_passive_no_plc(self): |
198 | 233 | #print("PASSIVE_NO_PLC") |
199 | - #if self.is_closing_or_restarting(): return | |
234 | + #if self.is_shuttingdown_or_restarting(): return | |
200 | 235 | #self.changeState("Passive No PLC") |
201 | 236 | print("Waiting for PLC connection") |
202 | 237 | # Wait until PCL is connected |
203 | 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 | 246 | print("PLC is connected") |
206 | 247 | # Set STATE to PASSIVE (with PLC) |
207 | 248 | self.changeState("Passive") |
208 | 249 | #return self.current_state |
209 | 250 | |
251 | + | |
210 | 252 | def behavior_passive(self): |
211 | 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 | 263 | self.changeState("Standby") |
216 | 264 | #return self.current_state |
217 | 265 | |
266 | + | |
218 | 267 | def behavior_standby(self): |
219 | 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 | 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 | 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 | 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 | 286 | self.changeState("Startup") |
228 | 287 | #return self.current_state |
229 | 288 | |
289 | + | |
230 | 290 | def behavior_remote(self): |
231 | 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 | 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 | 305 | #return self.current_state |
245 | 306 | |
307 | + | |
246 | 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 | 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 | 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 | 323 | #return self.current_state |
258 | 324 | |
259 | 325 | |
260 | 326 | def behavior_scheduler(self): |
261 | 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 | 330 | self.changeState("Standby") |
267 | 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 | 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 | 350 | #return self.current_state |
282 | 351 | |
283 | 352 | behavior = { |
... | ... | @@ -288,17 +357,21 @@ class Majordome(Task): |
288 | 357 | "Remote": behavior_remote, |
289 | 358 | "Startup": behavior_startup, |
290 | 359 | "Scheduler": behavior_scheduler, |
291 | - "Closing": behavior_closing, | |
360 | + #"Closing": sub_behavior_closing, | |
292 | 361 | } |
293 | 362 | def do_behavior_for_state(self, current_state:str) -> str: |
294 | 363 | print("CURRENT OCS (MAJORDOME) STATE: "+current_state) |
364 | + time.sleep(2) | |
295 | 365 | # EXIT if PLC not connected |
296 | 366 | #if not self.plc_is_connected(): return |
297 | 367 | # EXIT if closing or restarting |
298 | - #if self.is_closing_or_restarting(): return | |
368 | + #if self.is_shuttingdown_or_restarting(): return | |
299 | 369 | # run behavior for this state |
300 | 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 | 375 | return self.current_state |
303 | 376 | |
304 | 377 | ... | ... |