Blame view

src/majordome/tasks.py 39.7 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
d51386bf   Etienne Pallier   new file majordom...
26
27
from django.conf import settings as djangosettings

cfc9d09c   Jeremy   Added dome simula...
28

03814884   Etienne Pallier   launch majordome ...
29
30
from threading import Thread

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

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

4cb0ff36   Jeremy   Update
37
    check the environment status in database
05038bc8   Jeremy   Majordome logic i...
38
39
40
    check the devices status (telescope / cameras)
    check if the last schedule made has to be planned
    launch schedule's sequences
65149de7   Jeremy   Update
41
'''
3001ec20   Etienne Pallier   majordome small fix
42
43
44
45
46


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() ...
47
    
65149de7   Jeremy   Update
48
49
    loop_speed = 1
    julian_div = 86400
05038bc8   Jeremy   Majordome logic i...
50
51
52
53
54
    executing_sequence = None
    next_sequence = None
    status_tel = ""
    status_nir = ""
    status_vis = ""
cfc9d09c   Jeremy   Added dome simula...
55
    status_dom = ""
ce470283   Jeremy   Plc simulator fin...
56
57
    site_status = "OK"
    weather_status = "OK"
ef60c3ec   Jeremy   Majordome and mon...
58
59
60
    timers = {}
    functions = {}
    schedule = None
c53a13e0   Jeremy   Updating a lot of...
61
    available_status = []
678838ed   Jeremy   Weather ans insid...
62
    alarm_list = []
468a79dc   Etienne Pallier   added comments
63
64

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

    
6aec6155   theopuhl   Majordome algorit...
77
    '''
0997e1c3   Etienne Pallier   moved main run() ...
78
79
80
81
82
83
84
85
86
87
        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...
88
        Change behavior with the pyros states
0997e1c3   Etienne Pallier   moved main run() ...
89
90
91
92
93
94
95
96
97
98
99
        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()


d51386bf   Etienne Pallier   new file majordom...
100
101
        print("DB3 used is:", djangosettings.DATABASES['default']['NAME'])

0ca00ebd   Etienne Pallier   refactorized and ...
102
        while True:
d0b663be   Etienne Pallier   refactorized majo...
103
104
            
            # SETUP
1179175f   Etienne Pallier   Majordome agent c...
105
            try :
d0b663be   Etienne Pallier   refactorized majo...
106
                self.config = get_object_or_404(Config, id=1)
f3534c59   Etienne Pallier   Simulators web pa...
107
108
109
                # By default, set mode to SCHEDULER (False = REMOTE, which should never be the default)
                self.config.global_mode = True
                self.config.save()
03814884   Etienne Pallier   launch majordome ...
110
111
                #self.config = Config.objects.get(pk=1)
                #self.config = Config.objects.get()[0]
03814884   Etienne Pallier   launch majordome ...
112
                #print("maj config id is", self.config.id)
03814884   Etienne Pallier   launch majordome ...
113
114
            #except Config.ObjectDoesNotExist:
            except Exception as e:
f3534c59   Etienne Pallier   Simulators web pa...
115
                print("Config read (or write) exception", str(e))
d0b663be   Etienne Pallier   refactorized majo...
116
117
                return -1
            
0ca00ebd   Etienne Pallier   refactorized and ...
118
            #self.config.ntc = False
d0b663be   Etienne Pallier   refactorized majo...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
            
            # 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 ...
142
            while self.plc_is_connected() and not self.is_shuttingdown_or_restarting():          
d0b663be   Etienne Pallier   refactorized majo...
143
144
145
146
147
148
                # 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...
149
150
                self.reload_config()
                if self.config.majordome_state == "STOP": break
f3534c59   Etienne Pallier   Simulators web pa...
151
152
153
154
155
                if self.config.majordome_state in ("OCS-RESTART", "OCS-SHUTDOWN"):
                    if self.config.majordome_state == "OCS-SHUTDOWN": self.NEED_TO_CLOSE=True
                    self.closing_mode = self.config.majordome_state
                    self.config.majordome_state = "RUNNING"
                    self.config.save()
0ca00ebd   Etienne Pallier   refactorized and ...
156
157
158
                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...
159
                if self.current_state not in ['STARTING', 'PASSIVE_NO_PLC']:
0ca00ebd   Etienne Pallier   refactorized and ...
160
161
                    if self.plc_is_not_auto(): self.changeState("PASSIVE")
                '''        
03814884   Etienne Pallier   launch majordome ...
162
                self.current_state = self.do_behavior_for_current_state()
1179175f   Etienne Pallier   Majordome agent c...
163
                    
d0b663be   Etienne Pallier   refactorized majo...
164
            # Shutdown options change by the main program
1179175f   Etienne Pallier   Majordome agent c...
165
            if self.config.majordome_state == "STOP" or self.closing_mode == "OCS-SHUTDOWN":
f3534c59   Etienne Pallier   Simulators web pa...
166
167
168
169
                if self.config.majordome_state == "STOP": print("STOP Majordome agent from DB")
                self.config.majordome_state = "RUNNING"
                self.changeState("KILLED")
                #self.config.save()
1179175f   Etienne Pallier   Majordome agent c...
170
                #self.shutdown()
d0b663be   Etienne Pallier   refactorized majo...
171
                #self.closeBehaviour(self)
0ca00ebd   Etienne Pallier   refactorized and ...
172
173
                #self.sub_behavior_closing()
                break
d0b663be   Etienne Pallier   refactorized majo...
174
            
0ca00ebd   Etienne Pallier   refactorized and ...
175
            if self.closing_mode == "OCS-RESTART":
d0b663be   Etienne Pallier   refactorized majo...
176
177
                self.config.majordome_restarted = True
                self.config.save()
f3534c59   Etienne Pallier   Simulators web pa...
178
179
                self.closing_mode = "NONE"

d0b663be   Etienne Pallier   refactorized majo...
180
                #TODO: self.kill_all_agents()
0ca00ebd   Etienne Pallier   refactorized and ...
181
                #self.send_alarm_if_not_closed()
d0b663be   Etienne Pallier   refactorized majo...
182
                #self.run()
0ca00ebd   Etienne Pallier   refactorized and ...
183
184

            '''    
d0b663be   Etienne Pallier   refactorized majo...
185
186
187
188
189
190
            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 ...
191
192
193
194
            '''
        
        self.shutdown()
 
0997e1c3   Etienne Pallier   moved main run() ...
195
 
d0b663be   Etienne Pallier   refactorized majo...
196
 
0ca00ebd   Etienne Pallier   refactorized and ...
197
198
199
200
201
202
203
204
205
    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...
206
207
        return self.closing_mode != "NONE"
    
0997e1c3   Etienne Pallier   moved main run() ...
208
209

    '''
6aec6155   theopuhl   Majordome algorit...
210
211
212
        Function called to change and save current state of pyros.
    '''
    def changeState(self, state):
468a79dc   Etienne Pallier   added comments
213
        # (local variable) idem self.config.pyros_state
f3534c59   Etienne Pallier   Simulators web pa...
214
        Log.objects.create(message="Go from " + self.current_state + " to " + state, agent="Majordome")
6aec6155   theopuhl   Majordome algorit...
215
        self.current_state = state
468a79dc   Etienne Pallier   added comments
216
217

        # (in DB) PASSIVE, STANDBY, REMOTE, OPERATING
6aec6155   theopuhl   Majordome algorit...
218
219
        self.config.pyros_state = state
        self.config.save()
d0b663be   Etienne Pallier   refactorized majo...
220
        
0ca00ebd   Etienne Pallier   refactorized and ...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
    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...
236
        
0ca00ebd   Etienne Pallier   refactorized and ...
237

6aec6155   theopuhl   Majordome algorit...
238
    '''
d0b663be   Etienne Pallier   refactorized majo...
239
240
        Each function with behavior describes the behavior of a state,
        they are all contained in a dictionary called in run()
