Commit ff448d4329b07d1ced978bc76f93bcff8b1cc995
1 parent
675fb3d5
Exists in
master
and in
1 other branch
Update
Showing
29 changed files
with
208 additions
and
99 deletions
Show diff stats
... | ... | @@ -0,0 +1 @@ |
1 | +test | ... | ... |
pyros.py
... | ... | @@ -363,6 +363,18 @@ class Pyros(AManager): |
363 | 363 | help_message = "python neo.py" |
364 | 364 | init_fixture = "initial_fixture.json" |
365 | 365 | |
366 | + def signal_handler(self, signal, frame): | |
367 | + self.printFullTerm(Colors.WARNING, "Ctrl-c catched") | |
368 | + for p in self.subproc: | |
369 | + proc, name = p | |
370 | + self.printColor(Colors.BLUE, "Killing process " + str(name)) | |
371 | + proc.kill() | |
372 | + if self.current_command == "simulator" or self.current_command == "simulator_development": | |
373 | + self.changeDirectory(self.path_dir_file) | |
374 | + self.kill_simulation() | |
375 | + self.printFullTerm(Colors.WARNING, "Exiting") | |
376 | + sys.exit(0) | |
377 | + | |
366 | 378 | def install(self): |
367 | 379 | if (self.system == "Windows"): |
368 | 380 | self.execProcess("python install/install.py install") |
... | ... | @@ -496,6 +508,7 @@ class Pyros(AManager): |
496 | 508 | def simulator_development(self): |
497 | 509 | self.changeDirectory("src") |
498 | 510 | self.replacePatternInFile("CELERY_TEST = False", "CELERY_TEST = True", "pyros/settings.py") |
511 | + self.replacePatternInFile("SIMULATOR = False", "SIMULATOR = True", "pyros/settings.py") | |
499 | 512 | self.execProcess("rm -f testdb.sqlite3") |
500 | 513 | self.changeDirectory("..") |
501 | 514 | self.migrate() |
... | ... | @@ -535,6 +548,7 @@ class Pyros(AManager): |
535 | 548 | def simulator(self): |
536 | 549 | self.changeDirectory("src") |
537 | 550 | self.replacePatternInFile("CELERY_TEST = False", "CELERY_TEST = True", "pyros/settings.py") |
551 | + self.replacePatternInFile("SIMULATOR = False", "SIMULATOR = True", "pyros/settings.py") | |
538 | 552 | self.execProcess("rm -f testdb.sqlite3") |
539 | 553 | self.changeDirectory("..") |
540 | 554 | self.migrate() |
... | ... | @@ -569,6 +583,7 @@ class Pyros(AManager): |
569 | 583 | def kill_simulation(self): |
570 | 584 | self.changeDirectory("src") |
571 | 585 | self.replacePatternInFile("CELERY_TEST = True", "CELERY_TEST = False", "pyros/settings.py") |
586 | + self.replacePatternInFile("SIMULATOR = True", "SIMULATOR = False", "pyros/settings.py") | |
572 | 587 | if (self.system == "Windows"): |
573 | 588 | self.execProcessAsync("taskkill /f /im python.exe") |
574 | 589 | self.execProcessAsync("rm -f testdb.sqlite3") |
... | ... | @@ -638,7 +653,7 @@ class Pyros(AManager): |
638 | 653 | "update": self.update, |
639 | 654 | "server": self.server, |
640 | 655 | "clean": self.clean, |
641 | - "simulator_scheduler": self.simulator_development, | |
656 | + "simulator_development": self.simulator_development, | |
642 | 657 | "clean_logs": self.clean_logs, |
643 | 658 | "test": self.test, |
644 | 659 | "migrate": self.migrate, |
... | ... | @@ -677,7 +692,7 @@ class Pyros(AManager): |
677 | 692 | "start": "Stop the celery workers then the web server", |
678 | 693 | "stop": "stops the celery workers", |
679 | 694 | "simulator": "Launch a simulation", |
680 | - "simulator_scheduler": "Simulation for the scheduler only", | |
695 | + "simulator_development": "Simulation for the scheduler only", | |
681 | 696 | "kill_simulation": "kill the simulators / celery workers / web server", |
682 | 697 | "sims_launch": "Launch only the simulators", |
683 | 698 | } | ... | ... |
simulators/config/conf.json
... | ... | @@ -40,6 +40,10 @@ |
40 | 40 | "userSimulator" : "routine_request_10.xml" |
41 | 41 | }, |
42 | 42 | { |
43 | + "time" : 200, | |
44 | + "userSimulator" : "rou" | |
45 | + }, | |
46 | + { | |
43 | 47 | "time" : 35, |
44 | 48 | "plcSimulator" : {"rain" : 5, "cloud" : 3} |
45 | 49 | }, |
... | ... | @@ -62,5 +66,9 @@ |
62 | 66 | { |
63 | 67 | "time" : 42, |
64 | 68 | "telescopeSimulator" : {"status" : "ERROR"} |
69 | + }, | |
70 | + { | |
71 | + "time" : 200, | |
72 | + "telescopeSimulator" : {"status" : "OFF"} | |
65 | 73 | } |
66 | 74 | ] | ... | ... |
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="6000" jd2="18000" name="Sequence1 (200secs)" target_coords="10"> | |
3 | + <sequence duration="200" jd1="15" jd2="60000" name="Sequence1 (200secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
simulators/resources/routine_request_02.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="100" jd1="6000" jd2="18000" name="Sequence2 (100 secs)" target_coords="10"> | |
3 | + <sequence duration="100" jd1="60" jd2="60000" name="Sequence2 (100 secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="100" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
simulators/resources/routine_request_03.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="40" jd1="10000" jd2="15000" name="Sequence3 (40secs)" target_coords="10"> | |
3 | + <sequence duration="40" jd1="60" jd2="60000" name="Sequence3 (40secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="40" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
simulators/resources/routine_request_04.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="500" jd1="12000" jd2="25000" name="Sequence 4 (500secs)" target_coords="10"> | |
3 | + <sequence duration="500" jd1="12000" jd2="60000" name="Sequence 4 (500secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="500" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
simulators/resources/routine_request_05.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="10" jd1="6000" jd2="22000" name="Sequence5 (10secs)" target_coords="10"> | |
3 | + <sequence duration="10" jd1="60" jd2="60000" name="Sequence5 (10secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="10" filter="First infrared filter" name="plan vis" nb_images="1"/> |
6 | 6 | </album> | ... | ... |
simulators/resources/routine_request_06.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="18000" name="Sequence6 (200 secs)" target_coords="10"> | |
3 | + <sequence duration="200" jd1="6000" jd2="60000" name="Sequence6 (200 secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
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="18000" name="Sequence7 (200secs)" target_coords="10"> | |
3 | + <sequence duration="200" jd1="6000" jd2="60000" name="Sequence7 (200secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
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="6000" jd2="18000" name="Sequence8 (200secs)" target_coords="10"> | |
3 | + <sequence duration="200" jd1="19000" jd2="60000" name="Sequence8 (200secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
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="6000" jd2="18000" name="Sequence9 (200secs)" target_coords="10"> | |
3 | + <sequence duration="200" jd1="1000" jd2="60000" name="Sequence9 (200secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
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="6000" jd2="18000" name="Sequence10 (200secs)" target_coords="10"> | |
3 | + <sequence duration="200" jd1="200" jd2="60000" name="Sequence10 (200secs)" target_coords="10"> | |
4 | 4 | <album detector="Visible camera" name="alb"> |
5 | 5 | <plan duration="200" filter="First infrared filter" name="New plan" nb_images="5"/> |
6 | 6 | </album> | ... | ... |
src/common/RequestBuilder.py
... | ... | @@ -31,7 +31,7 @@ class RequestBuilder(): |
31 | 31 | raise RuntimeError( |
32 | 32 | "start_new_request MUST be invoked before creating any sequence") |
33 | 33 | |
34 | - sequence = Sequence(name=name, status=Sequence.OBSERVABLE, priority=priority, | |
34 | + sequence = Sequence(name=name, status=Sequence.TOBEPLANNED, priority=priority, | |
35 | 35 | jd1=jd1, jd2=jd2, t_prefered=t_prefered, duration=duration) |
36 | 36 | self.sequences[self.sequence_id] = sequence |
37 | 37 | self.sequence_id += 1 | ... | ... |
src/common/models.py
... | ... | @@ -367,20 +367,19 @@ class Sequence(models.Model): |
367 | 367 | INCOMPLETE = "INCPL" |
368 | 368 | COMPLETE = "CPL" |
369 | 369 | TOBEPLANNED = "TBP" |
370 | - OBSERVABLE = "OBS" | |
371 | - UNPLANNABLE = "UNPLN" | |
370 | + PLANNED = "PLND" | |
372 | 371 | PENDING = "PNDG" |
373 | - EXECUTED = "EXD" | |
374 | 372 | EXECUTING = "EXING" |
373 | + EXECUTED = "EXD" | |
375 | 374 | REJECTED = "RJTD" |
376 | - CANCELLED = "CNCLD" | |
377 | 375 | INVALID = "INVL" |
378 | - DEVICE_ERROR = "DVER" | |
376 | + CANCELLED = "CNCLD" | |
377 | + UNPLANNABLE = "UNPLN" | |
379 | 378 | STATUS_CHOICES = ( |
380 | 379 | (INCOMPLETE, "Incomplete"), |
381 | 380 | (COMPLETE, "Complete"), |
382 | 381 | (TOBEPLANNED, "To be planned"), |
383 | - (OBSERVABLE, "Observable"), | |
382 | + (PLANNED, "Planned"), | |
384 | 383 | (UNPLANNABLE, "Unplannable"), |
385 | 384 | (PENDING, "Pending"), |
386 | 385 | (EXECUTED, "Executed"), |
... | ... | @@ -388,7 +387,6 @@ class Sequence(models.Model): |
388 | 387 | (REJECTED, "Rejected"), |
389 | 388 | (CANCELLED, "Cancelled"), |
390 | 389 | (INVALID, "Invalid"), |
391 | - (DEVICE_ERROR, "Device error"), | |
392 | 390 | ) |
393 | 391 | |
394 | 392 | request = models.ForeignKey( | ... | ... |
src/majordome/tasks.py
... | ... | @@ -16,6 +16,7 @@ from django.conf import settings |
16 | 16 | from utils.JDManipulator import * |
17 | 17 | import utils.Logger as L |
18 | 18 | |
19 | +DEBUG_FILE = False | |
19 | 20 | log = L.setupLogger("MajordomeTaskLogger", "Majordome") |
20 | 21 | |
21 | 22 | ''' |
... | ... | @@ -127,7 +128,7 @@ class Majordome(Task): |
127 | 128 | "schedule": self.timer_schedule, |
128 | 129 | "sequence": self.timer_sequence |
129 | 130 | } |
130 | - if (settings.DEBUG): | |
131 | + if (settings.DEBUG and DEBUG_FILE): | |
131 | 132 | log.info("Majordome started with timers : " + str(self.timers)) |
132 | 133 | # Functions called during the loop |
133 | 134 | self.functions = { |
... | ... | @@ -162,10 +163,10 @@ class Majordome(Task): |
162 | 163 | self.logDB("Executing timer " + str(timer_name)) |
163 | 164 | self.functions[timer_name]() |
164 | 165 | else: |
165 | - if (settings.DEBUG): | |
166 | + if (settings.DEBUG and DEBUG_FILE): | |
166 | 167 | log.info("Timer : " + str(timer_name) + "is not known by the Majordome") |
167 | 168 | self.logDB("Timer " + str(timer_name) + " unknown") |
168 | - if (settings.DEBUG): | |
169 | + if (settings.DEBUG and DEBUG_FILE): | |
169 | 170 | log.info("Timer : " + str(timer_name) + " executed") |
170 | 171 | return (0) |
171 | 172 | |
... | ... | @@ -175,7 +176,7 @@ class Majordome(Task): |
175 | 176 | site_status = SiteWatch.objects.latest('updated') |
176 | 177 | weather_status = WeatherWatch.objects.latest('updated') |
177 | 178 | except ObjectDoesNotExist: |
178 | - if (settings.DEBUG): | |
179 | + if (settings.DEBUG and DEBUG_FILE): | |
179 | 180 | log.info("No site_status or weather_status found in database") |
180 | 181 | return (1) |
181 | 182 | self.handlePLC(site_status, weather_status) |
... | ... | @@ -192,29 +193,26 @@ class Majordome(Task): |
192 | 193 | |
193 | 194 | def handleSequenceTimer(self): |
194 | 195 | self.timers["sequence"] = self.timer_sequence |
195 | - if (self.isValidStatus(self.status_tel)): | |
196 | - if (self.executing_sequence != None): | |
197 | - self.handleSequence(self.executing_sequence[0], | |
198 | - self.executing_sequence[1], self.executing_sequence[2]) | |
199 | - else: | |
200 | - self.notifyTelescopeStatus("sequence") | |
196 | + if (self.executing_sequence): | |
197 | + self.handleSequence(self.executing_sequence[0], | |
198 | + self.executing_sequence[1], self.executing_sequence[2]) | |
201 | 199 | return (0) |
202 | 200 | |
203 | 201 | def handleScheduleTimer(self): |
204 | 202 | self.timers["schedule"] = self.timer_schedule |
205 | 203 | if (self.isValidStatus(self.status_tel)): |
206 | - if (self.schedule == None): | |
204 | + if (self.schedule is None): | |
207 | 205 | try: |
208 | 206 | self.schedule = Schedule.objects.latest('created') |
209 | 207 | except ObjectDoesNotExist: |
210 | - if (settings.DEBUG): | |
208 | + if (settings.DEBUG and DEBUG_FILE): | |
211 | 209 | log.info("No schedule found in database") |
212 | 210 | return (1) |
213 | 211 | else: |
214 | 212 | try: |
215 | 213 | schedule = Schedule.objects.latest('created') |
216 | 214 | except ObjectDoesNotExist: |
217 | - if (settings.DEBUG): | |
215 | + if (settings.DEBUG and DEBUG_FILE): | |
218 | 216 | log.info("No schedule found in database") |
219 | 217 | return (1) |
220 | 218 | if (schedule.created != self.schedule.created): |
... | ... | @@ -256,52 +254,66 @@ class Majordome(Task): |
256 | 254 | Function called when a schedule has to be executed |
257 | 255 | ''' |
258 | 256 | def executeSchedule(self, shs_list): |
257 | + is_prev_planned = False | |
259 | 258 | self.logDB("Trying to execute a sequence from current schedule") |
260 | 259 | for shs in shs_list: # shs_list is sorted by tsp |
261 | - if (shs.sequence.status == Sequence.OBSERVABLE and self.observable(shs.sequence)): | |
260 | + if (shs.sequence.status == Sequence.PLANNED and self.observable(shs.sequence)): | |
262 | 261 | countdown = self.getCountdown(shs) |
263 | - if countdown <= JulianSeconds(5) and countdown > 0: | |
264 | - if (self.executing_sequence == None): | |
265 | - self.executeSequence(shs, shs.sequence, countdown) | |
266 | - else: | |
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) | |
268 | + else: | |
269 | + self.setNextSequence(shs, shs.sequence, countdown) | |
270 | + elif self.next_sequence is None: | |
267 | 271 | self.setNextSequence(shs, shs.sequence, countdown) |
268 | - else: | |
269 | - if (settings.DEBUG): | |
270 | - log.info("Sequence cannot be executed : countdown = " + str(countdown)) | |
271 | - self.logDB("Sequence cannot be executed : countdown = " + str(countdown)) | |
272 | + else: | |
273 | + return 0 | |
274 | + elif self.next_sequence is None: | |
275 | + self.setNextSequence(shs, shs.sequence, countdown) | |
272 | 276 | else: |
273 | - if (settings.DEBUG): | |
277 | + if (settings.DEBUG and DEBUG_FILE): | |
274 | 278 | log.info("Sequence cannot be executed : Not observable") |
275 | - self.logDB("Sequence cannot be executed : Not observable") | |
276 | - return (0) | |
279 | + self.logDB("Sequence "+shs.sequence.name+" cannot be executed : Not observable") | |
280 | + return 0 | |
277 | 281 | |
278 | 282 | def observable(self, sequence): |
279 | - if (sequence.jd2 - sequence.duration - getCurrentTime() <= 0): | |
280 | - return (0) | |
281 | - return (1) | |
283 | + if (sequence.jd2 - sequence.duration - secondsToPreciseJulianDate(getPreciseCurrentTime()) <= 0): | |
284 | + return 0 | |
285 | + return 1 | |
282 | 286 | |
283 | 287 | ''' |
284 | 288 | Launch the observation tasks associated to a sequence |
285 | 289 | ''' |
286 | 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 | + | |
287 | 300 | self.logDB("Executing sequence") |
288 | 301 | plans_results = [] |
289 | - | |
290 | 302 | if sequence.albums.filter(detector__name="Cagire").exists(): |
291 | 303 | if (self.isValidStatus(self.status_nir)): |
292 | 304 | for plan in sequence.albums.get(detector__name="Cagire").plans.all(): |
293 | - res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, countdown)) | |
305 | + res = observation_manager.tasks.execute_plan_nir.apply_async((plan.id, float(countdown))) | |
294 | 306 | TaskId.objects.create(task_id=res.id, task="execute_plan") |
295 | 307 | plans_results.append(res) |
296 | - else: | |
297 | - self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir) | |
298 | - sequence.status = Sequence.DEVICE_ERROR | |
299 | - sequence.save() | |
300 | - return (1) | |
308 | + else: | |
309 | + self.notifyDeviceStatus("Cagire", "Sequence execution", self.status_nir) | |
310 | + sequence.status = Sequence.DEVICE_ERROR | |
311 | + sequence.save() | |
312 | + return (1) | |
301 | 313 | if sequence.albums.filter(detector__name="Visible camera").exists(): |
302 | 314 | if (self.isValidStatus(self.status_vis)): |
303 | 315 | for plan in sequence.albums.get(detector__name="Visible camera").plans.all(): |
304 | - res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, countdown)) | |
316 | + res = observation_manager.tasks.execute_plan_vis.apply_async((plan.id, float(countdown))) | |
305 | 317 | TaskId.objects.create(task_id=res.id, task="execute_plan") |
306 | 318 | plans_results.append(res) |
307 | 319 | else: |
... | ... | @@ -320,20 +332,22 @@ class Majordome(Task): |
320 | 332 | Set the next sequence |
321 | 333 | ''' |
322 | 334 | def setNextSequence(self, shs, sequence, countdown): |
335 | + sequence.status = Sequence.PENDING | |
323 | 336 | self.next_sequence = [shs, sequence, countdown] |
337 | + sequence.save() | |
324 | 338 | return (0) |
325 | 339 | |
326 | 340 | ''' |
327 | 341 | Switch sequences |
328 | 342 | ''' |
329 | 343 | def switchSequence(self): |
330 | - if (self.next_sequence == None): | |
331 | - self.executing_sequence = None | |
332 | - else: | |
333 | - self.executing_sequence = None | |
344 | + self.executing_sequence = None | |
345 | + if (self.next_sequence is not None): | |
334 | 346 | self.executeSequence(self.next_sequence[0], |
335 | 347 | self.next_sequence[1], self.next_sequence[2]) |
336 | 348 | self.next_sequence = None |
349 | + else: | |
350 | + return 1 | |
337 | 351 | return (0) |
338 | 352 | |
339 | 353 | ''' |
... | ... | @@ -414,7 +428,7 @@ class Majordome(Task): |
414 | 428 | ''' |
415 | 429 | def getCountdown(self, shs): |
416 | 430 | # TODO start sequence as soon as possible (a lot of verifications must be done there) |
417 | - current_time = secondsToJulianDate(getPreciseCurrentTime()); | |
431 | + current_time = secondsToPreciseJulianDate(getPreciseCurrentTime()) | |
418 | 432 | countdown = shs.tsp - current_time |
419 | 433 | return countdown |
420 | 434 | ... | ... |
3.27 KB
3.79 KB
src/observation_manager/tasks.py
... | ... | @@ -6,6 +6,7 @@ from devices import CameraVIS as VIS |
6 | 6 | from devices import CameraNIR as NIR |
7 | 7 | from devices import Telescope |
8 | 8 | import time |
9 | +from utils.Logger import setupLogger | |
9 | 10 | |
10 | 11 | ''' |
11 | 12 | Super class for execute_plan_vis / _nir |
... | ... | @@ -13,6 +14,7 @@ import time |
13 | 14 | class execute_plan(Task): |
14 | 15 | |
15 | 16 | def run(self, plan_id, countdown, type): |
17 | + | |
16 | 18 | if countdown > 0: |
17 | 19 | time.sleep(countdown) |
18 | 20 | TaskId.objects.filter(task_id=self.request.id).delete() |
... | ... | @@ -102,7 +104,10 @@ class execute_plan(Task): |
102 | 104 | Send the images to the analyzer |
103 | 105 | ''' |
104 | 106 | class execute_plan_vis(execute_plan): |
107 | + logger = setupLogger("PlanVIS", "PlanVIS") | |
108 | + | |
105 | 109 | def run(self, plan_id, countdown): |
110 | + self.log.info("------------------ RUNNING PLAN VIS ----------------------------") | |
106 | 111 | super().run(plan_id, countdown, "VIS") |
107 | 112 | |
108 | 113 | |
... | ... | @@ -111,8 +116,11 @@ class execute_plan_vis(execute_plan): |
111 | 116 | Send the images to the analyzer |
112 | 117 | ''' |
113 | 118 | class execute_plan_nir(execute_plan): |
119 | + log = setupLogger("PlanNIR", "PlanNIR") | |
120 | + | |
114 | 121 | def run(self, plan_id, countdown): |
115 | 122 | super().run(plan_id, countdown, "NIR") |
123 | + self.log.info("------------------ RUNNING PLAN NIR ----------------------------") | |
116 | 124 | |
117 | 125 | |
118 | 126 | ''' |
... | ... | @@ -120,6 +128,8 @@ class execute_plan_nir(execute_plan): |
120 | 128 | When they are all finished, it creates the 'super' calibration files. |
121 | 129 | ''' |
122 | 130 | class create_calibrations(Task): |
123 | - def run(self): | |
124 | - # TODO: attendre que tout soit idle | |
125 | - pass | |
131 | + logger = setupLogger("Calibrations", "Calibrations") | |
132 | + | |
133 | + def run(self): | |
134 | + self.log.info("------------------ RUNNING CALIBRATIONS ----------------------------") | |
135 | + # TODO: attendre que tout soit idle | ... | ... |
src/pyros/settings.py.bak
src/routine_manager/RequestSerializer.py
... | ... | @@ -88,8 +88,6 @@ class RequestSerializer(): |
88 | 88 | sequence.jd1 = (time.time() + float(sequence.jd1)) / 86400 + TIMESTAMP_JD |
89 | 89 | sequence.jd2 = (time.time() + float(sequence.jd2)) / 86400 + TIMESTAMP_JD |
90 | 90 | sequence.request = self.request |
91 | - # TODO: REMOVE WHEN WE KNOW HOW TO DECIDE IF THE SEQUENCE IS OBSERVABLE | |
92 | - sequence.status = Sequence.OBSERVABLE | |
93 | 91 | sequence.save() |
94 | 92 | for album, plans in albums: |
95 | 93 | album.sequence = sequence | ... | ... |
src/routine_manager/validators.py
1 | 1 | from common.models import Sequence |
2 | +from django.conf import settings | |
2 | 3 | |
3 | 4 | def check_plan_validity(plan): |
4 | 5 | """ |
... | ... | @@ -52,7 +53,11 @@ def check_sequence_validity(seq): |
52 | 53 | if seq.albums.filter(complete=False).count() != 0 or seq.albums.count() == 0: |
53 | 54 | seq.status = Sequence.INCOMPLETE |
54 | 55 | else: |
55 | - seq.status = Sequence.COMPLETE | |
56 | + #TODO CHANGE WHEN WE KNOW HOW TO DECIDE IF THE SEQUENCE IS OBSERVABLE | |
57 | + if settings.SIMULATOR: | |
58 | + seq.status = Sequence.TOBEPLANNED | |
59 | + else: | |
60 | + seq.status = Sequence.COMPLETE | |
56 | 61 | seq.save() |
57 | 62 | return check_request_validity(seq.request) |
58 | 63 | ... | ... |
src/routine_manager/views.py
... | ... | @@ -428,7 +428,7 @@ def submit_request(request, req_id, redir): |
428 | 428 | return redirect(action_request, req_id=req_id, action="view", status=-1, message=message) |
429 | 429 | |
430 | 430 | for seq in req.sequences.all(): |
431 | - seq.status = Sequence.OBSERVABLE # TODO: utiliser le monitoring (regarder les conditions d'obseration pour dire si on met TBP ou OBS) | |
431 | + seq.status = Sequence.TOBEPLANNED | |
432 | 432 | seq.save() |
433 | 433 | req.submitted = True |
434 | 434 | req.save() |
... | ... | @@ -460,7 +460,7 @@ def unsubmit_request(request, req_id): |
460 | 460 | |
461 | 461 | req.submitted = False |
462 | 462 | req.save() |
463 | - sequences = req.sequences.filter(Q(status=Sequence.TOBEPLANNED) | Q(status=Sequence.OBSERVABLE) | | |
463 | + sequences = req.sequences.filter(Q(status=Sequence.TOBEPLANNED) | Q(status=Sequence.PLANNED) | | |
464 | 464 | Q(status=Sequence.INVALID) | Q(status=Sequence.UNPLANNABLE)) |
465 | 465 | for seq in sequences: |
466 | 466 | seq.status = Sequence.COMPLETE | ... | ... |
src/scheduler/Scheduler.py
1 | 1 | from operator import attrgetter |
2 | 2 | from .UserManager import UserManager |
3 | 3 | from .Interval import * |
4 | +from django.db.models import Q | |
4 | 5 | |
5 | 6 | SIMULATION = False |
6 | - | |
7 | +DEBUG_FILE = False | |
7 | 8 | |
8 | 9 | class Scheduler(IntervalManagement): |
9 | 10 | REJECTED_ROOM = "Insufficient room for this sequence" |
... | ... | @@ -29,27 +30,43 @@ class Scheduler(IntervalManagement): |
29 | 30 | def isFirstSchedule(self) -> bool: |
30 | 31 | return False |
31 | 32 | |
33 | + def determinePlanStart(self, previous_sched): | |
34 | + start = secondsToPreciseJulianDate(getPreciseCurrentTime()) | |
35 | + if start > previous_sched.plan_start + self.max_overhead: | |
36 | + return start + self.max_overhead | |
37 | + return previous_sched.plan_start | |
38 | + | |
32 | 39 | def copyFromPrevious(self) -> int: |
33 | 40 | if len(Schedule.objects.all()) == 1: |
34 | 41 | self.schedule.plan_night_start = self.schedule.plan_start |
35 | - self.log("No schedule found") | |
42 | + if DEBUG_FILE: | |
43 | + self.log("No schedule found") | |
36 | 44 | return 1 |
37 | 45 | try: |
38 | 46 | previous_sched = Schedule.objects.order_by('-created')[1] |
39 | - previous_exc_seq = previous_sched.sequences.filter(status=Sequence.EXECUTED) | |
47 | + previous_exc_seq = previous_sched.sequences.filter(Q(status=Sequence.EXECUTED) | | |
48 | + Q(status=Sequence.EXECUTING)) | |
40 | 49 | except: |
41 | 50 | self.schedule.plan_night_start = self.schedule.plan_start |
42 | - self.debug("Scheduler could not get information from previous schedule") | |
51 | + if DEBUG_FILE: | |
52 | + self.debug("Scheduler could not get information from previous schedule") | |
43 | 53 | return 1 |
44 | 54 | for seq in previous_exc_seq: |
45 | - shs = seq.shs | |
55 | + shs = seq.shs.latest("schedule__created") | |
46 | 56 | shs.pk = None |
47 | 57 | shs.schedule = self.schedule |
48 | 58 | shs.save() |
59 | + adder = 0 | |
60 | + try: | |
61 | + executing = Sequence.objects.filter(status=Sequence.EXECUTING) | |
62 | + if executing: | |
63 | + s = Sequence.shs.latest("schedule__created") | |
64 | + adder = s.tsp - secondsToPreciseJulianDate(getPreciseCurrentTime()) | |
65 | + except: | |
66 | + pass | |
49 | 67 | self.schedule.plan_night_start = previous_sched.plan_night_start |
50 | 68 | self.schedule.plan_end = previous_sched.plan_end |
51 | - start = Decimal(secondsToJulianDate(getCurrentTime())) + self.max_overhead | |
52 | - self.schedule.plan_start = (start if start > previous_sched.plan_start else previous_sched.plan_start) | |
69 | + self.schedule.plan_start = self.determinePlanStart(previous_sched) + adder | |
53 | 70 | return 0 |
54 | 71 | |
55 | 72 | def simulateSchedule(self, sequences) -> tuple: |
... | ... | @@ -68,7 +85,8 @@ class Scheduler(IntervalManagement): |
68 | 85 | def computeSchedule(self) -> int: |
69 | 86 | interval = Interval(self.schedule.plan_start, self.schedule.plan_end) |
70 | 87 | self.intervals.append(interval) |
71 | - self.log("Interval created : " + str(interval.__dict__)) | |
88 | + if DEBUG_FILE: | |
89 | + self.log("Interval created : " + str(interval.__dict__)) | |
72 | 90 | self.removeInvalidSequences() |
73 | 91 | self.determinePriorities() |
74 | 92 | self.removeNonEligible() |
... | ... | @@ -86,21 +104,27 @@ class Scheduler(IntervalManagement): |
86 | 104 | if self.copyFromPrevious(): |
87 | 105 | self.schedule.plan_night_start = self.schedule.plan_start |
88 | 106 | |
89 | - self.sequences = list(Sequence.objects.filter()) | |
107 | + self.sequences = list(Sequence.objects.filter(Q(status=Sequence.PLANNED) | Q(status=Sequence.TOBEPLANNED) | |
108 | + | Q(status=Sequence.PENDING))) | |
90 | 109 | self.sequences = [(sequence, ScheduleHasSequences(sequence=sequence, schedule=self.schedule)) |
91 | 110 | for sequence in self.sequences] |
92 | - self.log(str(len(self.sequences)) + " sequences found") | |
111 | + if DEBUG_FILE: | |
112 | + self.log(str(len(self.sequences)) + " sequences found") | |
93 | 113 | self.computeSchedule() |
94 | 114 | self.saveSchedule() |
95 | - self.log("Saving schedule with " + str(len(self.schedule.sequences.all())) + " sequences") | |
115 | + if DEBUG_FILE: | |
116 | + self.log("Saving schedule with " + str(len(self.schedule.sequences.all())) + " sequences") | |
96 | 117 | return self.schedule |
97 | 118 | |
98 | 119 | def saveSchedule(self) -> int: |
99 | 120 | self.schedule.save() |
100 | - for _, shs in self.sequences: | |
121 | + for sequence, shs in self.sequences: | |
122 | + sequence.status = Sequence.PLANNED | |
101 | 123 | shs.schedule = self.schedule |
124 | + sequence.save() | |
102 | 125 | shs.save() |
103 | - self.logSchedule() | |
126 | + if DEBUG_FILE: | |
127 | + self.logSchedule() | |
104 | 128 | return 0 |
105 | 129 | |
106 | 130 | |
... | ... | @@ -116,7 +140,8 @@ class Scheduler(IntervalManagement): |
116 | 140 | if not SIMULATION: |
117 | 141 | sequence.save() |
118 | 142 | self.sequences.remove((sequence, shs)) |
119 | - self.log("Removing non eligible sequence") | |
143 | + if DEBUG_FILE: | |
144 | + self.log("Removing non eligible sequence") | |
120 | 145 | return 0 |
121 | 146 | |
122 | 147 | def removeInvalidSequences(self): |
... | ... | @@ -124,7 +149,8 @@ class Scheduler(IntervalManagement): |
124 | 149 | if (sequence.jd1 < 0 or sequence.jd2 < 0 or |
125 | 150 | is_nearby_less_or_equal(sequence.duration, Decimal(0)) or |
126 | 151 | sequence.jd2 - sequence.jd1 < sequence.duration): |
127 | - self.log("Removing sequence in removeInvalidSequences") | |
152 | + if DEBUG_FILE: | |
153 | + self.log("Removing sequence in removeInvalidSequences") | |
128 | 154 | self.sequences.remove((sequence, shs)) |
129 | 155 | sequence.status = Sequence.INVALID |
130 | 156 | if not SIMULATION: |
... | ... | @@ -160,7 +186,8 @@ class Scheduler(IntervalManagement): |
160 | 186 | shs.status = Sequence.PENDING |
161 | 187 | self.decreaseQuota(sequence, sequence.duration) |
162 | 188 | else: |
163 | - self.log("Removing sequence in place_sequences") | |
189 | + if DEBUG_FILE: | |
190 | + self.log("Removing sequence in place_sequences") | |
164 | 191 | shs.status = Sequence.REJECTED |
165 | 192 | shs.desc = self.REJECTED_ROOM |
166 | 193 | return 0 | ... | ... |
src/scheduler/simulator.py
... | ... | @@ -76,7 +76,7 @@ class Simulator(): |
76 | 76 | jd1 = Decimal("%.8f" % float(sequence_array[5])) |
77 | 77 | jd2 = Decimal("%.8f" % float(sequence_array[6])) |
78 | 78 | |
79 | - sequence = Sequence(request=req, status=Sequence.OBSERVABLE, | |
79 | + sequence = Sequence(request=req, status=Sequence.PLANNED, | |
80 | 80 | name="sequence", id=id_seq, priority=priority, duration=duration, jd1=jd1, jd2=jd2, t_prefered=-1) |
81 | 81 | sequences.append(sequence) |
82 | 82 | ... | ... |
src/scheduler/tasks.py
... | ... | @@ -11,9 +11,7 @@ class scheduling(Task): |
11 | 11 | def run(self, first_schedule=False, alert=False): |
12 | 12 | |
13 | 13 | Log.objects.create(agent='Scheduler', message='Start schedule : ' + str(datetime.datetime.now())) |
14 | - log.info("Scheduling start") | |
15 | 14 | self.scheduler = Scheduler() |
16 | 15 | self.scheduler.setNightLimits(secondsToJulianDate(getNightStart()), secondsToJulianDate(getNightEnd())) |
17 | 16 | self.scheduler.makeSchedule() |
18 | - log.info("Scheduling done") | |
19 | 17 | Log.objects.create(agent='Scheduler', message='Scheduling finished : ' + str(datetime.datetime.now())) |
20 | 18 | \ No newline at end of file | ... | ... |
src/scheduler/templates/scheduler/retrieve_schedule.html
... | ... | @@ -63,12 +63,16 @@ |
63 | 63 | {% for sequence in sequences %} |
64 | 64 | <tr> |
65 | 65 | <td> |
66 | - {% if sequence.processing == 1 %} | |
67 | - <img src="{% static "media/arrow_green.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/> | |
68 | - {% elif sequence.processing == 0 and sequence.status == "EXECUTED" %} | |
69 | - <img src="{% static "media/validate.jpg" %}" alt="html5" height="30" width="30" style="margin-left:25%"/> | |
66 | + {% if sequence.0.status == "EXING" == 1 %} | |
67 | + <img src="{% static "media/arrow_green.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/> | |
68 | + {% elif sequence.0.status == "EXD" %} | |
69 | + <img src="{% static "media/validate.jpg" %}" alt="html5" height="30" width="30" style="margin-left:25%"/> | |
70 | + {% elif sequence.0.status == "PNDG" %} | |
71 | + <img src="{% static "media/next.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/> | |
72 | + {% elif sequence.0.status == "PLND" %} | |
73 | + <img src="{% static "media/planned.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/> | |
70 | 74 | {% else %} |
71 | - <img src="{% static "media/error.png" %}" alt="{{sequence.processing}}" height="30" width="30" style="margin-left:25%"/> | |
75 | + <img src="{% static "media/error.png" %}" alt="html5" height="30" width="30" style="margin-left:25%"/> | |
72 | 76 | {% endif %} |
73 | 77 | </td> |
74 | 78 | <td>{{ sequence.0.id }}</td> |
... | ... | @@ -79,7 +83,7 @@ |
79 | 83 | <td>{{ sequence.0.jd2|jdtodate }}</td> |
80 | 84 | <td>{{ sequence.0.duration|jdtoduration }}</td> |
81 | 85 | <td>{{ sequence.0.priority }}</td> |
82 | - <td>{{ sequence.1.status }}</td> | |
86 | + <td>{{ sequence.0.status }}</td> | |
83 | 87 | </tr> |
84 | 88 | {% endfor %} |
85 | 89 | </tbody> | ... | ... |
src/scheduler/views.py
... | ... | @@ -10,7 +10,7 @@ SIMULATION_FILE = 'file:./scheduler/sequences_cador.html' |
10 | 10 | def retrieve_schedule(request): |
11 | 11 | if (len(Schedule.objects.all()) > 0): # checking if the schedule is empty |
12 | 12 | schedule = Schedule.objects.order_by("-created")[0] # Sorting Schedule |
13 | - shs_list = schedule.shs.all() # getting all the schedule has sequences references | |
13 | + shs_list = schedule.shs.order_by("tsp") # getting all the schedule has sequences references | |
14 | 14 | sequences = [(shs.sequence, shs) for shs in shs_list] # getting all sequences |
15 | 15 | |
16 | 16 | nb_scheduled_sequences = len(shs_list) |
... | ... | @@ -33,7 +33,7 @@ def schedule_simulation(request): |
33 | 33 | simulator = Simulator() |
34 | 34 | schedule, sequences = simulator.simulate(SIMULATION_FILE) |
35 | 35 | |
36 | - nb_scheduled_sequences = len([sequence for sequence in sequences if sequence[1].status != Sequence.OBSERVABLE]) | |
36 | + nb_scheduled_sequences = len([sequence for sequence in sequences if sequence[1].status != Sequence.PLANNED]) | |
37 | 37 | executed_sequences = len([sequence for sequence in sequences if sequence[1].status == Sequence.EXECUTED]) |
38 | 38 | |
39 | 39 | ... | ... |
src/utils/JDManipulator.py
1 | +from django.conf import settings | |
1 | 2 | import datetime |
2 | 3 | import time |
3 | 4 | from decimal import * |
... | ... | @@ -5,9 +6,23 @@ from decimal import * |
5 | 6 | JD_VALUE = 86400 |
6 | 7 | TIMESTAMP_JD = 2440587.500000 |
7 | 8 | DAILY_SECOND = 1 / 86400 |
9 | +SECOND_DIV = 86400 | |
10 | + | |
11 | +def getSimTime(): | |
12 | + current_time = datetime.datetime.now() | |
13 | + if current_time.minute == 59: | |
14 | + current_time = current_time.replace(hour=(current_time.hour + 1), minute=0, second=10) | |
15 | + else: | |
16 | + if current_time.second >= 50: | |
17 | + current_time = current_time.replace(minute=current_time.minute + 1, second=10) | |
18 | + else: | |
19 | + current_time = current_time.replace(second=(current_time.second + 10)) | |
20 | + return (time.mktime(current_time.timetuple())) | |
21 | + | |
22 | +SIM_TIME_START = getSimTime() | |
8 | 23 | |
9 | 24 | def JulianSeconds(value): |
10 | - return (Decimal(value * DAILY_SECOND)) | |
25 | + return (Decimal(value) / SECOND_DIV) | |
11 | 26 | |
12 | 27 | def getPreciseCurrentTime(): |
13 | 28 | return (Decimal(getCurrentTime())) |
... | ... | @@ -21,6 +36,9 @@ def getPreciseNightEnd(): |
21 | 36 | def secondsToJulianDate(time_seconds): |
22 | 37 | return (time_seconds / 86400 + TIMESTAMP_JD) |
23 | 38 | |
39 | +def secondsToPreciseJulianDate(time_seconds): | |
40 | + return (Decimal(time_seconds) / 86400 + Decimal(TIMESTAMP_JD)) | |
41 | + | |
24 | 42 | def julianDateToSeconds(time_julian): |
25 | 43 | return ((time_julian - TIMESTAMP_JD) * 86400) |
26 | 44 | |
... | ... | @@ -46,7 +64,18 @@ def getNextDefaultNightEnd(): |
46 | 64 | |
47 | 65 | def getDefaultNightStart(): |
48 | 66 | current_time = datetime.datetime.now() |
49 | - current_time = current_time.replace(hour=18, minute=0, second=0, microsecond=0) | |
67 | + if settings.SIMULATOR: | |
68 | + if settings.SIMULATOR: | |
69 | + return SIM_TIME_START | |
70 | + if current_time.minute == 59: | |
71 | + current_time = current_time.replace(hour=(current_time.hour + 1), minute=0, second=10) | |
72 | + else: | |
73 | + if current_time.second > 50: | |
74 | + current_time = current_time.replace(minute=current_time.minute + 1, second=10) | |
75 | + else: | |
76 | + current_time = current_time.replace(second=(current_time.second + 10)) | |
77 | + else: | |
78 | + current_time = current_time.replace(hour=18, minute=0, second=0, microsecond=0) | |
50 | 79 | return (time.mktime(current_time.timetuple())) |
51 | 80 | |
52 | 81 | def getDefaultNightEnd(): | ... | ... |