Commit c53a13e0429855aaeae07da38ff391b160b81a4e

Authored by Jeremy
1 parent ff448d43
Exists in master and in 1 other branch dev

Updating a lot of things (spotted a bug in scheduler)

logs/2 deleted
... ... @@ -1 +0,0 @@
1   -test
pyros.py
... ... @@ -436,6 +436,14 @@ class Pyros(AManager):
436 436 self.migrate()
437 437 return 0
438 438  
  439 + def reset_config(self):
  440 + self.changeDirectory("src")
  441 + self.replacePatternInFile("CELERY_TEST = True", "CELERY_TEST = False", "pyros/settings.py")
  442 + self.replacePatternInFile("SIMULATOR = True", "SIMULATOR = False", "pyros/settings.py")
  443 + self.addExecuted(self.current_command, "reset configuration")
  444 + self.changeDirectory("..")
  445 + return 0
  446 +
439 447 def unittest(self):
440 448 self.changeDirectory("src")
441 449 self.execProcessFromVenv(self.venv_bin + " manage.py test common scheduler routine_manager user_manager alert_manager.tests.TestStrategyChange")
... ... @@ -476,13 +484,10 @@ class Pyros(AManager):
476 484 self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q majordome_q -n pyros@majordome -c 1")
477 485  
478 486 self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q scheduling_q --purge -n pyros@scheduling -c 1")
479   - self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q execute_sequence_q --purge -n pyros@execute_sequence -c 1")
480 487 self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q execute_plan_vis_q --purge -n pyros@execute_plan_vis -c 1")
481   - self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q execute_plan_vis_q --purge -n pyros@execute_plan_nir -c 1")
  488 + self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q execute_plan_nir_q --purge -n pyros@execute_plan_nir -c 1")
482 489 self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q create_calibrations_q --purge -n pyros@create_calibrations -c 1")
483 490 self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q analysis_q --purge -n pyros@analysis -c 1")
484   - self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q system_status_q --purge -n pyros@system_status -c 1")
485   - self.execProcessFromVenvAsync(self.venv_cel + " worker -A pyros -Q change_obs_conditions_q --purge -n pyros@change_obs_conditions -c 1")
486 491 self.changeDirectory("..")
487 492 return 0
488 493  
... ... @@ -520,7 +525,7 @@ class Pyros(AManager):
520 525 self.printColor(Colors.GREEN, "The simulator run on a temp database : src/testdb.sqlite3")
521 526 self.printColor(Colors.GREEN, "The simulation will be ended by the task 'simulator herself'")
522 527 self.printColor(Colors.GREEN, "If you want to shutdown the simulation, please run :")
523   - self.printColor(Colors.GREEN, "CTRL-C or ./pyrosrun.sh kill_simulation")
  528 + self.printColor(Colors.GREEN, "CTRL-C or python pyros.py kill_simulation")
524 529 self.printColor(Colors.GREEN, "If the simulation isn't correctly killed, please switch the variable")
525 530 self.printColor(Colors.GREEN, "CELERY_TEST in src/pyros/settings.py to false")
526 531 self.printFullTerm(Colors.WARNING, "SUMMARY")
... ... @@ -533,6 +538,10 @@ class Pyros(AManager):
533 538 self.changeDirectory("..")
534 539 self.singleWorker("scheduling")
535 540 self.singleWorker("majordome")
  541 + self.singleWorker("execute_plan_vis")
  542 + self.singleWorker("execute_plan_nir")
  543 + self.singleWorker("create_calibrations")
  544 + self.singleWorker("analysis")
536 545 self.sleep(3)
537 546 procs = []
538 547 self.changeDirectory("simulators")
... ... @@ -646,6 +655,20 @@ class Pyros(AManager):
646 655 self.changeDirectory("..")
647 656 return 0
648 657  
  658 + def mysql_on(self):
  659 + self.changeDirectory("src")
  660 + self.replacePatternInFile("MYSQL = False", "MYSQL = True", "pyros/settings.py")
  661 + self.addExecuted(self.current_command, "Switch to mysql")
  662 + self.changeDirectory("..")
  663 + return 0
  664 +
  665 + def mysql_off(self):
  666 + self.changeDirectory("src")
  667 + self.replacePatternInFile("MYSQL = True", "MYSQL = False", "pyros/settings.py")
  668 + self.addExecuted(self.current_command, "Switch to sqlite")
  669 + self.changeDirectory("..")
  670 + return 0
  671 +
