Blame view

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

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
'''
3001ec20   Etienne Pallier   majordome small fix
40
41
42
43
44


class Majordome(Task):
# (EP) do this so that Majordome can be run from a thread, and called with thread.start():
#class Majordome(Task, Thread):
0997e1c3   Etienne Pallier   moved main run() ...
45
    
65149de7   Jeremy   Update
46
47
    loop_speed = 1
    julian_div = 86400
05038bc8   Jeremy   Majordome logic i...
48
49
50
51
52
    executing_sequence = None
    next_sequence = None
    status_tel = ""
    status_nir = ""
    status_vis = ""
cfc9d09c   Jeremy   Added dome simula...
53
    status_dom = ""
ce470283   Jeremy   Plc simulator fin...
54
55
    site_status = "OK"
    weather_status = "OK"
ef60c3ec   Jeremy   Majordome and mon...
56
57
58
    timers = {}
    functions = {}
    schedule = None
c53a13e0   Jeremy   Updating a lot of...
59
    available_status = []
678838ed   Jeremy   Weather ans insid...
60
    alarm_list = []
468a79dc   Etienne Pallier   added comments
61
62

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

    
6aec6155   theopuhl   Majordome algorit...
75
    '''
0997e1c3   Etienne Pallier   moved main run() ...
76
77
78
79
80
81
82
83
84
85
        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...
86
        Change behavior with the pyros states
0997e1c3   Etienne Pallier   moved main run() ...
87
88
89
90
91
92
93
94
95
96
97
        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 ...
98
        while True:
d0b663be   Etienne Pallier   refactorized majo...
99
100
            
            # SETUP
1179175f   Etienne Pallier   Majordome agent c...
101
            try :
d0b663be   Etienne Pallier   refactorized majo...
102
                self.config = get_object_or_404(Config, id=1)
03814884   Etienne Pallier   launch majordome ...
103
104
105
106
107
108
109
110
                #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...
111
112
                return -1
            
0ca00ebd   Etienne Pallier   refactorized and ...
113
            #self.config.ntc = False
d0b663be   Etienne Pallier   refactorized majo...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
            
            # 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 ...
137
            while self.plc_is_connected() and not self.is_shuttingdown_or_restarting():          
d0b663be   Etienne Pallier   refactorized majo...
138
139
140
141
142
143
                # 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:
1179175f   Etienne Pallier   Majordome agent c...
144
145
                self.reload_config()
                if self.config.majordome_state == "STOP": break
0ca00ebd   Etienne Pallier   refactorized and ...
146
147
148
                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...
149
                if self.current_state not in ['STARTING', 'PASSIVE_NO_PLC']:
0ca00ebd   Etienne Pallier   refactorized and ...
150
151
                    if self.plc_is_not_auto(): self.changeState("PASSIVE")
                '''        
03814884   Etienne Pallier   launch majordome ...
152
                self.current_state = self.do_behavior_for_current_state()
1179175f   Etienne Pallier   Majordome agent c...
153
                    
d0b663be   Etienne Pallier   refactorized majo...
154
            # Shutdown options change by the main program
1179175f   Etienne Pallier   Majordome agent c...
155
156
157
158
159
            if self.config.majordome_state == "STOP" or self.closing_mode == "OCS-SHUTDOWN":
                if self.config.majordome_state == "STOP":
                    self.config.majordome_state = "RUNNING"
                    self.config.save()
                #self.shutdown()
d0b663be   Etienne Pallier   refactorized majo...
160
                #self.closeBehaviour(self)
0ca00ebd   Etienne Pallier   refactorized and ...
161
162
                #self.sub_behavior_closing()
                break
d0b663be   Etienne Pallier   refactorized majo...
163
            
0ca00ebd   Etienne Pallier   refactorized and ...
164
            if self.closing_mode == "OCS-RESTART":
d0b663be   Etienne Pallier   refactorized majo...
165
166
167
                self.config.majordome_restarted = True
                self.config.save()
                #TODO: self.kill_all_agents()
0ca00ebd   Etienne Pallier   refactorized and ...
168
                #self.send_alarm_if_not_closed()
d0b663be   Etienne Pallier   refactorized majo...
169
                #self.run()
0ca00ebd   Etienne Pallier   refactorized and ...
170
171

            '''    
