Blame view

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

5b5566ab   haribo   added celery
3
from celery.task import Task
ce470283   Jeremy   Plc simulator fin...
4
5
6
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q

9774228b   haribo   Date: 22/06/2016
7
import observation_manager
abfb02e2   Jeremy   Device Model is n...
8
import observation_manager.tasks
ce470283   Jeremy   Plc simulator fin...
9
10
11
import scheduler
import scheduler.tasks as sched_task
import utils.Logger as L
c72eb17a   Jeremy   Update celery task
12
13
import monitoring.tasks
import alert_manager.tasks
ce470283   Jeremy   Plc simulator fin...
14
from common.models import *
65149de7   Jeremy   Update
15
from devices.CameraNIR import NIRCameraController
ce470283   Jeremy   Plc simulator fin...
16
from devices.CameraVIS import VISCameraController
cfc9d09c   Jeremy   Added dome simula...
17
from devices.Dome import DomeController
65149de7   Jeremy   Update
18
from devices.PLC import PLCController
ce470283   Jeremy   Plc simulator fin...
19
20
from devices.Telescope import TelescopeController
from majordome.MajordomeDecorators import *
65149de7   Jeremy   Update
21
from utils.JDManipulator import *
cfc9d09c   Jeremy   Added dome simula...
22

ff448d43   Jeremy   Update
23
DEBUG_FILE = False
65149de7   Jeremy   Update
24
log = L.setupLogger("MajordomeTaskLogger", "Majordome")
5b5566ab   haribo   added celery
25

65149de7   Jeremy   Update
26
'''
05038bc8   Jeremy   Majordome logic i...
27
    Task to handle the execution of the program
65149de7   Jeremy   Update
28

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

e8e6f017   Jeremy   Reworked devices ...
52
53
54
55
56
57
58
59
    '''
        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
60
61
62
63
64
65

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

c72eb17a   Jeremy   Update celery task
69
70
    def createTask(self):
        try:
1a2dc19f   Etienne Pallier   nombreux bugfixes...
71
72
73
            # (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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
        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
89
90
91
92
93
94
95
96
97
    '''
        Function called by celery task
        Behavior:
            Init telescope / cameras
            set night limits
            check the software version
            launch the majordome loop
    '''
    def run(self):
c72eb17a   Jeremy   Update celery task
98
        self.createTask()
65149de7   Jeremy   Update
99
        self.updateSoftware()
65149de7   Jeremy   Update
100
        self.setContext()
4cb0ff36   Jeremy   Update
101
        self.setTime()
c72eb17a   Jeremy   Update celery task
102
        self.setTasks()
65149de7   Jeremy   Update
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
        self.loop()

    '''
        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...
119
        Loop to wait for the device to be idle with the starting configurations.
65149de7   Jeremy   Update
120
121
    '''
    def waitDevices(self):
ce470283   Jeremy   Plc simulator fin...
122
123
124
125
126
        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
127
128
129
130
        return (0)

    '''
        Computes the beginning and the end of the following (or current) night
257abe9b   Jeremy   Added comments
131
        set the timers -> maybe put timers in a config file ?
65149de7   Jeremy   Update
132
133
134
135
136
137
    '''
    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...
138
139
        self.timer_night_start = self.night_start - getCurrentTime()
        self.timer_night_end = self.night_end - getCurrentTime()
65149de7   Jeremy   Update
140
        self.timer_status = 5
c72eb17a   Jeremy   Update celery task
141
        self.tasks_timer = 5
65149de7   Jeremy   Update
142
        self.timer_plc = 2
1aed430d   jeremy   Alert handled + k...
143
        self.alert_timer = 1
65149de7   Jeremy   Update
144
        self.timer_schedule = 1
05038bc8   Jeremy   Majordome logic i...
145
        self.timer_sequence = 1
65149de7   Jeremy   Update
146
147
148
149

        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
150
151
        if (getCurrentTime() > self.night_start):
            self.adaptTimers()
