#!/usr/bin/env python3 import sys ##import utils.Logger as L import threading import time ##from .Agent import Agent sys.path.append("..") from agent.Agent import Agent, build_agent from common.models import AgentDeviceStatus, Command, get_or_create_unique_row_from_model sys.path.append("../../..") from device_controller.abstract_component.device_controller import DeviceController, DCCNotFoundException, NotImplementedGenericCmdException ##log = L.setupLogger("AgentXTaskLogger", "AgentX") class AgentDevice(Agent): # Default host and port of the device controller _device_ctrl = None _device_sim = None HOST, PORT = None, None _thread_device_simulator = None _agent_device_status = None # FOR TEST ONLY # Run this agent in simulator mode TEST_MODE = False # Run the assertion tests at the end TEST_WITH_FINAL_TEST = False #TEST_MAX_DURATION_SEC = None TEST_MAX_DURATION_SEC = 100 # Who should I send commands to ? #TEST_COMMANDS_DEST = "myself" TEST_COMMANDS_DEST = "AgentB" # Scenario to be executed TEST_COMMANDS_LIST = [ # Ask receiver to delete all its previous commands "flush_commands", "go_active", # Because of this command, the receiver agent : # - will no more send any new command # - will only execute "generic" commands (and not the "specific" ones) "go_idle", # Not executed (skipped) because receiver agent is now "idle" #"specific0", # Because of this command, the receiver agent # will now be able to send new commands "go_active", # Executed because recipient agent is now "active" "specific1", # should abort previous command (specific1) "abort", # Executed completely because no abort "specific2", # fully executed, result is 7 "eval 4+3", "go_idle", "exit", ] """ ================================================================= FUNCTIONS RUN INSIDE MAIN THREAD ================================================================= """ # @override #def __init__(self, name:str=None, config_filename=None, RUN_IN_THREAD=True, device_controller, host, port): #def __init__(self, name:str, config_filename, RUN_IN_THREAD, device_controller, host, port, device_simulator): ##def __init__(self, config_filename, RUN_IN_THREAD, device_controller:DeviceController, host, port, device_simulator): def __init__(self, config_filename, RUN_IN_THREAD, device_controller:DeviceController, host, port): ##if name is None: name = self.__class__.__name__ #super().__init__(name, config_filename, RUN_IN_THREAD) super().__init__(config_filename, RUN_IN_THREAD) self.HOST, self.PORT = host, port self._device_ctrl = device_controller ##self._device_sim = device_simulator # Initialize the device table status # If table is empty, create a default 1st row ##self._agent_device_status = get_or_create_unique_row_from_model(AgentDeviceStatus) self._agent_device_status = AgentDeviceStatus.getStatusForAgent(self.name) """ if not AgentDeviceTelescopeStatus.objects.exists(): print("CREATE first row") self._agent_device_status = AgentDeviceTelescopeStatus.objects.create(id=1) # Get 1st row (will be updated at each iteration by routine_process() with current device status) print("GET first row") self._agent_device_status = AgentDeviceTelescopeStatus.objects.get(id=1) """ # Initialize the device socket # Port local AK 8085 = redirigé sur l’IP du tele 192.168.0.12 sur port 11110 ##HOST, PORT = "82.64.28.71", 11110 #HOST, PORT = "localhost", 11110 #self._device_ctrl = TelescopeControllerGEMINI(host, port, True) ##self._device_ctrl = device_controller(HOST, PORT, True) ##self._device_ctrl = device_controller(host, port, True) self._log.print("init done") # @override def init(self): super().init() # --- Set the mode according the startmode value ##agent_alias = self.__class__.__name__ ##self.set_mode_from_config(agent_alias) # If in test and simulator mode ==> set my DC as connected to localhost (simulator server) if self.is_in_test_mode() and self.WITH_SIMULATOR: # START device SIMULATOR (in a thread) so that we can connect to it in place of the real device self.HOST = "localhost" ''' self._thread_device_simulator = threading.Thread(target=self.device_simulator_run) self._thread_device_simulator.start() ''' # Create instance of device controller (device client) # Ex: this can be the Gemini or the SBIG (...) DC self._device_ctrl = self._device_ctrl(self.HOST, self.PORT, True) # Device socket init # (optional) Only useful for TCP (does nothing for UDP) self._device_ctrl._connect_to_device() self._device_ctrl.print_available_commands() # Telescope (long) init # TODO: def is_using_simulator(self): return self.WITH_SIMULATOR ''' def device_simulator_run(self): #HOST, PORT = "localhost", 11110 #with get_SocketServer_UDP_TCP(HOST, PORT, "UDP") as myserver: print("Starting device simulator on (host, port): ", self.HOST, self.PORT) self._device_sim.serve_forever(self.PORT) #with get_SocketServer_UDP_TCP(self.HOST, self.PORT, "UDP") as myserver: myserver.serve_forever() #'' myserver = get_SocketServer_UDP_TCP(self.HOST, self.PORT, "UDP") myserver.serve_forever() #'' ''' ''' # @override def load_config(self): super().load_config() ''' ''' # @override def update_survey(self): super().update_survey() ''' ''' # @override def get_next_command(self): return super().get_next_command() ''' # @override def do_log(self): super().do_log() # @override def routine_process(self): self.print("ROUTINE PROCESS START: reading my dedicated device status information and storing it in DB)...") # Save current device status to DB #AgentDeviceTelescopeStatus.objects.create(radec=myradec) #if not self.is_running_specific_cmd(): self._save_device_status() self.print("Status saved in DB") #time.sleep(3) self.print("ROUTINE PROCESS END") def _save_device_status(self): self._agent_device_status.status = self.get_device_status() self._agent_device_status.save() # To be overriden by subclass def get_device_status(self): return 'Abstract status' # @override def kill_running_specific_cmd_if_exists(self, abort_sender): super().kill_running_specific_cmd_if_exists(abort_sender) print("Close device socket") self._device_ctrl.close() ''' # Stop device simulator (only if used) if self.is_using_simulator(): print("Stopping device simulator") self._device_sim.stop() ''' """ # @override def specific_process(self, cmd): cmd.set_read_time() cmd.set_as_running() res = self._device_ctrl.execute_cmd(cmd.name) cmd.set_result(str(res)) print("result is", str(res)) if res.ok: print("OK") cmd.set_as_processed() time.sleep(1) """ """ ================================================================= FUNCTIONS RUN INSIDE A SUB-THREAD (OR A PROCESS) (thread_*()) ================================================================= """ # This method is also called DIRECTLY from routine_process().get_device_status() (NOT FROM A THREAD) # @override parent class (Agent) def exec_specific_cmd(self, cmd:Command): #cmd = self._current_specific_cmd self.printd("*** SPECIFIC cmd name is", cmd.name) self.printd("*** PASS IT TO DEVICE TYPE", cmd.device_type) try: res = self._device_ctrl.execute_cmd(cmd.full_name) except (DCCNotFoundException, NotImplementedGenericCmdException) as e: print(f"EXCEPTION caught by {type(self).__name__} (from AD)", e) raise print("result is", str(res)) if res.ok: self.printd("OK") time.sleep(1) return res # @override superclass (Agent) method def OLD_cmd_step_OLD(self, step:int): cmd = self._current_specific_cmd print("cmd name is", cmd.name) #res = self._device_ctrl.execute_cmd(cmd.name_and_args) res = self._device_ctrl.execute_cmd(cmd.full_name) ##cmd.set_result(str(res)) print("result is", str(res)) if res.ok: print("OK") #cmd.set_as_processed() time.sleep(1) #cmd.set_result(f"in step #{step}/{self._thread_total_steps_number}") cmd.set_result(res) # @override def OLD_thread_exec_specific_cmd_main_OLD(self): # This is optional self.thread_set_total_steps_number(1) # HERE, write your own scenario self.thread_exec_specific_cmd_step(1, self.cmd_step, 1) # ... as many as you need """ other scenario self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1) self.thread_exec_specific_cmd_step(2, self.cmd_step2, 2) self.thread_exec_specific_cmd_step(3, self.cmd_step1, 2) self.thread_exec_specific_cmd_step(4, self.cmd_step3, 2) self.thread_exec_specific_cmd_step(5, self.cmd_step1, 3) """ ''' # @override def exec_specific_cmd_end(self, cmd:Command, from_thread=True): super().exec_specific_cmd_end(cmd, from_thread) ''' """ ================================================================= MAIN FUNCTION ================================================================= """ if __name__ == "__main__": # with thread RUN_IN_THREAD=True # with process #RUN_IN_THREAD=False agent = build_agent(AgentDevice, RUN_IN_THREAD=RUN_IN_THREAD) ''' TEST_MODE, WITH_SIM, configfile = extract_parameters() #agent = AgentX() agent = AgentDevice("AgentDevice", configfile, RUN_IN_THREAD) #agent.setSimulatorMode(TEST_MODE) agent.setTestMode(TEST_MODE) agent.setWithSimulator(WITH_SIM) print(agent) ''' agent.run()