d0b663be   Etienne Pallier   refactorized majo...
172
173
174
175
176
177
            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 ...
178
179
180
181
            '''
        
        self.shutdown()
 
0997e1c3   Etienne Pallier   moved main run() ...
182
 
d0b663be   Etienne Pallier   refactorized majo...
183
 
0ca00ebd   Etienne Pallier   refactorized and ...
184
185
186
187
188
189
190
191
192
    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...
193
194
        return self.closing_mode != "NONE"
    
0997e1c3   Etienne Pallier   moved main run() ...
195
196

    '''
6aec6155   theopuhl   Majordome algorit...
197
198
199
        Function called to change and save current state of pyros.
    '''
    def changeState(self, state):
468a79dc   Etienne Pallier   added comments
200
        # (local variable) idem self.config.pyros_state
6aec6155   theopuhl   Majordome algorit...
201
        self.current_state = state
468a79dc   Etienne Pallier   added comments
202
203

        # (in DB) PASSIVE, STANDBY, REMOTE, OPERATING
6aec6155   theopuhl   Majordome algorit...
204
205
        self.config.pyros_state = state
        self.config.save()
d0b663be   Etienne Pallier   refactorized majo...
206
        
0ca00ebd   Etienne Pallier   refactorized and ...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    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...
222
        
0ca00ebd   Etienne Pallier   refactorized and ...
223

6aec6155   theopuhl   Majordome algorit...
224
    '''
d0b663be   Etienne Pallier   refactorized majo...
225
226
        Each function with behavior describes the behavior of a state,
        they are all contained in a dictionary called in run()