65149de7   Jeremy   Update
152
153

        self.timers = {
4cb0ff36   Jeremy   Update
154
155
156
157
158
            "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
159
160
            "sequence": self.timer_sequence,
            "tasks": self.tasks_timer
4cb0ff36   Jeremy   Update
161
        }
ff448d43   Jeremy   Update
162
        if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
163
164
            log.info("Majordome started with timers : " + str(self.timers))
        # Functions called during the loop
4cb0ff36   Jeremy   Update
165
166
167
168
169
170
        self.functions = {
            "status": self.handleStatusTimer,
            "environment": self.handleEnvironmentTimer,
            "night_start": self.handleNightStartTimer,
            "night_end": self.handleNightEndTimer,
            "schedule": self.handleScheduleTimer,
c72eb17a   Jeremy   Update celery task
171
172
            "sequence": self.handleSequenceTimer,
            "tasks": self.handleTasks
65149de7   Jeremy   Update
173
        }
65149de7   Jeremy   Update
174
175
        return (0)

257abe9b   Jeremy   Added comments
176
177
178
    '''
        Function called by the main loop to handle the task event (check monitoring and alert_manager)
    '''
c72eb17a   Jeremy   Update celery task
179
    def handleTasks(self):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
180
181
        if not settings.USE_CELERY: return 0

c72eb17a   Jeremy   Update celery task
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
        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
200
201
202
    def adaptTimers(self):
        pass

bca9a283   Jeremy   Reworked the sche...
203
204
205
    def logDB(self, message: str):
        Log.objects.create(agent="Majordome", message=message)

65149de7   Jeremy   Update
206
207
    '''
        Infinite loop according to the majordome behavior
65149de7   Jeremy   Update
208
209
    '''
    def loop(self):
c53a13e0   Jeremy   Updating a lot of...
210
        while (self.current_status != "SHUTDOWN"):
