Commit bd83eb17322571a0b26d3be2db5b47602e530881

Authored by Quentin Durand
1 parent 1179175f
Exists in dev

Control command Cagire web + back

simulators/config/grammar.json
@@ -245,6 +245,197 @@ @@ -245,6 +245,197 @@
245 "label": "Change the wanted filter", 245 "label": "Change the wanted filter",
246 "input_label": [], 246 "input_label": [],
247 "help": "Change the wanted filter" 247 "help": "Change the wanted filter"
  248 + },
  249 + {
  250 + "name": "EXPOSURE",
  251 + "label": "Exposure time for 1 image in seconds",
  252 + "input_label": [
  253 + {
  254 + "exposure" : [15, "Int", "Exposure time"]
  255 + }
  256 + ],
  257 + "help": "Exposure time for 1 image in seconds"
  258 + },
  259 + {
  260 + "name": "BINNING",
  261 + "label": "Binning of cells",
  262 + "input_label": [
  263 + {
  264 + "binning" : [15, "Int", "Binning"]
  265 + }
  266 + ],
  267 + "help": "Set the Binning of cells."
  268 + }
  269 + ],
  270 + "get": [
  271 + {
  272 + "name": "STATUS",
  273 + "label": "Get camera status values (dict)",
  274 + "input_label": [],
  275 + "help": "Get camera status values (dict): struct(key, value, type, unit, comment)"
  276 + },
  277 + {
  278 + "name": "SETUP",
  279 + "label": "Get static values for config (dict)",
  280 + "input_label": [],
  281 + "help": "Get static values for config (eg. limit speed)"
  282 + },
  283 + {
  284 + "name": "TIMER",
  285 + "label": "Get the ime before end of pose",
  286 + "input_label": [],
  287 + "help": "Time before end of pose (-1 == idle / finished, 0 == readout (recup-ing img))"
  288 + }
  289 +
  290 + ],
  291 + "do": [
  292 + {
  293 + "name": "COOLER ON",
  294 + "label": "Turn On the cooler with the given temperature",
  295 + "input_label": [
  296 + {
  297 + "temp":[15, "Float", "temperature"]
  298 + }
  299 + ],
  300 + "help": "Turn On the cooler with the given temperature."
  301 + },
  302 + {
  303 + "name": "COOLER OFF",
  304 + "label": "Turn off the cooler",
  305 + "input_label": [],
  306 + "help": "Turn off the cooler."
  307 + },
  308 + {
  309 + "name": "DOME SHUTTER OPEN",
  310 + "label": "Open the dome shutter",
  311 + "input_label": [],
  312 + "help": "Open the dome shutter."
  313 + },
  314 + {
  315 + "name": "DOME SHUTTER CLOSE",
  316 + "label": "Close the dome shutter",
  317 + "input_label": [],
  318 + "help": "Close the dome shutter"
  319 + },
  320 + {
  321 + "name": "DOME SHUTTER SYNCHRO",
  322 + "label": "Dome Shutter Synchro",
  323 + "input_label": [],
  324 + "help": "Dome Shutter Synchro"
  325 + },
  326 + {
  327 + "name": "START",
  328 + "label": "Start Pose",
  329 + "input_label": [],
  330 + "help": "Start Pose"
  331 + },
  332 + {
  333 + "name": "ABORT",
  334 + "label": "Stop Pose",
  335 + "input_label": [],
  336 + "help": "Stop Pose"
  337 + },
  338 + {
  339 + "name": "STOP",
  340 + "label": "End image then stop pose",
  341 + "input_label": [],
  342 + "help": "End image then stop pose"
  343 + }
  344 +
  345 + ]
  346 +
  347 +
  348 + },
  349 + "CameraNIR" : {
  350 + "set": [
  351 + {
  352 + "name": "WINDOW",
  353 + "label": "Set the window coordinates",
  354 + "input_label": [
  355 + {
  356 + "x1":[10, "Int", "x left bottom"],
  357 + "x2":[10, "Int", "y left bottom"],
  358 + "y1":[10, "Int", "x right top corner"],
  359 + "y2":[10, "Int", "y right top corner"]
  360 + }
  361 + ],
  362 + "help": "Coordinates of window corners (left bot, right top)"
  363 + },
  364 + {
  365 + "name": "READMODE [MODE 1]",
  366 + "label": "Set Mode of observation (ramp, ...)",
  367 + "input_label": [],
  368 + "help": "Set the Mode of observation (ramp, ...)"
  369 + },
  370 + {
  371 + "name": "READMODE [MODE 2]",
  372 + "label": "Set Mode of observation (ramp, ...)",
  373 + "input_label": [],
  374 + "help": "Set the Mode of observation (ramp, ...)"
  375 + },
  376 + {
  377 + "name": "READMODE [MODE 3]",
  378 + "label": "Set Mode of observation (ramp, ...)",
  379 + "input_label": [],
  380 + "help": "Set the Mode of observation (ramp, ...)"
  381 + },
  382 + {
  383 + "name": "FILENAME",
  384 + "label": "Change the used file",
  385 + "input_label": [
  386 + {
  387 + "filename" : [256, "Str", "filename"]
  388 + }
  389 + ],
  390 + "help": "Optional, not wanting default file name (reset between each image)"
  391 + },
  392 + {
  393 + "name": "HEADER",
  394 + "label": "Set particular values in the header",
  395 + "input_label": [
  396 + {
  397 + "header values" : [1024, "Str (dict)", "header values"]
  398 + }
  399 + ],
  400 + "help": "Set particular values in the header"
  401 + },
  402 + {
  403 + "name": "READOUT_FREQUENCY",
  404 + "label": "Readout frequency in pix/s (~= Hz)",
  405 + "input_label": [
  406 + {
  407 + "readout freq" : [15, "Float", "readout freq pix/s ~= Hz"]
  408 + }
  409 + ],
  410 + "help": "Readout frequency in pix/s (~= Hz)"
  411 + },
  412 + {
  413 + "name": "FILTER [FILTER 1]",
  414 + "label": "Change the wanted filter",
  415 + "input_label": [],
  416 + "help": "Change the wanted filter"
  417 + },
  418 + {
  419 + "name": "FILTER [FILTER 2]",
  420 + "label": "Change the wanted filter",
  421 + "input_label": [],
  422 + "help": "Change the wanted filter"
  423 + },
  424 + {
  425 + "name": "FILTER [FILTER 3]",
  426 + "label": "Change the wanted filter",
  427 + "input_label": [],
  428 + "help": "Change the wanted filter"
  429 + },
  430 + {
  431 + "name": "NB_IMAGES",
  432 + "label": "Number of images in the ramp (x1.4s)",
  433 + "input_label": [
  434 + {
  435 + "nb_imgs" : [15, "Int", "nb images"]
  436 + }
  437 + ],
  438 + "help": "Set the number of images in the ramp (x1.4s)"
248 } 439 }
249 ], 440 ],
250 "get": [ 441 "get": [
src/dashboard/templates/dashboard/observation_status.html
@@ -125,6 +125,11 @@ @@ -125,6 +125,11 @@
125 {% for log in cagire_logs %} 125 {% for log in cagire_logs %}
126 <li>{{log.created}} : {{log.message}}</li> {% endfor %} 126 <li>{{log.created}} : {{log.message}}</li> {% endfor %}
127 </ul> 127 </ul>
  128 + {% if not config.global_mode %}
  129 + <form action={% url "send_command_to_cameraNIR" %}>
  130 + <input class="send_command_button" id="send_command_cameraNIR" type="submit" value="Send Command" />
  131 + </form>
  132 + {% endif %}
128 </div> 133 </div>
129 <div class="element" id=DDRAGORED> 134 <div class="element" id=DDRAGORED>
130 <h2><button id="ddrago_r_button">DDRAGO RED</button></h2> 135 <h2><button id="ddrago_r_button">DDRAGO RED</button></h2>
src/dashboard/templates/dashboard/send_command_cameraNIR.html 0 โ†’ 100644
@@ -0,0 +1,124 @@ @@ -0,0 +1,124 @@
  1 +{% extends "base.html" %}
  2 +{% load staticfiles%}
  3 +
  4 +{% block title %}
  5 + Send Command to CAGIRE
  6 +{% endblock %}
  7 +
  8 +{% block content %}
  9 +<html lang="en">
  10 +<head>
  11 + <meta charset="UTF-8">
  12 +
  13 +</head>
  14 +<body>
  15 + <style>
  16 +
  17 + .conteneur
  18 + {
  19 + display: flex;
  20 + flex-wrap: wrap-reverse;
  21 + justify-content: space-between;
  22 + }
  23 + .element
  24 + {
  25 +
  26 + margin: auto;
  27 + list-style-image: none;
  28 + font-family: 'Montserra', sans-serif;
  29 +
  30 + }
  31 +
  32 + .element h2
  33 + {
  34 + text-align: center;
  35 + font-weight: normal;
  36 + }
  37 + .log
  38 + {
  39 + font-size: 1.13em;
  40 + list-style-image: none;
  41 + list-style-type: none;
  42 + color: green;
  43 + font-weight: bold;
  44 + font-family: "Arial";
  45 + height: 500px;
  46 + width: 650px;
  47 + overflow: scroll;
  48 + background-color: black;
  49 + }
  50 +
  51 + #id_first_command
  52 + {
  53 + font-size: 19px;
  54 + }
  55 +
  56 +
  57 + #submit_button
  58 + {
  59 + display: block;
  60 + font-size: 20px;
  61 + margin: auto;
  62 + }
  63 + #expert_mode
  64 + {
  65 + font-size: 15px;
  66 + }
  67 +</style>
  68 +
  69 + <!-- TODO:Passer aux django forms une fois que la grammaire sera fixรฉe -->
  70 +
  71 + <div class="conteneur">
  72 + <div id="command" class="element">
  73 + <form id=command_form method="POST" action={% url "submit_command_to_cameraNIR" %}>
  74 +
  75 + <label for="Command"><h2>Select the command</h2></label><br/>
  76 +
  77 + <select name="first_command" id="id_first_command">
  78 + <option value="Command" selected>Command :</option>
  79 + <option value="SET">SET</option>
  80 + <option value="GET">GET</option>
  81 + <option value="DO">DO</option>
  82 + </select>
  83 +
  84 + </form>
  85 + <br><br>
  86 + <form id="command_form_expert" method="POST" action="{% url "submit_command_to_cameraNIR_expert" %}">
  87 + <label for="Command"><h2>Enter the command in expert mode</h2></label><br/>
  88 + <button id="expert_mode" type="button">Expert Mode</button>
  89 + {% csrf_token %}
  90 + </form>
  91 + </div>
  92 + <div id="logs" class="element">
  93 + <div id="cagire">
  94 + <h2>CAGIRE</h2>
  95 + <ul class="log" id="cagire_logs">
  96 + <br>
  97 + </ul>
  98 + </div>
  99 + </div>
  100 + </div>
  101 + <script> var data = {{ json_str | safe }}</script>
  102 + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  103 + <script src="{% static "/js/command_control_cameraNIR.js" %}" type=text/javascript></script>
  104 + <script>
  105 +
  106 + $( "#command_form" ).submit(function( event ) {
  107 + alert( "Handler for .submit() called." );
  108 + event.preventDefault();
  109 + var inputElem = document.createElement('input');
  110 + inputElem.type = 'hidden';
  111 + inputElem.name = 'csrfmiddlewaretoken';
  112 + inputElem.value = '{{ csrf_token }}';
  113 +
  114 + document.getElementById("command_form").appendChild(inputElem);
  115 + $( "#command_form" ).submit();
  116 +});
  117 +
  118 +
  119 + </script>
  120 +
  121 +
  122 +</body>
  123 +</html>
  124 +{% endblock %}
0 \ No newline at end of file 125 \ No newline at end of file
src/dashboard/urls.py
@@ -24,6 +24,9 @@ urlpatterns = [ @@ -24,6 +24,9 @@ urlpatterns = [
24 path('observation_status/send_command_to_telescope/submit_expert', views.submit_command_to_telescope_expert, name='submit_command_to_telescope_expert'), 24 path('observation_status/send_command_to_telescope/submit_expert', views.submit_command_to_telescope_expert, name='submit_command_to_telescope_expert'),
25 path('observation_status/send_command_to_telescope/submit', views.submit_command_to_telescope, name='submit_command_to_telescope'), 25 path('observation_status/send_command_to_telescope/submit', views.submit_command_to_telescope, name='submit_command_to_telescope'),
26 path('observation_status/send_command_to_telescope', views.send_command_to_telescope, name='send_command_to_telescope'), 26 path('observation_status/send_command_to_telescope', views.send_command_to_telescope, name='send_command_to_telescope'),
  27 + path('observation_status/send_command_to_cameraNIR/submit_expert', views.submit_command_to_cameraNIR_expert, name='submit_command_to_cameraNIR_expert'),
  28 + path('observation_status/send_command_to_cameraNIR/submit', views.submit_command_to_cameraNIR, name='submit_command_to_cameraNIR'),
  29 + path('observation_status/send_command_to_cameraNIR', views.send_command_to_cameraNIR, name='send_command_to_cameraNIR'),
27 path('observation_status/send_command_to_cameraVIS_1/submit_expert', views.submit_command_to_cameraVIS_1_expert, name='submit_command_to_cameraVIS_1_expert'), 30 path('observation_status/send_command_to_cameraVIS_1/submit_expert', views.submit_command_to_cameraVIS_1_expert, name='submit_command_to_cameraVIS_1_expert'),
28 path('observation_status/send_command_to_cameraVIS_1/submit', views.submit_command_to_cameraVIS_1, name='submit_command_to_cameraVIS_1'), 31 path('observation_status/send_command_to_cameraVIS_1/submit', views.submit_command_to_cameraVIS_1, name='submit_command_to_cameraVIS_1'),
29 path('observation_status/send_command_to_cameraVIS_1', views.send_command_to_cameraVIS_1, name='send_command_to_cameraVIS_1'), 32 path('observation_status/send_command_to_cameraVIS_1', views.send_command_to_cameraVIS_1, name='send_command_to_cameraVIS_1'),
src/dashboard/views.py
@@ -19,6 +19,7 @@ from random import randint @@ -19,6 +19,7 @@ from random import randint
19 from devices.Telescope import TelescopeController 19 from devices.Telescope import TelescopeController
20 from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault 20 from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault
21 from devices.CameraVISRemoteControlDefault import CameraVISRemoteControlDefault 21 from devices.CameraVISRemoteControlDefault import CameraVISRemoteControlDefault
  22 +from devices.CameraNIRRemoteControlDefault import CameraNIRRemoteControlDefault
22 from django.core.mail import send_mail 23 from django.core.mail import send_mail
23 import time 24 import time
24 import utils.celme as celme 25 import utils.celme as celme
@@ -361,6 +362,53 @@ def submit_command_to_cameraVIS_1_expert(request): @@ -361,6 +362,53 @@ def submit_command_to_cameraVIS_1_expert(request):
361 362
362 363
363 364
  365 +@login_required
  366 +@level_required(3)
  367 +def send_command_to_cameraNIR(request):
  368 + data = ""
  369 + with open('../simulators/config/grammar.json') as f:
  370 + data = json.load(f, object_pairs_hook=OrderedDict)
  371 + json_str = json.dumps(data)
  372 + return render(request, "dashboard/send_command_cameraNIR.html", locals())
  373 +
  374 +
  375 +@login_required
  376 +@level_required(3)
  377 +def submit_command_to_cameraNIR(request):
  378 + if request.method == 'POST':
  379 + commands = [request.POST.get("first_command"), request.POST.get("first_param")]
  380 + try: #TODO faire un truc plus joli pour gรฉrer les params queqlue soit leur nombre
  381 + input_0 = request.POST.get("input_number_0")
  382 + input_1 = request.POST.get("input_number_1")
  383 + input_2 = request.POST.get("input_number_2")
  384 + if input_0:
  385 + commands.append(input_0)
  386 + if input_1:
  387 + commands.append(input_1)
  388 + if input_2:
  389 + commands.append(input_2)
  390 + except Exception:
  391 + pass
  392 + response = CameraNIRRemoteControlDefault(commands, expert_mode=False).exec_command()
  393 + #TODO passer en JS pour send les rรฉponses en AJAX
  394 + return redirect('send_command_to_cameraNIR')
  395 +
  396 +@login_required
  397 +@level_required(3)
  398 +def submit_command_to_cameraNIR_expert(request):
  399 + #import os
  400 + if request.method == 'POST':
  401 + param = request.POST.get("commande_expert")
  402 + if param:
  403 + response = CameraNIRRemoteControlDefault(param, expert_mode=True).exec_command()
  404 + #os.system("echo \"status :" + response + "\" >> /home/portos/IRAP/pyros/src/status")
  405 + return HttpResponse(json.dumps({'message': "Command send OK", 'response': response}))
  406 + return HttpResponse(json.dumps({'message': "Missing command data"}))
  407 + return redirect('submit_command_to_cameraNIR')
  408 +
  409 +
  410 +
  411 +
364 412
365 413
366 414
src/devices/CameraNIR.py
@@ -5,7 +5,11 @@ from .Device import DeviceController @@ -5,7 +5,11 @@ from .Device import DeviceController
5 ''' 5 '''
6 Device controller for NIRCamera. 6 Device controller for NIRCamera.
7 This class must implement set, get and do functions (DeviceController is an abstract) 7 This class must implement set, get and do functions (DeviceController is an abstract)
  8 +
8 ''' 9 '''
  10 +
  11 +#TODO: refactoriser cette classe, la seule mรฉthode utilisรฉe est sendMessage, les autres sont obsolรจtes
  12 +
9 class NIRCameraController(DeviceController): 13 class NIRCameraController(DeviceController):
10 14
11 def __init__(self): 15 def __init__(self):
@@ -34,3 +38,7 @@ class NIRCameraController(DeviceController): @@ -34,3 +38,7 @@ class NIRCameraController(DeviceController):
34 def open_shutter(self): 38 def open_shutter(self):
35 self.do("OPEN SHUTTER") 39 self.do("OPEN SHUTTER")
36 return 0 40 return 0
  41 +
  42 + def send_command(self, command):
  43 + self.sendMessage(command)
  44 + return self.blockAndReadMessage()
src/devices/CameraNIRRemoteControlDefault.py 0 โ†’ 100644
@@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
  1 +from devices.CameraRemoteControlAbstract import CameraRemoteControlAbstract
  2 +from devices import CameraNIR
  3 +
  4 +'''
  5 + Class binding method for real grammar corresponding to the generic command received in the command_matchers
  6 +'''
  7 +
  8 +class CameraNIRRemoteControlDefault(CameraRemoteControlAbstract):
  9 + def __init__(self, command, expert_mode):
  10 + super().__init__(command, expert_mode)
  11 + self._camera = CameraNIR.NIRCameraController()
  12 +
  13 + self._command_matcher_set = {
  14 + "WINDOW": self.set,
  15 + "READMODE [MODE 1]": self.set,
  16 + "READMODE [MODE 2]": self.set,
  17 + "READMODE [MODE 3]": self.set,
  18 + "FILENAME": self.set,
  19 + "HEADER": self.set,
  20 + "READOUT_FREQUENCY": self.set,
  21 + "FILTER [FILTER 1]": self.set,
  22 + "FILTER [FILTER 2]": self.set,
  23 + "FILTER [FILTER 3]": self.set,
  24 + "NB_IMAGES": self.set,
  25 + }
  26 + self._command_matcher_get = {
  27 + "STATUS": self.get,
  28 + "SETUP": self.get,
  29 + "TIMER": self.get
  30 + }
  31 + self._command_matcher_do = {
  32 + "COOLER ON": self.do,
  33 + "COOLER OFF": self.do,
  34 + "DOME SHUTTER OPEN": self.do,
  35 + "DOME SHUTTER CLOSE": self.do,
  36 + "DOME SHUTTER SYNCHRO": self.do,
  37 + "START": self.do,
  38 + "ABORT": self.do,
  39 + "STOP": self.do
  40 + }
  41 +
  42 +
  43 +
  44 +
  45 + def exec_command(self):
  46 +
  47 + #os.system("echo \"status :" + str(self._command) + "\" >> /home/portos/IRAP/pyros/src/commande_recu")
  48 + if self._command[0] == "GET":
  49 + self._current_matcher = self._command_matcher_get
  50 + elif self._command[0] == "SET":
  51 + self._current_matcher = self._command_matcher_set
  52 + elif self._command[0] == "DO":
  53 + self._current_matcher = self._command_matcher_do
  54 + else: return "KO: Unknown command"
  55 + if self._command[1] in self._current_matcher:
  56 + return self._current_matcher[self._command[1]]()
  57 + else:
  58 + return "KO: Unknown command"
  59 +
  60 +
  61 + '''
  62 + Locals methods for the generic grammar
  63 + '''
  64 +
  65 + def do(self):
  66 + definitive_command = "DO " + self._command[1] + ' ' + ' '.join(self._command[2:])
  67 + response = self._camera.send_command(definitive_command)
  68 + return response
  69 +
  70 + def set(self):
  71 + definitive_command = "SET " + self._command[1] + ' ' + ' '.join(self._command[2:])
  72 + response = self._camera.send_command(definitive_command)
  73 + return response
  74 +
  75 + def get(self):
  76 + definitive_command = "GET " + self._command[1] #+ ' ' + ' '.join(self._command[2:])
  77 + response = self._camera.send_command(definitive_command)
  78 + return response
0 \ No newline at end of file 79 \ No newline at end of file
src/devices/CameraVISRemoteControlDefault.py
1 from devices.CameraRemoteControlAbstract import CameraRemoteControlAbstract 1 from devices.CameraRemoteControlAbstract import CameraRemoteControlAbstract
2 from devices import CameraVIS 2 from devices import CameraVIS
3 3
  4 +'''
  5 + Class binding method for real grammar corresponding to the generic command received in the command_matchers
  6 +'''
  7 +
4 class CameraVISRemoteControlDefault(CameraRemoteControlAbstract): 8 class CameraVISRemoteControlDefault(CameraRemoteControlAbstract):
5 def __init__(self, command, expert_mode, chosen_camera): 9 def __init__(self, command, expert_mode, chosen_camera):
6 super().__init__(command, expert_mode) 10 super().__init__(command, expert_mode)
@@ -19,7 +23,9 @@ class CameraVISRemoteControlDefault(CameraRemoteControlAbstract): @@ -19,7 +23,9 @@ class CameraVISRemoteControlDefault(CameraRemoteControlAbstract):
19 "READOUT_FREQUENCY": self.set, 23 "READOUT_FREQUENCY": self.set,
20 "FILTER [FILTER 1]": self.set, 24 "FILTER [FILTER 1]": self.set,
21 "FILTER [FILTER 2]": self.set, 25 "FILTER [FILTER 2]": self.set,
22 - "FILTER [FILTER 3]": self.set 26 + "FILTER [FILTER 3]": self.set,
  27 + "BINNING": self.set,
  28 + "EXPOSURE": self.set
23 } 29 }
24 self._command_matcher_get = { 30 self._command_matcher_get = {
25 "STATUS": self.get, 31 "STATUS": self.get,
src/devices/Device.py
@@ -104,7 +104,7 @@ class DeviceController(): @@ -104,7 +104,7 @@ class DeviceController():
104 readable, writable, exceptional = select.select([self.sock], [], [self.sock], 0) 104 readable, writable, exceptional = select.select([self.sock], [], [self.sock], 0)
105 if not (readable or exceptional): 105 if not (readable or exceptional):
106 #ret = self.sock.recv(size).decode() 106 #ret = self.sock.recv(size).decode()
107 - raise (Exception("KO: socket error")) 107 + raise (Exception("KO: socket error or not implemented command"))
108 108
109 ret = self.sock.recv(size).decode() 109 ret = self.sock.recv(size).decode()
110 if (not ret): 110 if (not ret):
src/misc/static/js/command_control_cameraNIR.js 0 โ†’ 100644
@@ -0,0 +1,203 @@ @@ -0,0 +1,203 @@
  1 +var LOGS_REFRESH_FREQUENCE = 2000; //in milliseconds
  2 +var expert_mode = false;
  3 +
  4 +jQuery(document).ready(function(){
  5 +
  6 + var current_command = data;
  7 + var help = null;
  8 +
  9 + /**
  10 + These functions are event watchers on the img_display_help
  11 + **/
  12 +
  13 + $(document).on("mouseenter", "#img_display_help", function() {
  14 + $('#img_display_help').attr('width','40px');
  15 + $('#img_display_help').attr('height','40px');
  16 + });
  17 +
  18 + $(document).on("mouseleave", "#img_display_help", function() {
  19 + $('#img_display_help').attr('width','30px');
  20 + $('#img_display_help').attr('height','30px');
  21 +});
  22 +
  23 +
  24 +$(document).on('click','#img_display_help', function() {
  25 + alert(help);
  26 +});
  27 +
  28 +
  29 +/**
  30 + This function detete the childs of command_form after the child nยฐ start_position
  31 +**/
  32 +
  33 +function delete_childs_after(start_position)
  34 +{
  35 + var form = $("#command_form");
  36 + var length = form.children().length;
  37 +
  38 + for (var i = start_position; i < length; i++) {
  39 + form.children().last().remove();
  40 + }
  41 +}
  42 +
  43 +/**
  44 + This function create the select item with the commands in grammar.json
  45 +**/
  46 +function init_first_param(corresponding_data)
  47 +{
  48 + var sel = $('<select>', {name: "first_param", id:"id_first_param"}).appendTo('#command_form');
  49 + sel.append($("<option>").attr('value', "Choose Value").text("Choose Value: "));
  50 + for (var tmp in corresponding_data)
  51 + {
  52 + sel.append($("<option>").attr('value', corresponding_data[tmp]["name"]).text(corresponding_data[tmp]["name"]));
  53 + }
  54 + sel.css("font-size", "20px");
  55 +}
  56 +
  57 +/**
  58 + This event watcher is triggered when the first_param (second submit element) is changed, it creates the inputs fields, desc, help and the submit button
  59 + with the corresponding values in grammar.json with current_command previously defined
  60 +**/
  61 +
  62 + $(document).on('change','#id_first_param', function() {
  63 + delete_childs_after(4);
  64 + var form = $("#command_form");
  65 + var selected_command = $("#id_first_param").find(":selected").val();
  66 + var input = null;
  67 + var label = null;
  68 + for (var tmp in current_command)ย 
  69 + {
  70 + if (current_command[tmp]["name"] === selected_command)
  71 + {
  72 + input = current_command[tmp]["input_label"][0];
  73 + help = current_command[tmp]["help"];
  74 + label = current_command[tmp]["label"];
  75 + }
  76 + }
  77 +
  78 + var number = 0;
  79 + for (var input_field in input)
  80 + {
  81 + var maxlength = input[input_field][0];
  82 + var type_input = input[input_field][1];
  83 + var desc = input[input_field][2];
  84 + var id = "input_number_" + number;
  85 + var name = "input_number_" + number;
  86 + var title = desc + ". value type: " + type_input;
  87 + number++;
  88 + input_element = $("<label>" + input_field + " </label><input title=\"" + title + "\" type=\"text\" id=\"" + id + "\" name=\"" + id + "\" maxlength=\"" + maxlength + "\" size=\"10\" text=\"" + input_field + "\"/>");
  89 + form.append(input_element);
  90 + }
  91 +
  92 + var img_display_help = document.createElement('img');
  93 + img_display_help.src = "/public/static/media/question-mark.png";
  94 + img_display_help.width = 30;
  95 + img_display_help.height = 30;
  96 + img_display_help.title = "Click to display help for this command";
  97 + img_display_help.id ="img_display_help";
  98 + img_display_help.alt="html5";
  99 +
  100 + form.append(img_display_help);
  101 + $("#img_display_help").css("margin-left", "10px");
  102 + form.append("<br><br><p id=\"command_label\">Command description: " + label + "</p>");
  103 + //$("#command_label").css("text-align", "center");
  104 + $("#command_label").css({
  105 + 'font-size' : '15px',
  106 + 'text-align' : 'center',
  107 + 'font-weight' : 'bold'
  108 + });
  109 + form.append("<br>")
  110 + $('<input>', {id:"submit_button", type:"submit", value:"SEND"}).appendTo(form);
  111 +
  112 + });
  113 +
  114 +
  115 + /**
  116 + This event watcher is triggered when the first select element is changed, it set the json current_command to SET, GET or DO, it
  117 + calls init_first_param
  118 + **/
  119 + $("#id_first_command").change(function() {
  120 + delete_childs_after(3);
  121 + var selected_command = $("#id_first_command").find(":selected").val();
  122 + if (selected_command !== "Command")
  123 + {
  124 + current_command = data["CameraNIR"][selected_command.toLowerCase()];
  125 + init_first_param(data["CameraNIR"][selected_command.toLowerCase()]);
  126 + }
  127 + });
  128 +
  129 +
  130 + /**
  131 + This event watcher is triggered when the expert mode is activated, it generates the corresponding input field and submit_button
  132 + **/
  133 +
  134 +$("#expert_mode").click(function(){
  135 + if (!expert_mode)
  136 + {
  137 + expert_mode = true;
  138 + $("#command_form_expert").append("<input id='input_command_expert' type='text' name='commande_expert'>");
  139 + $('<input>', {id:"submit_button_expert", type:"submit", value:"SEND"}).appendTo('#command_form_expert');
  140 + }
  141 + else {
  142 + $("#input_command_expert").remove();
  143 + $("#submit_button_expert").remove();
  144 + expert_mode = false;
  145 + }
  146 + //$("#command_form").remove();
  147 +});
  148 +
  149 +/**
  150 + This event watcher is triggered when the expert form is submitted, it's and AJAX POST request, the response is displayed in the console
  151 +**/
  152 +
  153 +$("#command_form_expert").submit(function(event){
  154 +
  155 + event.preventDefault();
  156 + $.post('observation_status/send_command_to_cameraNIR/submit_expert', $(this).serialize(), function(data){
  157 + var obj = JSON.parse(data);
  158 + console.log(obj.message);
  159 + console.log(obj.response);
  160 + if (obj.response === "KO: Unknown command")
  161 + alert("Unknown command");
  162 + else if (obj.response.startsWith("KO"))
  163 + alert(obj.response);
  164 + })
  165 + .fail(function() {
  166 + alert( "An error occured" );
  167 + })
  168 + });
  169 +
  170 +
  171 +/**
  172 + This AJAX refreshed request is a get retrieving the Logs of the telescope
  173 +**/
  174 +
  175 + interval_camera = setInterval(function() {ajax_request();}, LOGS_REFRESH_FREQUENCE);
  176 +
  177 + function ajax_request(){
  178 + var camera_url ="/devices/update_cagire_logs";
  179 + $.ajax({
  180 + url: camera_url,
  181 + type: 'get',
  182 + dataType: 'text',
  183 + success: function(data)
  184 + {
  185 + var obj = JSON.parse(data);
  186 + if (obj) {
  187 + var listDiv = document.getElementById('cagire_logs');
  188 + listDiv.innerHTML = '';
  189 + for (var tmp in obj) {
  190 + var li = document.createElement('li');
  191 + li.innerHTML = obj[tmp]['fields']['created'] + ": " + obj[tmp]['fields']['message']; // Use innerHTML to set the text
  192 + listDiv.appendChild(li);
  193 + }
  194 + }
  195 + },
  196 + error: function()
  197 + {
  198 + console.log('Ajax error: GET request failed\n');
  199 + }
  200 +
  201 + });
  202 + }
  203 +});