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 | -<?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 = {} | ... | ... |