Blame view

src/majordome/tasks.py 38.1 KB
5b5566ab   haribo   added celery
1
from __future__ import absolute_import
ce470283   Jeremy   Plc simulator fin...
2

5b5566ab   haribo   added celery
3
from celery.task import Task
ce470283   Jeremy   Plc simulator fin...
4
5
6
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q

9774228b   haribo   Date: 22/06/2016
7
import observation_manager
abfb02e2   Jeremy   Device Model is n...
8
import observation_manager.tasks
ce470283   Jeremy   Plc simulator fin...
9
10
11
import scheduler
import scheduler.tasks as sched_task
import utils.Logger as L
c72eb17a   Jeremy   Update celery task
12
13
import monitoring.tasks
import alert_manager.tasks
ce470283   Jeremy   Plc simulator fin...
14
from common.models import *
6aec6155   theopuhl   Majordome algorit...
15
16
17
from dashboard.views import get_sunelev
from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault
from django.shortcuts import get_object_or_404
65149de7   Jeremy   Update
18
from devices.CameraNIR import NIRCameraController
ce470283   Jeremy   Plc simulator fin...
19
from devices.CameraVIS import VISCameraController
cfc9d09c   Jeremy   Added dome simula...
20
from devices.Dome import DomeController
65149de7   Jeremy   Update
21
from devices.PLC import PLCController
ce470283   Jeremy   Plc simulator fin...
22
23
from devices.Telescope import TelescopeController
from majordome.MajordomeDecorators import *
65149de7   Jeremy   Update
24
from utils.JDManipulator import *
6aec6155   theopuhl   Majordome algorit...
25
import time
cfc9d09c   Jeremy   Added dome simula...
26

03814884   Etienne Pallier   launch majordome ...
27
28
from threading import Thread

ff448d43   Jeremy   Update
29
DEBUG_FILE = False
65149de7   Jeremy   Update
30
log = L.setupLogger("MajordomeTaskLogger", "Majordome")
5b5566ab   haribo   added celery
31

65149de7   Jeremy   Update
32
'''
05038bc8   Jeremy   Majordome logic i...
33
    Task to handle the execution of the program
65149de7   Jeremy   Update
34

4cb0ff36   Jeremy   Update
35
    check the environment status in database
05038bc8   Jeremy   Majordome logic i...
36
37
38
    check the devices status (telescope / cameras)
    check if the last schedule made has to be planned
    launch schedule's sequences
65149de7   Jeremy   Update
39
'''
03814884   Etienne Pallier   launch majordome ...
40
class Majordome(Task, Thread):
0997e1c3   Etienne Pallier   moved main run() ...
41
    
65149de7   Jeremy   Update
42
43
    loop_speed = 1
    julian_div = 86400
05038bc8   Jeremy   Majordome logic i...
44
45
46
47
48
    executing_sequence = None
    next_sequence = None
    status_tel = ""
    status_nir = ""
    status_vis = ""
cfc9d09c   Jeremy   Added dome simula...
49
    status_dom = ""
ce470283   Jeremy   Plc simulator fin...
50
51
    site_status = "OK"
    weather_status = "OK"
ef60c3ec   Jeremy   Majordome and mon...
52
53
54
    timers = {}
    functions = {}
    schedule = None
c53a13e0   Jeremy   Updating a lot of...
55
    available_status = []
678838ed   Jeremy   Weather ans insid...
56
    alarm_list = []
468a79dc   Etienne Pallier   added comments
57
58

    # New variables from TP:
d0b663be   Etienne Pallier   refactorized majo...
59
    
6aec6155   theopuhl   Majordome algorit...
60
    config = None
468a79dc   Etienne Pallier   added comments
61
    plc_status = None
0ca00ebd   Etienne Pallier   refactorized and ...
62
    current_state = "Starting"
d0b663be   Etienne Pallier   refactorized majo...
63
64
65
66
    
    # OCS-RESTART, OCS-SHUTDOWN, or NONE (default)
    closing_mode = "NONE"
    
0ca00ebd   Etienne Pallier   refactorized and ...
67
68
69
70
    NEED_TO_CLOSE = False
    PLC_IS_SAFE = False

    
6aec6155   theopuhl   Majordome algorit...
71
    '''
0997e1c3   Etienne Pallier   moved main run() ...
72
73
74
75
76
77
78
79
80
81
        OLD //// Function called by celery task
        Behavior:
            Init telescope / cameras
            set night limits
            check the software version
            launch the majordome loop ///// OLD

        Main loop of Majordome
        startup everything if needed
        Loop over Majordome state
d0b663be   Etienne Pallier   refactorized majo...
82
        Change behavior with the pyros states
0997e1c3   Etienne Pallier   moved main run() ...
83
84
85
86
87
88
89
90
91
92
93
        Take suitable decision thanks to states in database
    '''
    def run(self):
        #self.createTask()
        #self.updateSoftware()
        #self.setContext()
        #self.setTime()                     /// OLD Majordome
        #self.setTasks()
        #self.loop()


0ca00ebd   Etienne Pallier   refactorized and ...
94
        while True:
d0b663be   Etienne Pallier   refactorized majo...
95
96
97
98
            
            # SETUP
            try : 
                self.config = get_object_or_404(Config, id=1)
03814884   Etienne Pallier   launch majordome ...
99
100
101
102
103
104
105
106
                #self.config = Config.objects.get(pk=1)
                #self.config = Config.objects.get()[0]

                #print("maj config id is", self.config.id)

            #except Config.ObjectDoesNotExist:
            except Exception as e:
                print("Config read exception", str(e))
d0b663be   Etienne Pallier   refactorized majo...
107
108
                return -1
            
0ca00ebd   Etienne Pallier   refactorized and ...
109
            #self.config.ntc = False
d0b663be   Etienne Pallier   refactorized majo...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
            
            # Set STATE to STARTING
            self.changeState("STARTING")
            
            '''
            if not self.config.majordome_restarted:
                #in order to start other agents etc....
                self.setup()
            
            # Set STATE to PASSIVE (NO PLC)
            self.changeState("Passive No PLC")
            print("Waiting for PLC connection")
            # Wait until PCL is connected
            while not self.plc_is_connected():                  
                pass           
            print("PLC is connected")
                    
            # Set STATE to PASSIVE (with PLC)
            self.changeState("Passive")
            self.config.majordome_state = "RUNNING"
    
            # MAIN LOOP: iterate on current state
            #while self.plc_is_connected() != False and self.closing_mode == "RUNNING" :          
0ca00ebd   Etienne Pallier   refactorized and ...
133
            while self.plc_is_connected() and not self.is_shuttingdown_or_restarting():          
d0b663be   Etienne Pallier   refactorized majo...
134
135
136
137
138
139
                # Call behavior for the current state and set new current state (can stay the same if no state change)
                #self.behavior[self.current_state](self)
                self.current_state = self.behavior[self.current_state](self)
                time.sleep(2)
            '''              
            while True:
0ca00ebd   Etienne Pallier   refactorized and ...
140
141
142
                if self.current_state in ['STARTING', 'PASSIVE_NO_PLC', 'PASSIVE']:
                    if self.is_shuttingdown_or_restarting() and not self.NEED_TO_CLOSE: break
                '''
d0b663be   Etienne Pallier   refactorized majo...
143
                if self.current_state not in ['STARTING', 'PASSIVE_NO_PLC']:
0ca00ebd   Etienne Pallier   refactorized and ...
144
145
                    if self.plc_is_not_auto(): self.changeState("PASSIVE")
                '''        
03814884   Etienne Pallier   launch majordome ...
146
                self.current_state = self.do_behavior_for_current_state()
d0b663be   Etienne Pallier   refactorized majo...
147
                             
0ca00ebd   Etienne Pallier   refactorized and ...
148
149

            '''                      
d0b663be   Etienne Pallier   refactorized majo...
150
151
            # Shutdown options change by the main program
            if self.closing_mode == "OCS-SHUTDOWN":          
0ca00ebd   Etienne Pallier   refactorized and ...
152
                self.shutdown()
d0b663be   Etienne Pallier   refactorized majo...
153
                #self.closeBehaviour(self)
0ca00ebd   Etienne Pallier   refactorized and ...
154
155
156
                #self.sub_behavior_closing()
                break
            '''
d0b663be   Etienne Pallier   refactorized majo...
157
            
0ca00ebd   Etienne Pallier   refactorized and ...
158
            if self.closing_mode == "OCS-RESTART":
d0b663be   Etienne Pallier   refactorized majo...
159
160
161
                self.config.majordome_restarted = True
                self.config.save()
                #TODO: self.kill_all_agents()
0ca00ebd   Etienne Pallier   refactorized and ...
162
                #self.send_alarm_if_not_closed()
d0b663be   Etienne Pallier   refactorized majo...
163
                #self.run()
0ca00ebd   Etienne Pallier   refactorized and ...
164
165

            '''    
d0b663be   Etienne Pallier   refactorized majo...
166
167
168
169
170
171
            elif not self.plc_is_connected():
                #self.config.majordome_restarted = True
                #self.config.save()
                self.changeState("Passive No PLC")
                self.send_alarm_if_not_closed()
                #self.run()
0ca00ebd   Etienne Pallier   refactorized and ...
172
173
174
175
            '''
        
        self.shutdown()
 
0997e1c3   Etienne Pallier   moved main run() ...
176
 
d0b663be   Etienne Pallier   refactorized majo...
177
 
0ca00ebd   Etienne Pallier   refactorized and ...
178
179
180
181
182
183
184
185
186
    def shutdown(self):
        #TODO: write shutdown code (kill agents...)
        print("OCS SHUTDOWN")
    
    def is_restarting(self):
        return self.closing_mode == "OCS-RESTART"
    def is_shuttingdown(self):
        return self.closing_mode == "OCS-SHUTDOWN"
    def is_shuttingdown_or_restarting(self):
d0b663be   Etienne Pallier   refactorized majo...
187
188
        return self.closing_mode != "NONE"
    
0997e1c3   Etienne Pallier   moved main run() ...
189
190

    '''
6aec6155   theopuhl   Majordome algorit...
191
192
193
        Function called to change and save current state of pyros.
    '''
    def changeState(self, state):
468a79dc   Etienne Pallier   added comments
194
        # (local variable) idem self.config.pyros_state
6aec6155   theopuhl   Majordome algorit...
195
        self.current_state = state
468a79dc   Etienne Pallier   added comments
196
197

        # (in DB) PASSIVE, STANDBY, REMOTE, OPERATING
6aec6155   theopuhl   Majordome algorit...
198
199
        self.config.pyros_state = state
        self.config.save()
d0b663be   Etienne Pallier   refactorized majo...
200
        
0ca00ebd   Etienne Pallier   refactorized and ...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    def _plc_is_not_auto(self):
        if not self.plc_is_connected(): return True;
        # now, self.plc_status has been updated, so check it:
        return self.plc_status.plc_mode != "AUTO"
    def plc_is_auto(self):
        return not self._plc_is_not_auto()
    
    def plc_is_safe(self):
        if not self.plc_is_connected(): return False;
        # now, self.plc_status has been updated, so check it:
        return self.plc_status.is_safe
        
    
    def is_night(self):
        return get_sunelev() < -10
d0b663be   Etienne Pallier   refactorized majo...
216
        
0ca00ebd   Etienne Pallier   refactorized and ...
217

6aec6155   theopuhl   Majordome algorit...
218
    '''
d0b663be   Etienne Pallier   refactorized majo...
219
220
        Each function with behavior describes the behavior of a state,
        they are all contained in a dictionary called in run()
6aec6155   theopuhl   Majordome algorit...
221
    '''
0ca00ebd   Etienne Pallier   refactorized and ...
222

d0b663be   Etienne Pallier   refactorized majo...
223
224
    def behavior_starting(self):
        #print("STARTING")
0ca00ebd   Etienne Pallier   refactorized and ...
225
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
        if not self.config.majordome_restarted:
            #TODO: Do setup things... (start agents...)
            time.sleep(2)
        '''
        Cette variable sert à indiquer l'état du majordome dans la DB.
        Elle va aussi être changée par le panneau Simulator pour passer à l'état SHUTDOWN ou RESTART.
        Elle est récupérée à chaque itération par la fonction plcConnection()
        '''
        self.config.majordome_state = "RUNNING"
        #self.config.majordome_state = "NONE"

        self.changeState("PASSIVE_NO_PLC")
        #return self.current_state

0ca00ebd   Etienne Pallier   refactorized and ...
240

d0b663be   Etienne Pallier   refactorized majo...
241
242
    def behavior_passive_no_plc(self):
        #print("PASSIVE_NO_PLC")
0ca00ebd   Etienne Pallier   refactorized and ...
243
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
244
245
246
247
        #self.changeState("Passive No PLC")
        print("Waiting for PLC connection")
        # Wait until PCL is connected
        while not self.plc_is_connected():
03814884   Etienne Pallier   launch majordome ...
248
            time.sleep(3)
0ca00ebd   Etienne Pallier   refactorized and ...
249
250
251
252
253
254
            '''
            if self.is_restarting():
                self.changeState("STARTING")
                return
            '''
            if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
255
256
257
258
259
        print("PLC is connected")
        # Set STATE to PASSIVE (with PLC)
        self.changeState("Passive")
        #return self.current_state
        
0ca00ebd   Etienne Pallier   refactorized and ...
260
        
d0b663be   Etienne Pallier   refactorized majo...
261
262
    def behavior_passive(self):
        #print("Passive")