6aec6155   theopuhl   Majordome algorit...
227
    '''
0ca00ebd   Etienne Pallier   refactorized and ...
228

d0b663be   Etienne Pallier   refactorized majo...
229
230
    def behavior_starting(self):
        #print("STARTING")
0ca00ebd   Etienne Pallier   refactorized and ...
231
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
        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 ...
246

d0b663be   Etienne Pallier   refactorized majo...
247
248
    def behavior_passive_no_plc(self):
        #print("PASSIVE_NO_PLC")
0ca00ebd   Etienne Pallier   refactorized and ...
249
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
250
251
252
253
        #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 ...
254
            time.sleep(3)
0ca00ebd   Etienne Pallier   refactorized and ...
255
256
257
258
259
            '''
            if self.is_restarting():
                self.changeState("STARTING")
                return
            '''
1179175f   Etienne Pallier   Majordome agent c...
260
261
            self.reload_config()
            if self.config.majordome_state == "STOP" or self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
262
263
264
265
266
        print("PLC is connected")
        # Set STATE to PASSIVE (with PLC)
        self.changeState("Passive")
        #return self.current_state
        
0ca00ebd   Etienne Pallier   refactorized and ...
267
        
d0b663be   Etienne Pallier   refactorized majo...
268
269
    def behavior_passive(self):
        #print("Passive")
0ca00ebd   Etienne Pallier   refactorized and ...
270
271
272
273
274
275
276
277
278
        #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...
279
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
280
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
281
            
0ca00ebd   Etienne Pallier   refactorized and ...
282
            
d0b663be   Etienne Pallier   refactorized majo...
283
284
    def behavior_standby(self):
        #print("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
285
286
287
288
289
        #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...
290
            self.changeState("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
291
            #self.sub_behavior_closing()
03814884   Etienne Pallier   launch majordome ...
292
            self.do_behavior_for_current_state()
0ca00ebd   Etienne Pallier   refactorized and ...
293
294
295
296
            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...
297
            self.changeState("Passive")
0ca00ebd   Etienne Pallier   refactorized and ...
298
        elif not self.config.global_mode and not self.config.lock:
6aec6155   theopuhl   Majordome algorit...
299
            self.changeState("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
300
301
            
        elif self.is_night() and self.plc_is_safe() and self.config.ack and not self.config.lock :
6aec6155   theopuhl   Majordome algorit...
302
            self.changeState("Startup")
d0b663be   Etienne Pallier   refactorized majo...
303
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
304

0ca00ebd   Etienne Pallier   refactorized and ...
305

d0b663be   Etienne Pallier   refactorized majo...
306
307
    def behavior_remote(self):
        #print("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
308
309
310
        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...
311
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
312
313
314
315
316
317
318
319
320
            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...
321
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
322

0ca00ebd   Etienne Pallier   refactorized and ...
323

d0b663be   Etienne Pallier   refactorized majo...
324
    def behavior_startup(self):
d0b663be   Etienne Pallier   refactorized majo...
325
        #print("Startup")
0ca00ebd   Etienne Pallier   refactorized and ...
326
327
        if self.config.lock or not self.plc_is_auto():
            self.NEED_TO_CLOSE=True
6aec6155   theopuhl   Majordome algorit...
328
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
329
330
331
332
333
334
335
336
337
338
            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...
339
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
340
341
        

d0b663be   Etienne Pallier   refactorized majo...
342
343
    def behavior_scheduler(self):
        #print("Scheduler")
0ca00ebd   Etienne Pallier   refactorized and ...
344
345
        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...
346
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
347
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
348

0ca00ebd   Etienne Pallier   refactorized and ...
349
350
351

    def sub_behavior_closing(self):
        #print("CURRENT OCS (MAJORDOME) STATE: "+ self.current_state)
d0b663be   Etienne Pallier   refactorized majo...
352
        #print("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
353
354
355
356
357
358
359
360
361
362
363
364
365
        #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...
366
367
368
369
370
371
372
373
374
375
        #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 ...
376
        #"Closing": sub_behavior_closing,
d0b663be   Etienne Pallier   refactorized majo...
377
    }
03814884   Etienne Pallier   launch majordome ...
378
379
    def do_behavior_for_current_state(self) -> str:
        print("CURRENT OCS (MAJORDOME) STATE: " + self.current_state)
0ca00ebd   Etienne Pallier   refactorized and ...
380
        time.sleep(2)
d0b663be   Etienne Pallier   refactorized majo...
381
382
383
        # EXIT if PLC not connected
        #if not self.plc_is_connected(): return                  
        # EXIT if closing or restarting
0ca00ebd   Etienne Pallier   refactorized and ...
384
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
385
386
        # run behavior for this state
        #self.behavior[current_state](self)
03814884   Etienne Pallier   launch majordome ...
387
        if self.current_state == "Closing": 
0ca00ebd   Etienne Pallier   refactorized and ...
388
389
            self.sub_behavior_closing()
        else:
03814884   Etienne Pallier   launch majordome ...
390
391
            self.behavior[self.current_state](self)
        return self.current_state
468a79dc   Etienne Pallier   added comments
392

0997e1c3   Etienne Pallier   moved main run() ...
393
           
6aec6155   theopuhl   Majordome algorit...
394
    '''
6aec6155   theopuhl   Majordome algorit...
395
396
        Function called to send alarms is the site isn't closed (Empty for the moment)
    '''
d0b663be   Etienne Pallier   refactorized majo...
397
    def send_alarm_if_not_closed(self):
6aec6155   theopuhl   Majordome algorit...
398
399
        pass

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

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


1179175f   Etienne Pallier   Majordome agent c...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
    def reload_config(self):
        self.config = Config.objects.get(pk=1)
        '''
        try :
            self.config = Config.objects.get(pk=1)
        except Config.DoesNotExist:
            return (False)
        return self.config
        '''
            






""" OLD MAJORDOME CODE
6aec6155   theopuhl   Majordome algorit...
435
436


e8e6f017   Jeremy   Reworked devices ...
437
438
439
440
441
442
443
444
    '''
        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
445
446
447
448
449
450

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

c72eb17a   Jeremy   Update celery task
454
455
    def createTask(self):
        try:
1a2dc19f   Etienne Pallier   nombreux bugfixes...
456
457
458
            # (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
459
460
461
462
463
464
465
466
467
468
469
470
471
472
        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
