Commit 729f836f7e2b54e3103a42fd2bf6910b35109f85

Authored by Etienne Pallier
2 parents 0393f729 4778e01f
Exists in master and in 1 other branch dev

Merge branch 'master' of https://gitlab.irap.omp.eu/epallier/pyros

.pydevproject deleted
... ... @@ -1,14 +0,0 @@
1   -<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2   -<?eclipse-pydev version="1.0"?><pydev_project>
3   -<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">pyros_venv_py3</pydev_property>
4   -<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 3.0</pydev_property>
5   -<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
6   -<path>/${PROJECT_DIR_NAME}/src</path>
7   -</pydev_pathproperty>
8   -<pydev_variables_property name="org.python.pydev.PROJECT_VARIABLE_SUBSTITUTION">
9   -<key>DJANGO_MANAGE_LOCATION</key>
10   -<value>src/manage.py</value>
11   -<key>DJANGO_SETTINGS_MODULE</key>
12   -<value>pyros.settings</value>
13   -</pydev_variables_property>
14   -</pydev_project>
install/install_requirements.sh
... ... @@ -17,7 +17,7 @@ PORT=8000
17 17  
18 18 # String variables
19 19  
20   -ASK_USE_MYSQL="-Do you wish to use mysql in your project ? Only if mysql-server is installed. (Y/N)"
  20 +ASK_USE_MYSQL="-Do you wish to use mysql in your project ? Only if mysql-server is installed. (Default: No) (Y/N)"
21 21 ASK_MYSQL_USERNAME="-MySQL server login (default $USERNAME): "
22 22 SQL_SCRIPT="CREATE DATABASE IF NOT EXISTS pyros; GRANT USAGE ON *.* TO '$DB_USER'; DROP USER '$DB_USER'; GRANT ALL ON pyros.* TO '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD'; GRANT ALL ON test_pyros.* TO '$DB_USER'@'localhost'"
23 23 SQL_FAIL="-Failed to execute database script, probably due to a wrong username or password"
... ...
src/analyzer/tasks.py
... ... @@ -9,12 +9,17 @@ import os
9 9 import observation_manager
10 10  
11 11 class analysis(Task):
  12 + '''
  13 + Gets the name of the image to analyze in parameter
  14 + It applies the calibrations, then makes the
  15 + '''
12 16  
13 17 def run(self, image_name):
14 18 # je dois jsute créer mes deux fonctions, une pour les corrections, et l'autre pour les analyses
15 19 print("analysis : ", image_name)
16 20  
17 21 new_img = self.apply_calibrations(image_name)
  22 + # TODO: Faire ça uniquement si c'est une image provenant d'une alerte
18 23 self.do_analysis(new_img)
19 24  
20 25 # TODO: virer tout ça
... ... @@ -25,12 +30,20 @@ class analysis(Task):
25 30 Log.objects.create(agent='Analyzer', message=message)
26 31  
27 32 def apply_calibrations(self, image_name):
  33 + '''
  34 + Uses the calibration files to correct the image (changes the image bytes)
  35 + Send the new images to the FSC
  36 + '''
28 37 # TODO: récupérer les bonne images dans le dossier analyzer/calibrations, et les appliquer
29 38 # renvoie le nom de l'image calibrée; penser à vérifier que les fichiers de calibration existent à cet endroit
30 39 # TODO: copier l'image dans le bon dossier pour le filesync (lien symbolique)
31 40 return "toto.fitz"
32 41  
33 42 def do_analysis(self, new_img):
  43 + '''
  44 + Use the scientific softwares to create analysis files (doesn't change the image bytes)
  45 + Sends the results to the FSC
  46 + '''
34 47 # TODO: utiliser les programmes scientifiques pour générer les analyses
35 48 # TODO: copier les résultats des analyses dans le bon dossier pour le filesync (lien symbolique)
36 49 pass
37 50 \ No newline at end of file
... ...
src/common/Device.py
... ... @@ -2,13 +2,23 @@ from pyrosapp.models import *
2 2  
3 3  
4 4 class DeviceObj():
  5 + '''
  6 + Generic object for the communication with all the devices (need inheritance)
  7 + '''
  8 +
5 9  
6 10 def __init__(self):
  11 + '''
  12 + The messages and their parameters will be defined in the objects that inherits from this class
  13 + '''
7 14 set_msgs = []
8 15 get_msgs = []
9 16 do_msgs = []
10 17  
11 18 def set(self, cmd, *args):
  19 + '''
  20 + Send a SET message to the device
  21 + '''