0ca00ebd   Etienne Pallier   refactorized and ...
263
264
265
266
267
268
269
270
271
        #if self.is_shuttingdown_or_restarting(): return
        #if self.plc_status.plc_mode == "AUTO":
        if not self.plc_is_connected(): 
            self.changeState("PASSIVE_NO_PLC")
            return
        
        if self.plc_is_auto():
            #if not self.config.majordome_restarted: self.config.ntc = True
            if not self.config.majordome_restarted: self.NEED_TO_CLOSE=True
6aec6155   theopuhl   Majordome algorit...
272
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
273
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
274
            
0ca00ebd   Etienne Pallier   refactorized and ...
275
            
d0b663be   Etienne Pallier   refactorized majo...
276
277
    def behavior_standby(self):
        #print("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
278
279
280
281
282
        #if self.config.ntc:
        if self.is_shuttingdown() and not self.NEED_TO_CLOSE:
            self.NEED_TO_CLOSE = True
            
        if self.NEED_TO_CLOSE:
6aec6155   theopuhl   Majordome algorit...
283
            self.changeState("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
284
            #self.sub_behavior_closing()
03814884   Etienne Pallier   launch majordome ...
285
            self.do_behavior_for_current_state()
0ca00ebd   Etienne Pallier   refactorized and ...
286
287
288
289
            self.changeState("Standby")
            
        #elif self.plc_status.plc_mode != "AUTO" or self.is_shuttingdown_or_restarting():
        if not self.plc_is_auto() or self.is_shuttingdown_or_restarting():
6aec6155   theopuhl   Majordome algorit...
290
            self.changeState("Passive")
0ca00ebd   Etienne Pallier   refactorized and ...
291
        elif not self.config.global_mode and not self.config.lock:
6aec6155   theopuhl   Majordome algorit...
292
            self.changeState("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
293
294
            
        elif self.is_night() and self.plc_is_safe() and self.config.ack and not self.config.lock :
6aec6155   theopuhl   Majordome algorit...
295
            self.changeState("Startup")
d0b663be   Etienne Pallier   refactorized majo...
296
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
297

0ca00ebd   Etienne Pallier   refactorized and ...
298

d0b663be   Etienne Pallier   refactorized majo...
299
300
    def behavior_remote(self):
        #print("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
301
302
303
        if self.config.global_mode or self.is_shuttingdown_or_restarting() or not self.plc_is_auto() or self.config.lock:
            if not self.plc_is_auto() or self.config.lock or self.is_shuttingdown():
                self.NEED_TO_CLOSE=True
6aec6155   theopuhl   Majordome algorit...
304
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
305
306
307
308
309
310
311
312
313
            return
        
        #TODO: get shutter state from db status (then wait until close/open)
        if not self.plc_is_safe() and self.PLC_IS_SAFE:
            PLC_IS_SAFE = False
            response = TelescopeRemoteControlDefault("DOME SHUTTER CLOSE", expert_mode=True).exec_command()
        if self.plc_is_safe() and not self.PLC_IS_SAFE:
            PLC_IS_SAFE = True
            response = TelescopeRemoteControlDefault("DOME SHUTTER OPEN", expert_mode=True).exec_command()
d0b663be   Etienne Pallier   refactorized majo...
314
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
315

0ca00ebd   Etienne Pallier   refactorized and ...
316

d0b663be   Etienne Pallier   refactorized majo...
317
    def behavior_startup(self):
d0b663be   Etienne Pallier   refactorized majo...
318
        #print("Startup")
0ca00ebd   Etienne Pallier   refactorized and ...
319
320
        if self.config.lock or not self.plc_is_auto():
            self.NEED_TO_CLOSE=True
6aec6155   theopuhl   Majordome algorit...
321
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
322
323
324
325
326
327
328
329
330
331
            return
        
        #TODO: get shutter and telescope from db status
        time.sleep(5)
        '''
        if not (dome_shutter == Open and telescope == Ready)
            TelescopeRemoteControlDefault("DO DOME SHUTTER OPEN", expert_mode=True).exec_command()
            TelescopeRemoteControlDefault("DO START", expert_mode=True).exec_command()
        '''
        self.changeState("Scheduler")
d0b663be   Etienne Pallier   refactorized majo...
332
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
333
334
        

d0b663be   Etienne Pallier   refactorized majo...
335
336
    def behavior_scheduler(self):
        #print("Scheduler")
0ca00ebd   Etienne Pallier   refactorized and ...
337
338
        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():
            if not ( not self.config.global_mode or self.is_restarting() ): self.NEED_TO_CLOSE = True
6aec6155   theopuhl   Majordome algorit...
339
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
340
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
341

0ca00ebd   Etienne Pallier   refactorized and ...
342
343
344

    def sub_behavior_closing(self):
        #print("CURRENT OCS (MAJORDOME) STATE: "+ self.current_state)
d0b663be   Etienne Pallier   refactorized majo...
345
        #print("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
346
347
348
349
350
351
352
353
354
355
356
357
358
        #self.config.save()
        if not self.plc_is_auto():
            # PLC not AUTO => we can do nothing, so only send email if dome not closed...
            self.send_alarm_if_not_closed()
        else:
            # These commands should do nothing if instruments are already closed/parked...
            response = TelescopeRemoteControlDefault("DO DOME SHUTTER CLOSE", expert_mode=True).exec_command()
            response = TelescopeRemoteControlDefault("DO DOME PARK", expert_mode=True).exec_command()
            response = TelescopeRemoteControlDefault("DO TELESCOPE PARK", expert_mode=True).exec_command()

        self.NEED_TO_CLOSE = False

        #self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
359
360
361
362
363
364
365
366
367
368
        #return self.current_state

    behavior = {
        "STARTING": behavior_starting,
        "PASSIVE_NO_PLC": behavior_passive_no_plc,
        "Passive": behavior_passive,
        "Standby": behavior_standby,
        "Remote": behavior_remote,
        "Startup": behavior_startup,
        "Scheduler": behavior_scheduler,
0ca00ebd   Etienne Pallier   refactorized and ...
369
        #"Closing": sub_behavior_closing,
d0b663be   Etienne Pallier   refactorized majo...
370
    }
03814884   Etienne Pallier   launch majordome ...
371
372
    def do_behavior_for_current_state(self) -> str:
        print("CURRENT OCS (MAJORDOME) STATE: " + self.current_state)
0ca00ebd   Etienne Pallier   refactorized and ...
373
        time.sleep(2)
d0b663be   Etienne Pallier   refactorized majo...
374
375
376
        # EXIT if PLC not connected
        #if not self.plc_is_connected(): return                  
        # EXIT if closing or restarting
0ca00ebd   Etienne Pallier   refactorized and ...
377
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
378
379
        # run behavior for this state
        #self.behavior[current_state](self)
03814884   Etienne Pallier   launch majordome ...
380
        if self.current_state == "Closing": 
0ca00ebd   Etienne Pallier   refactorized and ...
381
382
            self.sub_behavior_closing()
        else:
03814884   Etienne Pallier   launch majordome ...
383
384
            self.behavior[self.current_state](self)
        return self.current_state
468a79dc   Etienne Pallier   added comments
385

0997e1c3   Etienne Pallier   moved main run() ...
386
           
6aec6155   theopuhl   Majordome algorit...
387
    '''
6aec6155   theopuhl   Majordome algorit...
388
389
        Function called to send alarms is the site isn't closed (Empty for the moment)
    '''
d0b663be   Etienne Pallier   refactorized majo...
390
    def send_alarm_if_not_closed(self):
6aec6155   theopuhl   Majordome algorit...
391
392
        pass

0997e1c3   Etienne Pallier   moved main run() ...
393

6aec6155   theopuhl   Majordome algorit...
394
395
396
397
    '''
        Function called by run to wait for PLC connection before and during the loop
        (also gathering needed info)
    '''
d0b663be   Etienne Pallier   refactorized majo...
398
    def plc_is_connected(self):
6aec6155   theopuhl   Majordome algorit...
399
400
401
        try :
            self.config = Config.objects.get(pk=1)
            self.plc_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
6aec6155   theopuhl   Majordome algorit...
402
            timeout = (datetime.datetime.now() - self.plc_status.created).total_seconds()
d0b663be   Etienne Pallier   refactorized majo...
403
            if timeout >= self.config.plc_timeout_seconds:
6aec6155   theopuhl   Majordome algorit...
404
405
                return (False)
            return (True)
d0b663be   Etienne Pallier   refactorized majo...
406
        
6aec6155   theopuhl   Majordome algorit...
407
408
409
410
411
412
        except Config.DoesNotExist or PlcDeviceStatus.DoesNotExist:
            return (False)




e8e6f017   Jeremy   Reworked devices ...
413
414
415
416
417
418
419
420
    '''
        Check if the instrument status is valid
    '''
    def isValidStatus(self, status):
        # TODO REMOVE COMMENT AND CHANGE WHEN DEFINED
        # if (status == "" or status == "ERROR" or status == "FAILED" or status == "NOT_SET"):
        #     return (False)
        return (True)
65149de7   Jeremy   Update
421
422
423
424
425
426

    def setContext(self):
        self.tel = TelescopeController()
        self.vis_camera = VISCameraController()
        self.nir_camera = NIRCameraController()
        self.plc = PLCController()
cfc9d09c   Jeremy   Added dome simula...
427
        self.dom = DomeController()
65149de7   Jeremy   Update
428
        return (0)
65149de7   Jeremy   Update
429

c72eb17a   Jeremy   Update celery task
430
431
    def createTask(self):
        try:
1a2dc19f   Etienne Pallier   nombreux bugfixes...
432
433
434
            # (EP) NO find() method available from Django ORM !!!! 
            #TaskId.objects.find(task="majordome").delete()
            TaskId.objects.filter(task="majordome").delete()
c72eb17a   Jeremy   Update celery task
435
436
437
438
439
440
441
442
443
444
445
446
447
448
        except Exception as e:
            log.info(str(e))
            return 1
        TaskId.objects.create(task_id=self.request.id, task="majordome")
        return 0

    def setTasks(self):
        try:
            self.monitoring_task = TaskId.objects.get(task="monitoring")
            self.alert_task = TaskId.objects.get(task="alert_manager")
        except Exception as e:
            self.monitoring_task = None
            self.alert_task = None
        return 0
65149de7   Jeremy   Update
449
450
451
452
453
454
455
456
457
458
459
460
461
462
    '''
        Reads the softwares versions in the settings.py, store them in the DB and send them to the IC.
    '''
    def updateSoftware(self):
        versions = settings.MODULES_VERSIONS
        for module, version in versions.items():
            same_module_versions = Version.objects.filter(module_name=module)
            if same_module_versions.count() == 0:
                Version.objects.create(module_name=module, version=version)
            elif same_module_versions.order_by("-created")[0].version != version:
                Version.objects.create(module_name=module, version=version)
        return (0)

    '''
ce470283   Jeremy   Plc simulator fin...
463
        Loop to wait for the device to be idle with the starting configurations.
65149de7   Jeremy   Update
464
465
    '''
    def waitDevices(self):
ce470283   Jeremy   Plc simulator fin...
466
467
468
469
470
        while self.status_vis == "" and self.status_tel == "" and self.status_nir == "" and self.status_dom == "":
            self.status_vis = self.vis_camera.getStatus()
            self.status_nir = self.nir_camera.getStatus()
            self.status_tel = self.tel.getStatus()
            self.status_dom = self.dom.getStatus()
65149de7   Jeremy   Update
471
472
473
474
        return (0)

    '''
        Computes the beginning and the end of the following (or current) night
257abe9b   Jeremy   Added comments
475
        set the timers -> maybe put timers in a config file ?
65149de7   Jeremy   Update
476
477
478
479
480
481
    '''
    def setTime(self):
        self.night_start = getNightStart()
        self.night_end = getNightEnd()
        self.night_start_jd = secondsToJulianDate(getNightStart())
        self.night_end_jd = secondsToJulianDate(getNightEnd())
ef60c3ec   Jeremy   Majordome and mon...
482
483
        self.timer_night_start = self.night_start - getCurrentTime()
        self.timer_night_end = self.night_end - getCurrentTime()
65149de7   Jeremy   Update
484
        self.timer_status = 5
c72eb17a   Jeremy   Update celery task
485
        self.tasks_timer = 5
65149de7   Jeremy   Update
486
        self.timer_plc = 2
1aed430d   jeremy   Alert handled + k...
487
        self.alert_timer = 1
65149de7   Jeremy   Update
488
        self.timer_schedule = 1
05038bc8   Jeremy   Majordome logic i...
489
        self.timer_sequence = 1
65149de7   Jeremy   Update
490
491
492
493

        if (self.night_start - 120 > getCurrentTime()):
            self.timer_night_start = self.night_start - 120 - getCurrentTime()
        self.timer_night_end = self.night_end - getCurrentTime()
4cb0ff36   Jeremy   Update
494
495
        if (getCurrentTime() > self.night_start):
            self.adaptTimers()
65149de7   Jeremy   Update
496
497

        self.timers = {
4cb0ff36   Jeremy   Update
498
499
500
501
502
            "status": self.timer_status,
            "environment": self.timer_plc,
            "night_start": self.timer_night_start,
            "night_end": self.timer_night_end,
            "schedule": self.timer_schedule,
c72eb17a   Jeremy   Update celery task
503
504
            "sequence": self.timer_sequence,
            "tasks": self.tasks_timer
4cb0ff36   Jeremy   Update
505
        }
ff448d43   Jeremy   Update
506
        if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
507
508
            log.info("Majordome started with timers : " + str(self.timers))
        # Functions called during the loop
4cb0ff36   Jeremy   Update
509
510
511
512
513
514
        self.functions = {
            "status": self.handleStatusTimer,
            "environment": self.handleEnvironmentTimer,
            "night_start": self.handleNightStartTimer,
            "night_end": self.handleNightEndTimer,
            "schedule": self.handleScheduleTimer,
c72eb17a   Jeremy   Update celery task
515
516
            "sequence": self.handleSequenceTimer,
            "tasks": self.handleTasks
65149de7   Jeremy   Update
517
        }
65149de7   Jeremy   Update
518
519
        return (0)

257abe9b   Jeremy   Added comments
520
521
522
    '''
        Function called by the main loop to handle the task event (check monitoring and alert_manager)
    '''
c72eb17a   Jeremy   Update celery task
523
    def handleTasks(self):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
524
525
        if not settings.USE_CELERY: return 0

c72eb17a   Jeremy   Update celery task
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
        self.timers["tasks"] = self.tasks_timer
        if self.monitoring_task is None:
            try:
                self.monitoring_task = TaskId.objects.get(task="monitoring")
            except Exception as e:
                monitoring.tasks.Monitoring.apply_async()
                if settings.DEBUG and DEBUG_FILE:
                    log.info(str(e))
        if self.alert_task is None:
            try:
                self.alert_task = TaskId.objects.get(task="alert_manager")
            except Exception as e:
                alert_manager.tasks.AlertListener.apply_async()
                if settings.DEBUG and DEBUG_FILE:
                    log.info(str(e))
        return 0

    # TODO adapt timers if the majordome is started during the night or not ?
4cb0ff36   Jeremy   Update
544
545
546
    def adaptTimers(self):
        pass

bca9a283   Jeremy   Reworked the sche...
547
548
549
    def logDB(self, message: str):
        Log.objects.create(agent="Majordome", message=message)

65149de7   Jeremy   Update
550
551
    '''
        Infinite loop according to the majordome behavior
65149de7   Jeremy   Update
552
553
    '''
    def loop(self):
d0b663be   Etienne Pallier   refactorized majo...
554
        while (self.closing_mode != "OCS-SHUTDOWN"):
b4e8963c   Etienne Pallier   Each agent (envmo...
555
            print("(MAJOR): start new iteration")
65149de7   Jeremy   Update
556
557
558
559
            minimal_timer = min(self.timers, key=self.timers.get)
            if (self.timers[minimal_timer] > 0):
                time.sleep(self.timers[minimal_timer])
                self.timers = {key: value - self.timers[minimal_timer] for key, value in self.timers.items()}
65149de7   Jeremy   Update
560
561
            for timer_name, timer_value in self.timers.items():
                if (timer_value <= 0):
4cb0ff36   Jeremy   Update
562
                    if timer_name in self.functions:
bca9a283   Jeremy   Reworked the sche...
563
                        self.logDB("Executing timer " + str(timer_name))
4cb0ff36   Jeremy   Update
564
                        self.functions[timer_name]()
65149de7   Jeremy   Update
565
                    else:
ff448d43   Jeremy   Update
566
                        if (settings.DEBUG and DEBUG_FILE):
4cb0ff36   Jeremy   Update
567
                            log.info("Timer : " + str(timer_name) + "is not known by the Majordome")
bca9a283   Jeremy   Reworked the sche...
568
                        self.logDB("Timer " + str(timer_name) + " unknown")
ff448d43   Jeremy   Update
569
                    if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
570
                        log.info("Timer : " + str(timer_name) + " executed")
075082e1   Etienne Pallier   added start of ag...
571
572
            # EP added because loop is too quick (without CELERY)
            if not settings.USE_CELERY: time.sleep(2)
05038bc8   Jeremy   Majordome logic i...
573
574
        return (0)

257abe9b   Jeremy   Added comments
575
576
577
    '''
        Function called by the main loop to handle environment event (PLC info)
    '''
4cb0ff36   Jeremy   Update
578
579
    def handleEnvironmentTimer(self):
        self.timers["environment"] = self.timer_plc
ce470283   Jeremy   Plc simulator fin...
580
        self.handlePLC()
4cb0ff36   Jeremy   Update
581
582
        return (0)

257abe9b   Jeremy   Added comments
583
584
585
    '''
        Function called by the main loop to handle the devices status
    '''
4cb0ff36   Jeremy   Update
586
587
    def handleStatusTimer(self):
        self.timers["status"] = self.timer_status
ce470283   Jeremy   Plc simulator fin...
588
589
590
591
        self.status_tel = self.tel.getStatus()
        self.status_nir = self.nir_camera.getStatus()
        self.status_vis = self.vis_camera.getStatus()
        self.status_dom = self.dom.getStatus()
4cb0ff36   Jeremy   Update
592
        self.handleStatus()
c72eb17a   Jeremy   Update celery task
593
        return 0
4cb0ff36   Jeremy   Update
594

257abe9b   Jeremy   Added comments
595
596
597
    '''
        Function called by the main loop to check if the executing sequence is finished
    '''
4cb0ff36   Jeremy   Update
598
599
    def handleSequenceTimer(self):
        self.timers["sequence"] = self.timer_sequence
ff448d43   Jeremy   Update
600
601
602
        if (self.executing_sequence):
            self.handleSequence(self.executing_sequence[0],
                                self.executing_sequence[1], self.executing_sequence[2])
4cb0ff36   Jeremy   Update
603
604
        return (0)

257abe9b   Jeremy   Added comments
605
606
607
    '''
        Function called by the main loop to check if there is a new schedule and to execute its sequences
    '''
4cb0ff36   Jeremy   Update
608
    def handleScheduleTimer(self):
ef60c3ec   Jeremy   Majordome and mon...
609
        self.timers["schedule"] = self.timer_schedule
4cb0ff36   Jeremy   Update
610
        if (self.isValidStatus(self.status_tel)):
ff448d43   Jeremy   Update
611
            if (self.schedule is None):
ef60c3ec   Jeremy   Majordome and mon...
612
613
614
                try:
                    self.schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
615
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
616
617
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
618
            else:
ef60c3ec   Jeremy   Majordome and mon...
619
620
621
                try:
                    schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
622
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
623
624
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
625
626
627
                if (schedule.created != self.schedule.created):
                    self.next_sequence = None
                    self.schedule = schedule
1aed430d   jeremy   Alert handled + k...
628
                    self.firstSequenceIsAlert()
4cb0ff36   Jeremy   Update
629
            if (self.schedule):
c53a13e0   Jeremy   Updating a lot of...
630
631
                shs_list = self.schedule.shs.filter(Q(status=Sequence.PLANNED) |
                                                    Q(status=Sequence.PENDING)).order_by('tsp')
4cb0ff36   Jeremy   Update
632
633
634
635
636
                self.executeSchedule(shs_list)
        else:
            self.notifyTelescopeStatus("scheduler")
        return (0)

257abe9b   Jeremy   Added comments
637
    '''
1aed430d   jeremy   Alert handled + k...
638
639
640
641
642
643
644
645
646
647
648
649
650
651
        Function called by handleScheduleTimer, the purpose is to kill the executing sequence if the
        first sequence in the new planning is from an alert
    '''
    @executingSequenceExist
    def firstSequenceIsAlert(self):
        shs_list = self.schedule.shs.filter(Q(status=Sequence.PLANNED) |
                                            Q(status=Sequence.PENDING)).order_by('tsp')
        if shs_list and shs_list[0].sequence.is_alert:
            if shs_list[0].sequence.created.date() >= (datetime.datetime.now() - datetime.timedelta(seconds=10)).date():
                self.killExecutingSequence()
                return 1
        return 0

    '''
257abe9b   Jeremy   Added comments
652
653
        Function called by the main loop to handle the end of a night
    '''
4cb0ff36   Jeremy   Update
654
    def handleNightEndTimer(self):
ce470283   Jeremy   Plc simulator fin...
655
        self.timers["night_end"] = getNightEnd()
4cb0ff36   Jeremy   Update
656
        if (self.isValidStatus(self.status_tel)):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
657
658
659
660
661
662
663
664
            #observation_manager.tasks.night_calibrations.apply_async()
            if settings.USE_CELERY:
                print("MJ: call observation_manager WITH CELERY")
                observation_manager.tasks.night_calibrations.apply_async()
            else:
                print("MJ: call observation_manager WITHOUT CELERY")
                observation_manager.tasks.night_calibrations().run()

4cb0ff36   Jeremy   Update
665
666
667
668
        else:
            self.notifyTelescopeStatus("night_end")
        return (0)

257abe9b   Jeremy   Added comments
669
    '''
ed1bf194   Etienne Pallier   bugfix task major...
670
        Function called by the main loop to handle the beginning of a night
257abe9b   Jeremy   Added comments
671
    '''
4cb0ff36   Jeremy   Update
672
673
    def handleNightStartTimer(self):
        self.timers["night_start"] = getNextNightStart()
c72eb17a   Jeremy   Update celery task
674
675
676
677
        if self.isOutsideOk():
            self.dom.open()
            self.vis_camera.open_shutter()
            self.nir_camera.open_shutter()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
678
679
680
681
682
683
684
685
        #scheduler.tasks.scheduling.apply_async((False, False))
        if settings.USE_CELERY:
            print("MJ: call schedule WITH CELERY")
            scheduler.tasks.scheduling.apply_async((False, False))
        else:
            print("MJ: call schedule WITHOUT CELERY")
            scheduler.tasks.scheduling().run((False, False))

4cb0ff36   Jeremy   Update
686
687
        return (0)

ef60c3ec   Jeremy   Majordome and mon...
688
689
690
    def notifyTelescopeStatus(self, timer_name):
        return (self.notifyDeviceStatus("telescope", timer_name, self.status_tel))

05038bc8   Jeremy   Majordome logic i...
691
    def notifyDeviceStatus(self, device_name, timer_name, status):
ef60c3ec   Jeremy   Majordome and mon...
692
693
        Log.objects.create(agent=device_name, created=datetime.datetime.now(),
                           message="The action : " + str(timer_name) + " has been canceled : Telescope status : " + str(status))
ce470283   Jeremy   Plc simulator fin...
694
        # TODO MAYBE reset some variables and do a scheduling
65149de7   Jeremy   Update
695
696
697
        return (0)

    '''
257abe9b   Jeremy   Added comments
698
        Execute a schedule
65149de7   Jeremy   Update
699
700
    '''
    def executeSchedule(self, shs_list):
c72eb17a   Jeremy   Update celery task
701
        for shs in shs_list:  # shs_list is sorted by tsp
c53a13e0   Jeremy   Updating a lot of...
702
703
704
            if (self.executableSequence(shs.sequence.status) and self.observable(shs.sequence)):
                if self.next_sequence is None:
                    self.setNextSequence(shs, shs.sequence)
678838ed   Jeremy   Weather ans insid...
705
                if self.isExecutable() and self.executing_sequence is None:
c53a13e0   Jeremy   Updating a lot of...
706
707
708
709
710
                    if self.isValidTimer(self.next_sequence[0]):
                        if self.executeSequence(self.next_sequence[0], self.next_sequence[1]) == -1:
                            return -1
                        if self.next_sequence[0] != shs and self.next_sequence[1] != shs.sequence:
                            self.setNextSequence(shs, shs.sequence)
ff448d43   Jeremy   Update
711
                        else:
c53a13e0   Jeremy   Updating a lot of...
712
                            self.next_sequence = None
ff448d43   Jeremy   Update
713
714
                    else:
                        return 0
bca9a283   Jeremy   Reworked the sche...
715
            else:
ff448d43   Jeremy   Update
716
                if (settings.DEBUG and DEBUG_FILE):
bca9a283   Jeremy   Reworked the sche...
717
                    log.info("Sequence cannot be executed : Not observable")
ff448d43   Jeremy   Update
718
719
                self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable")
        return 0
05038bc8   Jeremy   Majordome logic i...
720

4cb0ff36   Jeremy   Update
721
    def observable(self, sequence):
ff448d43   Jeremy   Update
722
723
724
        if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
            return 0
        return 1
4cb0ff36   Jeremy   Update
725

c53a13e0   Jeremy   Updating a lot of...
726
727
728
729
730
    def executableSequence(self, status):
        if status == Sequence.PLANNED or status == Sequence.PENDING:
            return 1
        return 0

257abe9b   Jeremy   Added comments
731
732
733
    '''
        Kill the executing sequence and set its state to cancelled
    '''
678838ed   Jeremy   Weather ans insid...
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
    @executingSequenceExist
    def killExecutingSequence(self):
        shs = self.executing_sequence[0]
        sequence = self.executing_sequence[1]
        executing_plans = self.executing_sequence[2]

        shs.status = Sequence.CANCELLED
        sequence.status = Sequence.CANCELLED
        shs.save()
        sequence.save()
        for rev in executing_plans:
            if (not rev.failed() and not rev.successful()):
                rev.revoke(terminate=True)
        self.executing_sequence = None
        return 0

    def reset(self, type):
        if type == "WEATHER":
            self.dom.open()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
753
754
755
756
757
758
759
760
            #scheduler.tasks.scheduling.delay((False, False))
            if settings.USE_CELERY:
                print("MJ: call schedule WITH CELERY")
                scheduler.tasks.scheduling.delay((False, False))
            else:
                print("MJ: call schedule WITHOUT CELERY")
                scheduler.tasks.scheduling().run((False, False))

678838ed   Jeremy   Weather ans insid...
761
        elif type == "INSIDE":
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
762
763
764
765
766
767
768
            #scheduler.tasks.scheduling.delay((False, False))
            if settings.USE_CELERY:
                print("MJ: call schedule WITH CELERY")
                scheduler.tasks.scheduling.delay((False, False))
            else:
                print("MJ: call schedule WITHOUT CELERY")
                scheduler.tasks.scheduling().run((False, False))
678838ed   Jeremy   Weather ans insid...
769

257abe9b   Jeremy   Added comments
770
771
772
    '''
        Handle a new alarm (called by isInsideOk or isWeatherOk)
    '''
678838ed   Jeremy   Weather ans insid...
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
    @SameAlarmCheck
    def handleAlarm(self, type, pos=-1):
        if type == "WEATHER":
            #TODO send email
            self.dom.close()
            self.killExecutingSequence()
            self.vis_camera.park()
            self.nir_camera.park()
        elif type == "INSIDE":
            #TODO send email
            self.killExecutingSequence()
            self.vis_camera.park()
            self.nir_camera.park()
        elif type == "ENDED":
            if len(self.alarm_list) > 0 and pos != -1:
                ended = self.alarm_list[pos]
                del self.alarm_list[pos]
                self.reset(ended)
            return 0
        else:
            return 1
        self.alarm_list.append(type)
        return 0

    '''
        for now weather_status and site_status contains something different than OK if the status is critical
        Later we may have other states to handle
    '''
ce470283   Jeremy   Plc simulator fin...
801
802
803
    def isOutsideOk(self) -> bool:
        self.handlePLC()
        if self.weather_status == "OK":
678838ed   Jeremy   Weather ans insid...
804
805
            if "WEATHER" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("WEATHER"))
ce470283   Jeremy   Plc simulator fin...
806
            return True
678838ed   Jeremy   Weather ans insid...
807
        self.handleAlarm("WEATHER")
ce470283   Jeremy   Plc simulator fin...
808
809
        return False

257abe9b   Jeremy   Added comments
810
811
812
    '''
        Check the telescope inside status
    '''
ce470283   Jeremy   Plc simulator fin...
813
814
815
    def isInsideOk(self) -> bool:
        self.handlePLC()
        if self.site_status == "OK":
678838ed   Jeremy   Weather ans insid...
816
817
            if "INSIDE" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("INSIDE"))
ce470283   Jeremy   Plc simulator fin...
818
            return True
678838ed   Jeremy   Weather ans insid...
819
        self.handleAlarm("INSIDE")
ce470283   Jeremy   Plc simulator fin...
820
821
822
823
824
825
826
827
828
829
830
831
832
833
        return False

    def isDevicesOk(self) -> bool:
        if self.isValidStatus(self.status_tel) and self.isValidStatus(self.status_dom)\
            and self.isValidStatus(self.status_vis) and self.isValidStatus(self.status_nir):
            return True
        return False

    def isExecutable(self) -> bool:
        if self.isValidStatus(self.status_tel) and self.isValidStatus(self.status_dom)\
                and self.isOutsideOk() and self.isInsideOk():
            return True
        return False

257abe9b   Jeremy   Added comments
834
835
836
    '''
        check if the sequence timer is valid for execution, also check if there is a scheduling task running
    '''
ce470283   Jeremy   Plc simulator fin...
837
    def isValidTimer(self, shs) -> bool:
c53a13e0   Jeremy   Updating a lot of...
838
839
        current_countdown = self.getCountdown(shs)
        if (current_countdown <= JulianSeconds(5)):
c53a13e0   Jeremy   Updating a lot of...
840
841
842
            try:
                task = TaskId.objects.filter(task="scheduling")
                if not task:
ce470283   Jeremy   Plc simulator fin...
843
844
                    return True
                return False
c53a13e0   Jeremy   Updating a lot of...
845
            except:
ce470283   Jeremy   Plc simulator fin...
846
847
                return True
        return False
c53a13e0   Jeremy   Updating a lot of...
848

05038bc8   Jeremy   Majordome logic i...
849
    '''
257abe9b   Jeremy   Added comments
850
        Launch the observation tasks NIR and VIS associated to a sequence
05038bc8   Jeremy   Majordome logic i...
851
    '''
c53a13e0   Jeremy   Updating a lot of...
852
    def executeSequence(self, shs, sequence):
3224f14a   Jeremy   Fixed some simula...
853
854
855
856
        shs.status = Sequence.EXECUTING
        sequence.status = Sequence.EXECUTING
        shs.save()
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
857
        log.info("Executing sequence id = " + str(sequence.pk))
bca9a283   Jeremy   Reworked the sche...
858
        self.logDB("Executing sequence")
05038bc8   Jeremy   Majordome logic i...
859
        plans_results = []
05038bc8   Jeremy   Majordome logic i...
860
861
862
        if sequence.albums.filter(detector__name="Cagire").exists():
            if (self.isValidStatus(self.status_nir)):
                for plan in sequence.albums.get(detector__name="Cagire").plans.all():
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
863
864
865
866
867
868
869
870
871
872
                    #res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, float(self.getCountdown(shs))))
                    if settings.USE_CELERY:
                        print("MJ: call observation_manager WITH CELERY")
                        res = observation_manager.tasks.execute_plan_nir.apply_async(
                            (plan.id, float(self.getCountdown(shs))))
                    else:
                        print("MJ: call observation_manager WITHOUT CELERY")
                        res = observation_manager.tasks.execute_plan_nir().run(
                            (plan.id, float(self.getCountdown(shs))))

c53a13e0   Jeremy   Updating a lot of...
873
874
                    # JB TODO : is it still usefull ?
                    # TaskId.objects.create(task_id=res.id, task="execute_plan")
05038bc8   Jeremy   Majordome logic i...
875
                    plans_results.append(res)
ff448d43   Jeremy   Update
876
877
            else:
                self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
c53a13e0   Jeremy   Updating a lot of...
878
879
880
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
ff448d43   Jeremy   Update
881
882
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
883
884
885
        if sequence.albums.filter(detector__name="Visible camera").exists():
            if (self.isValidStatus(self.status_vis)):
                for plan in sequence.albums.get(detector__name="Visible camera").plans.all():
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
886
887
888
889
890
891
892
893
                    #res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, float(self.getCountdown(shs))))
                    if settings.USE_CELERY:
                        print("MJ: call observation_manager WITH CELERY")
                        res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, float(self.getCountdown(shs))))
                    else:
                        print("MJ: call observation_manager WITHOUT CELERY")
                        res = observation_manager.tasks.execute_plan_vis().run((plan.id, float(self.getCountdown(shs))))

