Blame view

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

d243a3ef   Etienne Pallier   Bugfix majordome_...
3
4
5
import time
import datetime

5b5566ab   haribo   added celery
6
from celery.task import Task
d243a3ef   Etienne Pallier   Bugfix majordome_...
7
8
9
10
#from django.core.exceptions import ObjectDoesNotExist
#from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.conf import settings as djangosettings
ce470283   Jeremy   Plc simulator fin...
11

d243a3ef   Etienne Pallier   Bugfix majordome_...
12
13
import utils.Logger as L
'''
9774228b   haribo   Date: 22/06/2016
14
import observation_manager
abfb02e2   Jeremy   Device Model is n...
15
import observation_manager.tasks
ce470283   Jeremy   Plc simulator fin...
16
17
import scheduler
import scheduler.tasks as sched_task
c72eb17a   Jeremy   Update celery task
18
19
import monitoring.tasks
import alert_manager.tasks
d243a3ef   Etienne Pallier   Bugfix majordome_...
20
21
22
'''
#from common.models import *
from common.models import Config, Log, PlcDeviceStatus
6aec6155   theopuhl   Majordome algorit...
23
24
from dashboard.views import get_sunelev
from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault
d243a3ef   Etienne Pallier   Bugfix majordome_...
25
'''
65149de7   Jeremy   Update
26
from devices.CameraNIR import NIRCameraController
ce470283   Jeremy   Plc simulator fin...
27
from devices.CameraVIS import VISCameraController
cfc9d09c   Jeremy   Added dome simula...
28
from devices.Dome import DomeController
65149de7   Jeremy   Update
29
from devices.PLC import PLCController
ce470283   Jeremy   Plc simulator fin...
30
31
from devices.Telescope import TelescopeController
from majordome.MajordomeDecorators import *
65149de7   Jeremy   Update
32
from utils.JDManipulator import *
d243a3ef   Etienne Pallier   Bugfix majordome_...
33
'''
d51386bf   Etienne Pallier   new file majordom...
34

cfc9d09c   Jeremy   Added dome simula...
35

03814884   Etienne Pallier   launch majordome ...
36
37
from threading import Thread

ff448d43   Jeremy   Update
38
DEBUG_FILE = False
65149de7   Jeremy   Update
39
log = L.setupLogger("MajordomeTaskLogger", "Majordome")
5b5566ab   haribo   added celery
40

65149de7   Jeremy   Update
41
'''
05038bc8   Jeremy   Majordome logic i...
42
    Task to handle the execution of the program
65149de7   Jeremy   Update
43

4cb0ff36   Jeremy   Update
44
    check the environment status in database
05038bc8   Jeremy   Majordome logic i...
45
46
47
    check the devices status (telescope / cameras)
    check if the last schedule made has to be planned
    launch schedule's sequences
65149de7   Jeremy   Update
48
'''
3001ec20   Etienne Pallier   majordome small fix
49
50
51
52
53


class Majordome(Task):
# (EP) do this so that Majordome can be run from a thread, and called with thread.start():
#class Majordome(Task, Thread):
d243a3ef   Etienne Pallier   Bugfix majordome_...
54
55
56

    FOR_REAL = True

65149de7   Jeremy   Update
57
58
    loop_speed = 1
    julian_div = 86400
05038bc8   Jeremy   Majordome logic i...
59
60
61
62
63
    executing_sequence = None
    next_sequence = None
    status_tel = ""
    status_nir = ""
    status_vis = ""
cfc9d09c   Jeremy   Added dome simula...
64
    status_dom = ""
ce470283   Jeremy   Plc simulator fin...
65
66
    site_status = "OK"
    weather_status = "OK"
ef60c3ec   Jeremy   Majordome and mon...
67
68
69
    timers = {}
    functions = {}
    schedule = None
c53a13e0   Jeremy   Updating a lot of...
70
    available_status = []
678838ed   Jeremy   Weather ans insid...
71
    alarm_list = []
468a79dc   Etienne Pallier   added comments
72
73

    # New variables from TP:
d0b663be   Etienne Pallier   refactorized majo...
74
    
6aec6155   theopuhl   Majordome algorit...
75
    config = None
468a79dc   Etienne Pallier   added comments
76
    plc_status = None
f3534c59   Etienne Pallier   Simulators web pa...
77
    current_state = "NONE"
d0b663be   Etienne Pallier   refactorized majo...
78
79
80
81
    
    # OCS-RESTART, OCS-SHUTDOWN, or NONE (default)
    closing_mode = "NONE"
    
