Blame view

src/majordome/tasks.py 37.8 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

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

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

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

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

    
6aec6155   theopuhl   Majordome algorit...
69
    '''
0997e1c3   Etienne Pallier   moved main run() ...
70
71
72
73
74
75
76
77
78
79
        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...
80
        Change behavior with the pyros states
0997e1c3   Etienne Pallier   moved main run() ...
81
82
83
84
85
86
87
88
89
90
91
        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 ...
92
        while True:
d0b663be   Etienne Pallier   refactorized majo...
93
94
95
96
97
98
99
            
            # SETUP
            try : 
                self.config = get_object_or_404(Config, id=1)
            except Config.ObjectDoesNotExist:
                return -1
            
0ca00ebd   Etienne Pallier   refactorized and ...
100
            #self.config.ntc = False
d0b663be   Etienne Pallier   refactorized majo...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
            
            # 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 ...
124
            while self.plc_is_connected() and not self.is_shuttingdown_or_restarting():          
d0b663be   Etienne Pallier   refactorized majo...
125
126
127
128
129
130
                # 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 ...
131
132
133
                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...
134
                if self.current_state not in ['STARTING', 'PASSIVE_NO_PLC']:
0ca00ebd   Etienne Pallier   refactorized and ...
135
136
                    if self.plc_is_not_auto(): self.changeState("PASSIVE")
                '''        
d0b663be   Etienne Pallier   refactorized majo...
137
138
                self.current_state = self.do_behavior_for_state(self.current_state)
                             
0ca00ebd   Etienne Pallier   refactorized and ...
139
140

            '''                      
d0b663be   Etienne Pallier   refactorized majo...
141
142
            # Shutdown options change by the main program
            if self.closing_mode == "OCS-SHUTDOWN":          
0ca00ebd   Etienne Pallier   refactorized and ...
143
                self.shutdown()
d0b663be   Etienne Pallier   refactorized majo...
144
                #self.closeBehaviour(self)
0ca00ebd   Etienne Pallier   refactorized and ...
145
146
147
                #self.sub_behavior_closing()
                break
            '''
d0b663be   Etienne Pallier   refactorized majo...
148
            
0ca00ebd   Etienne Pallier   refactorized and ...
149
            if self.closing_mode == "OCS-RESTART":
d0b663be   Etienne Pallier   refactorized majo...
150
151
152
                self.config.majordome_restarted = True
                self.config.save()
                #TODO: self.kill_all_agents()
0ca00ebd   Etienne Pallier   refactorized and ...
153
                #self.send_alarm_if_not_closed()
d0b663be   Etienne Pallier   refactorized majo...
154
                #self.run()
0ca00ebd   Etienne Pallier   refactorized and ...
155
156

            '''    
d0b663be   Etienne Pallier   refactorized majo...
157
158
159
160
161
162
            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 ...
163
164
165
166
            '''
        
        self.shutdown()
 
0997e1c3   Etienne Pallier   moved main run() ...
167
 
d0b663be   Etienne Pallier   refactorized majo...
168
 
0ca00ebd   Etienne Pallier   refactorized and ...
169
170
171
172
173
174
175
176
177
    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...
178
179
        return self.closing_mode != "NONE"
    
0997e1c3   Etienne Pallier   moved main run() ...
180
181

    '''
6aec6155   theopuhl   Majordome algorit...
182
183
184
        Function called to change and save current state of pyros.
    '''
    def changeState(self, state):
468a79dc   Etienne Pallier   added comments
185
        # (local variable) idem self.config.pyros_state
6aec6155   theopuhl   Majordome algorit...
186
        self.current_state = state
468a79dc   Etienne Pallier   added comments
187
188

        # (in DB) PASSIVE, STANDBY, REMOTE, OPERATING
6aec6155   theopuhl   Majordome algorit...
189
190
        self.config.pyros_state = state
        self.config.save()
d0b663be   Etienne Pallier   refactorized majo...
191
        