b4e8963c   Etienne Pallier   Each agent (envmo...
211
            print("(MAJOR): start new iteration")
65149de7   Jeremy   Update
212
213
214
215
            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
216
217
            for timer_name, timer_value in self.timers.items():
                if (timer_value <= 0):
4cb0ff36   Jeremy   Update
218
                    if timer_name in self.functions:
bca9a283   Jeremy   Reworked the sche...
219
                        self.logDB("Executing timer " + str(timer_name))
4cb0ff36   Jeremy   Update
220
                        self.functions[timer_name]()
65149de7   Jeremy   Update
221
                    else:
ff448d43   Jeremy   Update
222
                        if (settings.DEBUG and DEBUG_FILE):
4cb0ff36   Jeremy   Update
223
                            log.info("Timer : " + str(timer_name) + "is not known by the Majordome")
bca9a283   Jeremy   Reworked the sche...
224
                        self.logDB("Timer " + str(timer_name) + " unknown")
ff448d43   Jeremy   Update
225
                    if (settings.DEBUG and DEBUG_FILE):
e8e6f017   Jeremy   Reworked devices ...
226
                        log.info("Timer : " + str(timer_name) + " executed")
075082e1   Etienne Pallier   added start of ag...
227
228
            # EP added because loop is too quick (without CELERY)
            if not settings.USE_CELERY: time.sleep(2)
05038bc8   Jeremy   Majordome logic i...
229
230
        return (0)

257abe9b   Jeremy   Added comments
231
232
233
    '''
        Function called by the main loop to handle environment event (PLC info)
    '''
4cb0ff36   Jeremy   Update
234
235
    def handleEnvironmentTimer(self):
        self.timers["environment"] = self.timer_plc
ce470283   Jeremy   Plc simulator fin...
236
        self.handlePLC()
4cb0ff36   Jeremy   Update
237
238
        return (0)

257abe9b   Jeremy   Added comments
239
240
241
    '''
        Function called by the main loop to handle the devices status
    '''
4cb0ff36   Jeremy   Update
242
243
    def handleStatusTimer(self):
        self.timers["status"] = self.timer_status
ce470283   Jeremy   Plc simulator fin...
244
245
246
247
        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
248
        self.handleStatus()
c72eb17a   Jeremy   Update celery task
249
        return 0
4cb0ff36   Jeremy   Update
250

257abe9b   Jeremy   Added comments
251
252
253
    '''
        Function called by the main loop to check if the executing sequence is finished
    '''
4cb0ff36   Jeremy   Update
254
255
    def handleSequenceTimer(self):
        self.timers["sequence"] = self.timer_sequence
ff448d43   Jeremy   Update
256
257
258
        if (self.executing_sequence):
            self.handleSequence(self.executing_sequence[0],
                                self.executing_sequence[1], self.executing_sequence[2])
4cb0ff36   Jeremy   Update
259
260
        return (0)

257abe9b   Jeremy   Added comments
261
262
263
    '''
        Function called by the main loop to check if there is a new schedule and to execute its sequences
    '''
4cb0ff36   Jeremy   Update
264
    def handleScheduleTimer(self):
ef60c3ec   Jeremy   Majordome and mon...
265
        self.timers["schedule"] = self.timer_schedule
4cb0ff36   Jeremy   Update
266
        if (self.isValidStatus(self.status_tel)):
ff448d43   Jeremy   Update
267
            if (self.schedule is None):
ef60c3ec   Jeremy   Majordome and mon...
268
269
270
                try:
                    self.schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
271
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
272
273
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
274
            else:
ef60c3ec   Jeremy   Majordome and mon...
275
276
277
                try:
                    schedule = Schedule.objects.latest('created')
                except ObjectDoesNotExist:
ff448d43   Jeremy   Update
278
                    if (settings.DEBUG and DEBUG_FILE):
ef60c3ec   Jeremy   Majordome and mon...
279
280
                        log.info("No schedule found in database")
                    return (1)
4cb0ff36   Jeremy   Update
281
282
283
                if (schedule.created != self.schedule.created):
                    self.next_sequence = None
                    self.schedule = schedule
1aed430d   jeremy   Alert handled + k...
284
                    self.firstSequenceIsAlert()
4cb0ff36   Jeremy   Update
285
            if (self.schedule):
c53a13e0   Jeremy   Updating a lot of...
286
287
                shs_list = self.schedule.shs.filter(Q(status=Sequence.PLANNED) |
                                                    Q(status=Sequence.PENDING)).order_by('tsp')
4cb0ff36   Jeremy   Update
288
289
290
291
292
                self.executeSchedule(shs_list)
        else:
            self.notifyTelescopeStatus("scheduler")
        return (0)

257abe9b   Jeremy   Added comments
293
    '''
1aed430d   jeremy   Alert handled + k...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
        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
308
309
        Function called by the main loop to handle the end of a night
    '''
4cb0ff36   Jeremy   Update
310
    def handleNightEndTimer(self):
ce470283   Jeremy   Plc simulator fin...
311
        self.timers["night_end"] = getNightEnd()
4cb0ff36   Jeremy   Update
312
        if (self.isValidStatus(self.status_tel)):
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
313
314
315
316
317
318
319
320
            #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
321
322
323
324
        else:
            self.notifyTelescopeStatus("night_end")
        return (0)

257abe9b   Jeremy   Added comments
325
    '''
ed1bf194   Etienne Pallier   bugfix task major...
326
        Function called by the main loop to handle the beginning of a night
257abe9b   Jeremy   Added comments
327
    '''
4cb0ff36   Jeremy   Update
328
329
    def handleNightStartTimer(self):
        self.timers["night_start"] = getNextNightStart()
c72eb17a   Jeremy   Update celery task
330
331
332
333
        if self.isOutsideOk():
            self.dom.open()
            self.vis_camera.open_shutter()
            self.nir_camera.open_shutter()
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
334
335
336
337
338
339
340
341
        #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
342
343
        return (0)

ef60c3ec   Jeremy   Majordome and mon...
344
345
346
    def notifyTelescopeStatus(self, timer_name):
        return (self.notifyDeviceStatus("telescope", timer_name, self.status_tel))

05038bc8   Jeremy   Majordome logic i...
347
    def notifyDeviceStatus(self, device_name, timer_name, status):
ef60c3ec   Jeremy   Majordome and mon...
348
349
        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...
350
        # TODO MAYBE reset some variables and do a scheduling
65149de7   Jeremy   Update
351
352
353
        return (0)

    '''
257abe9b   Jeremy   Added comments
354
        Execute a schedule
65149de7   Jeremy   Update
355
356
    '''
    def executeSchedule(self, shs_list):
c72eb17a   Jeremy   Update celery task
357
        for shs in shs_list:  # shs_list is sorted by tsp
c53a13e0   Jeremy   Updating a lot of...
358
359
360
            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...
361
                if self.isExecutable() and self.executing_sequence is None:
c53a13e0   Jeremy   Updating a lot of...
362
363
364
365
366
                    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
367
                        else:
c53a13e0   Jeremy   Updating a lot of...
368
                            self.next_sequence = None
ff448d43   Jeremy   Update
369
370
                    else:
                        return 0
bca9a283   Jeremy   Reworked the sche...
371
            else:
ff448d43   Jeremy   Update
372
                if (settings.DEBUG and DEBUG_FILE):
bca9a283   Jeremy   Reworked the sche...
373
                    log.info("Sequence cannot be executed : Not observable")
ff448d43   Jeremy   Update
374
375
                self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable")
        return 0
05038bc8   Jeremy   Majordome logic i...
376

4cb0ff36   Jeremy   Update
377
    def observable(self, sequence):
ff448d43   Jeremy   Update
378
379
380
        if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0):
            return 0
        return 1