12 22 msg = [msg for msg in self.set_msgs if msg[0] == cmd]
13 23 if len(msg) == 0:
14 24 raise ValueError("Invalid message argument %s" % (cmd,))
... ... @@ -24,6 +34,9 @@ class DeviceObj():
24 34  
25 35  
26 36 def get(self, cmd):
  37 + '''
  38 + Send a GET message to the device
  39 + '''
27 40 if cmd not in self.get_msgs:
28 41 raise ValueError("Invalid message argument %s" % (cmd,))
29 42  
... ... @@ -31,6 +44,9 @@ class DeviceObj():
31 44  
32 45  
33 46 def do(self, cmd, *args):
  47 + '''
  48 + Send a DO message to the device
  49 + '''
34 50 msg = [msg for msg in self.do_msgs if msg[0] == cmd]
35 51 if len(msg) == 0:
36 52 raise ValueError("Invalid message argument %s" % (cmd,))
... ...
src/majordome/tasks.py
... ... @@ -11,8 +11,18 @@ from DateTime import DateTime
11 11 import scheduler
12 12  
13 13 DAILY_SECOND = 1 / 86400
  14 +MAX_WAIT = 180
14 15  
15 16 class execute_sequence(Task):
  17 + '''
  18 + Task to handle the execution of ONE sequence
  19 + It receives the shs' id in parameter.
  20 + It prepairs the instruments and cut the sequence in plan. Then the execute_plan tasks are created.
  21 +
  22 + If possible, it advances the sequence start.
  23 + If the sequence can't start within MAX_WAIT seconds, it relaunches a scheduling
  24 + '''
  25 +
16 26  
17 27 def run(self, shs_pk):
18 28 # on ne supprime JAMAIS un séquence en cours, donc je peux la virer des tasks dès le début
... ... @@ -33,7 +43,7 @@ class execute_sequence(Task):
33 43  
34 44 countdown = self.get_countdown(shs, sequence)
35 45  
36   - if countdown > 180 * DAILY_SECOND:
  46 + if countdown > MAX_WAIT * DAILY_SECOND:
37 47 scheduler.tasks.scheduling.delay(first_schedule=True, alert=False) # TODO : changer le first_schedule à False
38 48 return
39 49  
... ... @@ -116,6 +126,10 @@ class execute_sequence(Task):
116 126 return countdown
117 127  
118 128 class system_pause(Task):
  129 + '''
  130 + Task called by the monitoring in case of problem.
  131 + It stops the system and the instruments.
  132 + '''
119 133  
120 134 def run(self):
121 135 time.sleep(5)
... ... @@ -123,14 +137,22 @@ class system_pause(Task):
123 137  
124 138  
125 139 class system_restart(Task):
126   -
  140 + '''
  141 + Task called by the monitoring when there is no more problem.
  142 + Should just make a scheduling.
  143 + '''
127 144 def run(self):
128 145 time.sleep(5)
129 146 print("system_restart")
130 147  
131 148  
132 149 class change_obs_conditions(Task):
133   -
  150 + '''
  151 + Task called by the monitoring when the obs condition have changed.
  152 + It reads them in the DB and changes the sequences status in consequence.
  153 + If needed, relaunches a scheduling
  154 + '''
134 155 def run(self):
  156 + # important : penser à rendre les quotas aux users
135 157 time.sleep(5)
136 158 print("change_obs_conditions")
... ...
src/monitoring/tasks.py
... ... @@ -16,6 +16,16 @@ import time
16 16 TIMER_CHECK = 10 # in seconds
17 17  
18 18 class monitoring(Task):
  19 + '''
  20 + Infinite task created at the program's start.
  21 + It initilize all the external connections, and starts the alert_listener.
  22 +
  23 + This is the place to put the starting configurations.
  24 +
  25 + Once the starting configurations are done, it becomes a loop that checks the PLC and instruments status.
  26 + It also handles the beginning and the end of the night, recalculating them at each end of night.
  27 + '''
  28 +
19 29  
20 30 def run(self):
21 31 self.configure_instruments()
... ... @@ -34,6 +44,9 @@ class monitoring(Task):
34 44 self.timers_loop()
35 45  
36 46 def configure_instruments(self):
  47 + '''
  48 + Creates the communication objects for each instrument, and give them the basic configurations.
  49 + '''
37 50 self.tel = TelescopeObj()
38 51 self.vis_camera = VISCameraObj()
39 52 self.nir_camera = NIRCameraObj()
... ... @@ -49,10 +62,16 @@ class monitoring(Task):
49 62 # Cette fonction dépendra du moyen de partager les connections des instruments
50 63  
51 64 def connect_to_plc(self):
  65 + '''
  66 + Initialize the connection to the PLC
  67 + '''