0ca00ebd   Etienne Pallier   refactorized and ...
82
83
84
85
    NEED_TO_CLOSE = False
    PLC_IS_SAFE = False

    
6aec6155   theopuhl   Majordome algorit...
86
    '''
0997e1c3   Etienne Pallier   moved main run() ...
87
88
89
90
91
92
93
94
95
96
        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...
97
        Change behavior with the pyros states
0997e1c3   Etienne Pallier   moved main run() ...
98
99
        Take suitable decision thanks to states in database
    '''
d243a3ef   Etienne Pallier   Bugfix majordome_...
100
101
102
103
104
105
    def run(self, FOR_REAL:bool=True):
        '''
            FOR_REAL: set to False if you don't want Majordome to send commands to devices
        '''

        self.FOR_REAL = FOR_REAL
0997e1c3   Etienne Pallier   moved main run() ...
106
107
108
109
110
111
112
        #self.createTask()
        #self.updateSoftware()
        #self.setContext()
        #self.setTime()                     /// OLD Majordome
        #self.setTasks()
        #self.loop()

d243a3ef   Etienne Pallier   Bugfix majordome_...
113
        print("FOR REAL ?", self.FOR_REAL)
d51386bf   Etienne Pallier   new file majordom...
114
115
        print("DB3 used is:", djangosettings.DATABASES['default']['NAME'])

0ca00ebd   Etienne Pallier   refactorized and ...
116
        while True:
d0b663be   Etienne Pallier   refactorized majo...
117
118
            
            # SETUP
1179175f   Etienne Pallier   Majordome agent c...
119
            try :
d0b663be   Etienne Pallier   refactorized majo...
120
                self.config = get_object_or_404(Config, id=1)
f3534c59   Etienne Pallier   Simulators web pa...
121
122
123
                # 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 ...
124
125
                #self.config = Config.objects.get(pk=1)
                #self.config = Config.objects.get()[0]
03814884   Etienne Pallier   launch majordome ...
126
                #print("maj config id is", self.config.id)
03814884   Etienne Pallier   launch majordome ...
127
128
            #except Config.ObjectDoesNotExist:
            except Exception as e:
f3534c59   Etienne Pallier   Simulators web pa...
129
                print("Config read (or write) exception", str(e))
d0b663be   Etienne Pallier   refactorized majo...
130
131
                return -1
            
0ca00ebd   Etienne Pallier   refactorized and ...
132
            #self.config.ntc = False
d0b663be   Etienne Pallier   refactorized majo...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
            
            # 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 ...
156
            while self.plc_is_connected() and not self.is_shuttingdown_or_restarting():          
d0b663be   Etienne Pallier   refactorized majo...
157
158
159
160
161
162
                # 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...
163
164
                self.reload_config()
                if self.config.majordome_state == "STOP": break
f3534c59   Etienne Pallier   Simulators web pa...
165
166
167
168
169
                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 ...
170
171
172
                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...
173
                if self.current_state not in ['STARTING', 'PASSIVE_NO_PLC']:
0ca00ebd   Etienne Pallier   refactorized and ...
174
175
                    if self.plc_is_not_auto(): self.changeState("PASSIVE")
                '''        
03814884   Etienne Pallier   launch majordome ...
176
                self.current_state = self.do_behavior_for_current_state()
1179175f   Etienne Pallier   Majordome agent c...
177
                    
d0b663be   Etienne Pallier   refactorized majo...
178
            # Shutdown options change by the main program
1179175f   Etienne Pallier   Majordome agent c...
179
            if self.config.majordome_state == "STOP" or self.closing_mode == "OCS-SHUTDOWN":
f3534c59   Etienne Pallier   Simulators web pa...
180
181
182
183
                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...
184
                #self.shutdown()
d0b663be   Etienne Pallier   refactorized majo...
185
                #self.closeBehaviour(self)
0ca00ebd   Etienne Pallier   refactorized and ...
186
187
                #self.sub_behavior_closing()
                break
d0b663be   Etienne Pallier   refactorized majo...
188
            
0ca00ebd   Etienne Pallier   refactorized and ...
189
            if self.closing_mode == "OCS-RESTART":
d0b663be   Etienne Pallier   refactorized majo...
190
191
                self.config.majordome_restarted = True
                self.config.save()
f3534c59   Etienne Pallier   Simulators web pa...
192
193
                self.closing_mode = "NONE"

d0b663be   Etienne Pallier   refactorized majo...
194
                #TODO: self.kill_all_agents()
0ca00ebd   Etienne Pallier   refactorized and ...
195
                #self.send_alarm_if_not_closed()
d0b663be   Etienne Pallier   refactorized majo...
196
                #self.run()
0ca00ebd   Etienne Pallier   refactorized and ...
197
198

            '''    