6aec6155   theopuhl   Majordome algorit...
241
    '''
0ca00ebd   Etienne Pallier   refactorized and ...
242

d0b663be   Etienne Pallier   refactorized majo...
243
244
    def behavior_starting(self):
        #print("STARTING")
0ca00ebd   Etienne Pallier   refactorized and ...
245
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
        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 ...
260

d0b663be   Etienne Pallier   refactorized majo...
261
262
    def behavior_passive_no_plc(self):
        #print("PASSIVE_NO_PLC")
0ca00ebd   Etienne Pallier   refactorized and ...
263
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
264
265
266
267
        #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 ...
268
            time.sleep(3)
0ca00ebd   Etienne Pallier   refactorized and ...
269
270
271
272
273
            '''
            if self.is_restarting():
                self.changeState("STARTING")
                return
            '''
1179175f   Etienne Pallier   Majordome agent c...
274
275
            self.reload_config()
            if self.config.majordome_state == "STOP" or self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
276
277
        print("PLC is connected")
        # Set STATE to PASSIVE (with PLC)
d51386bf   Etienne Pallier   new file majordom...
278
        self.changeState("PASSIVE")
d0b663be   Etienne Pallier   refactorized majo...
279
280
        #return self.current_state
        
0ca00ebd   Etienne Pallier   refactorized and ...
281
        
d0b663be   Etienne Pallier   refactorized majo...
282
283
    def behavior_passive(self):
        #print("Passive")
0ca00ebd   Etienne Pallier   refactorized and ...
284
285
286
287
288
289
290
291
292
        #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
f3534c59   Etienne Pallier   Simulators web pa...
293
            self.config.majordome_restarted = False
6aec6155   theopuhl   Majordome algorit...
294
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
295
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
296
            
0ca00ebd   Etienne Pallier   refactorized and ...
297
            
d0b663be   Etienne Pallier   refactorized majo...
298
299
    def behavior_standby(self):
        #print("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
300
301
302
303
304
        #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...
305
            self.changeState("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
306
            #self.sub_behavior_closing()
03814884   Etienne Pallier   launch majordome ...
307
            self.do_behavior_for_current_state()
0ca00ebd   Etienne Pallier   refactorized and ...
308
309
310
311
            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():
d51386bf   Etienne Pallier   new file majordom...
312
            self.changeState("PASSIVE")
0ca00ebd   Etienne Pallier   refactorized and ...
313
        elif not self.config.global_mode and not self.config.lock:
6aec6155   theopuhl   Majordome algorit...
314
            self.changeState("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
315
316
            
        elif self.is_night() and self.plc_is_safe() and self.config.ack and not self.config.lock :
6aec6155   theopuhl   Majordome algorit...
317
            self.changeState("Startup")
d0b663be   Etienne Pallier   refactorized majo...
318
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
319

0ca00ebd   Etienne Pallier   refactorized and ...
320

d0b663be   Etienne Pallier   refactorized majo...
321
322
    def behavior_remote(self):
        #print("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
323
324
325
        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...
326
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
327
328
329
330
331
332
333
334
335
            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...
336
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
337

0ca00ebd   Etienne Pallier   refactorized and ...
338

d0b663be   Etienne Pallier   refactorized majo...
339
    def behavior_startup(self):
d0b663be   Etienne Pallier   refactorized majo...
340
        #print("Startup")
0ca00ebd   Etienne Pallier   refactorized and ...
341
342
        if self.config.lock or not self.plc_is_auto():
            self.NEED_TO_CLOSE=True
6aec6155   theopuhl   Majordome algorit...
343
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
344
345
346
347
348
349
350
351
352
353
            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...
354
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
355
356
        

d0b663be   Etienne Pallier   refactorized majo...
357
358
    def behavior_scheduler(self):
        #print("Scheduler")
0ca00ebd   Etienne Pallier   refactorized and ...
359
360
        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...
361
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
362
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
363

0ca00ebd   Etienne Pallier   refactorized and ...
364
365
366

    def sub_behavior_closing(self):
        #print("CURRENT OCS (MAJORDOME) STATE: "+ self.current_state)
d0b663be   Etienne Pallier   refactorized majo...
367
        #print("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
368
369
370
371
372
373
374
375
376
377
378
379
380
        #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...
381
382
383
384
385
        #return self.current_state

    behavior = {
        "STARTING": behavior_starting,
        "PASSIVE_NO_PLC": behavior_passive_no_plc,
d51386bf   Etienne Pallier   new file majordom...
386
        "PASSIVE": behavior_passive,
d0b663be   Etienne Pallier   refactorized majo...
387
388
389
390
        "Standby": behavior_standby,
        "Remote": behavior_remote,
        "Startup": behavior_startup,
        "Scheduler": behavior_scheduler,
0ca00ebd   Etienne Pallier   refactorized and ...
391
        #"Closing": sub_behavior_closing,
d0b663be   Etienne Pallier   refactorized majo...
392
    }
03814884   Etienne Pallier   launch majordome ...
393
394
    def do_behavior_for_current_state(self) -> str:
        print("CURRENT OCS (MAJORDOME) STATE: " + self.current_state)
0ca00ebd   Etienne Pallier   refactorized and ...
395
        time.sleep(2)
d0b663be   Etienne Pallier   refactorized majo...
396
397
398
        # EXIT if PLC not connected
        #if not self.plc_is_connected(): return                  
        # EXIT if closing or restarting
0ca00ebd   Etienne Pallier   refactorized and ...
399
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
400
401
        # run behavior for this state
        #self.behavior[current_state](self)
03814884   Etienne Pallier   launch majordome ...
402
        if self.current_state == "Closing": 
0ca00ebd   Etienne Pallier   refactorized and ...
403
404
            self.sub_behavior_closing()
        else:
03814884   Etienne Pallier   launch majordome ...
405
406
            self.behavior[self.current_state](self)
        return self.current_state
468a79dc   Etienne Pallier   added comments
407

0997e1c3   Etienne Pallier   moved main run() ...
408
           
6aec6155   theopuhl   Majordome algorit...
409
    '''