4cb0ff36   Jeremy   Update
381

c53a13e0   Jeremy   Updating a lot of...
382
383
384
385
386
    def executableSequence(self, status):
        if status == Sequence.PLANNED or status == Sequence.PENDING:
            return 1
        return 0

257abe9b   Jeremy   Added comments
387
388
389
    '''
        Kill the executing sequence and set its state to cancelled
    '''
678838ed   Jeremy   Weather ans insid...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
    @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...
409
410
411
412
413
414
415
416
            #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...
417
        elif type == "INSIDE":
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
418
419
420
421
422
423
424
            #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...
425

257abe9b   Jeremy   Added comments
426
427
428
    '''
        Handle a new alarm (called by isInsideOk or isWeatherOk)
    '''
678838ed   Jeremy   Weather ans insid...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
    @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...
457
458
459
    def isOutsideOk(self) -> bool:
        self.handlePLC()
        if self.weather_status == "OK":
678838ed   Jeremy   Weather ans insid...
460
461
            if "WEATHER" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("WEATHER"))
ce470283   Jeremy   Plc simulator fin...
462
            return True
678838ed   Jeremy   Weather ans insid...
463
        self.handleAlarm("WEATHER")
ce470283   Jeremy   Plc simulator fin...
464
465
        return False

257abe9b   Jeremy   Added comments
466
467
468
    '''
        Check the telescope inside status
    '''
ce470283   Jeremy   Plc simulator fin...
469
470
471
    def isInsideOk(self) -> bool:
        self.handlePLC()
        if self.site_status == "OK":
678838ed   Jeremy   Weather ans insid...
472
473
            if "INSIDE" in self.alarm_list:
                self.handleAlarm("ENDED", self.alarm_list.index("INSIDE"))
ce470283   Jeremy   Plc simulator fin...
474
            return True
678838ed   Jeremy   Weather ans insid...
475
        self.handleAlarm("INSIDE")
ce470283   Jeremy   Plc simulator fin...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
        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
490
491
492
    '''
        check if the sequence timer is valid for execution, also check if there is a scheduling task running
    '''
ce470283   Jeremy   Plc simulator fin...
493
    def isValidTimer(self, shs) -> bool:
c53a13e0   Jeremy   Updating a lot of...
494
495
        current_countdown = self.getCountdown(shs)
        if (current_countdown <= JulianSeconds(5)):