d0b663be   Etienne Pallier   refactorized majo...
199
200
201
202
203
204
            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 ...
205
206
207
208
            '''
        
        self.shutdown()
 
0997e1c3   Etienne Pallier   moved main run() ...
209
 
d0b663be   Etienne Pallier   refactorized majo...
210
 
0ca00ebd   Etienne Pallier   refactorized and ...
211
212
213
214
215
216
217
218
219
    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...
220
221
        return self.closing_mode != "NONE"
    
0997e1c3   Etienne Pallier   moved main run() ...
222
223

    '''
6aec6155   theopuhl   Majordome algorit...
224
225
226
        Function called to change and save current state of pyros.
    '''
    def changeState(self, state):
468a79dc   Etienne Pallier   added comments
227
        # (local variable) idem self.config.pyros_state
f3534c59   Etienne Pallier   Simulators web pa...
228
        Log.objects.create(message="Go from " + self.current_state + " to " + state, agent="Majordome")
6aec6155   theopuhl   Majordome algorit...
229
        self.current_state = state
468a79dc   Etienne Pallier   added comments
230
231

        # (in DB) PASSIVE, STANDBY, REMOTE, OPERATING
6aec6155   theopuhl   Majordome algorit...
232
233
        self.config.pyros_state = state
        self.config.save()
d0b663be   Etienne Pallier   refactorized majo...
234
        
0ca00ebd   Etienne Pallier   refactorized and ...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
    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...
250
        
0ca00ebd   Etienne Pallier   refactorized and ...
251

6aec6155   theopuhl   Majordome algorit...
252
    '''
d0b663be   Etienne Pallier   refactorized majo...
253
254
        Each function with behavior describes the behavior of a state,
        they are all contained in a dictionary called in run()
6aec6155   theopuhl   Majordome algorit...
255
    '''
0ca00ebd   Etienne Pallier   refactorized and ...
256

d0b663be   Etienne Pallier   refactorized majo...
257
258
    def behavior_starting(self):
        #print("STARTING")
0ca00ebd   Etienne Pallier   refactorized and ...
259
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
        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 ...
274

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

0ca00ebd   Etienne Pallier   refactorized and ...
334

d0b663be   Etienne Pallier   refactorized majo...
335
336
    def behavior_remote(self):
        #print("Remote")
0ca00ebd   Etienne Pallier   refactorized and ...
337
338
339
        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...
340
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
341
342
343
344
345
            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
d243a3ef   Etienne Pallier   Bugfix majordome_...
346
            if self.FOR_REAL: response = TelescopeRemoteControlDefault("DOME SHUTTER CLOSE", expert_mode=True).exec_command()
0ca00ebd   Etienne Pallier   refactorized and ...
347
348
        if self.plc_is_safe() and not self.PLC_IS_SAFE:
            PLC_IS_SAFE = True
d243a3ef   Etienne Pallier   Bugfix majordome_...
349
            if self.FOR_REAL: response = TelescopeRemoteControlDefault("DOME SHUTTER OPEN", expert_mode=True).exec_command()
d0b663be   Etienne Pallier   refactorized majo...
350
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
351

0ca00ebd   Etienne Pallier   refactorized and ...
352

d0b663be   Etienne Pallier   refactorized majo...
353
    def behavior_startup(self):
d0b663be   Etienne Pallier   refactorized majo...
354
        #print("Startup")
0ca00ebd   Etienne Pallier   refactorized and ...
355
356
        if self.config.lock or not self.plc_is_auto():
            self.NEED_TO_CLOSE=True
6aec6155   theopuhl   Majordome algorit...
357
            self.changeState("Standby")
0ca00ebd   Etienne Pallier   refactorized and ...
358
359
360
361
362
363
364
365
366
367
            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...
368
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
369
370
        

d0b663be   Etienne Pallier   refactorized majo...
371
372
    def behavior_scheduler(self):
        #print("Scheduler")
0ca00ebd   Etienne Pallier   refactorized and ...
373
374
        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...
375
            self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
376
        #return self.current_state
6aec6155   theopuhl   Majordome algorit...
377

0ca00ebd   Etienne Pallier   refactorized and ...
378
379
380

    def sub_behavior_closing(self):
        #print("CURRENT OCS (MAJORDOME) STATE: "+ self.current_state)
d0b663be   Etienne Pallier   refactorized majo...
381
        #print("Closing")
0ca00ebd   Etienne Pallier   refactorized and ...
382
383
384
385
        #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()
d243a3ef   Etienne Pallier   Bugfix majordome_...
386
387
388
389
390
391
        else: 
            if self.FOR_REAL:
                # 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()
0ca00ebd   Etienne Pallier   refactorized and ...
392
393
394
395

        self.NEED_TO_CLOSE = False

        #self.changeState("Standby")
d0b663be   Etienne Pallier   refactorized majo...
396
397
398
399
400
        #return self.current_state

    behavior = {
        "STARTING": behavior_starting,
        "PASSIVE_NO_PLC": behavior_passive_no_plc,
d51386bf   Etienne Pallier   new file majordom...
401
        "PASSIVE": behavior_passive,
d0b663be   Etienne Pallier   refactorized majo...
402
403
404
405
        "Standby": behavior_standby,
        "Remote": behavior_remote,
        "Startup": behavior_startup,
        "Scheduler": behavior_scheduler,
0ca00ebd   Etienne Pallier   refactorized and ...
406
        #"Closing": sub_behavior_closing,
d0b663be   Etienne Pallier   refactorized majo...
407
    }
03814884   Etienne Pallier   launch majordome ...
408
409
    def do_behavior_for_current_state(self) -> str:
        print("CURRENT OCS (MAJORDOME) STATE: " + self.current_state)
0ca00ebd   Etienne Pallier   refactorized and ...
410
        time.sleep(2)
d0b663be   Etienne Pallier   refactorized majo...
411
412
413
        # EXIT if PLC not connected
        #if not self.plc_is_connected(): return                  
        # EXIT if closing or restarting
0ca00ebd   Etienne Pallier   refactorized and ...
414
        #if self.is_shuttingdown_or_restarting(): return
d0b663be   Etienne Pallier   refactorized majo...
415
416
        # run behavior for this state
        #self.behavior[current_state](self)
03814884   Etienne Pallier   launch majordome ...
417
        if self.current_state == "Closing": 
0ca00ebd   Etienne Pallier   refactorized and ...
418
419
            self.sub_behavior_closing()
        else:
03814884   Etienne Pallier   launch majordome ...
420
421
            self.behavior[self.current_state](self)
        return self.current_state
468a79dc   Etienne Pallier   added comments
422

0997e1c3   Etienne Pallier   moved main run() ...
423
           
6aec6155   theopuhl   Majordome algorit...
424
    '''