6aec6155   theopuhl   Majordome algorit...
410
411
        Function called to send alarms is the site isn't closed (Empty for the moment)
    '''
d0b663be   Etienne Pallier   refactorized majo...
412
    def send_alarm_if_not_closed(self):
6aec6155   theopuhl   Majordome algorit...
413
414
        pass

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

6aec6155   theopuhl   Majordome algorit...
416
417
418
419
    '''
        Function called by run to wait for PLC connection before and during the loop
        (also gathering needed info)
    '''
d0b663be   Etienne Pallier   refactorized majo...
420
    def plc_is_connected(self):
6aec6155   theopuhl   Majordome algorit...
421
422
423
        try :
            self.config = Config.objects.get(pk=1)
            self.plc_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
6aec6155   theopuhl   Majordome algorit...
424
            timeout = (datetime.datetime.now() - self.plc_status.created).total_seconds()
d0b663be   Etienne Pallier   refactorized majo...
425
            if timeout >= self.config.plc_timeout_seconds:
6aec6155   theopuhl   Majordome algorit...
426
427
                return (False)
            return (True)
d0b663be   Etienne Pallier   refactorized majo...
428
        
6aec6155   theopuhl   Majordome algorit...
429
430
431
432
        except Config.DoesNotExist or PlcDeviceStatus.DoesNotExist:
            return (False)


1179175f   Etienne Pallier   Majordome agent c...
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    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...
450
451


e8e6f017   Jeremy   Reworked devices ...
452
453
454
455
456
457
458
459
    '''
        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
460
461
462
463
464
465

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

c72eb17a   Jeremy   Update celery task
469
470
    def createTask(self):
        try:
1a2dc19f   Etienne Pallier   nombreux bugfixes...
471
472
473
            # (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
474
475
476
477
478
479
480
481
482
483
484
485
486
487
        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
488
489
490
491
492
493
494
495
496
497
498
499
500
501
    '''
        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...
502
        Loop to wait for the device to be idle with the starting configurations.
65149de7   Jeremy   Update
503
504
    '''
    def waitDevices(self):
ce470283   Jeremy   Plc simulator fin...
505
506
507
508
509
        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
510
511
512
513
        return (0)

    '''
        Computes the beginning and the end of the following (or current) night
257abe9b   Jeremy   Added comments
514
        set the timers -> maybe put timers in a config file ?
65149de7   Jeremy   Update
515
516
517
518
519
520
    '''
    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...
521
522
        self.timer_night_start = self.night_start - getCurrentTime()
        self.timer_night_end = self.night_end - getCurrentTime()
65149de7   Jeremy   Update
523
        self.timer_status = 5
c72eb17a   Jeremy   Update celery task
524
        self.tasks_timer = 5
65149de7   Jeremy   Update
525
        self.timer_plc = 2
1aed430d   jeremy   Alert handled + k...
526
        self.alert_timer = 1
65149de7   Jeremy   Update
527
        self.timer_schedule = 1
05038bc8   Jeremy   Majordome logic i...
528
        self.timer_sequence = 1
65149de7   Jeremy   Update
529
530
531
532

        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
533
534
        if (getCurrentTime() > self.night_start):
            self.adaptTimers()
