Commit 729f836f7e2b54e3103a42fd2bf6910b35109f85
Exists in
master
and in
1 other branch
Merge branch 'master' of https://gitlab.irap.omp.eu/epallier/pyros
Showing
9 changed files
with
103 additions
and
21 deletions
Show diff stats
.pydevproject deleted
@@ -1,14 +0,0 @@ | @@ -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,7 +17,7 @@ PORT=8000 | ||
17 | 17 | ||
18 | # String variables | 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 | ASK_MYSQL_USERNAME="-MySQL server login (default $USERNAME): " | 21 | ASK_MYSQL_USERNAME="-MySQL server login (default $USERNAME): " |
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'" | 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 | SQL_FAIL="-Failed to execute database script, probably due to a wrong username or password" | 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,12 +9,17 @@ import os | ||
9 | import observation_manager | 9 | import observation_manager |
10 | 10 | ||
11 | class analysis(Task): | 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 | def run(self, image_name): | 17 | def run(self, image_name): |
14 | # je dois jsute créer mes deux fonctions, une pour les corrections, et l'autre pour les analyses | 18 | # je dois jsute créer mes deux fonctions, une pour les corrections, et l'autre pour les analyses |
15 | print("analysis : ", image_name) | 19 | print("analysis : ", image_name) |
16 | 20 | ||
17 | new_img = self.apply_calibrations(image_name) | 21 | new_img = self.apply_calibrations(image_name) |
22 | + # TODO: Faire ça uniquement si c'est une image provenant d'une alerte | ||
18 | self.do_analysis(new_img) | 23 | self.do_analysis(new_img) |
19 | 24 | ||
20 | # TODO: virer tout ça | 25 | # TODO: virer tout ça |
@@ -25,12 +30,20 @@ class analysis(Task): | @@ -25,12 +30,20 @@ class analysis(Task): | ||
25 | Log.objects.create(agent='Analyzer', message=message) | 30 | Log.objects.create(agent='Analyzer', message=message) |
26 | 31 | ||
27 | def apply_calibrations(self, image_name): | 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 | # TODO: récupérer les bonne images dans le dossier analyzer/calibrations, et les appliquer | 37 | # TODO: récupérer les bonne images dans le dossier analyzer/calibrations, et les appliquer |
29 | # renvoie le nom de l'image calibrée; penser à vérifier que les fichiers de calibration existent à cet endroit | 38 | # renvoie le nom de l'image calibrée; penser à vérifier que les fichiers de calibration existent à cet endroit |
30 | # TODO: copier l'image dans le bon dossier pour le filesync (lien symbolique) | 39 | # TODO: copier l'image dans le bon dossier pour le filesync (lien symbolique) |
31 | return "toto.fitz" | 40 | return "toto.fitz" |
32 | 41 | ||
33 | def do_analysis(self, new_img): | 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 | # TODO: utiliser les programmes scientifiques pour générer les analyses | 47 | # TODO: utiliser les programmes scientifiques pour générer les analyses |
35 | # TODO: copier les résultats des analyses dans le bon dossier pour le filesync (lien symbolique) | 48 | # TODO: copier les résultats des analyses dans le bon dossier pour le filesync (lien symbolique) |
36 | pass | 49 | pass |
37 | \ No newline at end of file | 50 | \ No newline at end of file |
src/common/Device.py
@@ -2,13 +2,23 @@ from pyrosapp.models import * | @@ -2,13 +2,23 @@ from pyrosapp.models import * | ||
2 | 2 | ||
3 | 3 | ||
4 | class DeviceObj(): | 4 | class DeviceObj(): |
5 | + ''' | ||
6 | + Generic object for the communication with all the devices (need inheritance) | ||
7 | + ''' | ||
8 | + | ||
5 | 9 | ||
6 | def __init__(self): | 10 | def __init__(self): |
11 | + ''' | ||
12 | + The messages and their parameters will be defined in the objects that inherits from this class | ||
13 | + ''' | ||
7 | set_msgs = [] | 14 | set_msgs = [] |
8 | get_msgs = [] | 15 | get_msgs = [] |
9 | do_msgs = [] | 16 | do_msgs = [] |
10 | 17 | ||
11 | def set(self, cmd, *args): | 18 | def set(self, cmd, *args): |
19 | + ''' | ||
20 | + Send a SET message to the device | ||
21 | + ''' | ||
12 | msg = [msg for msg in self.set_msgs if msg[0] == cmd] | 22 | msg = [msg for msg in self.set_msgs if msg[0] == cmd] |
13 | if len(msg) == 0: | 23 | if len(msg) == 0: |
14 | raise ValueError("Invalid message argument %s" % (cmd,)) | 24 | raise ValueError("Invalid message argument %s" % (cmd,)) |
@@ -24,6 +34,9 @@ class DeviceObj(): | @@ -24,6 +34,9 @@ class DeviceObj(): | ||
24 | 34 | ||
25 | 35 | ||
26 | def get(self, cmd): | 36 | def get(self, cmd): |
37 | + ''' | ||
38 | + Send a GET message to the device | ||
39 | + ''' | ||
27 | if cmd not in self.get_msgs: | 40 | if cmd not in self.get_msgs: |
28 | raise ValueError("Invalid message argument %s" % (cmd,)) | 41 | raise ValueError("Invalid message argument %s" % (cmd,)) |
29 | 42 | ||
@@ -31,6 +44,9 @@ class DeviceObj(): | @@ -31,6 +44,9 @@ class DeviceObj(): | ||
31 | 44 | ||
32 | 45 | ||
33 | def do(self, cmd, *args): | 46 | def do(self, cmd, *args): |
47 | + ''' | ||
48 | + Send a DO message to the device | ||
49 | + ''' | ||
34 | msg = [msg for msg in self.do_msgs if msg[0] == cmd] | 50 | msg = [msg for msg in self.do_msgs if msg[0] == cmd] |
35 | if len(msg) == 0: | 51 | if len(msg) == 0: |
36 | raise ValueError("Invalid message argument %s" % (cmd,)) | 52 | raise ValueError("Invalid message argument %s" % (cmd,)) |
src/majordome/tasks.py
@@ -11,8 +11,18 @@ from DateTime import DateTime | @@ -11,8 +11,18 @@ from DateTime import DateTime | ||
11 | import scheduler | 11 | import scheduler |
12 | 12 | ||
13 | DAILY_SECOND = 1 / 86400 | 13 | DAILY_SECOND = 1 / 86400 |
14 | +MAX_WAIT = 180 | ||
14 | 15 | ||
15 | class execute_sequence(Task): | 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 | def run(self, shs_pk): | 27 | def run(self, shs_pk): |
18 | # on ne supprime JAMAIS un séquence en cours, donc je peux la virer des tasks dès le début | 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,7 +43,7 @@ class execute_sequence(Task): | ||
33 | 43 | ||
34 | countdown = self.get_countdown(shs, sequence) | 44 | countdown = self.get_countdown(shs, sequence) |
35 | 45 | ||
36 | - if countdown > 180 * DAILY_SECOND: | 46 | + if countdown > MAX_WAIT * DAILY_SECOND: |
37 | scheduler.tasks.scheduling.delay(first_schedule=True, alert=False) # TODO : changer le first_schedule à False | 47 | scheduler.tasks.scheduling.delay(first_schedule=True, alert=False) # TODO : changer le first_schedule à False |
38 | return | 48 | return |
39 | 49 | ||
@@ -116,6 +126,10 @@ class execute_sequence(Task): | @@ -116,6 +126,10 @@ class execute_sequence(Task): | ||
116 | return countdown | 126 | return countdown |
117 | 127 | ||
118 | class system_pause(Task): | 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 | def run(self): | 134 | def run(self): |
121 | time.sleep(5) | 135 | time.sleep(5) |
@@ -123,14 +137,22 @@ class system_pause(Task): | @@ -123,14 +137,22 @@ class system_pause(Task): | ||
123 | 137 | ||
124 | 138 | ||
125 | class system_restart(Task): | 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 | def run(self): | 144 | def run(self): |
128 | time.sleep(5) | 145 | time.sleep(5) |
129 | print("system_restart") | 146 | print("system_restart") |
130 | 147 | ||
131 | 148 | ||
132 | class change_obs_conditions(Task): | 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 | def run(self): | 155 | def run(self): |
156 | + # important : penser à rendre les quotas aux users | ||
135 | time.sleep(5) | 157 | time.sleep(5) |
136 | print("change_obs_conditions") | 158 | print("change_obs_conditions") |
src/monitoring/tasks.py
@@ -16,6 +16,16 @@ import time | @@ -16,6 +16,16 @@ import time | ||
16 | TIMER_CHECK = 10 # in seconds | 16 | TIMER_CHECK = 10 # in seconds |
17 | 17 | ||
18 | class monitoring(Task): | 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 | def run(self): | 30 | def run(self): |
21 | self.configure_instruments() | 31 | self.configure_instruments() |
@@ -34,6 +44,9 @@ class monitoring(Task): | @@ -34,6 +44,9 @@ class monitoring(Task): | ||
34 | self.timers_loop() | 44 | self.timers_loop() |
35 | 45 | ||
36 | def configure_instruments(self): | 46 | def configure_instruments(self): |
47 | + ''' | ||
48 | + Creates the communication objects for each instrument, and give them the basic configurations. | ||
49 | + ''' | ||
37 | self.tel = TelescopeObj() | 50 | self.tel = TelescopeObj() |
38 | self.vis_camera = VISCameraObj() | 51 | self.vis_camera = VISCameraObj() |
39 | self.nir_camera = NIRCameraObj() | 52 | self.nir_camera = NIRCameraObj() |
@@ -49,10 +62,16 @@ class monitoring(Task): | @@ -49,10 +62,16 @@ class monitoring(Task): | ||
49 | # Cette fonction dépendra du moyen de partager les connections des instruments | 62 | # Cette fonction dépendra du moyen de partager les connections des instruments |
50 | 63 | ||
51 | def connect_to_plc(self): | 64 | def connect_to_plc(self): |
65 | + ''' | ||
66 | + Initialize the connection to the PLC | ||
67 | + ''' | ||
52 | # TODO: initialiser la co avec le plc et stocker les identifiants de la co dans self | 68 | # TODO: initialiser la co avec le plc et stocker les identifiants de la co dans self |
53 | pass | 69 | pass |
54 | 70 | ||
55 | def update_software_versions(self): | 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 | versions = settings.MODULES_VERSIONS | 75 | versions = settings.MODULES_VERSIONS |
57 | 76 | ||
58 | for module, version in versions.items(): | 77 | for module, version in versions.items(): |
@@ -65,12 +84,18 @@ class monitoring(Task): | @@ -65,12 +84,18 @@ class monitoring(Task): | ||
65 | # TODO: envoyer les versions à l'IC | 84 | # TODO: envoyer les versions à l'IC |
66 | 85 | ||
67 | def get_night_start_end(self): | 86 | def get_night_start_end(self): |
87 | + ''' | ||
88 | + Computes the beginning and the end of the following (or current) night | ||
89 | + ''' | ||
68 | # TODO: utiliser un logiciel by AK pour stocker en local le début et la fin de la nuit (on est peut-être dedans) | 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 | self.night_start = time.time() + 180 / 86400 | 91 | self.night_start = time.time() + 180 / 86400 |
70 | self.night_end = time.time() + 360 / 86400 | 92 | self.night_end = time.time() + 360 / 86400 |
71 | pass | 93 | pass |
72 | 94 | ||
73 | def wait_devices_ready(self): | 95 | def wait_devices_ready(self): |
96 | + ''' | ||
97 | + Loop to wait for the device to be idle avec the starting configurations. | ||
98 | + ''' | ||
74 | # TODO: faire une boucle pour attendre que les devices soient prêts | 99 | # TODO: faire une boucle pour attendre que les devices soient prêts |
75 | pass | 100 | pass |
76 | 101 |
src/observation_manager/tasks.py
@@ -14,6 +14,10 @@ import os | @@ -14,6 +14,10 @@ import os | ||
14 | IMAGES_FOLDER = 'simulation_images' | 14 | IMAGES_FOLDER = 'simulation_images' |
15 | 15 | ||
16 | class execute_plan_vis(Task): | 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 | def run(self, plan_id, countdown): | 22 | def run(self, plan_id, countdown): |
19 | # print("ex plan : ", self.request.id) | 23 | # print("ex plan : ", self.request.id) |
@@ -48,6 +52,9 @@ class execute_plan_vis(Task): | @@ -48,6 +52,9 @@ class execute_plan_vis(Task): | ||
48 | Log.objects.create(agent='Observation manager', message=message) | 52 | Log.objects.create(agent='Observation manager', message=message) |
49 | 53 | ||
50 | def set_camera(self, cam, plan): | 54 | def set_camera(self, cam, plan): |
55 | + ''' | ||
56 | + Set the camera configuration | ||
57 | + ''' | ||
51 | 58 | ||
52 | cam.filter_wheel.set("FILTER", FilterW.FilterEnum.h) | 59 | cam.filter_wheel.set("FILTER", FilterW.FilterEnum.h) |
53 | cam.filter_wheel.do("CHANGE_FILTER") | 60 | cam.filter_wheel.do("CHANGE_FILTER") |
@@ -62,7 +69,9 @@ class execute_plan_vis(Task): | @@ -62,7 +69,9 @@ class execute_plan_vis(Task): | ||
62 | cam.set("BINNING", 300, 300) | 69 | cam.set("BINNING", 300, 300) |
63 | 70 | ||
64 | def wait_camera_ready(self, cam): | 71 | def wait_camera_ready(self, cam): |
65 | - | 72 | + ''' |
73 | + Loop to wait for the configuration to be done | ||
74 | + ''' | ||
66 | st = 0 | 75 | st = 0 |
67 | while st == 0: | 76 | while st == 0: |
68 | # TODO: uncomment quand on caura la télescope en global | 77 | # TODO: uncomment quand on caura la télescope en global |
@@ -77,7 +86,9 @@ class execute_plan_vis(Task): | @@ -77,7 +86,9 @@ class execute_plan_vis(Task): | ||
77 | 86 | ||
78 | 87 | ||
79 | def wait_camera_finished(self, cam): | 88 | def wait_camera_finished(self, cam): |
80 | - | 89 | + ''' |
90 | + Loop to wait for the observation to be finished | ||
91 | + ''' | ||
81 | # countdown = cam.get("TIMER") | 92 | # countdown = cam.get("TIMER") |
82 | # while countdown > 5: | 93 | # while countdown > 5: |
83 | # time.sleep(5) | 94 | # time.sleep(5) |
@@ -96,6 +107,10 @@ class execute_plan_vis(Task): | @@ -96,6 +107,10 @@ class execute_plan_vis(Task): | ||
96 | 107 | ||
97 | 108 | ||
98 | class execute_plan_nir(Task): | 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 | def run(self, plan_id, countdown): | 115 | def run(self, plan_id, countdown): |
101 | # print("ex plan : ", self.request.id) | 116 | # print("ex plan : ", self.request.id) |
@@ -181,4 +196,4 @@ class execute_calibrations(Task): | @@ -181,4 +196,4 @@ class execute_calibrations(Task): | ||
181 | When they are all finished, it creates the 'super' calibration files. | 196 | When they are all finished, it creates the 'super' calibration files. |
182 | ''' | 197 | ''' |
183 | def run(self): | 198 | def run(self): |
184 | - pass | ||
185 | \ No newline at end of file | 199 | \ No newline at end of file |
200 | + pass |
src/routine_manager/RequestSerializer.py
@@ -84,6 +84,10 @@ class RequestSerializer(): | @@ -84,6 +84,10 @@ class RequestSerializer(): | ||
84 | return "" | 84 | return "" |
85 | 85 | ||
86 | def unserialize_request(self, request): | 86 | def unserialize_request(self, request): |
87 | + ''' | ||
88 | + Receives an xml.etree request and unserialize it | ||
89 | + ''' | ||
90 | + | ||
87 | if request.tag != "request": | 91 | if request.tag != "request": |
88 | return "Main object should be a request (found %s instead)" % (request.tag,) | 92 | return "Main object should be a request (found %s instead)" % (request.tag,) |
89 | possible_attribs = ["name", "scientific_program", "target_type"] | 93 | possible_attribs = ["name", "scientific_program", "target_type"] |
src/scheduler/tasks.py
@@ -35,6 +35,7 @@ class scheduling(Task): | @@ -35,6 +35,7 @@ class scheduling(Task): | ||
35 | TaskId.objects.create(task_id=res.id, task="execute_sequence") | 35 | TaskId.objects.create(task_id=res.id, task="execute_sequence") |
36 | 36 | ||
37 | def determine_schedule_limits(self): | 37 | def determine_schedule_limits(self): |
38 | + # TODO: virer ce système là pour la production | ||
38 | sequences = Sequence.objects.all() | 39 | sequences = Sequence.objects.all() |
39 | ''' Find the most recurrent night in all sequences ''' | 40 | ''' Find the most recurrent night in all sequences ''' |
40 | days = {} | 41 | days = {} |