Commit 128e1a71f8c3d25e70c7bc0a9a795bd772f0caa0

Authored by Etienne Pallier
1 parent f7972fc3
Exists in dev

AgentDevice + AgentDeviceTelescopeStatus + AgentTelescopeRequester

Dans le détail :
- AgentDevice met à jour la table AgentDeviceTelescopeStatus
- AgentTelescopeRequester interroge AgentDevice
- Quelques bugfixes
- Mode opératoire:
./pyros start agentDevice
ou, en mode simu:
./pyros -t start agentTelescopeRequester,agentDevice
@@ -67,14 +67,22 @@ This software has been tested and validated with the following configurations : @@ -67,14 +67,22 @@ This software has been tested and validated with the following configurations :
67 -------------------------------------------------------------------------------------------- 67 --------------------------------------------------------------------------------------------
68 ## LAST VERSION 68 ## LAST VERSION
69 69
70 -Date: 17/04/2019 70 +Date: 26/04/2019
71 71
72 Author: E. Pallier 72 Author: E. Pallier
73 73
74 -VERSION: 0.20.38 74 +VERSION: 0.20.40
75 75
76 -Comment:  
77 - Génération automatique des diagrammes PlantUML avec "pyros update" 76 +Comment: AgentDevice + AgentDeviceTelescopeStatus + AgentTelescopeRequester
  77 +
  78 + - Dans le détail :
  79 + - AgentDevice met à jour la table AgentDeviceTelescopeStatus
  80 + - AgentTelescopeRequester interroge AgentDevice
  81 + - Quelques bugfixes
  82 + - Mode opératoire:
  83 + ./pyros start agentDevice
  84 + ou, en mode simu:
  85 + ./pyros -t start agentTelescopeRequester,agentDevice
78 86
79 - Scenario de test : 87 - Scenario de test :
80 - lancer agents A et B en mode simu (option -t): ./pyros.py -t start agentA,agentB 88 - lancer agents A et B en mode simu (option -t): ./pyros.py -t start agentA,agentB
@@ -89,6 +97,7 @@ Comment: @@ -89,6 +97,7 @@ Comment:
89 - pour utiliser thread ou processus : il suffit de mettre la constante RUN_IN_THREAD de AgentA (ou AgentB ou AgentX) à False ou True 97 - pour utiliser thread ou processus : il suffit de mettre la constante RUN_IN_THREAD de AgentA (ou AgentB ou AgentX) à False ou True
90 98
91 - Historique des nouveautés implémentées : 99 - Historique des nouveautés implémentées :
  100 + - Génération automatique des diagrammes PlantUML avec "pyros update"