05038bc8   Jeremy   Majordome logic i...
894
895
896
                    plans_results.append(res)
            else:
                self.notifyDeviceStatus("Camera visible", "Sequence execution", self.status_vis)
c53a13e0   Jeremy   Updating a lot of...
897
898
899
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
05038bc8   Jeremy   Majordome logic i...
900
901
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
902
        self.executing_sequence = [shs, sequence, plans_results]
05038bc8   Jeremy   Majordome logic i...
903
904
905
906
907
        return (0)

    '''
        Set the next sequence
    '''
c53a13e0   Jeremy   Updating a lot of...
908
    def setNextSequence(self, shs, sequence):
ff448d43   Jeremy   Update
909
        sequence.status = Sequence.PENDING
c53a13e0   Jeremy   Updating a lot of...
910
911
        shs.status = Sequence.PENDING
        self.next_sequence = [shs, sequence]
ff448d43   Jeremy   Update
912
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
913
        shs.save()
05038bc8   Jeremy   Majordome logic i...
914
915
916
917
918
919
        return (0)

    '''
        Check if the current sequence is finished
    '''
    def handleSequence(self, shs, sequence, executing_plans):
c53a13e0   Jeremy   Updating a lot of...
920
        count = 0
c53a13e0   Jeremy   Updating a lot of...
921
        for res in executing_plans:
05038bc8   Jeremy   Majordome logic i...
922
            try:
c53a13e0   Jeremy   Updating a lot of...
923
924
                if res.successful() or res.failed():
                    count += 1
05038bc8   Jeremy   Majordome logic i...
925
            except Exception as e:
678838ed   Jeremy   Weather ans insid...
926
927
                if DEBUG_FILE and settings.DEBUG:
                    log.info(str(e))
05038bc8   Jeremy   Majordome logic i...
928
929
930
931
932
                shs.status = Sequence.CANCELLED
                sequence.status = Sequence.CANCELLED
                shs.save()
                sequence.save()
                for rev in executing_plans:
c53a13e0   Jeremy   Updating a lot of...
933
934
935
                    if (not rev.failed() and not rev.successful()):
                        rev.revoke(terminate=True)
                self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
936
                return (-1)
c53a13e0   Jeremy   Updating a lot of...
937
        if count >= len(executing_plans):
05038bc8   Jeremy   Majordome logic i...
938
939
940
941
942
            sequence.status = Sequence.EXECUTED
            shs.status = Sequence.EXECUTED
            sequence.save()
            shs.save()
            message = "Finished sequence " + str(sequence.pk) + " execution"
05038bc8   Jeremy   Majordome logic i...
943
            Log.objects.create(agent="Majordome", message=message)