52 68 # TODO: initialiser la co avec le plc et stocker les identifiants de la co dans self
53 69 pass
54 70  
55 71 def update_software_versions(self):
  72 + '''
  73 + Reads the softwares versions in the settings.py, store them in the DB and send them to the IC.
  74 + '''
56 75 versions = settings.MODULES_VERSIONS
57 76  
58 77 for module, version in versions.items():
... ... @@ -65,12 +84,18 @@ class monitoring(Task):
65 84 # TODO: envoyer les versions à l'IC
66 85  
67 86 def get_night_start_end(self):
  87 + '''
  88 + Computes the beginning and the end of the following (or current) night
  89 + '''
68 90 # TODO: utiliser un logiciel by AK pour stocker en local le début et la fin de la nuit (on est peut-être dedans)
69 91 self.night_start = time.time() + 180 / 86400
70 92 self.night_end = time.time() + 360 / 86400
71 93 pass
72 94  
73 95 def wait_devices_ready(self):
  96 + '''
  97 + Loop to wait for the device to be idle avec the starting configurations.
  98 + '''
74 99 # TODO: faire une boucle pour attendre que les devices soient prêts
75 100 pass
76 101  
... ...
src/observation_manager/tasks.py
... ... @@ -14,6 +14,10 @@ import os
14 14 IMAGES_FOLDER = 'simulation_images'
15 15  
16 16 class execute_plan_vis(Task):
  17 + '''
  18 + Gives the orders to the instruments to retrieve the image(s) of a plan VIS.
  19 + Send hte images to the analyzer
  20 + '''
17 21  
18 22 def run(self, plan_id, countdown):
19 23 # print("ex plan : ", self.request.id)
... ... @@ -48,6 +52,9 @@ class execute_plan_vis(Task):
48 52 Log.objects.create(agent='Observation manager', message=message)
49 53  
50 54 def set_camera(self, cam, plan):
  55 + '''
  56 + Set the camera configuration
  57 + '''
51 58  
52 59 cam.filter_wheel.set("FILTER", FilterW.FilterEnum.h)
53 60 cam.filter_wheel.do("CHANGE_FILTER")
... ... @@ -62,7 +69,9 @@ class execute_plan_vis(Task):
62 69 cam.set("BINNING", 300, 300)
63 70  
64 71 def wait_camera_ready(self, cam):
65   -
  72 + '''
  73 + Loop to wait for the configuration to be done
  74 + '''
66 75 st = 0
67 76 while st == 0:
68 77 # TODO: uncomment quand on caura la télescope en global
... ... @@ -77,7 +86,9 @@ class execute_plan_vis(Task):
77 86  
78 87  
79 88 def wait_camera_finished(self, cam):
80   -
  89 + '''
  90 + Loop to wait for the observation to be finished
  91 + '''
81 92 # countdown = cam.get("TIMER")
82 93 # while countdown > 5:
83 94 # time.sleep(5)
... ... @@ -96,6 +107,10 @@ class execute_plan_vis(Task):
96 107  
97 108  
98 109 class execute_plan_nir(Task):
  110 + '''
  111 + Gives the orders to the instruments to retrieve the image(s) of a plan NIR.
  112 + Send the images to the analyzer
  113 + '''
99 114  
100 115 def run(self, plan_id, countdown):
101 116 # print("ex plan : ", self.request.id)
... ... @@ -181,4 +196,4 @@ class execute_calibrations(Task):
181 196 When they are all finished, it creates the 'super' calibration files.
182 197 '''
183 198 def run(self):
184   - pass
185 199 \ No newline at end of file
  200 + pass
... ...
src/routine_manager/RequestSerializer.py
... ... @@ -84,6 +84,10 @@ class RequestSerializer():
84 84 return ""
85 85  
86 86 def unserialize_request(self, request):
  87 + '''
  88 + Receives an xml.etree request and unserialize it
  89 + '''
  90 +
87 91 if request.tag != "request":
88 92 return "Main object should be a request (found %s instead)" % (request.tag,)
89 93 possible_attribs = ["name", "scientific_program", "target_type"]
... ...
src/scheduler/tasks.py
... ... @@ -35,6 +35,7 @@ class scheduling(Task):
35 35 TaskId.objects.create(task_id=res.id, task="execute_sequence")
36 36  
37 37 def determine_schedule_limits(self):
  38 + # TODO: virer ce système là pour la production
38 39 sequences = Sequence.objects.all()
39 40 ''' Find the most recurrent night in all sequences '''
40 41 days = {}
... ...