Commit 0ca00ebdacc4277fc306d840f85630fc9672cfa2

Authored by Etienne Pallier
1 parent 4078466e
Exists in dev

refactorized and improved majordome

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  
... ...