6aec6155   theopuhl   Majordome algorit...
425
426
        Function called to send alarms is the site isn't closed (Empty for the moment)
    '''
d0b663be   Etienne Pallier   refactorized majo...
427
    def send_alarm_if_not_closed(self):
6aec6155   theopuhl   Majordome algorit...
428
429
        pass

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

6aec6155   theopuhl   Majordome algorit...
431
432
433
434
    '''
        Function called by run to wait for PLC connection before and during the loop
        (also gathering needed info)
    '''
d0b663be   Etienne Pallier   refactorized majo...
435
    def plc_is_connected(self):
6aec6155   theopuhl   Majordome algorit...
436
437
438
        try :
            self.config = Config.objects.get(pk=1)
            self.plc_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
6aec6155   theopuhl   Majordome algorit...
439
            timeout = (datetime.datetime.now() - self.plc_status.created).total_seconds()
d0b663be   Etienne Pallier   refactorized majo...
440
            if timeout >= self.config.plc_timeout_seconds:
6aec6155   theopuhl   Majordome algorit...
441
442
                return (False)
            return (True)
d0b663be   Etienne Pallier   refactorized majo...
443
        
6aec6155   theopuhl   Majordome algorit...
444
445
446
447
        except Config.DoesNotExist or PlcDeviceStatus.DoesNotExist:
            return (False)


1179175f   Etienne Pallier   Majordome agent c...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
    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...
465
466


e8e6f017   Jeremy   Reworked devices ...
467
468
469
470
471
472
473
474
    '''
        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
475
476
477
478
479
480

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

c72eb17a   Jeremy   Update celery task
484
485
    def createTask(self):
        try:
1a2dc19f   Etienne Pallier   nombreux bugfixes...
486
487
488
            # (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
489
490
491
492
493
494
495
496
497
498
499
500
501
502
        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
503
504
505
506
507
508
509
510
511
512
513
514
515
516
    '''
        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...
517
        Loop to wait for the device to be idle with the starting configurations.
65149de7   Jeremy   Update
518
519
    '''
    def waitDevices(self):
ce470283   Jeremy   Plc simulator fin...
520
521
522
523
524
        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
