Blame view

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

d243a3ef   Etienne Pallier   Bugfix majordome_...
6
7
8
9
#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...
10

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

cfc9d09c   Jeremy   Added dome simula...
34

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

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

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

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


5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
50
class Majordome():
3001ec20   Etienne Pallier   majordome small fix
51
52
# (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_...
53
54
55

    FOR_REAL = True

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

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

    
6aec6155   theopuhl   Majordome algorit...
85
    '''
0997e1c3   Etienne Pallier   moved main run() ...
86
87
88
89
90
91
92
93
94
        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...
95
        Change behavior with the pyros states
0997e1c3   Etienne Pallier   moved main run() ...
96
97
        Take suitable decision thanks to states in database
    '''
d243a3ef   Etienne Pallier   Bugfix majordome_...
98
99
100
101
102
103
    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() ...
104
105
106
107
108
109
110
        #self.createTask()
        #self.updateSoftware()
        #self.setContext()
        #self.setTime()                     /// OLD Majordome
        #self.setTasks()
        #self.loop()

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

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

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

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

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

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

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

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

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

0ca00ebd   Etienne Pallier   refactorized and ...
332

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

0ca00ebd   Etienne Pallier   refactorized and ...
350

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

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

0ca00ebd   Etienne Pallier   refactorized and ...
376
377
378

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

        self.NEED_TO_CLOSE = False

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

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

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

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

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


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


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

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

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

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

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

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

257abe9b   Jeremy   Added comments
572
573
574
    '''
        Function called by the main loop to handle the task event (check monitoring and alert_manager)
    '''
c72eb17a   Jeremy   Update celery task
575
    def handleTasks(self):
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
576
        return 0
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
577

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

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

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

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

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

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

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

257abe9b   Jeremy   Added comments
689
    '''
1aed430d   jeremy   Alert handled + k...
690
691
692
693
694
695
696
697
698
699
700
701
702
703
        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
704
705
        Function called by the main loop to handle the end of a night
    '''
4cb0ff36   Jeremy   Update
706
    def handleNightEndTimer(self):
ce470283   Jeremy   Plc simulator fin...
707
        self.timers["night_end"] = getNightEnd()
4cb0ff36   Jeremy   Update
708
        if (self.isValidStatus(self.status_tel)):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
709
            #observation_manager.tasks.night_calibrations.apply_async()
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
710
711
            print("MJ: call observation_manager WITHOUT CELERY")
            observation_manager.tasks.night_calibrations().run()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
712

4cb0ff36   Jeremy   Update
713
714
715
716
        else:
            self.notifyTelescopeStatus("night_end")
        return (0)

257abe9b   Jeremy   Added comments
717
    '''
ed1bf194   Etienne Pallier   bugfix task major...
718
        Function called by the main loop to handle the beginning of a night
257abe9b   Jeremy   Added comments
719
    '''
4cb0ff36   Jeremy   Update
720
721
    def handleNightStartTimer(self):
        self.timers["night_start"] = getNextNightStart()
c72eb17a   Jeremy   Update celery task
722
723
724
725
        if self.isOutsideOk():
            self.dom.open()
            self.vis_camera.open_shutter()
            self.nir_camera.open_shutter()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
726
        #scheduler.tasks.scheduling.apply_async((False, False))
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
727
728
        print("MJ: call schedule WITHOUT CELERY")
        scheduler.tasks.scheduling().run((False, False))
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
729

4cb0ff36   Jeremy   Update
730
731
        return (0)

ef60c3ec   Jeremy   Majordome and mon...
732
733
734
    def notifyTelescopeStatus(self, timer_name):
        return (self.notifyDeviceStatus("telescope", timer_name, self.status_tel))

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

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

4cb0ff36   Jeremy   Update
765
    def observable(self, sequence):
ff448d43   Jeremy   Update
766
767
768
        if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
            return 0
        return 1
4cb0ff36   Jeremy   Update
769

c53a13e0   Jeremy   Updating a lot of...
770
771
772
773
774
    def executableSequence(self, status):
        if status == Sequence.PLANNED or status == Sequence.PENDING:
            return 1
        return 0

257abe9b   Jeremy   Added comments
775
776
777
    '''
        Kill the executing sequence and set its state to cancelled
    '''
678838ed   Jeremy   Weather ans insid...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
    @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...
797
            #scheduler.tasks.scheduling.delay((False, False))
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
798
799
            print("MJ: call schedule WITHOUT CELERY")
            scheduler.tasks.scheduling().run((False, False))
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
800