92 - Implémentation complète du "Command state diag" 101 - Implémentation complète du "Command state diag"
93 - Nouveaux diagrammes UML pour Command (state diag) et Agent (activity diag) 102 - Nouveaux diagrammes UML pour Command (state diag) et Agent (activity diag)
94 - Déplacé AgentM dans src/monitoring/ (pyros start agentM) 103 - Déplacé AgentM dans src/monitoring/ (pyros start agentM)
@@ -31,6 +31,7 @@ AGENTS = { @@ -31,6 +31,7 @@ AGENTS = {
31 "agentB" : "AgentB", 31 "agentB" : "AgentB",
32 "agentM" : "AgentM", 32 "agentM" : "AgentM",
33 "agentDevice" : "AgentDevice", 33 "agentDevice" : "AgentDevice",
  34 + "agentTelescopeRequester" : "AgentTelescopeRequester",
34 "webserver" : "webserver", 35 "webserver" : "webserver",
35 "monitoring" : "monitoring", 36 "monitoring" : "monitoring",
36 "majordome" : "majordome", 37 "majordome" : "majordome",
src/agent/Agent.py
@@ -490,8 +490,8 @@ class Agent: @@ -490,8 +490,8 @@ class Agent:
490 if not self.DO_MAIN_LOOP: break 490 if not self.DO_MAIN_LOOP: break
491 except KeyboardInterrupt: 491 except KeyboardInterrupt:
492 # In case of CTRL-C, kill the current thread (process) before dying (in error) 492 # In case of CTRL-C, kill the current thread (process) before dying (in error)
493 - self.print("CTRL-C Interrupted, I kill the current thread (process) before exiting")  
494 - self.kill_running_specific_cmd_if_exists() 493 + self.print("CTRL-C Interrupted, I kill the current thread (process) before exiting (if exists)")
  494 + self.kill_running_specific_cmd_if_exists("USER_CTRLC")
495 exit(1) 495 exit(1)
496 #if self.DO_EXIT: exit(0) 496 #if self.DO_EXIT: exit(0)
497 497
@@ -1025,9 +1025,9 @@ class Agent: @@ -1025,9 +1025,9 @@ class Agent:
1025 1025
1026 def kill_running_specific_cmd_if_exists(self, abort_sender): 1026 def kill_running_specific_cmd_if_exists(self, abort_sender):
1027 if (self._current_specific_thread is None) or not self._current_specific_thread.is_alive(): 1027 if (self._current_specific_thread is None) or not self._current_specific_thread.is_alive():
1028 - self.printd("...No current specific command thread to abort...") 1028 + self.print("...No current specific command thread to abort...")
1029 else: 1029 else:
1030 - self.printd(f"Killing command {self._current_specific_cmd.name}") 1030 + self.print(f"Killing command {self._current_specific_cmd.name}")
1031 # Ask the thread to stop itself 1031 # Ask the thread to stop itself
1032 #self._current_specific_thread.stop() 1032 #self._current_specific_thread.stop()
1033 #self._current_specific_thread._stop() 1033 #self._current_specific_thread._stop()
src/agent/AgentDevice.py
@@ -8,6 +8,7 @@ import time @@ -8,6 +8,7 @@ import time
8 ##from .Agent import Agent 8 ##from .Agent import Agent
9 sys.path.append("..") 9 sys.path.append("..")
10 from agent.Agent import Agent, extract_parameters 10 from agent.Agent import Agent, extract_parameters
  11 +from common.models import AgentDeviceTelescopeStatus
11 from devices_channel.client.telescope_controller_gemini import TelescopeControllerGEMINI 12 from devices_channel.client.telescope_controller_gemini import TelescopeControllerGEMINI
12 13
13 ##log = L.setupLogger("AgentXTaskLogger", "AgentX") 14 ##log = L.setupLogger("AgentXTaskLogger", "AgentX")
@@ -78,16 +79,24 @@ class AgentDevice(Agent): @@ -78,16 +79,24 @@ class AgentDevice(Agent):
78 #HOST, PORT = "localhost", 11110 79 #HOST, PORT = "localhost", 11110
79 self.tele_ctrl = TelescopeControllerGEMINI(HOST, PORT, True) 80 self.tele_ctrl = TelescopeControllerGEMINI(HOST, PORT, True)
80 81
  82 +
81 # @override 83 # @override
82 def init(self): 84 def init(self):
  85 +
83 super().init() 86 super().init()
84 # --- Set the mode according the startmode value 87 # --- Set the mode according the startmode value
85 ##agent_alias = self.__class__.__name__ 88 ##agent_alias = self.__class__.__name__
86 ##self.set_mode_from_config(agent_alias) 89 ##self.set_mode_from_config(agent_alias)
  90 +
  91 + # Device socket init
87 # (optional) Only useful for TCP (does nothing for UDP) 92 # (optional) Only useful for TCP (does nothing for UDP)
88 self.tele_ctrl._connect_to_device() 93 self.tele_ctrl._connect_to_device()
89 self.tele_ctrl.print_available_commands() 94 self.tele_ctrl.print_available_commands()
90 95
  96 + # Telescope (long) init
  97 + # TODO:
  98 +
  99 +
91 ''' 100 '''
92 # @override 101 # @override
93 def load_config(self): 102 def load_config(self):
@@ -129,11 +138,19 @@ class AgentDevice(Agent): @@ -129,11 +138,19 @@ class AgentDevice(Agent):
129 cmd="get radec" 138 cmd="get radec"
130 res = self.tele_ctrl.execute_cmd(cmd) 139 res = self.tele_ctrl.execute_cmd(cmd)
131 print("result is", str(res)) 140 print("result is", str(res))
  141 + myradec = str(res)
132 if res.ok: print("OK") 142 if res.ok: print("OK")
133 143
  144 + AgentDeviceTelescopeStatus.objects.create(radec=myradec)
  145 +
134 time.sleep(3) 146 time.sleep(3)
135 self.print("ROUTINE PROCESS END") 147 self.print("ROUTINE PROCESS END")
136 148
  149 + # @override
  150 + def kill_running_specific_cmd_if_exists(self, abort_sender):
  151 + super().kill_running_specific_cmd_if_exists(abort_sender)
  152 + print("Close telescope socket")
  153 + self.tele_ctrl.close()
137 154
138 155
139 156
src/agent/AgentTelescopeRequester.py 0 → 100755
@@ -0,0 +1,245 @@ @@ -0,0 +1,245 @@
  1 +#!/usr/bin/env python3
  2 +
  3 +
  4 +import sys
  5 +##import utils.Logger as L
  6 +
  7 +##from .Agent import Agent
  8 +sys.path.append("..")
  9 +from agent.Agent import Agent, extract_parameters
  10 +
  11 +
  12 +##log = L.setupLogger("AgentXTaskLogger", "AgentX")
  13 +
  14 +
  15 +
  16 +class AgentTelescopeRequester(Agent):
  17 +
  18 + # FOR TEST ONLY
  19 + # Run this agent in simulator mode
  20 + SIMULATOR_MODE = False
  21 + # Run the assertion tests at the end
  22 + SIMULATOR_WITH_TEST = True
  23 + #SIMULATOR_MAX_DURATION_SEC = None
  24 + SIMULATOR_MAX_DURATION_SEC = 100
  25 + # Who should I send commands to ?
  26 + #SIMULATOR_COMMANDS_DEST = "myself"
  27 + SIMULATOR_COMMANDS_DEST = "AgentDevice"
  28 + # Scenario to be executed
  29 + SIMULATOR_COMMANDS_LIST = [
  30 + # Ask receiver to delete all its previous commands
  31 + "flush_commands",
  32 +
  33 + "go_active",
  34 +
  35 + # Because of this command, the receiver agent :
  36 + # - will no more send any new command
  37 + # - will only execute "generic" commands (and not the "specific" ones)
  38 + "go_idle",
  39 +
  40 + # Not executed (skipped) because receiver agent is now "idle"
  41 + #"specific0",
  42 +
  43 + # Because of this command, the receiver agent
  44 + # will now be able to send new commands
  45 + "go_active",
  46 +
  47 + # Executed because recipient agent is now "active"
  48 + "specific1",
  49 + # should abort previous command (specific1)
  50 + "abort",
  51 +
  52 + # Executed completely because no abort
  53 + "specific2",
  54 +
  55 + # fully executed, result is 7
  56 + "eval 4+3",
  57 +
  58 + "go_idle",
  59 + "exit",
  60 + ]
  61 +
  62 +
  63 +
  64 + """
  65 + =================================================================
  66 + FUNCTIONS RUN INSIDE MAIN THREAD
  67 + =================================================================
  68 + """
  69 +
  70 + # @override
  71 + def __init__(self, name:str=None, config_filename=None, RUN_IN_THREAD=True):
  72 + if name is None: name = self.__class__.__name__
  73 + super().__init__(name, config_filename, RUN_IN_THREAD)
  74 + self._log.print(f"init done for {name}")
  75 +
  76 + # @override
  77 + def init(self):
  78 + super().init()
  79 + # --- Set the mode according the startmode value
  80 + ##agent_alias = self.__class__.__name__
  81 + ##self.set_mode_from_config(agent_alias)
  82 +
  83 + '''
  84 + # @override
  85 + def load_config(self):
  86 + super().load_config()
  87 + '''
  88 +
  89 + '''
  90 + # @override
  91 + def update_survey(self):
  92 + super().update_survey()
  93 + '''
  94 +
  95 + '''
  96 + # @override
  97 + def get_next_command(self):
  98 + return super().get_next_command()
  99 + '''
  100 +
  101 + # @override
  102 + def do_log(self):
  103 + super().do_log()
  104 +
  105 +
  106 +
  107 + """
  108 + =================================================================
  109 + FUNCTIONS RUN INSIDE A SUB-THREAD (OR A PROCESS) (thread_*())
  110 + =================================================================
  111 + """
  112 +
  113 + # Define your own command step(s) here
  114 + def cmd_step1(self, step:int):
  115 + cmd = self._current_specific_cmd
  116 + cmd.result = f"in step #{step}/{self._thread_total_steps_number}"
  117 + cmd.save()
  118 + """
  119 + if self.RUN_IN_THREAD:
  120 + print("(save from thread)")
  121 + cmd.save()
  122 + else:
  123 + #@transaction.atomic
  124 + print("(save from process)")
  125 + with transaction.atomic():
  126 + cmd.save()
  127 + #Command.objects.select_for_update()
  128 + """
  129 +
  130 + def cmd_step2(self, step:int):
  131 + self.cmd_step1(step)
  132 + def cmd_step3(self, step:int):
  133 + self.cmd_step1(step)
  134 + def cmd_step4(self, step:int):
  135 + self.cmd_step1(step)
  136 +
  137 + """
  138 + # @override
  139 + def thread_exec_specific_cmd_step(self, step:int, sleep_time:float=1.0):
  140 + self.thread_stop_if_asked()
  141 + cmd = self._current_specific_cmd
  142 + print(f">>>>> Thread (cmd {cmd.name}): step #{step}/5")
  143 + self.sleep(sleep_time)
  144 + """
  145 +
  146 + '''
  147 + # @override
  148 + def exec_specific_cmd_start(self, cmd:Command, from_thread=True):
  149 + super().exec_specific_cmd_start(cmd, from_thread)
  150 + '''
  151 +
  152 +
  153 + # @override
  154 + def thread_exec_specific_cmd_main(self):
  155 + # This is optional
  156 + self.thread_set_total_steps_number(5)
  157 +
  158 + # HERE, write your own scenario
  159 +
  160 + # scenario OK
  161 + self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1)
  162 + self.thread_exec_specific_cmd_step(2, self.cmd_step2, 3)
  163 + self.thread_exec_specific_cmd_step(3, self.cmd_step1, 5)
  164 + self.thread_exec_specific_cmd_step(4, self.cmd_step3, 10)
  165 + self.thread_exec_specific_cmd_step(5, self.cmd_step1, 4)
  166 + # ... as many as you need
  167 +
  168 + """ autre scenario
  169 + self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1)
  170 + self.thread_exec_specific_cmd_step(2, self.cmd_step2, 2)
  171 + self.thread_exec_specific_cmd_step(3, self.cmd_step1, 2)
  172 + self.thread_exec_specific_cmd_step(4, self.cmd_step3, 2)
  173 + self.thread_exec_specific_cmd_step(5, self.cmd_step1, 3)
  174 + """
  175 +
  176 + '''
  177 + # @override
  178 + def exec_specific_cmd_end(self, cmd:Command, from_thread=True):
  179 + super().exec_specific_cmd_end(cmd, from_thread)
  180 + '''
  181 +
  182 + # @override
  183 + def simulator_test_results_main(self, commands):
  184 + nb_asserted = 0
  185 + for cmd in commands:
  186 + if cmd.name == "flush_commands":
  187 + assert cmd.is_executed()
  188 + nb_asserted+=1
  189 + # 2 times
  190 + if cmd.name == "go_active":
  191 + assert cmd.is_executed()
  192 + nb_asserted+=1
  193 + # 2 times
  194 + if cmd.name == "go_idle":
  195 + assert cmd.is_executed()
  196 + nb_asserted+=1
  197 + """
  198 + if cmd.name == "specific0":
  199 + assert cmd.is_skipped()
  200 + assert cmd.result == "in step #5/5"
  201 + nb_asserted+=1
  202 + """
  203 + if cmd.name == "specific1":
  204 + assert cmd.is_killed()
  205 + nb_asserted+=1
  206 + if cmd.name == "specific2":
  207 + assert cmd.is_executed()
  208 + assert cmd.result == "in step #5/5"
  209 + nb_asserted+=1
  210 + if cmd.name == "eval 4+3":
  211 + assert cmd.is_executed()
  212 + assert cmd.get_result() == "7"
  213 + nb_asserted+=1
  214 + if cmd.name in ("abort"):
  215 + assert cmd.is_executed()
  216 + nb_asserted+=1
  217 + if cmd.name in ("exit"):
  218 + assert cmd.is_executed()
  219 + nb_asserted+=1
  220 + return nb_asserted
  221 +
  222 +
  223 +"""
  224 +=================================================================
  225 + MAIN FUNCTION
  226 +=================================================================
  227 +"""
  228 +if __name__ == "__main__":
  229 + # with thread
  230 + RUN_IN_THREAD=True
  231 + # with process
  232 + #RUN_IN_THREAD=False
  233 +
  234 + TEST_MODE, configfile = extract_parameters()
  235 + """
  236 + configfile = None
  237 + # arg 1 : config file
  238 + if len(sys.argv) == 2:
  239 + configfile = sys.argv[1]
  240 + """
  241 + #agent = AgentX()
  242 + agent = AgentTelescopeRequester("AgentTelescopeRequester", configfile, RUN_IN_THREAD)
  243 + agent.setSimulatorMode(TEST_MODE)
  244 + print(agent)
  245 + agent.run()
src/common/models.py
@@ -213,6 +213,20 @@ class Request(models.Model): @@ -213,6 +213,20 @@ class Request(models.Model):
213 ------------------------ 213 ------------------------
214 """ 214 """
215 215
  216 +class AgentDeviceTelescopeStatus(models.Model):
  217 + created = models.DateTimeField('status date', blank=True, null=True, auto_now_add=True)
  218 + radec = models.CharField('agent mode', max_length=30, blank=True)
  219 +
  220 + class Meta:
  221 + managed = True
  222 + db_table = 'agent_device_telescope_status'
  223 + #verbose_name = "agent survey"
  224 + #verbose_name_plural = "agents survey"
  225 +
  226 + """
  227 + def __str__(self):
  228 + return (f"Agent {self.name} at {self.updated} in mode {self.mode} and status {self.status}")
  229 + """
216 230
217 class AgentSurvey(models.Model): 231 class AgentSurvey(models.Model):
218 """ 232 """