c53a13e0   Jeremy   Updating a lot of...
944
            self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
945
        return (0)
65149de7   Jeremy   Update
946
947
948
949

    '''
        Function called to do an action with the devices status
    '''
05038bc8   Jeremy   Majordome logic i...
950
    def handleStatus(self):
05038bc8   Jeremy   Majordome logic i...
951
952
953
        telescope = Telescope.objects.first()
        camera_nir = Detector.objects.get(name="Cagire")
        camera_vis = Detector.objects.get(name="Visible camera")
ce470283   Jeremy   Plc simulator fin...
954
955
956
        dome = Dome.objects.get(name="Dome")

        dome.status = self.status_dom
05038bc8   Jeremy   Majordome logic i...
957
958
959
        telescope.status = self.status_tel
        camera_nir.status = self.status_nir
        camera_vis.status = self.status_vis
ce470283   Jeremy   Plc simulator fin...
960
961
962
963
964

        dome.save()
        telescope.save()
        camera_nir.save()
        camera_vis.save()
bca9a283   Jeremy   Reworked the sche...
965
966
        self.logDB("Instrument status : dome  = " + str(self.status_dom) + ", telescope = " + str(self.status_tel)
                   + ", camera_nir = " + str(self.status_nir) + ", camera_vis" + str(self.status_vis))