649 672 def __init__(self, argv):
650 673 super(Pyros, self).__init__(argv)
651 674 self.commandMatcher = {
... ... @@ -657,9 +680,12 @@ class Pyros(AManager):
657 680 "clean_logs": self.clean_logs,
658 681 "test": self.test,
659 682 "migrate": self.migrate,
  683 + "mysql_on": self.mysql_on,
  684 + "mysql_off": self.mysql_off,
660 685 "makemigrations": self.makemigrations,
661 686 "updatedb": self.updatedb,
662 687 "unittest": self.unittest,
  688 + "reset_config": self.reset_config,
663 689 "test_all": self.test_all,
664 690 "celery_on": self.celery_on,
665 691 "init_database": self.init_database,
... ... @@ -681,7 +707,10 @@ class Pyros(AManager):
681 707 "clean_logs": "clean the log directory",
682 708 "test": "launch the server tests",
683 709 "migrate": "execute migrations",
  710 + "mysql_on": "switch the database to be used to MYSQL",
  711 + "mysql_off": "switch the database to be used usage to SQLITE",
684 712 "makemigrations": "create new migrations",
  713 + "reset_config": "Reset the configuration in settings.py",
685 714 "help": "Help message",
686 715 "updatedb": "Update the database",
687 716 "kill_server": "Kill the web server on port 8000",
... ...
simulators/camera/cameraNIRSimulator.py
... ... @@ -10,7 +10,7 @@ from utils.StatusManager import StatusManager
10 10  
11 11 class CameraNIRSimulator(Device, StatusManager):
12 12 status = {"status" : "VALID"}
13   - images_folder = '../../src/misc/images'
  13 + images_folder = '../../images_folder/'
14 14 exposure_time = 5
15 15 shutter_time = 3
16 16 cooler_timer = 5
... ... @@ -42,6 +42,17 @@ class CameraNIRSimulator(Device, StatusManager):
42 42 else:
43 43 answer = "Invalid cmd for GET: " + cmd
44 44 self.cameraNIRPrint(answer)
  45 + elif (cmd_type == "DO"):
  46 + if (cmd == "CAPTURE"):
  47 + plan_name = args[0]
  48 + nb_images = int(args[1])
  49 + duration = args[2]
  50 + i = 0
  51 + while i < nb_images:
  52 + with open(self.images_folder + plan_name + os.sep + "nir_image_"+str(i), "w") as f:
  53 + f.write(plan_name+" "+str(nb_images)+" "+str(duration))
  54 + i += 1
  55 + answer = "CAPTURING"
45 56 else:
46 57 self.cameraNIRPrint("Ignored message " + data)
47 58  
... ...
simulators/camera/cameraVISSimulator.py
... ... @@ -10,7 +10,7 @@ from utils.StatusManager import StatusManager
10 10  
11 11 class CameraVISSimulator(Device, StatusManager):
12 12 status = {"status" : "VALID"}
13   - images_folder = '../../src/misc/images'
  13 + images_folder = '../../images_folder/'
14 14 exposure_time = 5
15 15 shutter_time = 3
16 16 cooler_timer = 5
... ... @@ -42,6 +42,17 @@ class CameraVISSimulator(Device, StatusManager):
42 42 else:
43 43 answer = "Invalid cmd for GET: " + cmd
44 44 self.cameraVISPrint(answer)
  45 + elif (cmd_type == "DO"):
  46 + if (cmd == "CAPTURE"):
  47 + plan_name = args[0]
  48 + nb_images = int(args[1])
  49 + duration = args[2]
  50 + i = 0
  51 + while i < nb_images:
  52 + with open(self.images_folder + plan_name + os.sep + "nir_image_" + str(i), "w") as f:
  53 + f.write(plan_name + " " + str(nb_images) + " " + str(duration))
  54 + i += 1
  55 + answer = "CAPTURING"
45 56 else:
46 57 self.cameraVISPrint("Ignored message " + data)
47 58  
... ...
simulators/resources/routine_request_01.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="15" jd2="60000" name="Sequence1 (200secs)" target_coords="10">
  3 + <sequence duration="10" jd1="15" jd2="60000" name="Sequence1 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5   - <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
  5 + <plan duration="10" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
7 7 </sequence>
8 8 </request>
... ...
simulators/resources/routine_request_07.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="6000" jd2="60000" name="Sequence7 (200secs)" target_coords="10">
  3 + <sequence duration="10" jd1="6000" jd2="60000" name="Sequence7 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5   - <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
  5 + <plan duration="10" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
7 7 </sequence>
8 8 </request>
... ...
simulators/resources/routine_request_08.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="19000" jd2="60000" name="Sequence8 (200secs)" target_coords="10">
  3 + <sequence duration="20" jd1="19000" jd2="60000" name="Sequence8 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5   - <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
  5 + <plan duration="20" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
7 7 </sequence>
8 8 </request>
... ...
simulators/resources/routine_request_09.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="1000" jd2="60000" name="Sequence9 (200secs)" target_coords="10">
  3 + <sequence duration="20" jd1="1000" jd2="60000" name="Sequence9 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5   - <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
  5 + <plan duration="20" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
7 7 </sequence>
8 8 </request>
... ...
simulators/resources/routine_request_10.xml
1 1 <?xml version="1.0" ?>
2 2 <request submitted="1" relative="1" name="RequestSimulator" scientific_program="GRB" target_type="test">
3   - <sequence duration="200" jd1="200" jd2="60000" name="Sequence10 (200secs)" target_coords="10">
  3 + <sequence duration="20" jd1="200" jd2="60000" name="Sequence10 (200secs)" target_coords="10">
4 4 <album detector="Visible camera" name="alb">
5   - <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/>
  5 + <plan duration="20" filter="First infrared filter" name="New plan" nb_images="5"/>
6 6 </album>
7 7 </sequence>
8 8 </request>
... ...
simulators/telescope/telescopeSimulator.py
... ... @@ -40,6 +40,9 @@ class TelescopeSimulator(Device, StatusManager):
40 40 else:
41 41 answer = "Invalid cmd for GET: " + cmd
42 42 self.telescopePrint(answer)
  43 + elif (cmd_type == "DO"):
  44 + if (cmd == "GOTO"):
  45 + answer = "NEW POSITION SET TO " + str(args)
43 46 else:
44 47 self.telescopePrint("Ignored message " + data)
45 48  
... ...
src/analyzer/analyzer 0 → 100755
No preview for this file type
src/analyzer/analyses/analysis_1.txt renamed to src/analyzer/analyzer_source/calibrations/dark.fits
src/analyzer/calibrations/dark.fits renamed to src/analyzer/analyzer_source/calibrations/flat.fits
src/analyzer/analyzer_source/main.cpp 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +#include <iostream>
  2 +#include <fstream>
  3 +
  4 +int main(int ac, char **av)
  5 +{
  6 + if (ac >= 4)
  7 + {
  8 + std::string folder_source = av[1];
  9 + std::string folder_plan = av[2];
  10 + std::string duration = av[3];
  11 + std::string file_dest;
  12 + std::ofstream myfile;
  13 +
  14 + file_dest = folder_source + "/" + folder_plan + "/analysis/analysis.result";
  15 + myfile.open(file_dest.c_str());
  16 + myfile << "Source folder = " + folder_source << std::endl;
  17 + myfile << "Plan folder = " + folder_plan << std::endl;
  18 + myfile << "duration = " + duration << std::endl;
  19 + return (0);
  20 + }
  21 + return (1);
  22 +}
... ...
src/analyzer/calibrations/flat.fits deleted
src/analyzer/tasks.py
1 1 from __future__ import absolute_import
2   -
3 2 from celery.task import Task
4 3 from common.models import *
5   -
6   -import time
  4 +from utils.Logger import setupLogger
  5 +from django.conf import settings
  6 +import subprocess
7 7 import os
8 8  
9   -IMAGES_FOLDER = "misc/images"
  9 +'''
  10 + Gets the folder path and the plan id
  11 + it makes an analysis of the calibrated images (in folder "calibrated")
  12 +'''
  13 +
10 14  
11 15 class analysis(Task):
12   - '''
13   - Gets the name of the image to analyze in parameter
14   - It applies the calibrations, then makes the
15   - '''
  16 + logger = setupLogger("analysis", "analysis")
  17 +
  18 + def log(self, message: str) -> int:
  19 + if settings.DEBUG:
  20 + self.logger.info(message)
  21 + return 0
16 22  
17   - def run(self, plan_id):
18   - # je dois jsute créer mes deux fonctions, une pour les corrections, et l'autre pour les analyses
  23 + def logDB(self, message: str) -> int:
  24 + Log.objects.create(agent='Analyzer', message=message)
  25 + return 0
19 26  
20   - plan = Plan.objects.get(id=plan_id)
21   - image_name = plan.name
  27 + def execProcess(self, command: str) -> int:
  28 + self.process = subprocess.Popen(command, shell=True)
  29 + return 0
22 30  
23   - print("analysis : ", image_name)
  31 + def start(self, plan_id: int, folder: str) -> int:
  32 + self.plan_id = plan_id
  33 + self.folder = folder
  34 + self.path_dir_file = os.path.dirname(os.path.realpath(__file__))
  35 + try:
  36 + self.plan = Plan.objects.get(id=self.plan_id)
  37 + except:
  38 + self.log("analysis not found")
  39 + self.logDB(message="Plan with id %d not found"%(self.plan_id))
  40 + return 1
  41 + self.dir_name = self.folder + os.sep + self.plan.name + "_" + str(self.plan_id) + os.sep + "analysis"
  42 + self.plan_folder = self.plan.name + "_" + str(self.plan_id)
  43 + if self.createDirectory():
  44 + self.log("analysis err dir")
  45 + self.logDB(message="Could not create the directory for analysis")
  46 + return 1
  47 + self.log("analysis start")
  48 + return self.logDB("Starting analysis for plan " + self.plan.name)
24 49  
25   - new_img = self.apply_calibrations(image_name)
26   - # TODO: Faire ça uniquement si c'est une image provenant d'une alerte
27   - self.do_analysis(new_img)
  50 + def createDirectory(self):
  51 + try:
  52 + if not os.path.isdir(self.dir_name):
  53 + os.makedirs(self.dir_name)
  54 + except:
  55 + return 1
  56 + return 0
28 57  
29   - # TODO: virer tout ça
30   - time.sleep(1)
31   - with open(os.path.join(IMAGES_FOLDER, str(image_name) + '_analyzed'), 'w'):
32   - pass
33   - message = 'Analyzed image in ' + str(image_name)
34   - Log.objects.create(agent='Analyzer', message=message)
  58 + def changeDirectory(self, path: str):
  59 + os.chdir(path)
  60 + return 0
  61 +
  62 + def execute(self) -> int:
  63 + self.changeDirectory(self.path_dir_file)
  64 + return self.execProcess("./analyzer "+str(self.folder)+" "+self.plan_folder+" "+str(self.plan.duration))
  65 +
  66 + def end(self) -> int:
  67 + self.process.wait()
  68 + if self.process.returncode == 0:
  69 + self.log("analysis executed")
  70 + self.logDB(message="Analysis executed successfully for plan " + str(self.plan.name))
  71 + else:
  72 + self.log("analysis failed")
  73 + self.logDB(message="Could not make an analysis for plan " + str(self.plan.name))
  74 + return self.process.returncode
35 75  
36   - def apply_calibrations(self, image_name):
37   - '''
38   - Uses the calibration files to correct the image (changes the image bytes)
39   - Send the new images to the FSC
40   - '''
41   - # TODO: récupérer les bonne images dans le dossier analyzer/calibrations, et les appliquer
42   - # renvoie le nom de l'image calibrée; penser à vérifier que les fichiers de calibration existent à cet endroit
43   - # TODO: copier l'image dans le bon dossier pour le filesync (lien symbolique)
44   - return "toto.fits"
45   -
46   - def do_analysis(self, new_img):
47   - '''
48   - Use the scientific softwares to create analysis files (doesn't change the image bytes)
49   - Sends the results to the FSC
50   - '''
51   - # TODO: utiliser les programmes scientifiques pour générer les analyses
52   - # TODO: copier les résultats des analyses dans le bon dossier pour le filesync (lien symbolique)
53   - pass
  76 + def run(self, plan_id, folder):
  77 + if self.start(plan_id, folder):
  78 + return 1
  79 + self.execute()
  80 + self.end()
  81 + return 0
... ...
src/common/models.py
... ... @@ -452,6 +452,11 @@ class ScheduleHasSequences(models.Model):
452 452  
453 453  
454 454 class SiteWatch(models.Model):
  455 + OPEN = "OPEN"
  456 + CLOSE = "CLOSE"
  457 + ON = "ON"
  458 + OFF = "OFF"
  459 +
455 460 updated = models.DateTimeField(blank=True, null=True, auto_now=True)
456 461 lights = models.CharField(max_length=45, blank=True, null=True)
457 462 dome = models.CharField(max_length=45, blank=True, null=True)
... ... @@ -569,6 +574,9 @@ class Version(models.Model):
569 574 return (str(self.module_name) + " - " + str(self.version))
570 575  
571 576 class WeatherWatch(models.Model):
  577 + WIND_LIMIT = 100
  578 + RAIN_LIMIT = 5
  579 +
572 580 updated = models.DateTimeField(blank=True, null=True)
573 581 humid_int = models.FloatField(blank=True, null=True)
574 582 humid_ext = models.FloatField(blank=True, null=True)
... ...
src/devices/Device.py
... ... @@ -9,6 +9,8 @@ import utils.Logger as L
9 9 Generic object for the communication with all the devices (need inheritance)
10 10 '''
11 11  
  12 +DEBUG_FILE = False
  13 +
12 14  
13 15 class DeviceController():
14 16 __metaclass__ = abc.ABCMeta
... ... @@ -124,7 +126,8 @@ class DeviceController():
124 126 return (0)
125 127  
126 128 def log(self, device_name: str, message: str):
127   - self.logger.info("From device : " + device_name + " -> " + message)
  129 + if DEBUG_FILE and settings.DEBUG:
  130 + self.logger.info("From device : " + device_name + " -> " + message)
128 131 return (0)
129 132  
130 133 def connect(self):
... ...
src/majordome/tasks.py
... ... @@ -2,9 +2,8 @@ from __future__ import absolute_import
2 2 from common.models import *
3 3 from django.core.exceptions import ObjectDoesNotExist
4 4 import scheduler
5   -import scheduler.tasks
  5 +import scheduler.tasks as sched_task
6 6 from celery.task import Task
7   -from celery import app
8 7 import observation_manager
9 8 import observation_manager.tasks
10 9 from devices.Telescope import TelescopeController
... ... @@ -12,8 +11,9 @@ from devices.CameraVIS import VISCameraController
12 11 from devices.CameraNIR import NIRCameraController
13 12 from devices.Dome import DomeController
14 13 from devices.PLC import PLCController
15   -from django.conf import settings
  14 +from django.db.models import Q
16 15 from utils.JDManipulator import *
  16 +from utils.StatusManager import *
17 17 import utils.Logger as L
18 18  
19 19 DEBUG_FILE = False
... ... @@ -39,7 +39,8 @@ class Majordome(Task):
39 39 timers = {}
40 40 functions = {}
41 41 schedule = None
42   - majordome_status = "STARTING"
  42 + available_status = []
  43 + current_status = NORMAL
43 44  
44 45 '''
45 46 Check if the instrument status is valid
... ... @@ -70,7 +71,6 @@ class Majordome(Task):
70 71 self.updateSoftware()
71 72 self.setContext()
72 73 self.setTime()
73   - self.majordome_status = "EXECUTING"
74 74 self.loop()
75 75  
76 76 '''
... ... @@ -96,7 +96,6 @@ class Majordome(Task):
96 96 self.status_nir = self.nir_camera.get("STATUS")
97 97 self.status_tel = self.tel.get("STATUS")
98 98 self.status_dom = self.dom.get("STATUS")
99   - print("Devices ready !")
100 99 return (0)
101 100  
102 101 '''
... ... @@ -152,7 +151,7 @@ class Majordome(Task):
152 151 Infinite loop according to the majordome behavior
153 152 '''
154 153 def loop(self):
155   - while (self.majordome_status != "SHUTDOWN"):
  154 + while (self.current_status != "SHUTDOWN"):
156 155 minimal_timer = min(self.timers, key=self.timers.get)
157 156 if (self.timers[minimal_timer] > 0):
158 157 time.sleep(self.timers[minimal_timer])
... ... @@ -219,7 +218,8 @@ class Majordome(Task):
219 218 self.next_sequence = None
220 219 self.schedule = schedule
221 220 if (self.schedule):
222   - shs_list = self.schedule.shs.filter(status=Sequence.PENDING).order_by('tsp')
  221 + shs_list = self.schedule.shs.filter(Q(status=Sequence.PLANNED) |
  222 + Q(status=Sequence.PENDING)).order_by('tsp')
223 223 self.executeSchedule(shs_list)
224 224 else:
225 225 self.notifyTelescopeStatus("scheduler")
... ... @@ -254,25 +254,21 @@ class Majordome(Task):
254 254 Function called when a schedule has to be executed
255 255 '''
256 256 def executeSchedule(self, shs_list):
257   - is_prev_planned = False
258 257 self.logDB("Trying to execute a sequence from current schedule")
259 258 for shs in shs_list: # shs_list is sorted by tsp
260   - if (shs.sequence.status == Sequence.PLANNED and self.observable(shs.sequence)):
261   - countdown = self.getCountdown(shs)
262   - # if (countdown <= 6):
263   - # TODO CHECK IF OBSERVABLE ELSE RESCHEDULE
264   - if countdown <= JulianSeconds(5):
265   - if self.executing_sequence is None:
266   - if self.switchSequence():
267   - self.executeSequence(shs, shs.sequence, countdown)
  259 + if (self.executableSequence(shs.sequence.status) and self.observable(shs.sequence)):
  260 + if self.next_sequence is None:
  261 + self.setNextSequence(shs, shs.sequence)
  262 + if self.executing_sequence is None:
  263 + if self.isValidTimer(self.next_sequence[0]):
  264 + if self.executeSequence(self.next_sequence[0], self.next_sequence[1]) == -1:
  265 + return -1
  266 + if self.next_sequence[0] != shs and self.next_sequence[1] != shs.sequence:
  267 + self.setNextSequence(shs, shs.sequence)
268 268 else:
269   - self.setNextSequence(shs, shs.sequence, countdown)
270   - elif self.next_sequence is None:
271   - self.setNextSequence(shs, shs.sequence, countdown)
  269 + self.next_sequence = None
272 270 else:
273 271 return 0
274   - elif self.next_sequence is None:
275   - self.setNextSequence(shs, shs.sequence, countdown)
276 272 else:
277 273 if (settings.DEBUG and DEBUG_FILE):
278 274 log.info("Sequence cannot be executed : Not observable")
... ... @@ -284,41 +280,58 @@ class Majordome(Task):
284 280 return 0
285 281 return 1
286 282  
  283 + def executableSequence(self, status):
  284 + if status == Sequence.PLANNED or status == Sequence.PENDING:
  285 + return 1
  286 + return 0
  287 +
  288 + def isValidTimer(self, shs):
  289 + current_countdown = self.getCountdown(shs)
  290 + if (current_countdown <= JulianSeconds(5)):
  291 + # Trick to be sure to not start the execution of a task if there is a schedule
  292 + try:
  293 + task = TaskId.objects.filter(task="scheduling")
  294 + if not task:
  295 + return 1
  296 + return 0
  297 + except:
  298 + return 1
  299 + return 0
  300 +
287 301 '''
288 302 Launch the observation tasks associated to a sequence
289 303 '''
290   - def executeSequence(self, shs, sequence, countdown):
291   - if (countdown > JulianSeconds(5)):
292   - if self.next_sequence and self.next_sequence[1].status == Sequence.PENDING:
293   - self.next_sequence[1].status = Sequence.PLANNED
294   - self.next_sequence[1].save()
295   - return 0
296   - if self.next_sequence and self.next_sequence[1].status == Sequence.PLANNED:
297   - self.next_sequence[1].status = Sequence.PENDING
298   - self.next_sequence[1].save()
299   -
  304 + @acceptedStatus(["NORMAL", "MINOR_ERROR"])
  305 + def executeSequence(self, shs, sequence):
  306 + log.info("Executing sequence id = " + str(sequence.pk))
300 307 self.logDB("Executing sequence")
301 308 plans_results = []
302 309 if sequence.albums.filter(detector__name="Cagire").exists():
303 310 if (self.isValidStatus(self.status_nir)):
304 311 for plan in sequence.albums.get(detector__name="Cagire").plans.all():
305   - res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, float(countdown)))
306   - TaskId.objects.create(task_id=res.id, task="execute_plan")
  312 + res = observation_manager.tasks.execute_plan_nir.apply_async(
  313 + (plan.id, float(self.getCountdown(shs))))
  314 + # JB TODO : is it still usefull ?
  315 + # TaskId.objects.create(task_id=res.id, task="execute_plan")