473
474
475
476
477
478
479
480
481
482
483
484
485
486
    '''
        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...
487
        Loop to wait for the device to be idle with the starting configurations.
65149de7   Jeremy   Update
488
489
    '''
    def waitDevices(self):
ce470283   Jeremy   Plc simulator fin...
490
491
492
493
494
        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
495
496
497
498
        return (0)

    '''
        Computes the beginning and the end of the following (or current) night
257abe9b   Jeremy   Added comments
499
        set the timers -> maybe put timers in a config file ?
65149de7   Jeremy   Update
500
501
502
503
504
505
    '''
    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...
506
507
        self.timer_night_start = self.night_start - getCurrentTime()
        self.timer_night_end = self.night_end - getCurrentTime()
65149de7   Jeremy   Update
508
        self.timer_status = 5
c72eb17a   Jeremy   Update celery task
509
        self.tasks_timer = 5
65149de7   Jeremy   Update
510
        self.timer_plc = 2
1aed430d   jeremy   Alert handled + k...
511
        self.alert_timer = 1
65149de7   Jeremy   Update
512
        self.timer_schedule = 1
05038bc8   Jeremy   Majordome logic i...
513
        self.timer_sequence = 1
65149de7   Jeremy   Update
514
515
516
517

        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
518
519
        if (getCurrentTime() > self.night_start):
            self.adaptTimers()
65149de7   Jeremy   Update
520
521

        self.timers = {
4cb0ff36   Jeremy   Update
522
523
524
525
526
            "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
527
528
            "sequence": self.timer_sequence,
            "tasks": self.tasks_timer
4cb0ff36   Jeremy   Update
529
        }
ff448d43   Jeremy   Update
530
        if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
531
532
            log.info("Majordome started with timers : " + str(self.timers))
        # Functions called during the loop
4cb0ff36   Jeremy   Update
533
534
535
536
537
538
        self.functions = {
            "status": self.handleStatusTimer,
            "environment": self.handleEnvironmentTimer,
            "night_start": self.handleNightStartTimer,
            "night_end": self.handleNightEndTimer,
            "schedule": self.handleScheduleTimer,
c72eb17a   Jeremy   Update celery task
539
540
            "sequence": self.handleSequenceTimer,
            "tasks": self.handleTasks
65149de7   Jeremy   Update
541
        }
65149de7   Jeremy   Update
542
543
        return (0)

257abe9b   Jeremy   Added comments
544
545
546
    '''
        Function called by the main loop to handle the task event (check monitoring and alert_manager)
    '''
c72eb17a   Jeremy   Update celery task
547
    def handleTasks(self):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
548
549
        if not settings.USE_CELERY: return 0

c72eb17a   Jeremy   Update celery task
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
        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
568
569
570
    def adaptTimers(self):
        pass

bca9a283   Jeremy   Reworked the sche...
571
572
573
    def logDB(self, message: str):
        Log.objects.create(agent="Majordome", message=message)

65149de7   Jeremy   Update
574
575
    '''
        Infinite loop according to the majordome behavior
65149de7   Jeremy   Update
576
577
    '''
    def loop(self):
d0b663be   Etienne Pallier   refactorized majo...
578
        while (self.closing_mode != "OCS-SHUTDOWN"):