0ca00ebd   Etienne Pallier   refactorized and ...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
    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...
207
        
0ca00ebd   Etienne Pallier   refactorized and ...
208

6aec6155   theopuhl   Majordome algorit...
209
    '''
d0b663be   Etienne Pallier   refactorized majo...
210
211
        Each function with behavior describes the behavior of a state,
        they are all contained in a dictionary called in run()
6aec6155   theopuhl   Majordome algorit...
212
    '''
0ca00ebd   Etienne Pallier   refactorized and ...
213

d0b663be   Etienne Pallier   refactorized majo...
214
215
    def behavior_starting(self):
        #print("STARTING")
0ca00ebd   Etienne Pallier   refactorized and ...
216
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
        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 ...
231

d0b663be   Etienne Pallier   refactorized majo...
232
233
    def behavior_passive_no_plc(self):
        #print("PASSIVE_NO_PLC")
0ca00ebd   Etienne Pallier   refactorized and ...
234
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
235
236
237
238
        #self.changeState("Passive No PLC")
        print("Waiting for PLC connection")
        # Wait until PCL is connected
        while not self.plc_is_connected():
0ca00ebd   Etienne Pallier   refactorized and ...
239
240
241
242
243
244
245
            time.sleep(2)
            '''
            if self.is_restarting():
                self.changeState("STARTING")
                return
            '''
            if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
246
247
248
249
250
        print("PLC is connected")
        # Set STATE to PASSIVE (with PLC)
        self.changeState("Passive")
        #return self.current_state
        
0ca00ebd   Etienne Pallier   refactorized and ...
251
        
d0b663be   Etienne Pallier   refactorized majo...
252
253
    def behavior_passive(self):
        #print("Passive")
0ca00ebd   Etienne Pallier   refactorized and ...
254
255
256
257
258
259
260
261
262
        #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...
263
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
264
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
265
            
0ca00ebd   Etienne Pallier   refactorized and ...
266
            
d0b663be   Etienne Pallier   refactorized majo...
267
268
    def behavior_standby(self):
        #print("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
269
270
271
272
273
        #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...