307 316 plans_results.append(res)
308 317 else:
309 318 self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir)
310   - sequence.status = Sequence.DEVICE_ERROR
  319 + sequence.status = Sequence.CANCELLED
  320 + shs.status = Sequence.CANCELLED
  321 + shs.save()
311 322 sequence.save()
312 323 return (1)
313 324 if sequence.albums.filter(detector__name="Visible camera").exists():
314 325 if (self.isValidStatus(self.status_vis)):
315 326 for plan in sequence.albums.get(detector__name="Visible camera").plans.all():
316   - res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, float(countdown)))
317   - TaskId.objects.create(task_id=res.id, task="execute_plan")
  327 + res = observation_manager.tasks.execute_plan_vis.apply_async(
  328 + (plan.id, float(self.getCountdown(shs))))
318 329 plans_results.append(res)
319 330 else:
320 331 self.notifyDeviceStatus("Camera visible", "Sequence execution", self.status_vis)
321   - sequence.status = Sequence.DEVICE_ERROR
  332 + sequence.status = Sequence.CANCELLED
  333 + shs.status = Sequence.CANCELLED
  334 + shs.save()
322 335 sequence.save()
323 336 return (1)
324 337 shs.status = Sequence.EXECUTING
... ... @@ -326,60 +339,51 @@ class Majordome(Task):
326 339 shs.save()
327 340 sequence.save()
328 341 self.executing_sequence = [shs, sequence, plans_results]
  342 + log.info("Sequence status should be executing = " + str(sequence.status))