525
526
527
528
        return (0)

    '''
        Computes the beginning and the end of the following (or current) night
257abe9b   Jeremy   Added comments
529
        set the timers -> maybe put timers in a config file ?
65149de7   Jeremy   Update
530
531
532
533
534
535
    '''
    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...
536
537
        self.timer_night_start = self.night_start - getCurrentTime()
        self.timer_night_end = self.night_end - getCurrentTime()
65149de7   Jeremy   Update
538
        self.timer_status = 5
c72eb17a   Jeremy   Update celery task
539
        self.tasks_timer = 5
65149de7   Jeremy   Update
540
        self.timer_plc = 2
1aed430d   jeremy   Alert handled + k...
541
        self.alert_timer = 1
65149de7   Jeremy   Update
542
        self.timer_schedule = 1
05038bc8   Jeremy   Majordome logic i...
543
        self.timer_sequence = 1
65149de7   Jeremy   Update
544
545
546
547

        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
548
549
        if (getCurrentTime() > self.night_start):
            self.adaptTimers()
65149de7   Jeremy   Update
550
551

        self.timers = {
4cb0ff36   Jeremy   Update
552
553
554
555
556
            "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
557
558
            "sequence": self.timer_sequence,
            "tasks": self.tasks_timer
4cb0ff36   Jeremy   Update
559
        }
ff448d43   Jeremy   Update
560
        if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
561
562
            log.info("Majordome started with timers : " + str(self.timers))
        # Functions called during the loop
4cb0ff36   Jeremy   Update
563
564
565
566
567
568
        self.functions = {
            "status": self.handleStatusTimer,
            "environment": self.handleEnvironmentTimer,
            "night_start": self.handleNightStartTimer,
            "night_end": self.handleNightEndTimer,
            "schedule": self.handleScheduleTimer,
c72eb17a   Jeremy   Update celery task
569
570
            "sequence": self.handleSequenceTimer,
            "tasks": self.handleTasks
65149de7   Jeremy   Update
571
        }
65149de7   Jeremy   Update
572
573
        return (0)

257abe9b   Jeremy   Added comments
574
575
576
    '''
        Function called by the main loop to handle the task event (check monitoring and alert_manager)
    '''
c72eb17a   Jeremy   Update celery task
577
    def handleTasks(self):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
578
579
        if not settings.USE_CELERY: return 0

c72eb17a   Jeremy   Update celery task
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
        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
598
599
600
    def adaptTimers(self):
        pass

bca9a283   Jeremy   Reworked the sche...
601
602
603
    def logDB(self, message: str):
        Log.objects.create(agent="Majordome", message=message)

65149de7   Jeremy   Update
604
605
    '''
        Infinite loop according to the majordome behavior
65149de7   Jeremy   Update
606
607
    '''
    def loop(self):
d0b663be   Etienne Pallier   refactorized majo...
608
        while (self.closing_mode != "OCS-SHUTDOWN"):