c53a13e0   Jeremy   Updating a lot of...
496
497
498
            try:
                task = TaskId.objects.filter(task="scheduling")
                if not task:
ce470283   Jeremy   Plc simulator fin...
499
500
                    return True
                return False
c53a13e0   Jeremy   Updating a lot of...
501
            except:
ce470283   Jeremy   Plc simulator fin...
502
503
                return True
        return False
c53a13e0   Jeremy   Updating a lot of...
504

05038bc8   Jeremy   Majordome logic i...
505
    '''
257abe9b   Jeremy   Added comments
506
        Launch the observation tasks NIR and VIS associated to a sequence
05038bc8   Jeremy   Majordome logic i...
507
    '''
c53a13e0   Jeremy   Updating a lot of...
508
    def executeSequence(self, shs, sequence):
3224f14a   Jeremy   Fixed some simula...
509
510
511
512
        shs.status = Sequence.EXECUTING
        sequence.status = Sequence.EXECUTING
        shs.save()
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
513
        log.info("Executing sequence id = " + str(sequence.pk))
bca9a283   Jeremy   Reworked the sche...
514
        self.logDB("Executing sequence")
05038bc8   Jeremy   Majordome logic i...
515
        plans_results = []
05038bc8   Jeremy   Majordome logic i...
516
517
518
        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...
519
520
521
522
523
524
525
526
527
528
                    #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...
529
530
                    # JB TODO : is it still usefull ?
                    # TaskId.objects.create(task_id=res.id, task="execute_plan")
05038bc8   Jeremy   Majordome logic i...
531
                    plans_results.append(res)
ff448d43   Jeremy   Update
532
533
            else:
                self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
c53a13e0   Jeremy   Updating a lot of...
534
535
536
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
ff448d43   Jeremy   Update
537
538
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
539
540
541
        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...
542
543
544
545
546
547
548
549
                    #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...
550
551
552
                    plans_results.append(res)
            else:
                self.notifyDeviceStatus("Camera visible", "Sequence execution", self.status_vis)
c53a13e0   Jeremy   Updating a lot of...
553
554
555
                sequence.status = Sequence.CANCELLED
                shs.status = Sequence.CANCELLED
                shs.save()
05038bc8   Jeremy   Majordome logic i...
556
557
                sequence.save()
                return (1)
05038bc8   Jeremy   Majordome logic i...
558
        self.executing_sequence = [shs, sequence, plans_results]
05038bc8   Jeremy   Majordome logic i...
559
560
561
562
563
        return (0)

    '''
        Set the next sequence
    '''
c53a13e0   Jeremy   Updating a lot of...
564
    def setNextSequence(self, shs, sequence):
ff448d43   Jeremy   Update
565
        sequence.status = Sequence.PENDING
c53a13e0   Jeremy   Updating a lot of...
566
567
        shs.status = Sequence.PENDING
        self.next_sequence = [shs, sequence]
ff448d43   Jeremy   Update
568
        sequence.save()
c53a13e0   Jeremy   Updating a lot of...
569
        shs.save()
05038bc8   Jeremy   Majordome logic i...
570
571
572
573
574
575
        return (0)

    '''
        Check if the current sequence is finished
    '''
    def handleSequence(self, shs, sequence, executing_plans):
c53a13e0   Jeremy   Updating a lot of...
576
        count = 0
c53a13e0   Jeremy   Updating a lot of...
577
        for res in executing_plans:
05038bc8   Jeremy   Majordome logic i...
578
            try:
c53a13e0   Jeremy   Updating a lot of...
579
580
                if res.successful() or res.failed():
                    count += 1
05038bc8   Jeremy   Majordome logic i...
581
            except Exception as e:
678838ed   Jeremy   Weather ans insid...
582
583
                if DEBUG_FILE and settings.DEBUG:
                    log.info(str(e))