329 343 return (0)
330 344  
331 345 '''
332 346 Set the next sequence
333 347 '''
334   - def setNextSequence(self, shs, sequence, countdown):
  348 + def setNextSequence(self, shs, sequence):
  349 + log.info("Setting next sequence id = " + str(sequence.pk))
335 350 sequence.status = Sequence.PENDING
336   - self.next_sequence = [shs, sequence, countdown]
  351 + shs.status = Sequence.PENDING
  352 + self.next_sequence = [shs, sequence]
337 353 sequence.save()
338   - return (0)
339   -
340   - '''
341   - Switch sequences
342   - '''
343   - def switchSequence(self):
344   - self.executing_sequence = None
345   - if (self.next_sequence is not None):
346   - self.executeSequence(self.next_sequence[0],
347   - self.next_sequence[1], self.next_sequence[2])
348   - self.next_sequence = None
349   - else:
350   - return 1
  354 + shs.save()
351 355 return (0)
352 356  
353 357 '''
354 358 Check if the current sequence is finished
355 359 '''
356 360 def handleSequence(self, shs, sequence, executing_plans):
357   - finished = False
358   - error = False
  361 + count = 0
359 362  
360   - for plan in executing_plans:
  363 + for res in executing_plans:
361 364 try:
362   - if plan.ready() == False:
363   - finished = True
  365 + if res.successful() or res.failed():
  366 + count += 1