b4e8963c   Etienne Pallier   Each agent (envmo...
579
            print("(MAJOR): start new iteration")
65149de7   Jeremy   Update
580
581
582
583
            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
584
585
            for timer_name, timer_value in self.timers.items():
                if (timer_value <= 0):
4cb0ff36   Jeremy   Update
586
                    if timer_name in self.functions:
bca9a283   Jeremy   Reworked the sche...
587
                        self.logDB("Executing timer " + str(timer_name))
4cb0ff36   Jeremy   Update
588
                        self.functions[timer_name]()
65149de7   Jeremy   Update
589
                    else:
ff448d43   Jeremy   Update
590
                        if (settings.DEBUG and DEBUG_FILE):
4cb0ff36   Jeremy   Update
591
                            log.info("Timer : " + str(timer_name) + "is not known by the Majordome")
bca9a283   Jeremy   Reworked the sche...
592
                        self.logDB("Timer " + str(timer_name) + " unknown")
ff448d43   Jeremy   Update
593
                    if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
594
                        log.info("Timer : " + str(timer_name) + " executed")
075082e1   Etienne Pallier   added start of ag...
595
596
            # EP added because loop is too quick (without CELERY)
            if not settings.USE_CELERY: time.sleep(2)
05038bc8   Jeremy   Majordome logic i...
597
598
        return (0)

257abe9b   Jeremy   Added comments
599
600
601
    '''
        Function called by the main loop to handle environment event (PLC info)
    '''
4cb0ff36   Jeremy   Update
602
603
    def handleEnvironmentTimer(self):
        self.timers["environment"] = self.timer_plc
ce470283   Jeremy   Plc simulator fin...
604
        self.handlePLC()
4cb0ff36   Jeremy   Update
605
606
        return (0)

257abe9b   Jeremy   Added comments
607
608
609
    '''
        Function called by the main loop to handle the devices status
    '''
4cb0ff36   Jeremy   Update
610
611
    def handleStatusTimer(self):
        self.timers["status"] = self.timer_status
ce470283   Jeremy   Plc simulator fin...
612
613
614
615
        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
616
        self.handleStatus()
c72eb17a   Jeremy   Update celery task
617
        return 0
4cb0ff36   Jeremy   Update
618

257abe9b   Jeremy   Added comments
619
620
621
    '''
        Function called by the main loop to check if the executing sequence is finished
    '''
4cb0ff36   Jeremy   Update
622
623
    def handleSequenceTimer(self):
        self.timers["sequence"] = self.timer_sequence
ff448d43   Jeremy   Update
624
625
626
        if (self.executing_sequence):
            self.handleSequence(self.executing_sequence[0],
                                self.executing_sequence[1], self.executing_sequence[2])
4cb0ff36   Jeremy   Update
627
628
        return (0)

257abe9b   Jeremy   Added comments
629
630
631
    '''
        Function called by the main loop to check if there is a new schedule and to execute its sequences
    '''
4cb0ff36   Jeremy   Update
632
    def handleScheduleTimer(self):
ef60c3ec   Jeremy   Majordome and mon...
633
        self.timers["schedule"] = self.timer_schedule
4cb0ff36   Jeremy   Update
634
        if (self.isValidStatus(self.status_tel)):
ff448d43   Jeremy   Update
635
            if (self.schedule is None):
ef60c3ec   Jeremy   Majordome and mon...
636
637
638
                try:
                    self.schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
639
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
640
641
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
642
            else:
ef60c3ec   Jeremy   Majordome and mon...
643
644
645
                try:
                    schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
646
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
647
648
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
649
650
651
                if (schedule.created != self.schedule.created):
                    self.next_sequence = None
                    self.schedule = schedule
1aed430d   jeremy   Alert handled + k...
652
                    self.firstSequenceIsAlert()
4cb0ff36   Jeremy   Update
653
            if (self.schedule):
c53a13e0   Jeremy   Updating a lot of...
654
655
                shs_list = self.schedule.shs.filter(Q(status=Sequence.PLANNED) |
                                                    Q(status=Sequence.PENDING)).order_by('tsp')
4cb0ff36   Jeremy   Update
656
657
658
659
660
                self.executeSchedule(shs_list)
        else:
            self.notifyTelescopeStatus("scheduler")
        return (0)

257abe9b   Jeremy   Added comments
661
    '''
1aed430d   jeremy   Alert handled + k...
662
663
664
665
666
667
668
669
670
671
672
673
674
675
        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
676
677
        Function called by the main loop to handle the end of a night
    '''
4cb0ff36   Jeremy   Update
678
    def handleNightEndTimer(self):
ce470283   Jeremy   Plc simulator fin...
679
        self.timers["night_end"] = getNightEnd()
4cb0ff36   Jeremy   Update
680
        if (self.isValidStatus(self.status_tel)):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
681
682
683
684
685
686
687
688
            #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
689
690
691
692
        else:
            self.notifyTelescopeStatus("night_end")
        return (0)

257abe9b   Jeremy   Added comments
693
    '''
ed1bf194   Etienne Pallier   bugfix task major...
694
        Function called by the main loop to handle the beginning of a night
257abe9b   Jeremy   Added comments
695
    '''
4cb0ff36   Jeremy   Update
696
697
    def handleNightStartTimer(self):
        self.timers["night_start"] = getNextNightStart()
c72eb17a   Jeremy   Update celery task
698
699
700
701
        if self.isOutsideOk():
            self.dom.open()
            self.vis_camera.open_shutter()
            self.nir_camera.open_shutter()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
702
703
704
705
706
707
708
709
        #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
710
711
        return (0)

ef60c3ec   Jeremy   Majordome and mon...
712
713
714
    def notifyTelescopeStatus(self, timer_name):
        return (self.notifyDeviceStatus("telescope", timer_name, self.status_tel))

05038bc8   Jeremy   Majordome logic i...
715
    def notifyDeviceStatus(self, device_name, timer_name, status):
ef60c3ec   Jeremy   Majordome and mon...
716
717
        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...
718
        # TODO MAYBE reset some variables and do a scheduling
65149de7   Jeremy   Update
719
720
721
        return (0)

    '''
257abe9b   Jeremy   Added comments
722
        Execute a schedule
65149de7   Jeremy   Update
723
724
    '''
    def executeSchedule(self, shs_list):
c72eb17a   Jeremy   Update celery task
725
        for shs in shs_list:  # shs_list is sorted by tsp
c53a13e0   Jeremy   Updating a lot of...
726
727
728
            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...
729
                if self.isExecutable() and self.executing_sequence is None:
c53a13e0   Jeremy   Updating a lot of...
730
731
732
733
734
                    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
735
                        else:
c53a13e0   Jeremy   Updating a lot of...
736
                            self.next_sequence = None
ff448d43   Jeremy   Update
737
738
                    else:
                        return 0
bca9a283   Jeremy   Reworked the sche...
739
            else:
ff448d43   Jeremy   Update
740
                if (settings.DEBUG and DEBUG_FILE):
bca9a283   Jeremy   Reworked the sche...
741
                    log.info("Sequence cannot be executed : Not observable")
ff448d43   Jeremy   Update
742
743
                self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable")
        return 0
05038bc8   Jeremy   Majordome logic i...
744

4cb0ff36   Jeremy   Update
745
    def observable(self, sequence):
ff448d43   Jeremy   Update
746
747
748
        if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
            return 0
        return 1
4cb0ff36   Jeremy   Update
749

c53a13e0   Jeremy   Updating a lot of...
750
751
752
753
754
    def executableSequence(self, status):
        if status == Sequence.PLANNED or status == Sequence.PENDING:
            return 1
        return 0

257abe9b   Jeremy   Added comments
755
756
757
    '''
        Kill the executing sequence and set its state to cancelled
    '''
678838ed   Jeremy   Weather ans insid...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
    @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...
777
778
779
780
781
782
783
784
            #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...
785
        elif type == "INSIDE":
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
786
787
788
789
790
791
792
            #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...
793

257abe9b   Jeremy   Added comments
794
795
796
    '''
        Handle a new alarm (called by isInsideOk or isWeatherOk)
    '''
678838ed   Jeremy   Weather ans insid...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
    @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...
825
826
827
    def isOutsideOk(self) -> bool:
        self.handlePLC()
        if self.weather_status == "OK":
678838ed   Jeremy   Weather ans insid...
828
829
            if "WEATHER" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("WEATHER"))
