tasks.py 5.17 KB
from __future__ import absolute_import

from celery.task import Task
import observation_manager
from pyrosapp.models import *

from common import Telescope as Tel

import time
import scheduler

from decimal import Decimal

TIMESTAMP_JD = 2440587.500000
DAILY_SECOND = 1 / 86400
MAX_WAIT = 180

class execute_sequence(Task):
    '''
        Task to handle the execution of ONE sequence
        It receives the shs' id in parameter.
        It prepairs the instruments and cut the sequence in plan. Then the execute_plan tasks are created.
        
        If possible, it advances the sequence start.
        If the sequence can't start within MAX_WAIT seconds, it relaunches a scheduling
    '''


    def run(self, shs_pk):
        # on ne supprime JAMAIS un séquence en cours, donc je peux la virer des tasks dès le début
        TaskId.objects.filter(task_id=self.request.id).delete()

        # TODO: Check PLC

        shs = ScheduleHasSequences.objects.get(pk=shs_pk)
        sequence = shs.sequence

        if sequence.status != Sequence.OBSERVABLE:
            return

        message = 'Start sequence ' + str(sequence.pk) + ' execution'
        Log.objects.create(agent='Majordome', message=message)

        print("execute_sequence : ", sequence.pk)

        countdown = self.get_countdown(shs, sequence)

        if countdown > MAX_WAIT * DAILY_SECOND:
            scheduler.tasks.scheduling.delay(first_schedule=True, alert=False)  # TODO : changer le first_schedule à False
            return

        tel = Tel.TelescopeObj()

        tel.set("SPEED", 10.0, 10.0, 10.0)
        tel.set("COORDS", 104.0, 12.0, 88.0)
        tel.set("COORDS_FRAME", Tel.CoordsFrameEnum.radec)
        tel.set("TRACKING_SPEED", 0.3, 0.3, 0.3)
        tel.set("ACCEL", 1.0, 1.0, 1.0)
        tel.set("ROTATOR", Tel.RotatorEnum.tracking)
        tel.set("FOCUS", 23562.0)
        tel.set("MOVE_MODE", Tel.MoveModeEnum.goto_track)

        tel.do("START")

        countdown = 1  # TODO: à virer, juste pour pouvoir tester

        plans_results = []

        if sequence.albums.filter(detector__device__name="Cagire").exists():
            for plan in sequence.albums.get(detector__device__name="Cagire").plans.all():
                res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, countdown))
                TaskId.objects.create(task_id=res.id, task="execute_plan")
                plans_results.append(res)

        if sequence.albums.filter(detector__device__name="Visible camera").exists():
            for plan in sequence.albums.get(detector__device__name="Visible camera").plans.all():
                res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, countdown))
                TaskId.objects.create(task_id=res.id, task="execute_plan")
                plans_results.append(res)

        shs.status = Sequence.EXECUTING
        sequence.status = Sequence.EXECUTING
        shs.save()
        sequence.save()

        for plan_result in plans_results:
            try:
                while plan_result.ready() == False:
                    print("not finished")
                    time.sleep(4)
                print("result : %s " % (plan_result.status,))
            except Exception as e:
                print("exception : %s" % (str(e),))
                shs.status = Sequence.CANCELLED
                shs.save()
                sequence.status = Sequence.CANCELLED
                sequence.save()
                return

        shs.status = Sequence.EXECUTED
        sequence.status = Sequence.EXECUTED
        shs.save()
        sequence.save()
        message = 'Finished sequence ' + str(sequence.pk) + ' execution'
        Log.objects.create(agent='Majordome', message=message)

    def get_countdown(self, shs, sequence):
        """
            Gets the time before the expected start of the execution.
            If it is > 10s, tries to get the sequence ahead according the JD1
        """
        countdown = 0

        current_time = Decimal(time.time() / 86400 + TIMESTAMP_JD)
        time_before_exec = shs.tsp - current_time

        if time_before_exec > 10 * DAILY_SECOND:
            time_before_jd1 = sequence.jd1 - current_time
            if time_before_jd1 < 0:
                pass
            elif time_before_jd1 < time_before_exec:
                countdown = time_before_jd1
            else:
                countdown = time_before_exec
        return countdown

class system_pause(Task):
    '''
        Task called by the monitoring in case of problem.
        It stops the system and the instruments.
    '''

    def run(self):
        time.sleep(5)
        print("system_pause")


class system_restart(Task):
    '''
        Task called by the monitoring when there is no more problem.
        Should just make a scheduling.
    '''
    def run(self):
        time.sleep(5)
        print("system_restart")


class change_obs_conditions(Task):
    '''
        Task called by the monitoring when the obs condition have changed.
        It reads them in the DB and changes the sequences status in consequence.
        If needed, relaunches a scheduling
    '''
    def run(self):
        # important : penser à rendre les quotas aux users
        time.sleep(5)
        print("change_obs_conditions")