364 367 except Exception as e:
365   - error = True
  368 + print(e)
366 369 shs.status = Sequence.CANCELLED
367 370 sequence.status = Sequence.CANCELLED
368 371 shs.save()
369 372 sequence.save()
370 373 for rev in executing_plans:
371   - if (not rev.failed() and rev.ready() != True):
372   - app.control.revoke(rev.id)
373   - self.switchSequence()
  374 + if (not rev.failed() and not rev.successful()):
  375 + rev.revoke(terminate=True)
  376 + self.executing_sequence = None
374 377 return (-1)
375   - if (finished):
  378 + if count >= len(executing_plans):
376 379 sequence.status = Sequence.EXECUTED
377 380 shs.status = Sequence.EXECUTED
378 381 sequence.save()
379 382 shs.save()
380 383 message = "Finished sequence " + str(sequence.pk) + " execution"
  384 + log.info(message)
381 385 Log.objects.create(agent="Majordome", message=message)
382   - self.switchSequence()
  386 + self.executing_sequence = None
383 387 return (0)
384 388  
385 389 '''
... ... @@ -387,6 +391,10 @@ class Majordome(Task):
387 391 '''
388 392 def handleStatus(self):
389 393 # TODO switch majordome state according to devices status
  394 + # if not self.isValidStatus(self.status_tel):
  395 + # self.current_status = "ERROR"
  396 + # if not self.isValidStatus(self.status_vis) and self.current_status == NORMAL:
  397 + # self.current_status = ""
390 398 telescope = Telescope.objects.first()
391 399 camera_nir = Detector.objects.get(name="Cagire")
392 400 camera_vis = Detector.objects.get(name="Visible camera")
... ... @@ -394,7 +402,7 @@ class Majordome(Task):
394 402 # dome = ???.objects.get(name="Dome")
395 403 # dome.status = self.status_dom
396 404 # dome.save()
397   - # TODO adapt the status (must be short)
  405 + # TODO adapt the status (must be a short string)
398 406 telescope.status = self.status_tel
399 407 camera_nir.status = self.status_nir
400 408 camera_vis.status = self.status_vis
... ... @@ -409,6 +417,7 @@ class Majordome(Task):
409 417 '''
410 418 Put the system in Pause
411 419 '''
  420 + @acceptedStatus(["CRITICAL"])
412 421 def systemPause(self, duration, cause: str):
413 422 self.logDB("System in pause for " + str(duration))
414 423 time.sleep(duration)
... ... @@ -421,6 +430,16 @@ class Majordome(Task):
421 430 Function called to do an action with the site status and the wheather status
422 431 '''
423 432 def handlePLC(self, site_status, weather_status):
  433 + if site_status.doors == SiteWatch.OPEN:
  434 + self.current_status = SITE_CONDITION
  435 + self.logDB("Doors are open")
  436 + self.stopExecution()
  437 + if weather_status.wind > WeatherWatch.WIND_LIMIT:
  438 + self.cause = "Wind"
  439 + self.logDB("Wind too strong")
  440 + self.stopExecution()
  441 + if weather_status.rain > WeatherWatch.RAIN_LIMIT:
  442 + self.cause = "Rain"
424 443 return (0)
425 444  
426 445 '''
... ...
src/observation_manager/calibrator 0 → 100755
No preview for this file type
src/observation_manager/calibrator_source/main.cpp 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +#include <iostream>
  2 +#include <fstream>
  3 +
  4 +int main(int ac, char **av)
  5 +{
  6 + if (ac >= 4)
  7 + {
  8 + std::string folder_source = av[1];
  9 + std::string folder_plan = av[2];
  10 + std::string img_number = av[3];
  11 + std::string file_dest;
  12 + std::ofstream myfile;
  13 +
  14 + file_dest = folder_source+"/"+folder_plan+"/calibrator/calibrator"+img_number+".result";
  15 + myfile.open(file_dest.c_str());
  16 + myfile << "Source folder = " + folder_source << std::endl;
  17 + myfile << "Source plan = " + folder_plan << std::endl;
  18 + myfile << "image number = " + img_number << std::endl;
  19 + return (0);
  20 + }
  21 + return (1);
  22 +}
... ...
src/observation_manager/tasks.py
1 1 from __future__ import absolute_import
2 2 from celery.task import Task
3   -from analyzer.tasks import analysis
  3 +from django.conf import settings
4 4 from common.models import *
5   -from devices import CameraVIS as VIS
6   -from devices import CameraNIR as NIR
7   -from devices import Telescope
8   -import time
9 5 from utils.Logger import setupLogger
  6 +from analyzer.tasks import analysis
  7 +from utils.JDManipulator import *
  8 +from devices.Telescope import TelescopeController
  9 +from devices.CameraNIR import NIRCameraController
  10 +from devices.CameraVIS import VISCameraController
  11 +import time
  12 +import subprocess
  13 +import os