ce470283   Jeremy   Plc simulator fin...
830
            return True
678838ed   Jeremy   Weather ans insid...
831
        self.handleAlarm("WEATHER")
ce470283   Jeremy   Plc simulator fin...
832
833
        return False

257abe9b   Jeremy   Added comments
834
835
836
    '''
        Check the telescope inside status
    '''
ce470283   Jeremy   Plc simulator fin...
837
838
839
    def isInsideOk(self) -> bool:
        self.handlePLC()
        if self.site_status == "OK":
678838ed   Jeremy   Weather ans insid...
840
841
            if "INSIDE" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("INSIDE"))
ce470283   Jeremy   Plc simulator fin...
842
            return True
678838ed   Jeremy   Weather ans insid...
843
        self.handleAlarm("INSIDE")
ce470283   Jeremy   Plc simulator fin...
844
845
846
847
848
849
850
851
852
853
854
855
856
857
        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
858
859
860
    '''
        check if the sequence timer is valid for execution, also check if there is a scheduling task running
    '''
ce470283   Jeremy   Plc simulator fin...
861
    def isValidTimer(self, shs) -> bool:
c53a13e0   Jeremy   Updating a lot of...
862
863
        current_countdown = self.getCountdown(shs)
        if (current_countdown <= JulianSeconds(5)):
