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 245 "label": "Change the wanted filter",
246 246 "input_label": [],
247 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 441 "get": [
... ...
src/dashboard/templates/dashboard/observation_status.html
... ... @@ -125,6 +125,11 @@
125 125 {% for log in cagire_logs %}
126 126 <li>{{log.created}} : {{log.message}}</li> {% endfor %}
127 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 133 </div>
129 134 <div class="element" id=DDRAGORED>
130 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 @@
  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 125 \ No newline at end of file
... ...
src/dashboard/urls.py
... ... @@ -24,6 +24,9 @@ urlpatterns = [
24 24 path('observation_status/send_command_to_telescope/submit_expert', views.submit_command_to_telescope_expert, name='submit_command_to_telescope_expert'),
25 25 path('observation_status/send_command_to_telescope/submit', views.submit_command_to_telescope, name='submit_command_to_telescope'),
26 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 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 31 path('observation_status/send_command_to_cameraVIS_1/submit', views.submit_command_to_cameraVIS_1, name='submit_command_to_cameraVIS_1'),
29 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 19 from devices.Telescope import TelescopeController
20 20 from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault
21 21 from devices.CameraVISRemoteControlDefault import CameraVISRemoteControlDefault
  22 +from devices.CameraNIRRemoteControlDefault import CameraNIRRemoteControlDefault
22 23 from django.core.mail import send_mail
23 24 import time
24 25 import utils.celme as celme
... ... @@ -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 5 '''
6 6 Device controller for NIRCamera.
7 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 13 class NIRCameraController(DeviceController):
10 14  
11 15 def __init__(self):
... ... @@ -34,3 +38,7 @@ class NIRCameraController(DeviceController):
34 38 def open_shutter(self):
35 39 self.do("OPEN SHUTTER")
36 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 @@
  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 79 \ No newline at end of file
... ...
src/devices/CameraVISRemoteControlDefault.py
1 1 from devices.CameraRemoteControlAbstract import CameraRemoteControlAbstract
2 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 8 class CameraVISRemoteControlDefault(CameraRemoteControlAbstract):
5 9 def __init__(self, command, expert_mode, chosen_camera):
6 10 super().__init__(command, expert_mode)
... ... @@ -19,7 +23,9 @@ class CameraVISRemoteControlDefault(CameraRemoteControlAbstract):
19 23 "READOUT_FREQUENCY": self.set,
20 24 "FILTER [FILTER 1]": self.set,
21 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 30 self._command_matcher_get = {
25 31 "STATUS": self.get,
... ...
src/devices/Device.py
... ... @@ -104,7 +104,7 @@ class DeviceController():
104 104 readable, writable, exceptional = select.select([self.sock], [], [self.sock], 0)
105 105 if not (readable or exceptional):
106 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 109 ret = self.sock.recv(size).decode()
110 110 if (not ret):
... ...
src/misc/static/js/command_control_cameraNIR.js 0 โ†’ 100644
... ... @@ -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 +});
... ...