10 14  
11 15 '''
12 16 Super class for execute_plan_vis / _nir
13 17 '''
14 18 class execute_plan(Task):
15   -
16   - def run(self, plan_id, countdown, type):
17   -
18   - if countdown > 0:
19   - time.sleep(countdown)
20   - TaskId.objects.filter(task_id=self.request.id).delete()
21   -
22   - self.type = type
23   - plan = Plan.objects.get(id=plan_id)
24   -
25   - message = 'Start plan ' + plan.name + ' execution'
  19 + def setTelescope(self):
  20 + self.tel = TelescopeController()
  21 + return 0
  22 +
  23 + def start(self) -> int:
  24 + self.setTelescope()
  25 + self.logger = setupLogger("Observation"+self.type, "Observation"+self.type)
  26 + self.image_count = 0
  27 + # JB TODO : is it still usefull ?
  28 + # TaskId.objects.filter(task_id=self.request.id).delete()
  29 + if self.countdown > 0:
  30 + time.sleep(self.countdown)
  31 + try:
  32 + self.plan = Plan.objects.get(id=self.plan_id)
  33 + self.duration = julianSecondsToSeconds(self.plan.duration)
  34 + except:
  35 + self.logDB(message="Plan with id %d not found" % (self.plan_id))
  36 + return 1
  37 + self.plan_dir = self.plan.name + "_" + str(self.plan_id)
  38 + self.dir_name = settings.OUTPUT_FOLDER + os.sep + self.plan_dir
  39 + if self.createDirs():
  40 + self.log("Could not create dirs")
  41 + self.logDB(message="Could not create directory " + self.dir_name + " for image storage")
  42 + return 1
  43 + self.launchAnalysis()
  44 + self.log("Starting execution " + self.type)
  45 + return self.logDB('Start plan %s observation from camera %s'%(self.plan.name, str(self.type)))
  46 +
  47 + def createDirs(self):
  48 + try:
  49 + if not os.path.isdir(settings.OUTPUT_FOLDER):
  50 + os.makedirs(settings.OUTPUT_FOLDER)
  51 + if not os.path.isdir(self.dir_name):
  52 + os.makedirs(self.dir_name)
  53 + except:
  54 + return 1
  55 + return 0
  56 +
  57 + def log(self, message: str) -> int:
  58 + self.logger.info(self.type + ' -> '+ message)
  59 + return 0
  60 +
  61 + def logDB(self, message: str) -> int:
26 62 Log.objects.create(agent='Observation manager', message=message)
27   - print("execute_plan " + self.type + " : ", plan.name)
28   -
29   - self.tel = Telescope.TelescopeController()
30   - if self.type == "VIS":
31   - cam = VIS.VISCameraController()
32   - else:
33   - cam = NIR.NIRCameraController()
34   -
35   - self.set_camera(cam, plan)
36   - self.wait_camera_ready(cam)
  63 + return 0
37 64  
38   - cam.do("START")
  65 + def launchAnalysis(self):
  66 + analysis.apply_async((self.plan_id, settings.OUTPUT_FOLDER))
  67 + return 0
39 68  
40   - st = self.wait_camera_finished(cam)
  69 + def launchCalibration(self) -> int:
  70 + create_calibrations.apply_async((self.plan_id, settings.OUTPUT_FOLDER, self.image_count))
  71 + return 0
41 72  
42   - # TODO: récupérer les vraies images ? je fais quoi ?
43   - time.sleep(1)
44   - # Penser qu'un plan peut créer plusieurs images (et analyser image par image)
45   - analysis.delay(plan_id)
46   - message = 'Finished plan ' + plan.name + ' execution'
47   - Log.objects.create(agent='Observation manager', message=message)
48   -
49   - '''
50   - Set the camera configuration
51   - '''
52   - def set_camera(self, cam, plan):
53   -
54   - # TODO: mettre les vraies configurations en fct du plan
55   - cam.set("WINDOW", 0, 100, 10, 100)
56   - cam.set("READMODE", "Ramp")
57   - cam.set("FILENAME", plan.name)
58   - cam.set("HEADER", {})
59   - cam.set("READOUT_FREQUENCY", 20.0)
60   - cam.set("FILTER", "H")
61   -
62   - if self.type == "VIS":
63   - cam.set("EXPOSURE", 180)
64   - cam.set("BINNING", 300, 300)
65   - else:
66   - cam.set("NB_IMAGES", 28)
67   -
68   - '''
69   - Loop to wait for the configuration to be done
70   - '''
71   - def wait_camera_ready(self, cam):
72   - st = 0
73   - while st == 0:
74   - st_tel = self.tel.get("STATUS")
75   -
76   - st_cam = cam.get("STATUS")
77   -
78   - st = 1
79   -
80   - # TODO: checker les statuts comme il faut, et repasser à 0 si on a des statuts pas bons
81   - if st_tel != "IDLE" or st_cam != "IDLE":
82   - st = 0
83   -
84   - '''
85   - Loop to wait for the observation to be finished
86   - '''
87   - def wait_camera_finished(self, cam):
88   - countdown = int(cam.get("TIMER"))
89   - while countdown > 5:
90   - time.sleep(5)
91   - countdown = int(cam.get("TIMER"))
92   -
93   - st = 0
94   - while st == 0:
95   - timer = int(cam.get("TIMER"))
96   - if timer == -1:
97   - st = 1
98   - else:
99   - time.sleep(1)
  73 + def end(self) -> int:
  74 + self.log("Finished plan observation")
  75 + return self.logDB('Finished plan observation ' + self.plan.name + ' from camera ' + str(self.type))
100 76  
  77 + def run(self, plan_id: int, countdown: float, type: str) -> int:
  78 + self.plan_id = plan_id
  79 + self.countdown = countdown
  80 + self.type = type
  81 + if self.start():
  82 + self.log("fail exec task -> leaving")
  83 + return 1
  84 + self.execute()
  85 + return self.end()
  86 +
  87 + def execute(self) -> int:
  88 + time = julianSecondsToSeconds(self.plan.duration)
  89 + self.log("Sleeping for " + str(int(self.duration)))
  90 + time.sleep(int(self.duration))
  91 + return 0
101 92  
102 93 '''
103 94 Gives the orders to the instruments to retrieve the image(s) of a plan VIS.
104   - Send the images to the analyzer
  95 + Send the images to the calibrator
105 96 '''
106 97 class execute_plan_vis(execute_plan):
107   - logger = setupLogger("PlanVIS", "PlanVIS")
  98 + def setCamera(self):
  99 + self.vis_camera = VISCameraController()
  100 + return 0
108 101  
109   - def run(self, plan_id, countdown):
110   - self.log.info("------------------ RUNNING PLAN VIS ----------------------------")
  102 + def run(self, plan_id: int, countdown: float) -> int:
  103 + self.setCamera()
111 104 super().run(plan_id, countdown, "VIS")
  105 + return 0
112 106  
  107 + def execute(self) -> int:
  108 + # TODO All the comunication protocol with the device
  109 + self.tel.do("GOTO " + str(self.plan.position))
  110 + self.vis_camera.do("CAPTURE "+self.plan.name+" "+str(self.plan.nb_images)+" "+str(self.plan.duration))
  111 + self.log("Sleeping for " + str(int(self.duration)))
  112 + time.sleep(int(self.duration))
  113 + self.launchCalibration()
  114 + return 0
113 115  
114 116 '''
115 117 Gives the orders to the instruments to retrieve the image(s) of a plan NIR.
116   - Send the images to the analyzer
  118 + Send the images to the calibrator
117 119 '''
118 120 class execute_plan_nir(execute_plan):
119   - log = setupLogger("PlanNIR", "PlanNIR")
  121 + def setCamera(self):
  122 + self.nir_camera = NIRCameraController()
  123 + return 0