c53a13e0   Jeremy   Updating a lot of...
864
865
866
            try:
                task = TaskId.objects.filter(task="scheduling")
                if not task:
ce470283   Jeremy   Plc simulator fin...
867
868
                    return True
                return False
c53a13e0   Jeremy   Updating a lot of...
869
            except:
ce470283   Jeremy   Plc simulator fin...
870
871
                return True
        return False
c53a13e0   Jeremy   Updating a lot of...
872

05038bc8   Jeremy   Majordome logic i...
873
    '''
257abe9b   Jeremy   Added comments
874
        Launch the observation tasks NIR and VIS associated to a sequence
05038bc8   Jeremy   Majordome logic i...
875
    '''
c53a13e0   Jeremy   Updating a lot of...
876
    def executeSequence(self, shs, sequence):
3224f14a   Jeremy   Fixed some simula...
877
878
879
880
        shs.status = Sequence.EXECUTING
        sequence.status = Sequence.EXECUTING
        shs.save()
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
881
        log.info("Executing sequence id = " + str(sequence.pk))
bca9a283   Jeremy   Reworked the sche...
882
        self.logDB("Executing sequence")
05038bc8   Jeremy   Majordome logic i...
883
        plans_results = []
05038bc8   Jeremy   Majordome logic i...
884
885
886
        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...
887
888
889
890
891
892
893
894
895
896
                    #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...
897
898
                    # JB TODO : is it still usefull ?
                    # TaskId.objects.create(task_id=res.id, task="execute_plan")
05038bc8   Jeremy   Majordome logic i...
899
                    plans_results.append(res)
ff448d43   Jeremy   Update
900
901
            else:
                self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
c53a13e0   Jeremy   Updating a lot of...
902
903
904
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
ff448d43   Jeremy   Update
905
906
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
907
908
909
        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...
910
911
912
913
914
915
916
917
                    #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...
918
919
920
                    plans_results.append(res)
            else:
                self.notifyDeviceStatus("Camera visible", "Sequence execution", self.status_vis)
c53a13e0   Jeremy   Updating a lot of...
921
922
923
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
05038bc8   Jeremy   Majordome logic i...
924
925
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
926
        self.executing_sequence = [shs, sequence, plans_results]
05038bc8   Jeremy   Majordome logic i...
927
928
929
930
931
        return (0)

    '''
        Set the next sequence
    '''
c53a13e0   Jeremy   Updating a lot of...
932
    def setNextSequence(self, shs, sequence):
ff448d43   Jeremy   Update
933
        sequence.status = Sequence.PENDING
c53a13e0   Jeremy   Updating a lot of...
934
935
        shs.status = Sequence.PENDING
        self.next_sequence = [shs, sequence]
ff448d43   Jeremy   Update
936
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
937
        shs.save()
05038bc8   Jeremy   Majordome logic i...
938
939
940
941
942
943
        return (0)

    '''
        Check if the current sequence is finished
    '''
    def handleSequence(self, shs, sequence, executing_plans):
c53a13e0   Jeremy   Updating a lot of...
944
        count = 0
c53a13e0   Jeremy   Updating a lot of...
945
        for res in executing_plans:
05038bc8   Jeremy   Majordome logic i...
946
            try:
c53a13e0   Jeremy   Updating a lot of...
947
948
                if res.successful() or res.failed():
                    count += 1
05038bc8   Jeremy   Majordome logic i...
949
            except Exception as e:
678838ed   Jeremy   Weather ans insid...
950
951
                if DEBUG_FILE and settings.DEBUG:
                    log.info(str(e))
05038bc8   Jeremy   Majordome logic i...
952
953
954
955
956
                shs.status = Sequence.CANCELLED
                sequence.status = Sequence.CANCELLED
                shs.save()
                sequence.save()
                for rev in executing_plans:
c53a13e0   Jeremy   Updating a lot of...
957
958
959
                    if (not rev.failed() and not rev.successful()):
                        rev.revoke(terminate=True)
                self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
960
                return (-1)
c53a13e0   Jeremy   Updating a lot of...
961
        if count >= len(executing_plans):
05038bc8   Jeremy   Majordome logic i...
962
963
964
965
966
            sequence.status = Sequence.EXECUTED
            shs.status = Sequence.EXECUTED
            sequence.save()
            shs.save()
            message = "Finished sequence " + str(sequence.pk) + " execution"
05038bc8   Jeremy   Majordome logic i...
967
            Log.objects.create(agent="Majordome", message=message)
c53a13e0   Jeremy   Updating a lot of...
968
            self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
969
        return (0)
65149de7   Jeremy   Update
970
971
972
973

    '''
        Function called to do an action with the devices status
    '''
05038bc8   Jeremy   Majordome logic i...
974
    def handleStatus(self):
05038bc8   Jeremy   Majordome logic i...
975
976
977
        telescope = Telescope.objects.first()
        camera_nir = Detector.objects.get(name="Cagire")
        camera_vis = Detector.objects.get(name="Visible camera")
ce470283   Jeremy   Plc simulator fin...
978
979
980
        dome = Dome.objects.get(name="Dome")

        dome.status = self.status_dom
05038bc8   Jeremy   Majordome logic i...
981
982
983
        telescope.status = self.status_tel
        camera_nir.status = self.status_nir
        camera_vis.status = self.status_vis
ce470283   Jeremy   Plc simulator fin...
984
985
986
987
988

        dome.save()
        telescope.save()
        camera_nir.save()
        camera_vis.save()
bca9a283   Jeremy   Reworked the sche...
989
990
        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
991
992
993
        return (0)

    '''
3224f14a   Jeremy   Fixed some simula...
994
        Put the majordome in pause
4cb0ff36   Jeremy   Update
995
    '''
4cb0ff36   Jeremy   Update
996
    def systemPause(self, duration, cause: str):
bca9a283   Jeremy   Reworked the sche...
997
        self.logDB("System in pause for " + str(duration))
4cb0ff36   Jeremy   Update
998
        time.sleep(duration)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
999
1000
1001
1002
1003
1004
1005
1006
        #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
1007
1008
1009
1010
1011
        self.setTime()
        print("system has been paused. Cause : " + cause)
        return (0)

    '''
65149de7   Jeremy   Update
1012
1013
        Function called to do an action with the site status and the wheather status
    '''
ce470283   Jeremy   Plc simulator fin...
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
    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...
1025
        return 0
5b5566ab   haribo   added celery
1026

4cb0ff36   Jeremy   Update
1027
    '''
05038bc8   Jeremy   Majordome logic i...
1028
        Gets the time before the expected start of the execution.
4cb0ff36   Jeremy   Update
1029
    '''
05038bc8   Jeremy   Majordome logic i...
1030
1031
    def getCountdown(self, shs):
        # TODO start sequence as soon as possible (a lot of verifications must be done there)
ff448d43   Jeremy   Update
1032
        current_time = secondsToPreciseJulianDate(getPreciseCurrentTime())
05038bc8   Jeremy   Majordome logic i...
1033
        countdown = shs.tsp - current_time
9774228b   haribo   Date: 22/06/2016
1034
        return countdown
7a79e25b   haribo   Date: 19/05/2016
1035

4cb0ff36   Jeremy   Update
1036
1037
1038
1039
    '''
        Change observation conditions
    '''
    def changeObsConditions(self):
5b5566ab   haribo   added celery
1040
        print("change_obs_conditions")
1179175f   Etienne Pallier   Majordome agent c...
1041
1042
1043
        pass

"""