274
            self.changeState("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
275
276
277
278
279
280
            #self.sub_behavior_closing()
            self.do_behavior_for_state("Closing")
            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...
281
            self.changeState("Passive")
0ca00ebd   Etienne Pallier   refactorized and ...
282
        elif not self.config.global_mode and not self.config.lock:
6aec6155   theopuhl   Majordome algorit...
283
            self.changeState("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
284
285
            
        elif self.is_night() and self.plc_is_safe() and self.config.ack and not self.config.lock :
6aec6155   theopuhl   Majordome algorit...
286
            self.changeState("Startup")
d0b663be   Etienne Pallier   refactorized majo...
287
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
288

0ca00ebd   Etienne Pallier   refactorized and ...
289

d0b663be   Etienne Pallier   refactorized majo...
290
291
    def behavior_remote(self):
        #print("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
292
293
294
        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...
295
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
296
297
298
299
300
301
302
303
304
            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...
305
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
306

0ca00ebd   Etienne Pallier   refactorized and ...
307

d0b663be   Etienne Pallier   refactorized majo...
308
    def behavior_startup(self):
d0b663be   Etienne Pallier   refactorized majo...
309
        #print("Startup")
0ca00ebd   Etienne Pallier   refactorized and ...
310
311
        if self.config.lock or not self.plc_is_auto():
            self.NEED_TO_CLOSE=True
6aec6155   theopuhl   Majordome algorit...
312
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
313
314
315
316
317
318
319
320
321
322
            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...
323
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
324
325
        

d0b663be   Etienne Pallier   refactorized majo...
326
327
    def behavior_scheduler(self):
        #print("Scheduler")
0ca00ebd   Etienne Pallier   refactorized and ...
328
329
        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...
330
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
331
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
332

0ca00ebd   Etienne Pallier   refactorized and ...
333
334
335

    def sub_behavior_closing(self):
        #print("CURRENT OCS (MAJORDOME) STATE: "+ self.current_state)
d0b663be   Etienne Pallier   refactorized majo...
336
        #print("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
337
338
339
340
341
342
343
344
345
346
347
348
349
        #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...
350
351
352
353
354
355
356
357
358
359
        #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 ...
360
        #"Closing": sub_behavior_closing,
d0b663be   Etienne Pallier   refactorized majo...
361
362
363
    }
    def do_behavior_for_state(self, current_state:str) -> str:
        print("CURRENT OCS (MAJORDOME) STATE: "+current_state)
0ca00ebd   Etienne Pallier   refactorized and ...
364
        time.sleep(2)
d0b663be   Etienne Pallier   refactorized majo...
365
366
367
        # EXIT if PLC not connected
        #if not self.plc_is_connected(): return                  
        # EXIT if closing or restarting
0ca00ebd   Etienne Pallier   refactorized and ...
368
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
369
370
        # run behavior for this state
        #self.behavior[current_state](self)
0ca00ebd   Etienne Pallier   refactorized and ...
371
372
373
374
        if current_state == "Closing": 
            self.sub_behavior_closing()
        else:
            self.behavior[current_state](self)
d0b663be   Etienne Pallier   refactorized majo...
375
        return self.current_state        
468a79dc   Etienne Pallier   added comments
376

0997e1c3   Etienne Pallier   moved main run() ...
377
           
6aec6155   theopuhl   Majordome algorit...
378
    '''
6aec6155   theopuhl   Majordome algorit...
379
380
        Function called to send alarms is the site isn't closed (Empty for the moment)
    '''
d0b663be   Etienne Pallier   refactorized majo...
381
    def send_alarm_if_not_closed(self):
6aec6155   theopuhl   Majordome algorit...
382
383
        pass

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

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




e8e6f017   Jeremy   Reworked devices ...
404
405
406
407
408
409
410
411
    '''
        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
412
413
414
415
416
417

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

c72eb17a   Jeremy   Update celery task
421
422
    def createTask(self):
        try:
1a2dc19f   Etienne Pallier   nombreux bugfixes...
423
424
425
            # (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
426
427
428
429
430
431
432
433
434
435
436
437
438
439
        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
440
441
442
443
444
445
446
447
448
449
450
451
452
453
    '''
        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...
454
        Loop to wait for the device to be idle with the starting configurations.
65149de7   Jeremy   Update
455
456
    '''
    def waitDevices(self):
ce470283   Jeremy   Plc simulator fin...
457
458
459
460
461
        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
462
463
464
465
        return (0)

    '''
        Computes the beginning and the end of the following (or current) night
257abe9b   Jeremy   Added comments
466
        set the timers -> maybe put timers in a config file ?
65149de7   Jeremy   Update
467
468
469
470
471
472
    '''
    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...
473
474
        self.timer_night_start = self.night_start - getCurrentTime()
        self.timer_night_end = self.night_end - getCurrentTime()
65149de7   Jeremy   Update
475
        self.timer_status = 5
c72eb17a   Jeremy   Update celery task
476
        self.tasks_timer = 5
65149de7   Jeremy   Update
477
        self.timer_plc = 2
1aed430d   jeremy   Alert handled + k...
478
        self.alert_timer = 1
65149de7   Jeremy   Update
479
        self.timer_schedule = 1
05038bc8   Jeremy   Majordome logic i...
480
        self.timer_sequence = 1
65149de7   Jeremy   Update
481
482
483
484

        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
485
486
        if (getCurrentTime() > self.night_start):
            self.adaptTimers()
65149de7   Jeremy   Update
487
488

        self.timers = {
4cb0ff36   Jeremy   Update
489
490
491
492
493
            "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
494
495
            "sequence": self.timer_sequence,
            "tasks": self.tasks_timer
4cb0ff36   Jeremy   Update
496
        }
ff448d43   Jeremy   Update
497
        if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
498
499
            log.info("Majordome started with timers : " + str(self.timers))
        # Functions called during the loop
4cb0ff36   Jeremy   Update
500
501
502
503
504
505
        self.functions = {
            "status": self.handleStatusTimer,
            "environment": self.handleEnvironmentTimer,
            "night_start": self.handleNightStartTimer,
            "night_end": self.handleNightEndTimer,
            "schedule": self.handleScheduleTimer,
c72eb17a   Jeremy   Update celery task
506
507
            "sequence": self.handleSequenceTimer,
            "tasks": self.handleTasks
65149de7   Jeremy   Update
508
        }
65149de7   Jeremy   Update
509
510
        return (0)

257abe9b   Jeremy   Added comments
511
512
513
    '''
        Function called by the main loop to handle the task event (check monitoring and alert_manager)
    '''
c72eb17a   Jeremy   Update celery task
514
    def handleTasks(self):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
515
516
        if not settings.USE_CELERY: return 0

c72eb17a   Jeremy   Update celery task
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
        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
535
536
537
    def adaptTimers(self):
        pass

bca9a283   Jeremy   Reworked the sche...
538
539
540
    def logDB(self, message: str):
        Log.objects.create(agent="Majordome", message=message)

65149de7   Jeremy   Update
541
542
    '''
        Infinite loop according to the majordome behavior
65149de7   Jeremy   Update
543
544
    '''
    def loop(self):
d0b663be   Etienne Pallier   refactorized majo...
545
        while (self.closing_mode != "OCS-SHUTDOWN"):
b4e8963c   Etienne Pallier   Each agent (envmo...
546
            print("(MAJOR): start new iteration")
65149de7   Jeremy   Update
547
548
549
550
            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
551
552
            for timer_name, timer_value in self.timers.items():
                if (timer_value <= 0):
4cb0ff36   Jeremy   Update
553
                    if timer_name in self.functions:
bca9a283   Jeremy   Reworked the sche...
554
                        self.logDB("Executing timer " + str(timer_name))
4cb0ff36   Jeremy   Update
555
                        self.functions[timer_name]()
65149de7   Jeremy   Update
556
                    else:
ff448d43   Jeremy   Update
557
                        if (settings.DEBUG and DEBUG_FILE):
4cb0ff36   Jeremy   Update
558
                            log.info("Timer : " + str(timer_name) + "is not known by the Majordome")
bca9a283   Jeremy   Reworked the sche...
559
                        self.logDB("Timer " + str(timer_name) + " unknown")
ff448d43   Jeremy   Update
560
                    if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
561
                        log.info("Timer : " + str(timer_name) + " executed")
075082e1   Etienne Pallier   added start of ag...
562
563
            # EP added because loop is too quick (without CELERY)
            if not settings.USE_CELERY: time.sleep(2)
05038bc8   Jeremy   Majordome logic i...
564
565
        return (0)

257abe9b   Jeremy   Added comments
566
567
568
    '''
        Function called by the main loop to handle environment event (PLC info)
    '''
4cb0ff36   Jeremy   Update
569
570
    def handleEnvironmentTimer(self):
        self.timers["environment"] = self.timer_plc
ce470283   Jeremy   Plc simulator fin...
571
        self.handlePLC()
4cb0ff36   Jeremy   Update
572
573
        return (0)

257abe9b   Jeremy   Added comments
574
575
576
    '''
        Function called by the main loop to handle the devices status
    '''
4cb0ff36   Jeremy   Update
577
578
    def handleStatusTimer(self):
        self.timers["status"] = self.timer_status
ce470283   Jeremy   Plc simulator fin...
579
580
581
582
        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
583
        self.handleStatus()
c72eb17a   Jeremy   Update celery task
584
        return 0
4cb0ff36   Jeremy   Update
585

257abe9b   Jeremy   Added comments
586
587
588
    '''
        Function called by the main loop to check if the executing sequence is finished
    '''
4cb0ff36   Jeremy   Update
589
590
    def handleSequenceTimer(self):
        self.timers["sequence"] = self.timer_sequence
ff448d43   Jeremy   Update
591
592
593
        if (self.executing_sequence):
            self.handleSequence(self.executing_sequence[0],
                                self.executing_sequence[1], self.executing_sequence[2])
4cb0ff36   Jeremy   Update
594
595
        return (0)

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

257abe9b   Jeremy   Added comments
628
    '''
1aed430d   jeremy   Alert handled + k...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
        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
643
644
        Function called by the main loop to handle the end of a night
    '''
4cb0ff36   Jeremy   Update
645
    def handleNightEndTimer(self):
ce470283   Jeremy   Plc simulator fin...
646
        self.timers["night_end"] = getNightEnd()
4cb0ff36   Jeremy   Update
647
        if (self.isValidStatus(self.status_tel)):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
648
649
650
651
652
653
654
655
            #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
656
657
658
659
        else:
            self.notifyTelescopeStatus("night_end")
        return (0)

257abe9b   Jeremy   Added comments
660
    '''
ed1bf194   Etienne Pallier   bugfix task major...
661
        Function called by the main loop to handle the beginning of a night
257abe9b   Jeremy   Added comments
662
    '''
4cb0ff36   Jeremy   Update
663
664
    def handleNightStartTimer(self):
        self.timers["night_start"] = getNextNightStart()
c72eb17a   Jeremy   Update celery task
665
666
667
668
        if self.isOutsideOk():
            self.dom.open()
            self.vis_camera.open_shutter()
            self.nir_camera.open_shutter()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
669
670
671
672
673
674
675
676
        #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
677
678
        return (0)

ef60c3ec   Jeremy   Majordome and mon...
679
680
681
    def notifyTelescopeStatus(self, timer_name):
        return (self.notifyDeviceStatus("telescope", timer_name, self.status_tel))

05038bc8   Jeremy   Majordome logic i...
682
    def notifyDeviceStatus(self, device_name, timer_name, status):
ef60c3ec   Jeremy   Majordome and mon...
683
684
        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...
685
        # TODO MAYBE reset some variables and do a scheduling
65149de7   Jeremy   Update
686
687
688
        return (0)

    '''
257abe9b   Jeremy   Added comments
689
        Execute a schedule
65149de7   Jeremy   Update
690
691
    '''
    def executeSchedule(self, shs_list):
c72eb17a   Jeremy   Update celery task
692
        for shs in shs_list:  # shs_list is sorted by tsp
c53a13e0   Jeremy   Updating a lot of...
693
694
695
            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...
696
                if self.isExecutable() and self.executing_sequence is None:
c53a13e0   Jeremy   Updating a lot of...
697
698
699
700
701
                    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
702
                        else:
c53a13e0   Jeremy   Updating a lot of...
703
                            self.next_sequence = None
ff448d43   Jeremy   Update
704
705
                    else:
                        return 0
bca9a283   Jeremy   Reworked the sche...
706
            else:
ff448d43   Jeremy   Update
707
                if (settings.DEBUG and DEBUG_FILE):
bca9a283   Jeremy   Reworked the sche...
708
                    log.info("Sequence cannot be executed : Not observable")
ff448d43   Jeremy   Update
709
710
                self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable")
        return 0
05038bc8   Jeremy   Majordome logic i...
711

4cb0ff36   Jeremy   Update
712
    def observable(self, sequence):
ff448d43   Jeremy   Update
713
714
715
        if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
            return 0
        return 1
4cb0ff36   Jeremy   Update
716

c53a13e0   Jeremy   Updating a lot of...
717
718
719
720
721
    def executableSequence(self, status):
        if status == Sequence.PLANNED or status == Sequence.PENDING:
            return 1
        return 0

257abe9b   Jeremy   Added comments
722
723
724
    '''
        Kill the executing sequence and set its state to cancelled
    '''
678838ed   Jeremy   Weather ans insid...
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
    @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...
744
745
746
747
748
749
750
751
            #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...
752
        elif type == "INSIDE":
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
753
754
755
756
757
758
759
            #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...
760

257abe9b   Jeremy   Added comments
761
762
763
    '''
        Handle a new alarm (called by isInsideOk or isWeatherOk)
    '''
678838ed   Jeremy   Weather ans insid...
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
    @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...
792
793
794
    def isOutsideOk(self) -> bool:
        self.handlePLC()
        if self.weather_status == "OK":
678838ed   Jeremy   Weather ans insid...
795
796
            if "WEATHER" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("WEATHER"))
ce470283   Jeremy   Plc simulator fin...
797
            return True
678838ed   Jeremy   Weather ans insid...
798
        self.handleAlarm("WEATHER")
ce470283   Jeremy   Plc simulator fin...
799
800
        return False

257abe9b   Jeremy   Added comments
801
802
803
    '''
        Check the telescope inside status
    '''
ce470283   Jeremy   Plc simulator fin...
804
805
806
    def isInsideOk(self) -> bool:
        self.handlePLC()
        if self.site_status == "OK":
678838ed   Jeremy   Weather ans insid...
807
808
            if "INSIDE" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("INSIDE"))
ce470283   Jeremy   Plc simulator fin...
809
            return True
678838ed   Jeremy   Weather ans insid...
810
        self.handleAlarm("INSIDE")
ce470283   Jeremy   Plc simulator fin...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
        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
825
826
827
    '''
        check if the sequence timer is valid for execution, also check if there is a scheduling task running
    '''
ce470283   Jeremy   Plc simulator fin...
828
    def isValidTimer(self, shs) -> bool:
c53a13e0   Jeremy   Updating a lot of...
829
830
        current_countdown = self.getCountdown(shs)
        if (current_countdown <= JulianSeconds(5)):
c53a13e0   Jeremy   Updating a lot of...
831
832
833
            try:
                task = TaskId.objects.filter(task="scheduling")
                if not task:
ce470283   Jeremy   Plc simulator fin...
834
835
                    return True
                return False
c53a13e0   Jeremy   Updating a lot of...
836
            except:
ce470283   Jeremy   Plc simulator fin...
837
838
                return True
        return False
c53a13e0   Jeremy   Updating a lot of...
839

05038bc8   Jeremy   Majordome logic i...
840
    '''
257abe9b   Jeremy   Added comments
841
        Launch the observation tasks NIR and VIS associated to a sequence
05038bc8   Jeremy   Majordome logic i...
842
    '''
c53a13e0   Jeremy   Updating a lot of...
843
    def executeSequence(self, shs, sequence):
3224f14a   Jeremy   Fixed some simula...
844
845
846
847
        shs.status = Sequence.EXECUTING
        sequence.status = Sequence.EXECUTING
        shs.save()
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
848
        log.info("Executing sequence id = " + str(sequence.pk))
bca9a283   Jeremy   Reworked the sche...
849
        self.logDB("Executing sequence")
05038bc8   Jeremy   Majordome logic i...
850
        plans_results = []
05038bc8   Jeremy   Majordome logic i...
851
852
853
        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...
854
855
856
857
858
859
860
861
862
863
                    #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...
864
865
                    # JB TODO : is it still usefull ?
                    # TaskId.objects.create(task_id=res.id, task="execute_plan")
05038bc8   Jeremy   Majordome logic i...
866
                    plans_results.append(res)
ff448d43   Jeremy   Update
867
868
            else:
                self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
c53a13e0   Jeremy   Updating a lot of...
869
870
871
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
ff448d43   Jeremy   Update
872
873
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
874
875
876
        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...
877
878
879
880
881
882
883
884
                    #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...
885
886
887
                    plans_results.append(res)
            else:
                self.notifyDeviceStatus("Camera visible", "Sequence execution", self.status_vis)
c53a13e0   Jeremy   Updating a lot of...
888
889
890
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
05038bc8   Jeremy   Majordome logic i...
891
892
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
893
        self.executing_sequence = [shs, sequence, plans_results]
05038bc8   Jeremy   Majordome logic i...
894
895
896
897
898
        return (0)

    '''
        Set the next sequence
    '''
c53a13e0   Jeremy   Updating a lot of...
899
    def setNextSequence(self, shs, sequence):
ff448d43   Jeremy   Update
900
        sequence.status = Sequence.PENDING
c53a13e0   Jeremy   Updating a lot of...
901
902
        shs.status = Sequence.PENDING
        self.next_sequence = [shs, sequence]
ff448d43   Jeremy   Update
903
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
904
        shs.save()
05038bc8   Jeremy   Majordome logic i...
905
906
907
908
909
910
        return (0)

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

    '''
        Function called to do an action with the devices status
    '''
05038bc8   Jeremy   Majordome logic i...
941
    def handleStatus(self):
05038bc8   Jeremy   Majordome logic i...
942
943
944
        telescope = Telescope.objects.first()
        camera_nir = Detector.objects.get(name="Cagire")
        camera_vis = Detector.objects.get(name="Visible camera")
ce470283   Jeremy   Plc simulator fin...
945
946
947
        dome = Dome.objects.get(name="Dome")

        dome.status = self.status_dom
05038bc8   Jeremy   Majordome logic i...
948
949
950
        telescope.status = self.status_tel
        camera_nir.status = self.status_nir
        camera_vis.status = self.status_vis
ce470283   Jeremy   Plc simulator fin...
951
952
953
954
955

        dome.save()
        telescope.save()
        camera_nir.save()
        camera_vis.save()
bca9a283   Jeremy   Reworked the sche...
956
957
        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
958
959
960
        return (0)

    '''
3224f14a   Jeremy   Fixed some simula...
961
        Put the majordome in pause
4cb0ff36   Jeremy   Update
962
    '''
4cb0ff36   Jeremy   Update
963
    def systemPause(self, duration, cause: str):
bca9a283   Jeremy   Reworked the sche...
964
        self.logDB("System in pause for " + str(duration))
4cb0ff36   Jeremy   Update
965
        time.sleep(duration)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
966
967
968
969
970
971
972
973
        #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
974
975
976
977
978
        self.setTime()
        print("system has been paused. Cause : " + cause)
        return (0)

    '''
65149de7   Jeremy   Update
979
980
        Function called to do an action with the site status and the wheather status
    '''
ce470283   Jeremy   Plc simulator fin...
981
982
983
984
985
986
987
988
989
990
991
    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...
992
        return 0
5b5566ab   haribo   added celery
993

4cb0ff36   Jeremy   Update
994
    '''
05038bc8   Jeremy   Majordome logic i...
995
        Gets the time before the expected start of the execution.
4cb0ff36   Jeremy   Update
996
    '''
05038bc8   Jeremy   Majordome logic i...
997
998
    def getCountdown(self, shs):
        # TODO start sequence as soon as possible (a lot of verifications must be done there)
ff448d43   Jeremy   Update
999
        current_time = secondsToPreciseJulianDate(getPreciseCurrentTime())
05038bc8   Jeremy   Majordome logic i...
1000
        countdown = shs.tsp - current_time
9774228b   haribo   Date: 22/06/2016
1001
        return countdown
7a79e25b   haribo   Date: 19/05/2016
1002

4cb0ff36   Jeremy   Update
1003
1004
1005
1006
    '''
        Change observation conditions
    '''
    def changeObsConditions(self):
5b5566ab   haribo   added celery
1007
        print("change_obs_conditions")
6aec6155   theopuhl   Majordome algorit...
1008
        pass