120 124  
121   - def run(self, plan_id, countdown):
  125 + def run(self, plan_id: int, countdown: float) -> int:
  126 + self.setCamera()
122 127 super().run(plan_id, countdown, "NIR")
123   - self.log.info("------------------ RUNNING PLAN NIR ----------------------------")
  128 + return 0
  129 +
  130 + def execute(self) -> int:
  131 + # TODO All the comunication protocol with the device
  132 + self.tel.do("GOTO " + str(self.plan.position))
  133 + self.nir_camera.do("CAPTURE "+self.plan.name+" "+str(self.plan.nb_images)+" "+str(self.plan.duration))
  134 + self.log("Sleeping for " + str(int(self.duration)))
  135 + time.sleep(int(self.duration))
  136 + self.launchCalibration()
  137 + return 0
124 138  
125 139  
126 140 '''
127   - Directly make the right calls to the instruments to create the calibration files.
128   - When they are all finished, it creates the 'super' calibration files.
  141 + Call a process with a folder and an image number as parameter who will create the
  142 + calibration for an image
129 143 '''
130 144 class create_calibrations(Task):
131   - logger = setupLogger("Calibrations", "Calibrations")
  145 + logger = setupLogger("calibrations", "calibrations")
  146 +
  147 + def log(self, message: str) -> int:
  148 + self.logger.info(message)
  149 + return 0
132 150  
133   - def run(self):
134   - self.log.info("------------------ RUNNING CALIBRATIONS ----------------------------")
135   - # TODO: attendre que tout soit idle
  151 + def logDB(self, message: str) -> int:
  152 + Log.objects.create(agent='Observation manager', message=message)
  153 + return 0
  154 +
  155 + def execProcess(self, command: str) -> int:
  156 + self.process = subprocess.Popen(command, shell=True)
  157 + return 0
  158 +
  159 + def start(self, plan_id: int, folder: str, image_number: int) -> int:
  160 + self.plan_id = plan_id
  161 + self.folder = folder
  162 + self.image_number = image_number
  163 + self.path_dir_file = os.path.dirname(os.path.realpath(__file__))
  164 + try:
  165 + self.plan = Plan.objects.get(id=self.plan_id)
  166 + self.plan_folder = self.plan.name + "_" + str(self.plan_id)
  167 + except:
  168 + self.log("not found")
  169 + self.logDB(message="Plan with id %d not found"%(self.plan_id))
  170 + return 1
  171 + self.dir_name = self.folder + os.sep + self.plan.name + "_" + str(self.plan_id) + os.sep + "calibrations"
  172 + if self.createDirectory():
  173 + self.log("err dir")
  174 + self.logDB(message="Could not create folder for calibrations")
  175 + return 1
  176 + self.log("start")
  177 + return self.logDB("Starting calibration for image " + str(self.image_number))
  178 +
  179 + def createDirectory(self):
  180 + try:
  181 + if not os.path.isdir(self.dir_name):
  182 + os.makedirs(self.dir_name)
  183 + except:
  184 + return 1
  185 + return 0
  186 +
  187 + def changeDirectory(self, path: str):
  188 + os.chdir(path)
  189 + return 0
  190 +
  191 + def execute(self) -> int:
  192 + self.changeDirectory(self.path_dir_file)
  193 + return self.execProcess("./calibrator "+str(self.folder)+" "+self.plan_folder+" "+str(self.image_number))
  194 +
  195 + def end(self) -> int:
  196 + self.process.wait()
  197 + if self.process.returncode == 0:
  198 + self.log("executed")
  199 + self.logDB(message="Calibration executed successfully for image " + str(self.image_number))
  200 + else:
  201 + self.log("failed")
  202 + self.logDB(message="Could not calibrate image " + str(self.image_number))
  203 + return self.process.returncode
  204 +
  205 + def run(self, plan_id: int, folder: str, image_number: int) -> int:
  206 + if self.start(plan_id, folder, image_number):
  207 + return 1
  208 + self.execute()
  209 + return self.end()