65149de7   Jeremy   Update
535
536

        self.timers = {
4cb0ff36   Jeremy   Update
537
538
539
540
541
            "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
542
543
            "sequence": self.timer_sequence,
            "tasks": self.tasks_timer
4cb0ff36   Jeremy   Update
544
        }
ff448d43   Jeremy   Update
545
        if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
546
547
            log.info("Majordome started with timers : " + str(self.timers))
        # Functions called during the loop
4cb0ff36   Jeremy   Update
548
549
550
551
552
553
        self.functions = {
            "status": self.handleStatusTimer,
            "environment": self.handleEnvironmentTimer,
            "night_start": self.handleNightStartTimer,
            "night_end": self.handleNightEndTimer,
            "schedule": self.handleScheduleTimer,
c72eb17a   Jeremy   Update celery task
554
555
            "sequence": self.handleSequenceTimer,
            "tasks": self.handleTasks
65149de7   Jeremy   Update
556
        }
65149de7   Jeremy   Update
557
558
        return (0)

257abe9b   Jeremy   Added comments
559
560
561
    '''
        Function called by the main loop to handle the task event (check monitoring and alert_manager)
    '''
c72eb17a   Jeremy   Update celery task
562
    def handleTasks(self):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
563
564
        if not settings.USE_CELERY: return 0

c72eb17a   Jeremy   Update celery task
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
        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
583
584
585
    def adaptTimers(self):
        pass

bca9a283   Jeremy   Reworked the sche...
586
587
588
    def logDB(self, message: str):
        Log.objects.create(agent="Majordome", message=message)

65149de7   Jeremy   Update
589
590
    '''
        Infinite loop according to the majordome behavior
65149de7   Jeremy   Update
591
592
    '''
    def loop(self):
d0b663be   Etienne Pallier   refactorized majo...
593
        while (self.closing_mode != "OCS-SHUTDOWN"):