b4e8963c   Etienne Pallier   Each agent (envmo...
609
            print("(MAJOR): start new iteration")
65149de7   Jeremy   Update
610
611
612
613
            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
614
615
            for timer_name, timer_value in self.timers.items():
                if (timer_value <= 0):
4cb0ff36   Jeremy   Update
616
                    if timer_name in self.functions:
bca9a283   Jeremy   Reworked the sche...
617
                        self.logDB("Executing timer " + str(timer_name))
4cb0ff36   Jeremy   Update
618
                        self.functions[timer_name]()
65149de7   Jeremy   Update
619
                    else:
ff448d43   Jeremy   Update
620
                        if (settings.DEBUG and DEBUG_FILE):
4cb0ff36   Jeremy   Update
621
                            log.info("Timer : " + str(timer_name) + "is not known by the Majordome")
bca9a283   Jeremy   Reworked the sche...
622
                        self.logDB("Timer " + str(timer_name) + " unknown")
ff448d43   Jeremy   Update
623
                    if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
624
                        log.info("Timer : " + str(timer_name) + " executed")
075082e1   Etienne Pallier   added start of ag...
625
626
            # EP added because loop is too quick (without CELERY)
            if not settings.USE_CELERY: time.sleep(2)
05038bc8   Jeremy   Majordome logic i...
627
628
        return (0)

257abe9b   Jeremy   Added comments
629
630
631
    '''
        Function called by the main loop to handle environment event (PLC info)
    '''
4cb0ff36   Jeremy   Update
632
633
    def handleEnvironmentTimer(self):
        self.timers["environment"] = self.timer_plc
ce470283   Jeremy   Plc simulator fin...
634
        self.handlePLC()
4cb0ff36   Jeremy   Update
635
636
        return (0)

257abe9b   Jeremy   Added comments
637
638
639
    '''
        Function called by the main loop to handle the devices status
    '''
4cb0ff36   Jeremy   Update
640
641
    def handleStatusTimer(self):
        self.timers["status"] = self.timer_status
ce470283   Jeremy   Plc simulator fin...
642
643
644
645
        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
646
        self.handleStatus()
c72eb17a   Jeremy   Update celery task
647
        return 0
4cb0ff36   Jeremy   Update
648

257abe9b   Jeremy   Added comments
649
650
651
    '''
        Function called by the main loop to check if the executing sequence is finished
    '''
4cb0ff36   Jeremy   Update
652
653
    def handleSequenceTimer(self):
        self.timers["sequence"] = self.timer_sequence
ff448d43   Jeremy   Update
654
655
656
        if (self.executing_sequence):
            self.handleSequence(self.executing_sequence[0],
                                self.executing_sequence[1], self.executing_sequence[2])
4cb0ff36   Jeremy   Update
657
658
        return (0)

257abe9b   Jeremy   Added comments
659
660
661
    '''
        Function called by the main loop to check if there is a new schedule and to execute its sequences
    '''
4cb0ff36   Jeremy   Update
662
    def handleScheduleTimer(self):
ef60c3ec   Jeremy   Majordome and mon...
663
        self.timers["schedule"] = self.timer_schedule
4cb0ff36   Jeremy   Update
664
        if (self.isValidStatus(self.status_tel)):
ff448d43   Jeremy   Update
665
            if (self.schedule is None):
ef60c3ec   Jeremy   Majordome and mon...
666
667
668
                try:
                    self.schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
669
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
670
671
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
672
            else:
ef60c3ec   Jeremy   Majordome and mon...
673
674
675
                try:
                    schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
676
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
677
678
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
679
680
681
                if (schedule.created != self.schedule.created):
                    self.next_sequence = None
                    self.schedule = schedule
1aed430d   jeremy   Alert handled + k...
682
                    self.firstSequenceIsAlert()
4cb0ff36   Jeremy   Update
683
            if (self.schedule):
c53a13e0   Jeremy   Updating a lot of...
684
685
                shs_list = self.schedule.shs.filter(Q(status=Sequence.PLANNED) |
                                                    Q(status=Sequence.PENDING)).order_by('tsp')
4cb0ff36   Jeremy   Update
686
687
688
689
690
                self.executeSchedule(shs_list)
        else:
            self.notifyTelescopeStatus("scheduler")
        return (0)

257abe9b   Jeremy   Added comments
691
    '''
1aed430d   jeremy   Alert handled + k...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
        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
706
707
        Function called by the main loop to handle the end of a night
    '''
4cb0ff36   Jeremy   Update
708
    def handleNightEndTimer(self):
ce470283   Jeremy   Plc simulator fin...
709
        self.timers["night_end"] = getNightEnd()
4cb0ff36   Jeremy   Update
710
        if (self.isValidStatus(self.status_tel)):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
711
712
713
714
715
716
717
718
            #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
719
720
721
722
        else:
            self.notifyTelescopeStatus("night_end")
        return (0)

257abe9b   Jeremy   Added comments
723
    '''
ed1bf194   Etienne Pallier   bugfix task major...
724
        Function called by the main loop to handle the beginning of a night
257abe9b   Jeremy   Added comments
725
    '''
4cb0ff36   Jeremy   Update
726
727
    def handleNightStartTimer(self):
        self.timers["night_start"] = getNextNightStart()
c72eb17a   Jeremy   Update celery task
728
729
730
731
        if self.isOutsideOk():
            self.dom.open()
            self.vis_camera.open_shutter()
            self.nir_camera.open_shutter()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
732
733
734
735
736
737
738
739
        #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
740
741
        return (0)

ef60c3ec   Jeremy   Majordome and mon...
742
743
744
    def notifyTelescopeStatus(self, timer_name):
        return (self.notifyDeviceStatus("telescope", timer_name, self.status_tel))

05038bc8   Jeremy   Majordome logic i...
745
    def notifyDeviceStatus(self, device_name, timer_name, status):
ef60c3ec   Jeremy   Majordome and mon...
746
747
        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...
748
        # TODO MAYBE reset some variables and do a scheduling
65149de7   Jeremy   Update
749
750
751
        return (0)

    '''
257abe9b   Jeremy   Added comments
752
        Execute a schedule
65149de7   Jeremy   Update
753
754
    '''
    def executeSchedule(self, shs_list):
c72eb17a   Jeremy   Update celery task
755
        for shs in shs_list:  # shs_list is sorted by tsp
c53a13e0   Jeremy   Updating a lot of...
756
757
758
            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...
759
                if self.isExecutable() and self.executing_sequence is None:
c53a13e0   Jeremy   Updating a lot of...
760
761
762
763
764
                    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
765
                        else:
c53a13e0   Jeremy   Updating a lot of...
766
                            self.next_sequence = None
ff448d43   Jeremy   Update
767
768
                    else:
                        return 0
bca9a283   Jeremy   Reworked the sche...
769
            else:
ff448d43   Jeremy   Update
770
                if (settings.DEBUG and DEBUG_FILE):
bca9a283   Jeremy   Reworked the sche...
771
                    log.info("Sequence cannot be executed : Not observable")
ff448d43   Jeremy   Update
772
773
                self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable")
        return 0
05038bc8   Jeremy   Majordome logic i...
774

4cb0ff36   Jeremy   Update
775
    def observable(self, sequence):
ff448d43   Jeremy   Update
776
777
778
        if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
            return 0
        return 1
4cb0ff36   Jeremy   Update
779

c53a13e0   Jeremy   Updating a lot of...
780
781
782
783
784
    def executableSequence(self, status):
        if status == Sequence.PLANNED or status == Sequence.PENDING:
            return 1
        return 0

257abe9b   Jeremy   Added comments
785
786
787
    '''
        Kill the executing sequence and set its state to cancelled
    '''
678838ed   Jeremy   Weather ans insid...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
    @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...
807
808
809
810
811
812
813
814
            #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...
815
        elif type == "INSIDE":
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
816
817
818
819
820
821
822
            #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...
823

257abe9b   Jeremy   Added comments
824
825
826
    '''
        Handle a new alarm (called by isInsideOk or isWeatherOk)
    '''
678838ed   Jeremy   Weather ans insid...
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
    @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...
855
856
857
    def isOutsideOk(self) -> bool:
        self.handlePLC()
        if self.weather_status == "OK":
678838ed   Jeremy   Weather ans insid...
858
859
            if "WEATHER" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("WEATHER"))
