AgentDevice.py 9.85 KB
#!/usr/bin/env python3
# ENCODING: Ok for Unix and Mac
# For Windows, replace Utf-8" with "Latin-1"
# -*-coding:Utf-8 -*

import sys
##import utils.Logger as L
import time

##from .Agent import Agent
sys.path.append("..")
from agent.Agent import Agent, extract_parameters
from common.models import AgentDeviceTelescopeStatus, get_or_create_unique_row_from_model
from devices_channel.client.telescope_controller_gemini import TelescopeControllerGEMINI

##log = L.setupLogger("AgentXTaskLogger", "AgentX")



class AgentDevice(Agent):

    _agent_device_telescope_status = None

    # FOR TEST ONLY
    # Run this agent in simulator mode
    SIMULATOR_MODE = False
    # Run the assertion tests at the end
    SIMULATOR_WITH_TEST = False
    #SIMULATOR_MAX_DURATION_SEC = None
    SIMULATOR_MAX_DURATION_SEC = 100
    # Who should I send commands to ?
    #SIMULATOR_COMMANDS_DEST = "myself"
    SIMULATOR_COMMANDS_DEST = "AgentB"
    # Scenario to be executed
    SIMULATOR_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=TelescopeControllerGEMINI):
        if name is None: name = self.__class__.__name__
        super().__init__(name, config_filename, RUN_IN_THREAD)

        # Initialize the device table status
        # If table is empty, create a default 1st row
        self._agent_device_telescope_status = get_or_create_unique_row_from_model(AgentDeviceTelescopeStatus)
        """
        if not AgentDeviceTelescopeStatus.objects.exists():
            print("CREATE first row")
            self._agent_device_telescope_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_telescope_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.tele_ctrl = TelescopeControllerGEMINI(HOST, PORT, True)
        self._log.print(f"init done for {name}")


    # @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)

        # Device socket init
        # (optional) Only useful for TCP (does nothing for UDP)
        self.tele_ctrl._connect_to_device()
        self.tele_ctrl.print_available_commands()

        # Telescope (long) init
        # TODO:


    '''
    # @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)")
        self.print("...")

        cmd="get date"
        res = self.tele_ctrl.execute_cmd(cmd)
        print("result is", str(res))
        if res.ok: print("OK")
        time.sleep(1)

        cmd="get time"
        res = self.tele_ctrl.execute_cmd(cmd)
        print("result is", str(res))
        if res.ok: print("OK")
        time.sleep(1)

        cmd="get radec"
        res = self.tele_ctrl.execute_cmd(cmd)
        print("result is", str(res))
        myradec = str(res)
        if res.ok: print("OK")
        time.sleep(1)

        # Save current device status to DB
        #AgentDeviceTelescopeStatus.objects.create(radec=myradec)
        self._agent_device_telescope_status.radec = myradec
        self._agent_device_telescope_status.save()


        #time.sleep(3)
        self.print("ROUTINE PROCESS END")

    # @override
    def kill_running_specific_cmd_if_exists(self, abort_sender):
        super().kill_running_specific_cmd_if_exists(abort_sender)
        print("Close telescope socket")
        self.tele_ctrl.close()

    # @override
    def specific_process(self, cmd):
        cmd.set_read_time()
        cmd.set_as_running()
        res = self.tele_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_*())
    =================================================================
    """

    # Define your own command step(s) here
    def cmd_step1(self, step:int):
        cmd = self._current_specific_cmd
        cmd.result = f"in step #{step}/{self._thread_total_steps_number}"
        cmd.save()
        """
        if self.RUN_IN_THREAD:
            print("(save from thread)")
            cmd.save()
        else:
            #@transaction.atomic
            print("(save from process)")
            with transaction.atomic():
                cmd.save()
                #Command.objects.select_for_update()
        """

    def cmd_step2(self, step:int):
        self.cmd_step1(step)
    def cmd_step3(self, step:int):
        self.cmd_step1(step)
    def cmd_step4(self, step:int):
        self.cmd_step1(step)

    """
    # @override
    def thread_exec_specific_cmd_step(self, step:int, sleep_time:float=1.0):
        self.thread_stop_if_asked()
        cmd = self._current_specific_cmd
        print(f">>>>> Thread (cmd {cmd.name}): step #{step}/5")
        self.sleep(sleep_time)
    """

    '''
    # @override
    def exec_specific_cmd_start(self, cmd:Command, from_thread=True):
        super().exec_specific_cmd_start(cmd, from_thread)
    '''


    # @override
    def thread_exec_specific_cmd_main(self):
        # This is optional
        self.thread_set_total_steps_number(5)

        # HERE, write your own scenario

        # scenario OK
        self.thread_exec_specific_cmd_step(1, self.cmd_step1, 1)
        self.thread_exec_specific_cmd_step(2, self.cmd_step2, 3)
        self.thread_exec_specific_cmd_step(3, self.cmd_step1, 5)
        self.thread_exec_specific_cmd_step(4, self.cmd_step3, 10)
        self.thread_exec_specific_cmd_step(5, self.cmd_step1, 4)
        # ... as many as you need

        """ autre 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)
    '''

    # @override
    def simulator_test_results_main(self, commands):
        nb_asserted = 0
        for cmd in commands:
            if cmd.name == "flush_commands":
                assert cmd.is_executed()
                nb_asserted+=1
            # 2 times
            if cmd.name == "go_active":
                assert cmd.is_executed()
                nb_asserted+=1
            # 2 times
            if cmd.name == "go_idle":
                assert cmd.is_executed()
                nb_asserted+=1
            """
            if cmd.name == "specific0":
                assert cmd.is_skipped()
                assert cmd.result == "in step #5/5"
                nb_asserted+=1
            """
            if cmd.name == "specific1":
                assert cmd.is_killed()
                nb_asserted+=1
            if cmd.name == "specific2":
                assert cmd.is_executed()
                assert cmd.result == "in step #5/5"
                nb_asserted+=1
            if cmd.name == "eval 4+3":
                assert cmd.is_executed()
                assert cmd.get_result() == "7"
                nb_asserted+=1
            if cmd.name in ("abort"):
                assert cmd.is_executed()
                nb_asserted+=1
            if cmd.name in ("exit"):
                assert cmd.is_executed()
                nb_asserted+=1
        return nb_asserted


"""
=================================================================
    MAIN FUNCTION
=================================================================
"""
if __name__ == "__main__":
    # with thread
    RUN_IN_THREAD=True
    # with process
    #RUN_IN_THREAD=False

    TEST_MODE, configfile = extract_parameters()
    """
    configfile = None
    # arg 1 : config file
    if len(sys.argv) == 2:
        configfile = sys.argv[1]
    """
    #agent = AgentX()
    agent = AgentDevice("AgentDevice", configfile, RUN_IN_THREAD)
    agent.setSimulatorMode(TEST_MODE)
    print(agent)
    agent.run()