05038bc8   Jeremy   Majordome logic i...
584
585
586
587
588
                shs.status = Sequence.CANCELLED
                sequence.status = Sequence.CANCELLED
                shs.save()
                sequence.save()
                for rev in executing_plans:
c53a13e0   Jeremy   Updating a lot of...
589
590
591
                    if (not rev.failed() and not rev.successful()):
                        rev.revoke(terminate=True)
                self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
592
                return (-1)
c53a13e0   Jeremy   Updating a lot of...
593
        if count >= len(executing_plans):
05038bc8   Jeremy   Majordome logic i...
594
595
596
597
598
            sequence.status = Sequence.EXECUTED
            shs.status = Sequence.EXECUTED
            sequence.save()
            shs.save()
            message = "Finished sequence " + str(sequence.pk) + " execution"
05038bc8   Jeremy   Majordome logic i...
599
            Log.objects.create(agent="Majordome", message=message)
c53a13e0   Jeremy   Updating a lot of...
600
            self.executing_sequence = None
05038bc8   Jeremy   Majordome logic i...
601
        return (0)
65149de7   Jeremy   Update
602
603
604
605

    '''
        Function called to do an action with the devices status
    '''
05038bc8   Jeremy   Majordome logic i...
606
    def handleStatus(self):
05038bc8   Jeremy   Majordome logic i...
607
608
609
        telescope = Telescope.objects.first()
        camera_nir = Detector.objects.get(name="Cagire")
        camera_vis = Detector.objects.get(name="Visible camera")
ce470283   Jeremy   Plc simulator fin...
610
611
612
        dome = Dome.objects.get(name="Dome")

        dome.status = self.status_dom
05038bc8   Jeremy   Majordome logic i...
613
614
615
        telescope.status = self.status_tel
        camera_nir.status = self.status_nir
        camera_vis.status = self.status_vis
ce470283   Jeremy   Plc simulator fin...
616
617
618
619
620

        dome.save()
        telescope.save()
        camera_nir.save()
        camera_vis.save()
bca9a283   Jeremy   Reworked the sche...
621
622
        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
623
624
625
        return (0)

    '''
3224f14a   Jeremy   Fixed some simula...
626
        Put the majordome in pause
4cb0ff36   Jeremy   Update
627
    '''
4cb0ff36   Jeremy   Update
628
    def systemPause(self, duration, cause: str):
bca9a283   Jeremy   Reworked the sche...
629
        self.logDB("System in pause for " + str(duration))
4cb0ff36   Jeremy   Update
630
        time.sleep(duration)
05bdcc44   Etienne Pallier   BIG DEMO tests (s...
631
632
633
634
635
636
637
638
        #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
639
640
641
642
643
        self.setTime()
        print("system has been paused. Cause : " + cause)
        return (0)

    '''
65149de7   Jeremy   Update
644
645
        Function called to do an action with the site status and the wheather status
    '''
ce470283   Jeremy   Plc simulator fin...
646
647
648
649
650
651
652
653
654
655
656
    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...
657
        return 0
5b5566ab   haribo   added celery
658

4cb0ff36   Jeremy   Update
659
    '''
05038bc8   Jeremy   Majordome logic i...
660
        Gets the time before the expected start of the execution.
4cb0ff36   Jeremy   Update
661
    '''
05038bc8   Jeremy   Majordome logic i...
662
663
    def getCountdown(self, shs):
        # TODO start sequence as soon as possible (a lot of verifications must be done there)
ff448d43   Jeremy   Update
664
        current_time = secondsToPreciseJulianDate(getPreciseCurrentTime())
05038bc8   Jeremy   Majordome logic i...
665
        countdown = shs.tsp - current_time
9774228b   haribo   Date: 22/06/2016
666
        return countdown
7a79e25b   haribo   Date: 19/05/2016
667

4cb0ff36   Jeremy   Update
668
669
670
671
    '''
        Change observation conditions
    '''
    def changeObsConditions(self):
5b5566ab   haribo   added celery
672
        print("change_obs_conditions")
4cb0ff36   Jeremy   Update
673
        pass