65149de7   Jeremy   Update
967
968
969
        return (0)

    '''
3224f14a   Jeremy   Fixed some simula...
970
        Put the majordome in pause
4cb0ff36   Jeremy   Update
971
    '''
4cb0ff36   Jeremy   Update
972
    def systemPause(self, duration, cause: str):
bca9a283   Jeremy   Reworked the sche...
973
        self.logDB("System in pause for " + str(duration))
4cb0ff36   Jeremy   Update
974
        time.sleep(duration)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
975
976
977
978
979
980
981
982
        #scheduler.tasks.scheduling.apply_async(first_schedule=False, alert=False)
        if settings.USE_CELERY:
            print("MJ: call schedule WITH CELERY")
            scheduler.tasks.scheduling.apply_async(first_schedule=False, alert=False)
        else:
            print("MJ: call schedule WITHOUT CELERY")
            scheduler.tasks.scheduling().run(first_schedule=False, alert=False)

4cb0ff36   Jeremy   Update
983
984
985
986
987
        self.setTime()
        print("system has been paused. Cause : " + cause)
        return (0)

    '''
65149de7   Jeremy   Update
988
989
        Function called to do an action with the site status and the wheather status
    '''
ce470283   Jeremy   Plc simulator fin...
990
991
992
993
994
995
996
997
998
999
1000
    def handlePLC(self):
        try:
            site_status = SiteWatch.objects.latest('updated')
            weather_status = WeatherWatch.objects.latest('updated')
            self.weather_status = weather_status.global_status
            self.site_status = site_status.global_status
        except ObjectDoesNotExist as e:
            if (settings.DEBUG and DEBUG_FILE):
                log.info("No site_status or weather_status found in database : " + str(e))
            # TODO shutdown everything
            return 1
3224f14a   Jeremy   Fixed some simula...
1001
        return 0
5b5566ab   haribo   added celery
1002

4cb0ff36   Jeremy   Update
1003
    '''
05038bc8   Jeremy   Majordome logic i...
1004
        Gets the time before the expected start of the execution.
4cb0ff36   Jeremy   Update
1005
    '''
05038bc8   Jeremy   Majordome logic i...
1006
1007
    def getCountdown(self, shs):
        # TODO start sequence as soon as possible (a lot of verifications must be done there)
ff448d43   Jeremy   Update
1008
        current_time = secondsToPreciseJulianDate(getPreciseCurrentTime())
05038bc8   Jeremy   Majordome logic i...
1009
        countdown = shs.tsp - current_time
9774228b   haribo   Date: 22/06/2016
1010
        return countdown
7a79e25b   haribo   Date: 19/05/2016
1011

4cb0ff36   Jeremy   Update
1012
1013
1014
1015
    '''
        Change observation conditions
    '''
    def changeObsConditions(self):
5b5566ab   haribo   added celery
1016
        print("change_obs_conditions")
6aec6155   theopuhl   Majordome algorit...
1017
        pass