... ...
src/pyros/settings.py
... ... @@ -29,13 +29,15 @@ MODULES_VERSIONS = {
29 29 # Set MYSQL to False if you want to use SQLITE
30 30 # This line MUST NOT be changed at all except from changing True/False
31 31 # (or install_requirements script will become invalid)
32   -MYSQL = False
  32 +MYSQL = True
33 33  
34 34 import os
35 35  
36 36 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
37 37 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
38 38  
  39 +# Output folder for images
  40 +OUTPUT_FOLDER = os.path.join(BASE_DIR, "../images_folder")
39 41  
40 42 # Quick-start development settings - unsuitable for production
41 43 # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
... ... @@ -114,13 +116,10 @@ FIXTURE_DIRS = (
114 116  
115 117 LOGIN_URL = "/"
116 118  
117   -# Database
118   -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
119   -
120   -# EP modif
121   -
  119 +# FOR SIMULATOR -> do not touch this variable
122 120 SIMULATOR = False
123 121  
  122 +# FOR TESTS and SIMULATOR -> do not touch this variable
124 123 CELERY_TEST = False
125 124  
126 125 if not CELERY_TEST:
... ... @@ -260,11 +259,11 @@ CELERY_QUEUES = {
260 259 "monitoring_q": {"exchange": "monitoring_q", "routing_key": "monitoring_q"},
261 260 "majordome_q": {"exchange": "majordome_q", "routing_key": "majordome_q"},
262 261 "analysis_q": {"exchange": "analysis_q", "routing_key": "analysis_q"},
263   - "system_status_q": {"exchange": "system_status_q", "routing_key": "system_status_q"},
264 262 "scheduling_q": {"exchange": "scheduling_q", "routing_key": "scheduling_q"},
265 263 "create_calibrations_q": {"exchange": "create_calibrations_q", "routing_key": "create_calibrations_q"},
  264 + "execute_plan_vis_q": {"exchange": "execute_plan_vis_q", "routing_key": "execute_plan_vis_q"},
  265 + "execute_plan_nir_q": {"exchange": "execute_plan_nir_q", "routing_key": "execute_plan_nir_q"},
266 266 }
267   - # "simulator_q": {"exchange": "simulator_q", "routing_key": "simulator_q"},
268 267  
269 268 CELERY_ROUTES = {
270 269 "alert_manager.tasks.AlertListener": {"queue": "alert_listener_q"},
... ...
src/pyros/settings.py.bak
... ... @@ -29,13 +29,15 @@ MODULES_VERSIONS = {
29 29 # Set MYSQL to False if you want to use SQLITE
30 30 # This line MUST NOT be changed at all except from changing True/False
31 31 # (or install_requirements script will become invalid)
32   -MYSQL = False
  32 +MYSQL = True
33 33  
34 34 import os
35 35  
36 36 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
37 37 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
38 38  
  39 +# Output folder for images
  40 +OUTPUT_FOLDER = os.path.join(BASE_DIR, "../images_folder")
39 41  
40 42 # Quick-start development settings - unsuitable for production
41 43 # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
... ... @@ -114,13 +116,10 @@ FIXTURE_DIRS = (
114 116  
115 117 LOGIN_URL = "/"
116 118  
117   -# Database
118   -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
119   -
120   -# EP modif
121   -
  119 +# FOR SIMULATOR -> do not touch this variable
122 120 SIMULATOR = True
123 121  
  122 +# FOR TESTS and SIMULATOR -> do not touch this variable
124 123 CELERY_TEST = False
125 124  
126 125 if not CELERY_TEST:
... ... @@ -260,11 +259,11 @@ CELERY_QUEUES = {
260 259 "monitoring_q": {"exchange": "monitoring_q", "routing_key": "monitoring_q"},
261 260 "majordome_q": {"exchange": "majordome_q", "routing_key": "majordome_q"},
262 261 "analysis_q": {"exchange": "analysis_q", "routing_key": "analysis_q"},
263   - "system_status_q": {"exchange": "system_status_q", "routing_key": "system_status_q"},
264 262 "scheduling_q": {"exchange": "scheduling_q", "routing_key": "scheduling_q"},
265 263 "create_calibrations_q": {"exchange": "create_calibrations_q", "routing_key": "create_calibrations_q"},
  264 + "execute_plan_vis_q": {"exchange": "execute_plan_vis_q", "routing_key": "execute_plan_vis_q"},
  265 + "execute_plan_nir_q": {"exchange": "execute_plan_nir_q", "routing_key": "execute_plan_nir_q"},
266 266 }
267   - # "simulator_q": {"exchange": "simulator_q", "routing_key": "simulator_q"},
268 267  
269 268 CELERY_ROUTES = {
270 269 "alert_manager.tasks.AlertListener": {"queue": "alert_listener_q"},
... ...
src/scheduler/Scheduler.py
... ... @@ -61,7 +61,7 @@ class Scheduler(IntervalManagement):
61 61 executing = Sequence.objects.filter(status=Sequence.EXECUTING)
62 62 if executing:
63 63 s = Sequence.shs.latest("schedule__created")
64   - adder = s.tsp - secondsToPreciseJulianDate(getPreciseCurrentTime())
  64 + adder = s.tep - secondsToPreciseJulianDate(getPreciseCurrentTime())
65 65 except:
66 66 pass
67 67 self.schedule.plan_night_start = previous_sched.plan_night_start
... ... @@ -183,7 +183,7 @@ class Scheduler(IntervalManagement):
183 183 else:
184 184 sequence_placed = self.tryShiftingSequences(sequence, shs)
185 185 if sequence_placed:
186   - shs.status = Sequence.PENDING
  186 + shs.status = Sequence.PLANNED
187 187 self.decreaseQuota(sequence, sequence.duration)
188 188 else:
189 189 if DEBUG_FILE:
... ... @@ -194,14 +194,14 @@ class Scheduler(IntervalManagement):
194 194  
195 195 def findSequenceBefore(self, interval: Interval):
196 196 for seq, s in self.sequences:
197   - if s.status == Sequence.PENDING:
  197 + if s.status == Sequence.PLANNED:
198 198 if is_nearby_equal(s.tep, interval.start):
199 199 return (seq, s)
200 200 return (None, None)
201 201  
202 202 def findSequenceAfter(self, interval: Interval):
203 203 for seq, s in self.sequences:
204   - if s.status == Sequence.PENDING:
  204 + if s.status == Sequence.PLANNED:
205 205 if is_nearby_equal(s.tsp - self.max_overhead, interval.end):
206 206 return (seq, s)
207 207 return (None, None)
... ... @@ -314,7 +314,7 @@ class Scheduler(IntervalManagement):
314 314 return 0
315 315  
316 316 def logSchedule(self) -> int:
317   - sequences = Sequence.objects.filter(shs__status=Sequence.PENDING).order_by('shs__tsp').distinct()
  317 + sequences = Sequence.objects.filter(shs__status=Sequence.PLANNED).order_by('shs__tsp').distinct()
318 318 self.log("There are %d sequence(s) planned" % len(sequences))
319 319 for sequence in sequences:
320 320 s = sequence.shs.latest("schedule__created")
... ...
src/scheduler/tasks.py
... ... @@ -4,14 +4,17 @@ from scheduler.Scheduler import Scheduler
4 4 from common.models import *
5 5 from utils.JDManipulator import *
6 6 from utils.Logger import setupLogger
  7 +
7 8 log = setupLogger("TaskSched", "TaskSched")
8 9  
9 10 class scheduling(Task):
10 11  
11 12 def run(self, first_schedule=False, alert=False):
12 13  
  14 + task = TaskId.objects.create(task_id=self.request.id, task="scheduling")
13 15 Log.objects.create(agent='Scheduler', message='Start schedule : ' + str(datetime.datetime.now()))
14 16 self.scheduler = Scheduler()
15 17 self.scheduler.setNightLimits(secondsToJulianDate(getNightStart()), secondsToJulianDate(getNightEnd()))
16 18 self.scheduler.makeSchedule()
17   - Log.objects.create(agent='Scheduler', message='Scheduling finished : ' + str(datetime.datetime.now()))
18 19 \ No newline at end of file
  20 + Log.objects.create(agent='Scheduler', message='Scheduling finished : ' + str(datetime.datetime.now()))
  21 + task.delete()
19 22 \ No newline at end of file
... ...
src/utils/JDManipulator.py
... ... @@ -39,6 +39,9 @@ def secondsToJulianDate(time_seconds):
39 39 def secondsToPreciseJulianDate(time_seconds):
40 40 return (Decimal(time_seconds) / 86400 + Decimal(TIMESTAMP_JD))
41 41  
  42 +def julianSecondsToSeconds(seconds_julian):
  43 + return seconds_julian * 86400
  44 +
42 45 def julianDateToSeconds(time_julian):
43 46 return ((time_julian - TIMESTAMP_JD) * 86400)
44 47  
... ...
src/utils/StatusManager.py 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +SITE_CONDITION = "SITE_CONDITION"
  2 +NORMAL = "NORMAL"
  3 +ERROR = "ERROR"
  4 +WEATHER_CONDITION = "SEVERE_WEATHER"
  5 +MINOR = "MINOR_ERROR"
  6 +CRITICAL = "CRITICAL"
  7 +
  8 +def acceptedStatus(status):
  9 + def deco(func):
  10 + def tag_decorator(self, *args, **kwargs):
  11 + for i in status:
  12 + if self.current_status == i:
  13 + return func(self, *args, **kwargs)
  14 + return -1
  15 + return tag_decorator
  16 + return deco
... ...