ce470283   Jeremy   Plc simulator fin...
860
            return True
678838ed   Jeremy   Weather ans insid...
861
        self.handleAlarm("WEATHER")
ce470283   Jeremy   Plc simulator fin...
862
863
        return False

257abe9b   Jeremy   Added comments
864
865
866
    '''
        Check the telescope inside status
    '''
ce470283   Jeremy   Plc simulator fin...
867
868
869
    def isInsideOk(self) -> bool:
        self.handlePLC()
        if self.site_status == "OK":
678838ed   Jeremy   Weather ans insid...
870
871
            if "INSIDE" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("INSIDE"))
ce470283   Jeremy   Plc simulator fin...
872
            return True
678838ed   Jeremy   Weather ans insid...
873
        self.handleAlarm("INSIDE")
ce470283   Jeremy   Plc simulator fin...
874
875
876
877
878
879
880
881
882
883
884
885
886
887
        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
888
889
890
    '''
        check if the sequence timer is valid for execution, also check if there is a scheduling task running
    '''
ce470283   Jeremy   Plc simulator fin...
891
    def isValidTimer(self, shs) -> bool:
c53a13e0   Jeremy   Updating a lot of...
892
893
        current_countdown = self.getCountdown(shs)
        if (current_countdown <= JulianSeconds(5)):
c53a13e0   Jeremy   Updating a lot of...
894
895
896
            try:
                task = TaskId.objects.filter(task="scheduling")
                if not task:
ce470283   Jeremy   Plc simulator fin...
897
898
                    return True
                return False
c53a13e0   Jeremy   Updating a lot of...
899
            except:
ce470283   Jeremy   Plc simulator fin...
900
901
                return True
        return False
c53a13e0   Jeremy   Updating a lot of...
902

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

    '''
        Set the next sequence
    '''
c53a13e0   Jeremy   Updating a lot of...
962
    def setNextSequence(self, shs, sequence):
ff448d43   Jeremy   Update
963
        sequence.status = Sequence.PENDING
c53a13e0   Jeremy   Updating a lot of...
964
965
        shs.status = Sequence.PENDING
        self.next_sequence = [shs, sequence]
ff448d43   Jeremy   Update
966
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
967
        shs.save()
05038bc8   Jeremy   Majordome logic i...
968
969
970
971
972
973
        return (0)

    '''
        Check if the current sequence is finished
    '''
    def handleSequence(self, shs, sequence, executing_plans):
c53a13e0   Jeremy   Updating a lot of...
974
        count = 0