b4e8963c   Etienne Pallier   Each agent (envmo...
594
            print("(MAJOR): start new iteration")
65149de7   Jeremy   Update
595
596
597
598
            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
599
600
            for timer_name, timer_value in self.timers.items():
                if (timer_value <= 0):
4cb0ff36   Jeremy   Update
601
                    if timer_name in self.functions:
bca9a283   Jeremy   Reworked the sche...
602
                        self.logDB("Executing timer " + str(timer_name))
4cb0ff36   Jeremy   Update
603
                        self.functions[timer_name]()
65149de7   Jeremy   Update
604
                    else:
ff448d43   Jeremy   Update
605
                        if (settings.DEBUG and DEBUG_FILE):
4cb0ff36   Jeremy   Update
606
                            log.info("Timer : " + str(timer_name) + "is not known by the Majordome")
bca9a283   Jeremy   Reworked the sche...
607
                        self.logDB("Timer " + str(timer_name) + " unknown")
ff448d43   Jeremy   Update
608
                    if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
609
                        log.info("Timer : " + str(timer_name) + " executed")
075082e1   Etienne Pallier   added start of ag...
610
611
            # EP added because loop is too quick (without CELERY)
            if not settings.USE_CELERY: time.sleep(2)
05038bc8   Jeremy   Majordome logic i...
612
613
        return (0)

257abe9b   Jeremy   Added comments
614
615
616
    '''
        Function called by the main loop to handle environment event (PLC info)
    '''
4cb0ff36   Jeremy   Update
617
618
    def handleEnvironmentTimer(self):
        self.timers["environment"] = self.timer_plc
ce470283   Jeremy   Plc simulator fin...
619
        self.handlePLC()
4cb0ff36   Jeremy   Update
620
621
        return (0)

257abe9b   Jeremy   Added comments
622
623
624
    '''
        Function called by the main loop to handle the devices status
    '''
4cb0ff36   Jeremy   Update
625
626
    def handleStatusTimer(self):
        self.timers["status"] = self.timer_status
ce470283   Jeremy   Plc simulator fin...
627
628
629
630
        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
631
        self.handleStatus()
c72eb17a   Jeremy   Update celery task
632
        return 0
4cb0ff36   Jeremy   Update
633

257abe9b   Jeremy   Added comments
634
635
636
    '''
        Function called by the main loop to check if the executing sequence is finished
    '''
4cb0ff36   Jeremy   Update
637
638
    def handleSequenceTimer(self):
        self.timers["sequence"] = self.timer_sequence
ff448d43   Jeremy   Update
639
640
641
        if (self.executing_sequence):
            self.handleSequence(self.executing_sequence[0],
                                self.executing_sequence[1], self.executing_sequence[2])
4cb0ff36   Jeremy   Update
642
643
        return (0)

257abe9b   Jeremy   Added comments
644
645
646
    '''
        Function called by the main loop to check if there is a new schedule and to execute its sequences
    '''
4cb0ff36   Jeremy   Update
647
    def handleScheduleTimer(self):
ef60c3ec   Jeremy   Majordome and mon...
648
        self.timers["schedule"] = self.timer_schedule
4cb0ff36   Jeremy   Update
649
        if (self.isValidStatus(self.status_tel)):
ff448d43   Jeremy   Update
650
            if (self.schedule is None):
ef60c3ec   Jeremy   Majordome and mon...
651
652
653
                try:
                    self.schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
654
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
655
656
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
657
            else:
ef60c3ec   Jeremy   Majordome and mon...
658
659
660
                try:
                    schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
661
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
662
663
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
664
665
666
                if (schedule.created != self.schedule.created):
                    self.next_sequence = None
                    self.schedule = schedule
1aed430d   jeremy   Alert handled + k...
667
                    self.firstSequenceIsAlert()
4cb0ff36   Jeremy   Update
668
            if (self.schedule):
c53a13e0   Jeremy   Updating a lot of...
669
670
                shs_list = self.schedule.shs.filter(Q(status=Sequence.PLANNED) |
                                                    Q(status=Sequence.PENDING)).order_by('tsp')
4cb0ff36   Jeremy   Update
671
672
673
674
675
                self.executeSchedule(shs_list)
        else:
            self.notifyTelescopeStatus("scheduler")
        return (0)

257abe9b   Jeremy   Added comments
676
    '''
1aed430d   jeremy   Alert handled + k...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
        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
691
692
        Function called by the main loop to handle the end of a night
    '''
4cb0ff36   Jeremy   Update
693
    def handleNightEndTimer(self):
ce470283   Jeremy   Plc simulator fin...
694
        self.timers["night_end"] = getNightEnd()
4cb0ff36   Jeremy   Update
695
        if (self.isValidStatus(self.status_tel)):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
696
697
698
699
700
701
702
703
            #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
704
705
706
707
        else:
            self.notifyTelescopeStatus("night_end")
        return (0)

257abe9b   Jeremy   Added comments
708
    '''
ed1bf194   Etienne Pallier   bugfix task major...
709
        Function called by the main loop to handle the beginning of a night
257abe9b   Jeremy   Added comments
710
    '''
4cb0ff36   Jeremy   Update
711
712
    def handleNightStartTimer(self):
        self.timers["night_start"] = getNextNightStart()
c72eb17a   Jeremy   Update celery task
713
714
715
716
        if self.isOutsideOk():
            self.dom.open()
            self.vis_camera.open_shutter()
            self.nir_camera.open_shutter()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
717
718
719
720
721
722
723
724
        #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
725
726
        return (0)

ef60c3ec   Jeremy   Majordome and mon...
727
728
729
    def notifyTelescopeStatus(self, timer_name):
        return (self.notifyDeviceStatus("telescope", timer_name, self.status_tel))

05038bc8   Jeremy   Majordome logic i...
730
    def notifyDeviceStatus(self, device_name, timer_name, status):
ef60c3ec   Jeremy   Majordome and mon...
731
732
        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...
733
        # TODO MAYBE reset some variables and do a scheduling
65149de7   Jeremy   Update
734
735
736
        return (0)

    '''
257abe9b   Jeremy   Added comments
737
        Execute a schedule
65149de7   Jeremy   Update
738
739
    '''
    def executeSchedule(self, shs_list):
c72eb17a   Jeremy   Update celery task
740
        for shs in shs_list:  # shs_list is sorted by tsp
c53a13e0   Jeremy   Updating a lot of...
741
742
743
            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...
744
                if self.isExecutable() and self.executing_sequence is None:
c53a13e0   Jeremy   Updating a lot of...
745
746
747
748
749
                    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
750
                        else:
c53a13e0   Jeremy   Updating a lot of...
751
                            self.next_sequence = None
ff448d43   Jeremy   Update
752
753
                    else:
                        return 0
bca9a283   Jeremy   Reworked the sche...
754
            else:
ff448d43   Jeremy   Update
755
                if (settings.DEBUG and DEBUG_FILE):
bca9a283   Jeremy   Reworked the sche...
756
                    log.info("Sequence cannot be executed : Not observable")
ff448d43   Jeremy   Update
757
758
                self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable")
        return 0
05038bc8   Jeremy   Majordome logic i...
759

4cb0ff36   Jeremy   Update
760
    def observable(self, sequence):
ff448d43   Jeremy   Update
761
762
763
        if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
            return 0
        return 1
4cb0ff36   Jeremy   Update
764

c53a13e0   Jeremy   Updating a lot of...
765
766
767
768
769
    def executableSequence(self, status):
        if status == Sequence.PLANNED or status == Sequence.PENDING:
            return 1
        return 0

257abe9b   Jeremy   Added comments
770
771
772
    '''
        Kill the executing sequence and set its state to cancelled
    '''
678838ed   Jeremy   Weather ans insid...
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
    @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...
792
793
794
795
796
797
798
799
            #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...
800
        elif type == "INSIDE":
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
801
802
803
804
805
806
807
            #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...
808

257abe9b   Jeremy   Added comments
809
810
811
    '''
        Handle a new alarm (called by isInsideOk or isWeatherOk)
    '''
678838ed   Jeremy   Weather ans insid...
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
    @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...
840
841
842
    def isOutsideOk(self) -> bool:
        self.handlePLC()
        if self.weather_status == "OK":
678838ed   Jeremy   Weather ans insid...
843
844
            if "WEATHER" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("WEATHER"))