678838ed   Jeremy   Weather ans insid...
801
        elif type == "INSIDE":
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
802
            #scheduler.tasks.scheduling.delay((False, False))
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
803
804
            print("MJ: call schedule WITHOUT CELERY")
            scheduler.tasks.scheduling().run((False, False))
678838ed   Jeremy   Weather ans insid...
805

257abe9b   Jeremy   Added comments
806
807
808
    '''
        Handle a new alarm (called by isInsideOk or isWeatherOk)
    '''
678838ed   Jeremy   Weather ans insid...
809
810
811
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
    @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...
837
838
839
    def isOutsideOk(self) -> bool:
        self.handlePLC()
        if self.weather_status == "OK":
678838ed   Jeremy   Weather ans insid...
840
841
            if "WEATHER" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("WEATHER"))
ce470283   Jeremy   Plc simulator fin...
842
            return True
678838ed   Jeremy   Weather ans insid...
843
        self.handleAlarm("WEATHER")
ce470283   Jeremy   Plc simulator fin...
844
845
        return False

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

05038bc8   Jeremy   Majordome logic i...
885
    '''
257abe9b   Jeremy   Added comments
886
        Launch the observation tasks NIR and VIS associated to a sequence
05038bc8   Jeremy   Majordome logic i...
887
    '''
c53a13e0   Jeremy   Updating a lot of...
888
    def executeSequence(self, shs, sequence):
3224f14a   Jeremy   Fixed some simula...
889
890
891
892
        shs.status = Sequence.EXECUTING
        sequence.status = Sequence.EXECUTING
        shs.save()
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
893
        log.info("Executing sequence id = " + str(sequence.pk))
bca9a283   Jeremy   Reworked the sche...
894
        self.logDB("Executing sequence")
05038bc8   Jeremy   Majordome logic i...
895
        plans_results = []
05038bc8   Jeremy   Majordome logic i...
896
897
898
        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...
899
                    #res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, float(self.getCountdown(shs))))
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
900
901
902
                    print("MJ: call observation_manager WITHOUT CELERY")
                    res = observation_manager.tasks.execute_plan_nir().run(
                        (plan.id, float(self.getCountdown(shs))))
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
903

c53a13e0   Jeremy   Updating a lot of...
904
905
                    # JB TODO : is it still usefull ?
                    # TaskId.objects.create(task_id=res.id, task="execute_plan")
05038bc8   Jeremy   Majordome logic i...
906
                    plans_results.append(res)
ff448d43   Jeremy   Update
907
908
            else:
                self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
c53a13e0   Jeremy   Updating a lot of...
909
910
911
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
ff448d43   Jeremy   Update
912
913
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
914
915
916
        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...
917
                    #res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, float(self.getCountdown(shs))))
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
918
919
                    print("MJ: call observation_manager WITHOUT CELERY")
                    res = observation_manager.tasks.execute_plan_vis().run((plan.id, float(self.getCountdown(shs))))
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
920

05038bc8   Jeremy   Majordome logic i...
921
922
923
                    plans_results.append(res)
            else:
                self.notifyDeviceStatus("Camera visible", "Sequence execution", self.status_vis)
c53a13e0   Jeremy   Updating a lot of...
924
925
926
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
05038bc8   Jeremy   Majordome logic i...
927
928
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
929
        self.executing_sequence = [shs, sequence, plans_results]
05038bc8   Jeremy   Majordome logic i...
930
931
932
933
934
        return (0)

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

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

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

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

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

    '''
3224f14a   Jeremy   Fixed some simula...
997
        Put the majordome in pause
4cb0ff36   Jeremy   Update
998
    '''
4cb0ff36   Jeremy   Update
999
    def systemPause(self, duration, cause: str):
bca9a283   Jeremy   Reworked the sche...
1000
        self.logDB("System in pause for " + str(duration))
4cb0ff36   Jeremy   Update
1001
        time.sleep(duration)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
1002
        #scheduler.tasks.scheduling.apply_async(first_schedule=False, alert=False)
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
1003
1004
        print("MJ: call schedule WITHOUT CELERY")
        scheduler.tasks.scheduling().run(first_schedule=False, alert=False)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
1005

4cb0ff36   Jeremy   Update
1006
1007
1008
1009
1010
        self.setTime()
        print("system has been paused. Cause : " + cause)
        return (0)

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

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

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

"""