c53a13e0   Jeremy   Updating a lot of...
975
        for res in executing_plans:
05038bc8   Jeremy   Majordome logic i...
976
            try:
c53a13e0   Jeremy   Updating a lot of...
977
978
                if res.successful() or res.failed():
                    count += 1
05038bc8   Jeremy   Majordome logic i...
979
            except Exception as e:
678838ed   Jeremy   Weather ans insid...
980
981
                if DEBUG_FILE and settings.DEBUG:
                    log.info(str(e))
05038bc8   Jeremy   Majordome logic i...
982
983
984
985
986
                shs.status = Sequence.CANCELLED
                sequence.status = Sequence.CANCELLED
                shs.save()
                sequence.save()
                for rev in executing_plans:
c53a13e0   Jeremy   Updating a lot of...
987
988
989
                    if (not rev.failed() and not rev.successful()):
                        rev.revoke(terminate=True)
                self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
990
                return (-1)
c53a13e0   Jeremy   Updating a lot of...
991
        if count >= len(executing_plans):
05038bc8   Jeremy   Majordome logic i...
992
993
994
995
996
            sequence.status = Sequence.EXECUTED
            shs.status = Sequence.EXECUTED
            sequence.save()
            shs.save()
            message = "Finished sequence " + str(sequence.pk) + " execution"
05038bc8   Jeremy   Majordome logic i...
997
            Log.objects.create(agent="Majordome", message=message)
c53a13e0   Jeremy   Updating a lot of...
998
            self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
999
        return (0)
65149de7   Jeremy   Update
1000
1001
1002
1003

    '''
        Function called to do an action with the devices status
    '''
05038bc8   Jeremy   Majordome logic i...
1004
    def handleStatus(self):
05038bc8   Jeremy   Majordome logic i...
1005
1006
1007
        telescope = Telescope.objects.first()
        camera_nir = Detector.objects.get(name="Cagire")
        camera_vis = Detector.objects.get(name="Visible camera")
ce470283   Jeremy   Plc simulator fin...
1008
1009
1010
        dome = Dome.objects.get(name="Dome")

        dome.status = self.status_dom
05038bc8   Jeremy   Majordome logic i...
1011
1012
1013
        telescope.status = self.status_tel
        camera_nir.status = self.status_nir
        camera_vis.status = self.status_vis
ce470283   Jeremy   Plc simulator fin...
1014
1015
1016
1017
1018

        dome.save()
        telescope.save()
        camera_nir.save()
        camera_vis.save()
bca9a283   Jeremy   Reworked the sche...
1019
1020
        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
1021
1022
1023
        return (0)

    '''
3224f14a   Jeremy   Fixed some simula...
1024
        Put the majordome in pause
4cb0ff36   Jeremy   Update
1025
    '''
4cb0ff36   Jeremy   Update
1026
    def systemPause(self, duration, cause: str):
bca9a283   Jeremy   Reworked the sche...
1027
        self.logDB("System in pause for " + str(duration))
4cb0ff36   Jeremy   Update
1028
        time.sleep(duration)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
1029
1030
1031
1032
1033
1034
1035
1036
        #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
1037
1038
1039
1040
1041
        self.setTime()
        print("system has been paused. Cause : " + cause)
        return (0)

    '''
65149de7   Jeremy   Update
1042
1043
        Function called to do an action with the site status and the wheather status
    '''
ce470283   Jeremy   Plc simulator fin...
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
    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...
1055
        return 0
5b5566ab   haribo   added celery
1056

4cb0ff36   Jeremy   Update
1057
    '''
05038bc8   Jeremy   Majordome logic i...
1058
        Gets the time before the expected start of the execution.
4cb0ff36   Jeremy   Update
1059
    '''
05038bc8   Jeremy   Majordome logic i...
1060
1061
    def getCountdown(self, shs):
        # TODO start sequence as soon as possible (a lot of verifications must be done there)
ff448d43   Jeremy   Update
1062
        current_time = secondsToPreciseJulianDate(getPreciseCurrentTime())
05038bc8   Jeremy   Majordome logic i...
1063
        countdown = shs.tsp - current_time
9774228b   haribo   Date: 22/06/2016
1064
        return countdown
7a79e25b   haribo   Date: 19/05/2016
1065

4cb0ff36   Jeremy   Update
1066
1067
1068
1069
    '''
        Change observation conditions
    '''
    def changeObsConditions(self):
5b5566ab   haribo   added celery
1070
        print("change_obs_conditions")
1179175f   Etienne Pallier   Majordome agent c...
1071
1072
1073
        pass

"""