ce470283   Jeremy   Plc simulator fin...
845
            return True
678838ed   Jeremy   Weather ans insid...
846
        self.handleAlarm("WEATHER")
ce470283   Jeremy   Plc simulator fin...
847
848
        return False

257abe9b   Jeremy   Added comments
849
850
851
    '''
        Check the telescope inside status
    '''
ce470283   Jeremy   Plc simulator fin...
852
853
854
    def isInsideOk(self) -> bool:
        self.handlePLC()
        if self.site_status == "OK":
678838ed   Jeremy   Weather ans insid...
855
856
            if "INSIDE" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("INSIDE"))
ce470283   Jeremy   Plc simulator fin...
857
            return True
678838ed   Jeremy   Weather ans insid...
858
        self.handleAlarm("INSIDE")
ce470283   Jeremy   Plc simulator fin...
859
860
861
862
863
864
865
866
867
868
869
870
871
872
        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
873
874
875
    '''
        check if the sequence timer is valid for execution, also check if there is a scheduling task running
    '''
ce470283   Jeremy   Plc simulator fin...
876
    def isValidTimer(self, shs) -> bool:
c53a13e0   Jeremy   Updating a lot of...
877
878
        current_countdown = self.getCountdown(shs)
        if (current_countdown <= JulianSeconds(5)):
c53a13e0   Jeremy   Updating a lot of...
879
880
881
            try:
                task = TaskId.objects.filter(task="scheduling")
                if not task:
ce470283   Jeremy   Plc simulator fin...
882
883
                    return True
                return False
c53a13e0   Jeremy   Updating a lot of...
884
            except:
ce470283   Jeremy   Plc simulator fin...
885
886
                return True
        return False
c53a13e0   Jeremy   Updating a lot of...
887

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

    '''
        Set the next sequence
    '''
c53a13e0   Jeremy   Updating a lot of...
947
    def setNextSequence(self, shs, sequence):
ff448d43   Jeremy   Update
948
        sequence.status = Sequence.PENDING
c53a13e0   Jeremy   Updating a lot of...
949
950
        shs.status = Sequence.PENDING
        self.next_sequence = [shs, sequence]
ff448d43   Jeremy   Update
951
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
952
        shs.save()
05038bc8   Jeremy   Majordome logic i...
953
954
955
956
957
958
        return (0)

    '''
        Check if the current sequence is finished
    '''
    def handleSequence(self, shs, sequence, executing_plans):
c53a13e0   Jeremy   Updating a lot of...
959
        count = 0
c53a13e0   Jeremy   Updating a lot of...
960
        for res in executing_plans:
05038bc8   Jeremy   Majordome logic i...
961
            try:
c53a13e0   Jeremy   Updating a lot of...
962
963
                if res.successful() or res.failed():
                    count += 1
05038bc8   Jeremy   Majordome logic i...
964
            except Exception as e:
678838ed   Jeremy   Weather ans insid...
965
966
                if DEBUG_FILE and settings.DEBUG:
                    log.info(str(e))
05038bc8   Jeremy   Majordome logic i...
967
968
969
970
971
                shs.status = Sequence.CANCELLED
                sequence.status = Sequence.CANCELLED
                shs.save()
                sequence.save()
                for rev in executing_plans:
c53a13e0   Jeremy   Updating a lot of...
972
973
974
                    if (not rev.failed() and not rev.successful()):
                        rev.revoke(terminate=True)
                self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
975
                return (-1)
c53a13e0   Jeremy   Updating a lot of...
976
        if count >= len(executing_plans):
05038bc8   Jeremy   Majordome logic i...
977
978
979
980
981
            sequence.status = Sequence.EXECUTED
            shs.status = Sequence.EXECUTED
            sequence.save()
            shs.save()
            message = "Finished sequence " + str(sequence.pk) + " execution"
05038bc8   Jeremy   Majordome logic i...
982
            Log.objects.create(agent="Majordome", message=message)
c53a13e0   Jeremy   Updating a lot of...
983
            self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
984
        return (0)
65149de7   Jeremy   Update
985
986
987
988

    '''
        Function called to do an action with the devices status
    '''
05038bc8   Jeremy   Majordome logic i...
989
    def handleStatus(self):
05038bc8   Jeremy   Majordome logic i...
990
991
992
        telescope = Telescope.objects.first()
        camera_nir = Detector.objects.get(name="Cagire")
        camera_vis = Detector.objects.get(name="Visible camera")
ce470283   Jeremy   Plc simulator fin...
993
994
995
        dome = Dome.objects.get(name="Dome")

        dome.status = self.status_dom
05038bc8   Jeremy   Majordome logic i...
996
997
998
        telescope.status = self.status_tel
        camera_nir.status = self.status_nir
        camera_vis.status = self.status_vis
ce470283   Jeremy   Plc simulator fin...
999
1000
1001
1002
1003

        dome.save()
        telescope.save()
        camera_nir.save()
        camera_vis.save()
bca9a283   Jeremy   Reworked the sche...
1004
1005
        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
1006
1007
1008
        return (0)

    '''
3224f14a   Jeremy   Fixed some simula...
1009
        Put the majordome in pause
4cb0ff36   Jeremy   Update
1010
    '''
4cb0ff36   Jeremy   Update
1011
    def systemPause(self, duration, cause: str):
bca9a283   Jeremy   Reworked the sche...
1012
        self.logDB("System in pause for " + str(duration))
4cb0ff36   Jeremy   Update
1013
        time.sleep(duration)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
1014
1015
1016
1017
1018
1019
1020
1021
        #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
1022
1023
1024
1025
1026
        self.setTime()
        print("system has been paused. Cause : " + cause)
        return (0)

    '''
65149de7   Jeremy   Update
1027
1028
        Function called to do an action with the site status and the wheather status
    '''
ce470283   Jeremy   Plc simulator fin...
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
    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...
1040
        return 0
5b5566ab   haribo   added celery
1041

4cb0ff36   Jeremy   Update
1042
    '''
05038bc8   Jeremy   Majordome logic i...
1043
        Gets the time before the expected start of the execution.
4cb0ff36   Jeremy   Update
1044
    '''
05038bc8   Jeremy   Majordome logic i...
1045
1046
    def getCountdown(self, shs):
        # TODO start sequence as soon as possible (a lot of verifications must be done there)
ff448d43   Jeremy   Update
1047
        current_time = secondsToPreciseJulianDate(getPreciseCurrentTime())
05038bc8   Jeremy   Majordome logic i...
1048
        countdown = shs.tsp - current_time
9774228b   haribo   Date: 22/06/2016
1049
        return countdown
7a79e25b   haribo   Date: 19/05/2016
1050

4cb0ff36   Jeremy   Update
1051
1052
1053
1054
    '''
        Change observation conditions
    '''
    def changeObsConditions(self):
5b5566ab   haribo   added celery
1055
        print("change_obs_conditions")
1179175f   Etienne Pallier   Majordome agent c...
1056
1057
1058
        pass

"""