diff --git a/src/core/pyros_django/bdf_process/A_BDFProcessor.py b/src/core/pyros_django/bdf_process/A_BDFProcessor.py new file mode 100644 index 0000000..ac20713 --- /dev/null +++ b/src/core/pyros_django/bdf_process/A_BDFProcessor.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python3 +# +# To launch this agent from the root of Pyros: +# cd /srv/develop/pyros +# .\PYROS -t start AgentImagesCalibrator -o tnc -fg +# +# Edit the file pyros/pyros.py, +# Add a new entry in the dict AGENT: +# "AgentImagesCalibrator": "observation_manager", +# --------------------------------------------------- + +import sys +import time + +import os +pwd = os.environ['PROJECT_ROOT_PATH'] +if pwd not in sys.path: + sys.path.append(pwd) + +short_paths = ['src', 'src/core/pyros_django'] +for short_path in short_paths: + path = os.path.join(pwd, short_path) + if path not in sys.path: + sys.path.insert(0, path) + +from src.core.pyros_django.majordome.agent.Agent import Agent, build_agent, log + +# = Specials +import glob +import shutil +import guitastro + +class A_BDFProcessor(Agent): + + # - All possible running states + RUNNING_NOTHING = 0 + RUNNING_ONE_IMAGE_PROCESSING = 1 + RUNNING_COMPUTE_RON_GAIN = 2 + + # TODO: Redefine valid timeout + _AGENT_SPECIFIC_COMMANDS = { + # Format : “cmd_name” : (timeout, exec_mode) + + "do_create_test_images_1" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), + "do_create_test_images_2" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), + "do_stop_current_processing" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), + } + + + + + # Scenario to be executed + # "self do_stop_current_processing" + # AgentCmd.CMD_STATUS_CODE.CMD_EXECUTED + _TEST_COMMANDS_LIST = [ + # Format : ("self cmd_name cmd_args", timeout, "expected_result", expected_status), + (True, "self do_create_test_images_1", 200, '', Agent.CMD_STATUS.CMD_EXECUTED), + (True, "self do_exit", 500, "STOPPING", Agent.CMD_STATUS.CMD_EXECUTED), + ] + + """ + ================================================================= + Methods running inside main thread + ================================================================= + """ + + def __init__(self, name:str=None): + if name is None: + name = self.__class__.__name__ + super().__init__() + + def _init(self): + super()._init() + log.debug("end super init()") + log.info(f"self.TEST_MODE = {self.TEST_MODE}") + + # === Get config infos + agent_alias = self.name + log.info(f"agent_alias = {agent_alias}") + # === Get the config object + self.config = self._oc['config'] + # === Get self._path_data_root + self._path_data_root = self.config.get_agent_path_data_root(agent_alias) + # === Get self._home of current unit + self._home = self.config.getHome() + # === Get self._paths the directories for all data (images). See obsconfig_class.py to know keys + self._paths = self.config.get_agent_path_data_tree(agent_alias, True) + # === Get bias strategies + unit_name = "TNC" + channel_name = "OpticalChannel_up1" + category = "BI" + self_strategy_bias = self.config.get_image_calibrations(unit_name, channel_name, category) + log.debug(f"self_strategy_bias={self_strategy_bias}") + + # === Instanciate an object Ima to make image processing + self._ima = guitastro.Ima() + home = guitastro.Home(self._home) + + # === Instanciate an object Filenames to manage file names + self._filename_manager = guitastro.FileNames() + self._filename_manager.naming("PyROS.1") + + # === Set longitude to ima object to generate the night yyyymmdd and subdirectories yyyy/mm/dd + longitude = home.longitude + log.info(f"Longitude={longitude}") + self._ima.longitude(longitude) + log.info("Init done with success") + + # === Status of routine processing + self._routine_running = self.RUNNING_NOTHING + log.debug("end init()") + + # Note : called by _routine_process() in Agent + # @override + def _routine_process_iter_start_body(self): + log.debug("in routine_process_before_body()") + + # Note : called by _routine_process() in Agent + # @override + def _routine_process_iter_end_body(self): + log.debug("in routine_process_after_body()") + if self._routine_running == self.RUNNING_NOTHING: + # Get files to process + fitsfiles = self.glob_images_to_process() + n = len(fitsfiles) + log.info(f"There are {n} image{self._plural(n)} to process") + if n > 0: + # - We select the oldest image + fitsfile = fitsfiles[0] + log.info(f"Process the file {fitsfile}") + # - Thread TODO + self._routine_running = self.RUNNING_ONE_IMAGE_PROCESSING + self.process_one_image(fitsfile) + + """ + ================================================================= + Methods of specific commands + ================================================================= + """ + + def do_stop_current_processing(self): + pass + + def do_create_test_images_1(self): + self._create_test_images_1() + + def do_create_test_images_2(self): + self._create_test_images_2() + + """ + ================================================================= + Methods called by commands or routine. Overload these methods + ================================================================= + """ + + def glob_images_to_process(self): + + # - glob the incoming directory: + fitsfiles = glob.glob(f"{self._paths['ima_incoming']}/BI_*.fit") + # - Please sort list of files in increasing dates (TODO) + return fitsfiles + + def bias_correction(self): + + # - Search the bias + path_bias = os.path.join( self._paths['ima_bias'], self._date_night ) + fitsbiasfiles = glob.glob(f"{path_bias}/*.fit") + log.info(f"fitsbiasfiles = {fitsbiasfiles}") + if len(fitsbiasfiles) > 0: + + # - Select the bias + pass + + def dark_correction(self): + + # - Search the dark + path_darks = os.path.join( self._paths['ima_darks'], self._date_night ) + fitsdarkfiles = glob.glob(f"{path_darks}/*.fit") + log.info(f"fitsdarkfiles = {fitsdarkfiles}") + if len(fitsdarkfiles) > 0: + + # - Select two darks and compute the therm using exposure + # - Correction of dark + pass + + def flat_correction(self): + + # - Search the flat + path_flats = os.path.join( self._paths['ima_flats'], self._date_night ) + fitsflatfiles = glob.glob(f"{path_flats}/*.fit") + log.info(f"fitsflatfiles = {fitsflatfiles}") + if len(fitsflatfiles) > 0: + + # - Select the flat (with the filter) + # - Correction of flat + pass + + def inversion_correction(self): + pass + + def cosmetic_correction(self): + pass + + def wcs_calibration(self): + return 0 + + def process_one_image(self, fitsfile: str): + """This is the general algorithm of processing + + The processing consists to make corrections of dark, flat, inversions, cosmetic + and perform WCS calibration. + + Args: + fitsfile: The file of the FITS file to process. + + """ + + # - Load file in memory + log.info("Load the file in memory") + #self.set_infos("Load the file in memory") + f = self._ima.genename(self._ima.load(fitsfile)) + # log.info(f"f={f}") + + # - Save as tmp + self._ima.path(self._paths['ima_tmp']) + log.info("Save the temporary file as tmp name") + self._ima.save("tmp") + + # - Load tmp and get infos + self._ima.load("tmp") + date_obs = self._ima.getkwd("DATE-OBS") + self._date_night = self._ima.get_night(date_obs) + log.info(f"Date_obs = {date_obs}") + log.info(f"Night = {self._date_night}") + exposure = self._ima.getkwd("EXPOSURE") + log.info(f"Exposure = {exposure}") + + # - Bias correction + self.bias_correction() + + # - Dark correction + self.dark_correction() + + # - Flat correction + self.flat_correction() + + # - Save tmp corrected by dark and flat + self._ima.path(self._paths['ima_tmp']) + self._ima.save("tmp") + + # - Inversion of mirrors or mirorxy + self.inversion_correction() + + # - Cosmetic correction + self.cosmetic_correction() + + # - WCS calibration + nmatched = self.wcs_calibration() + + # - Prepare the output file name + log.info("Decode the filename") + fgen_in = f['genename'] + f['sep'] + f['indexes'][0] + f['suffix'] + fext_in = f['file_extension'] + fext_out = ".fits" + + # - Save in processed + yyyy = self._date_night[0:4] + mm = self._date_night[4:6] + dd = self._date_night[6:8] + path_processed = os.path.join( self._paths['ima_processed'], yyyy, mm, dd ) + self._ima.path(path_processed) + fname_out = fgen_in + fext_out + fname = self._ima.save(fname_out) + log.info(f"Save the processed image {fname}") + + # - Delete the file in incoming directory + os.remove(fitsfile) + log.info(f"Delete the raw image {fitsfile}") + + # - Update the running state + self._routine_running = self.RUNNING_NOTHING + + time.sleep(5) + print("\n ...End of image calibration\n") + + """ + ================================================================= + Internal methods + ================================================================= + """ + + def _create_test_images_1(self): + try: + # === Define an image to test the processing and copy it in incoming directory + self._file_ima_test = os.path.join(self._path_data_root,"vendor/guitastro/tests/data/m57.fit") + file_in = self._file_ima_test + file_out = f"{self._paths['ima_incoming']}/m57.fit" + shutil.copyfile(file_in, file_out) + self._filename_manager.naming("") + except: + raise + + def _create_test_images_2(self): + try: + self._ima.etc.camera("Kepler 4040") + self._ima.etc.optics("Takahashi_180ED") + self._ima.etc.params("msky",18) + ra = 132.84583 + dec = 11.81333 + at = self._ima.simulation("GAIA", "PHOTOM", shutter_mode="closed", t=50) + file_out = os.path.join(self._paths['ima_tmp'], "m67.ecsv") + print(f"STEP TOTO 1 = {at}") + at.t.write(file_out, format='astrotable', overwrite=True) + print(f"STEP TOTO 2") + date_obs = self.getkwd("DATE-OBS") + except: + raise + + def _plural(self, n: int) -> str: + """Return "s" if n>1 for plurals. + + Args: + n: Number of entities + + Returns: + The string "s" or "" + """ + if n > 1: + s = "s" + else: + s = "" + return s + +if __name__ == "__main__": + + agent = build_agent(A_BDFProcessor) + print(agent) + agent.run() diff --git a/src/core/pyros_django/img_process/A_ImgProcessor.py b/src/core/pyros_django/img_process/A_ImgProcessor.py new file mode 100755 index 0000000..2de3624 --- /dev/null +++ b/src/core/pyros_django/img_process/A_ImgProcessor.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python3 +# +# To launch this agent from the root of Pyros: +# +# Linux console: +# cd /srv/develop/pyros/docker +# ./PYROS_DOCKER_START.sh +# +# Launch from Power Shell: +# To go from docker to Powershell: pyros_user@ORION:~/app$ exit (or Ctrl+d) +# Prompt is now PS ...> +# cd \srv\develop\pyros +# .\PYROS -t new-start -o tnc -fg -a A_AgentImagesProcessor_tnc_up1_akz +# +# Launch from docker: +# To go from Powershell to docker: PS ...> .\PYROS_DOCKER_SHELL +# Prompt is now pyros_user@ORION:~/app$ +# ./PYROS -t new-start -o tnc -fg -a A_AgentImagesProcessor_tnc_up1_akz +# +# --------------------------------------------------- + +import sys +import time +import argparse +import os +import pickle +import socket +pwd = os.environ['PROJECT_ROOT_PATH'] +if pwd not in sys.path: + sys.path.append(pwd) + +short_paths = ['src', 'src/core/pyros_django'] +for short_path in short_paths: + path = os.path.join(pwd, short_path) + if path not in sys.path: + sys.path.insert(0, path) + +from src.core.pyros_django.majordome.agent.Agent import Agent, build_agent, log, parse_args +from seq_submit.models import Sequence +# = Specials +import glob +import shutil +import guitastro + +class A_ImgProcessor(Agent): + + # - All possible running states + RUNNING_NOTHING = 0 + RUNNING_ONE_IMAGE_PROCESSING = 1 + RUNNING_COMPUTE_RON_GAIN = 2 + + # TODO: Redefine valid timeout + _AGENT_SPECIFIC_COMMANDS = { + # Format : “cmd_name” : (timeout, exec_mode) + + "do_create_loadseq_1" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), + "do_create_test_images_1" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), + "do_create_test_images_2" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), + "do_stop_current_processing" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), + } + + # Scenario to be executed + # "self do_stop_current_processing" + # AgentCmd.CMD_STATUS_CODE.CMD_EXECUTED + _TEST_COMMANDS_LIST = [ + # Format : ("self cmd_name cmd_args", timeout, "expected_result", expected_status), + (True, "self do_create_loadseq_1", 200, '', Agent.CMD_STATUS.CMD_EXECUTED), + (True, "self do_stop asap", 500, "STOPPING", Agent.CMD_STATUS.CMD_EXECUTED), + ] + + """ + ================================================================= + Methods running inside main thread + ================================================================= + """ + + def __init__(self, name:str=None,simulated_computer=None): + if name is None: + name = self.__class__.__name__ + super().__init__(simulated_computer=simulated_computer) + + def _init(self): + super()._init() + log.debug("end super init()") + log.info(f"self.TEST_MODE = {self.TEST_MODE}") + + # === Get the config object + self.config = self._oc['config'] + self.pconfig = self._oc['pyros_config'] + # === Get agent_alias + hostname = socket.gethostname() + log.info(f"{hostname=}") + log.info(f"{self.name=}") + agent_alias = self.config.get_agent_real_name(self.name, hostname) + log.info(f"{agent_alias=}") + # === Get self._path_data_root + self._path_data_root = self.config.get_agent_path_data_root(agent_alias) + # === Get self._home of current unit + self._home = self.config.getHome() + # === Get self._paths the directories for all data (images). See obsconfig_class.py to know keys + self._paths = self.config.get_agent_path_data_tree(agent_alias, True) + + # === Instanciate an object Ima to make image processing + self._ima = guitastro.Ima() + home = guitastro.Home(self._home) + + # === Instanciate an object Filenames to manage file names + self._filename_manager = guitastro.FileNames() + self._filename_manager.naming("PyROS.img.1") + + # === Set longitude to ima object to generate the night yyyymmdd and subdirectories yyyy/mm/dd + longitude = home.longitude + log.info(f"Longitude={longitude}") + self._ima.longitude(longitude) + log.info("Init done with success") + + # === Status of routine processing + self._routine_running = self.RUNNING_NOTHING + log.debug("end init()") + + # Note : calle d by _routine_process() in Agent + # @override + def _routine_process_iter_start_body(self): + log.debug("in routine_process_before_body()") + + # Note : called by _routine_process() in Agent + # @override + def _routine_process_iter_end_body(self): + log.debug("in routine_process_after_body()") + if self._routine_running == self.RUNNING_NOTHING: + # Get files to process + fitsfiles = self.glob_images_to_process() + n = len(fitsfiles) + log.info(f"There are {n} image{self._plural(n)} to process") + if n > 0: + # - We select the oldest image + fitsfile = fitsfiles[0] + log.info(f"Process the file {fitsfile}") + # - Thread TODO + self._routine_running = self.RUNNING_ONE_IMAGE_PROCESSING + self.process_one_image(fitsfile) + + """ + ================================================================= + Methods of specific commands + ================================================================= + """ + + def do_stop_current_processing(self): + pass + + def do_create_loadseq_1(self): + self._create_loadseq_1() + + def do_create_test_images_1(self): + self._create_test_images_1() + + def do_create_test_images_2(self): + self._create_test_images_2() + + """ + ================================================================= + Methods called by commands or routine. Overload these methods + ================================================================= + """ + def _create_loadseq_1(self): + self.pconfig.fn.fcontext = "pyros_seq" + main_folder_path = self.pconfig.fn.rootdir + nigth_id = "" + sequences = Sequence.objects.filter(night_id=nigth_id) + for sequence in sequences: + folder_path = main_folder_path + f"/P{sequence.period.id}/"+ f"{night_id}/" + file_name = folder_path + f"{sequence.id}.p" + if os.path.exists(file_name): + # if file exists, read it + seq_info = pickle.load(file_name) + target = seq_info["sequence"]["target_coords"] + ephem = seq_info.get("ephem") + # Sub folder per period PX (x is id of period) + # Sub folder per night + # File name is .p + + def glob_images_to_process(self): + + # - glob the incoming directory: + fitsfiles = glob.glob(f"{self._paths['ima_incoming']}/*.fit") + # - Please sort list of files in increasing dates (TODO) + return fitsfiles + + def bias_correction(self): + + # - Search the bias + path_bias = os.path.join( self._paths['ima_bias'], self._date_night ) + fitsbiasfiles = glob.glob(f"{path_bias}/*.fit") + log.info(f"fitsbiasfiles = {fitsbiasfiles}") + if len(fitsbiasfiles) > 0: + + # - Select the bias + pass + + def dark_correction(self): + + # - Search the dark + path_darks = os.path.join( self._paths['ima_darks'], self._date_night ) + fitsdarkfiles = glob.glob(f"{path_darks}/*.fit") + log.info(f"fitsdarkfiles = {fitsdarkfiles}") + if len(fitsdarkfiles) > 0: + + # - Select two darks and compute the therm using exposure + # - Correction of dark + pass + + def flat_correction(self): + + # - Search the flat + path_flats = os.path.join( self._paths['ima_flats'], self._date_night ) + fitsflatfiles = glob.glob(f"{path_flats}/*.fit") + log.info(f"fitsflatfiles = {fitsflatfiles}") + if len(fitsflatfiles) > 0: + + # - Select the flat (with the filter) + # - Correction of flat + pass + + def inversion_correction(self): + pass + + def cosmetic_correction(self): + pass + + def wcs_calibration(self): + return 0 + + def process_one_image(self, fitsfile: str): + """This is the general algorithm of processing + + The processing consists to make corrections of dark, flat, inversions, cosmetic + and perform WCS calibration. + + Args: + fitsfile: The file of the FITS file to process. + + """ + + # - Load file in memory + log.info("Load the file in memory") + #self.set_infos("Load the file in memory") + f = self._ima.genename(self._ima.load(fitsfile)) + # log.info(f"f={f}") + + # - Save as tmp + self._ima.path(self._paths['ima_tmp']) + log.info("Save the temporary file as tmp name") + self._ima.save("tmp") + + # - Load tmp and get infos + self._ima.load("tmp") + date_obs = self._ima.getkwd("DATE-OBS") + self._date_night = self._ima.get_night(date_obs) + log.info(f"Date_obs = {date_obs}") + log.info(f"Night = {self._date_night}") + exposure = self._ima.getkwd("EXPOSURE") + log.info(f"Exposure = {exposure}") + + # - Bias correction + self.bias_correction() + + # - Dark correction + self.dark_correction() + + # - Flat correction + self.flat_correction() + + # - Save tmp corrected by dark and flat + self._ima.path(self._paths['ima_tmp']) + self._ima.save("tmp") + + # - Inversion of mirrors or mirorxy + self.inversion_correction() + + # - Cosmetic correction + self.cosmetic_correction() + + # - WCS calibration + nmatched = self.wcs_calibration() + + # - Prepare the output file name + log.info("Decode the filename") + fgen_in = f['genename'] + f['sep'] + f['indexes'][0] + f['suffix'] + fext_in = f['file_extension'] + fext_out = ".fits" + + # - Save in processed + yyyy = self._date_night[0:4] + mm = self._date_night[4:6] + dd = self._date_night[6:8] + path_processed = os.path.join( self._paths['ima_processed'], yyyy, mm, dd ) + self._ima.path(path_processed) + fname_out = fgen_in + fext_out + fname = self._ima.save(fname_out) + log.info(f"Save the processed image {fname}") + + # - Delete the file in incoming directory + os.remove(fitsfile) + log.info(f"Delete the raw image {fitsfile}") + + # - Update the running state + self._routine_running = self.RUNNING_NOTHING + + time.sleep(5) + print("\n ...End of image calibration\n") + + """ + ================================================================= + Internal methods + ================================================================= + """ + def _create_test_loadseq_1(self): + try: + # === Define an image to test the processing and copy it in incoming directory + self._file_ima_test = os.path.join(self._path_data_root,"vendor/guitastro/tests/data/m57.fit") + file_in = self._file_ima_test + file_out = f"{self._paths['ima_incoming']}/m57.fit" + shutil.copyfile(file_in, file_out) + self._filename_manager.naming("") + except: + raise + + def _create_test_images_1(self): + try: + # === Define an image to test the processing and copy it in incoming directory + self._file_ima_test = os.path.join(self._path_data_root,"vendor/guitastro/tests/data/m57.fit") + file_in = self._file_ima_test + file_out = f"{self._paths['ima_incoming']}/m57.fit" + shutil.copyfile(file_in, file_out) + self._filename_manager.naming("") + except: + raise + + def _create_test_images_2(self): + try: + self._ima.etc.camera("Kepler 4040") + self._ima.etc.optics("Takahashi_180ED") + self._ima.etc.params("msky",18) + ra = 132.84583 + dec = 11.81333 + at = self._ima.simulation("GAIA", "PHOTOM", shutter_mode="closed", t=50, ra=ra, dec=dec) + file_out = os.path.join(self._paths['ima_tmp'], "m67.ecsv") + print(f"STEP TOTO 1 = {at}") + at.t.write(file_out, format='astrotable', overwrite=True) + print(f"STEP TOTO 2") + date_obs = self.getkwd("DATE-OBS") + except: + raise + + def _plural(self, n: int) -> str: + """Return "s" if n>1 for plurals. + + Args: + n: Number of entities + + Returns: + The string "s" or "" + """ + if n > 1: + s = "s" + else: + s = "" + return s + +if __name__ == "__main__": + args = parse_args(sys.argv[1:]) + #args = vars(parser.parse_args()) + agent = build_agent(A_ImgProcessor, param_constr=args) + print(agent) + agent.run() diff --git a/src/core/pyros_django/observation_manager/A_ImagesCalibrator.py b/src/core/pyros_django/observation_manager/A_ImagesCalibrator.py deleted file mode 100644 index 69f81ef..0000000 --- a/src/core/pyros_django/observation_manager/A_ImagesCalibrator.py +++ /dev/null @@ -1,338 +0,0 @@ -#!/usr/bin/env python3 -# -# To launch this agent from the root of Pyros: -# cd /srv/develop/pyros -# .\PYROS -t start AgentImagesCalibrator -o tnc -fg -# -# Edit the file pyros/pyros.py, -# Add a new entry in the dict AGENT: -# "AgentImagesCalibrator": "observation_manager", -# --------------------------------------------------- - -import sys -import time - -import os -pwd = os.environ['PROJECT_ROOT_PATH'] -if pwd not in sys.path: - sys.path.append(pwd) - -short_paths = ['src', 'src/core/pyros_django'] -for short_path in short_paths: - path = os.path.join(pwd, short_path) - if path not in sys.path: - sys.path.insert(0, path) - -from src.core.pyros_django.majordome.agent.Agent import Agent, build_agent, log - -# = Specials -import glob -import shutil -import guitastro - -class A_ImagesCalibrator(Agent): - - # - All possible running states - RUNNING_NOTHING = 0 - RUNNING_ONE_IMAGE_PROCESSING = 1 - RUNNING_COMPUTE_RON_GAIN = 2 - - # TODO: Redefine valid timeout - _AGENT_SPECIFIC_COMMANDS = { - # Format : “cmd_name” : (timeout, exec_mode) - - "do_create_test_images_1" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), - "do_create_test_images_2" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), - "do_stop_current_processing" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), - } - - - - - # Scenario to be executed - # "self do_stop_current_processing" - # AgentCmd.CMD_STATUS_CODE.CMD_EXECUTED - _TEST_COMMANDS_LIST = [ - # Format : ("self cmd_name cmd_args", timeout, "expected_result", expected_status), - (True, "self do_create_test_images_1", 200, '', Agent.CMD_STATUS.CMD_EXECUTED), - (True, "self do_exit", 500, "STOPPING", Agent.CMD_STATUS.CMD_EXECUTED), - ] - - """ - ================================================================= - Methods running inside main thread - ================================================================= - """ - - def __init__(self, name:str=None): - if name is None: - name = self.__class__.__name__ - super().__init__() - - def _init(self): - super()._init() - log.debug("end super init()") - log.info(f"self.TEST_MODE = {self.TEST_MODE}") - - # === Get config infos - agent_alias = self.name - log.info(f"agent_alias = {agent_alias}") - # === Get the config object - self.config = self._oc['config'] - # === Get self._path_data_root - self._path_data_root = self.config.get_agent_path_data_root(agent_alias) - # === Get self._home of current unit - self._home = self.config.getHome() - # === Get self._paths the directories for all data (images). See obsconfig_class.py to know keys - self._paths = self.config.get_agent_path_data_tree(agent_alias, True) - # === Get bias strategies - unit_name = "TNC" - channel_name = "OpticalChannel_up1" - category = "BI" - self_strategy_bias = self.config.get_image_calibrations(unit_name, channel_name, category) - log.debug(f"self_strategy_bias={self_strategy_bias}") - - # === Instanciate an object Ima to make image processing - self._ima = guitastro.Ima() - home = guitastro.Home(self._home) - - # === Instanciate an object Filenames to manage file names - self._filename_manager = guitastro.FileNames() - self._filename_manager.naming("PyROS.1") - - # === Set longitude to ima object to generate the night yyyymmdd and subdirectories yyyy/mm/dd - longitude = home.longitude - log.info(f"Longitude={longitude}") - self._ima.longitude(longitude) - log.info("Init done with success") - - # === Status of routine processing - self._routine_running = self.RUNNING_NOTHING - log.debug("end init()") - - # Note : called by _routine_process() in Agent - # @override - def _routine_process_iter_start_body(self): - log.debug("in routine_process_before_body()") - - # Note : called by _routine_process() in Agent - # @override - def _routine_process_iter_end_body(self): - log.debug("in routine_process_after_body()") - if self._routine_running == self.RUNNING_NOTHING: - # Get files to process - fitsfiles = self.glob_images_to_process() - n = len(fitsfiles) - log.info(f"There are {n} image{self._plural(n)} to process") - if n > 0: - # - We select the oldest image - fitsfile = fitsfiles[0] - log.info(f"Process the file {fitsfile}") - # - Thread TODO - self._routine_running = self.RUNNING_ONE_IMAGE_PROCESSING - self.process_one_image(fitsfile) - - """ - ================================================================= - Methods of specific commands - ================================================================= - """ - - def do_stop_current_processing(self): - pass - - def do_create_test_images_1(self): - self._create_test_images_1() - - def do_create_test_images_2(self): - self._create_test_images_2() - - """ - ================================================================= - Methods called by commands or routine. Overload these methods - ================================================================= - """ - - def glob_images_to_process(self): - - # - glob the incoming directory: - fitsfiles = glob.glob(f"{self._paths['ima_incoming']}/BI_*.fit") - # - Please sort list of files in increasing dates (TODO) - return fitsfiles - - def bias_correction(self): - - # - Search the bias - path_bias = os.path.join( self._paths['ima_bias'], self._date_night ) - fitsbiasfiles = glob.glob(f"{path_bias}/*.fit") - log.info(f"fitsbiasfiles = {fitsbiasfiles}") - if len(fitsbiasfiles) > 0: - - # - Select the bias - pass - - def dark_correction(self): - - # - Search the dark - path_darks = os.path.join( self._paths['ima_darks'], self._date_night ) - fitsdarkfiles = glob.glob(f"{path_darks}/*.fit") - log.info(f"fitsdarkfiles = {fitsdarkfiles}") - if len(fitsdarkfiles) > 0: - - # - Select two darks and compute the therm using exposure - # - Correction of dark - pass - - def flat_correction(self): - - # - Search the flat - path_flats = os.path.join( self._paths['ima_flats'], self._date_night ) - fitsflatfiles = glob.glob(f"{path_flats}/*.fit") - log.info(f"fitsflatfiles = {fitsflatfiles}") - if len(fitsflatfiles) > 0: - - # - Select the flat (with the filter) - # - Correction of flat - pass - - def inversion_correction(self): - pass - - def cosmetic_correction(self): - pass - - def wcs_calibration(self): - return 0 - - def process_one_image(self, fitsfile: str): - """This is the general algorithm of processing - - The processing consists to make corrections of dark, flat, inversions, cosmetic - and perform WCS calibration. - - Args: - fitsfile: The file of the FITS file to process. - - """ - - # - Load file in memory - log.info("Load the file in memory") - #self.set_infos("Load the file in memory") - f = self._ima.genename(self._ima.load(fitsfile)) - # log.info(f"f={f}") - - # - Save as tmp - self._ima.path(self._paths['ima_tmp']) - log.info("Save the temporary file as tmp name") - self._ima.save("tmp") - - # - Load tmp and get infos - self._ima.load("tmp") - date_obs = self._ima.getkwd("DATE-OBS") - self._date_night = self._ima.get_night(date_obs) - log.info(f"Date_obs = {date_obs}") - log.info(f"Night = {self._date_night}") - exposure = self._ima.getkwd("EXPOSURE") - log.info(f"Exposure = {exposure}") - - # - Bias correction - self.bias_correction() - - # - Dark correction - self.dark_correction() - - # - Flat correction - self.flat_correction() - - # - Save tmp corrected by dark and flat - self._ima.path(self._paths['ima_tmp']) - self._ima.save("tmp") - - # - Inversion of mirrors or mirorxy - self.inversion_correction() - - # - Cosmetic correction - self.cosmetic_correction() - - # - WCS calibration - nmatched = self.wcs_calibration() - - # - Prepare the output file name - log.info("Decode the filename") - fgen_in = f['genename'] + f['sep'] + f['indexes'][0] + f['suffix'] - fext_in = f['file_extension'] - fext_out = ".fits" - - # - Save in processed - yyyy = self._date_night[0:4] - mm = self._date_night[4:6] - dd = self._date_night[6:8] - path_processed = os.path.join( self._paths['ima_processed'], yyyy, mm, dd ) - self._ima.path(path_processed) - fname_out = fgen_in + fext_out - fname = self._ima.save(fname_out) - log.info(f"Save the processed image {fname}") - - # - Delete the file in incoming directory - os.remove(fitsfile) - log.info(f"Delete the raw image {fitsfile}") - - # - Update the running state - self._routine_running = self.RUNNING_NOTHING - - time.sleep(5) - print("\n ...End of image calibration\n") - - """ - ================================================================= - Internal methods - ================================================================= - """ - - def _create_test_images_1(self): - try: - # === Define an image to test the processing and copy it in incoming directory - self._file_ima_test = os.path.join(self._path_data_root,"vendor/guitastro/tests/data/m57.fit") - file_in = self._file_ima_test - file_out = f"{self._paths['ima_incoming']}/m57.fit" - shutil.copyfile(file_in, file_out) - self._filename_manager.naming("") - except: - raise - - def _create_test_images_2(self): - try: - self._ima.etc.camera("Kepler 4040") - self._ima.etc.optics("Takahashi_180ED") - self._ima.etc.params("msky",18) - ra = 132.84583 - dec = 11.81333 - at = self._ima.simulation("GAIA", "PHOTOM", shutter_mode="closed", t=50) - file_out = os.path.join(self._paths['ima_tmp'], "m67.ecsv") - print(f"STEP TOTO 1 = {at}") - at.t.write(file_out, format='astrotable', overwrite=True) - print(f"STEP TOTO 2") - date_obs = self.getkwd("DATE-OBS") - except: - raise - - def _plural(self, n: int) -> str: - """Return "s" if n>1 for plurals. - - Args: - n: Number of entities - - Returns: - The string "s" or "" - """ - if n > 1: - s = "s" - else: - s = "" - return s - -if __name__ == "__main__": - - agent = build_agent(A_ImagesCalibrator) - print(agent) - agent.run() diff --git a/src/core/pyros_django/observation_manager/A_ImagesProcessor.py b/src/core/pyros_django/observation_manager/A_ImagesProcessor.py deleted file mode 100755 index 75c62af..0000000 --- a/src/core/pyros_django/observation_manager/A_ImagesProcessor.py +++ /dev/null @@ -1,376 +0,0 @@ -#!/usr/bin/env python3 -# -# To launch this agent from the root of Pyros: -# -# Linux console: -# cd /srv/develop/pyros/docker -# ./PYROS_DOCKER_START.sh -# -# Launch from Power Shell: -# To go from docker to Powershell: pyros_user@ORION:~/app$ exit (or Ctrl+d) -# Prompt is now PS ...> -# cd \srv\develop\pyros -# .\PYROS -t new-start -o tnc -fg -a A_AgentImagesProcessor_tnc_up1_akz -# -# Launch from docker: -# To go from Powershell to docker: PS ...> .\PYROS_DOCKER_SHELL -# Prompt is now pyros_user@ORION:~/app$ -# ./PYROS -t new-start -o tnc -fg -a A_AgentImagesProcessor_tnc_up1_akz -# -# --------------------------------------------------- - -import sys -import time -import argparse -import os -import pickle -import socket -pwd = os.environ['PROJECT_ROOT_PATH'] -if pwd not in sys.path: - sys.path.append(pwd) - -short_paths = ['src', 'src/core/pyros_django'] -for short_path in short_paths: - path = os.path.join(pwd, short_path) - if path not in sys.path: - sys.path.insert(0, path) - -from src.core.pyros_django.majordome.agent.Agent import Agent, build_agent, log, parse_args -from seq_submit.models import Sequence -# = Specials -import glob -import shutil -import guitastro - -class A_ImagesProcessor(Agent): - - # - All possible running states - RUNNING_NOTHING = 0 - RUNNING_ONE_IMAGE_PROCESSING = 1 - RUNNING_COMPUTE_RON_GAIN = 2 - - # TODO: Redefine valid timeout - _AGENT_SPECIFIC_COMMANDS = { - # Format : “cmd_name” : (timeout, exec_mode) - - "do_create_loadseq_1" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), - "do_create_test_images_1" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), - "do_create_test_images_2" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), - "do_stop_current_processing" : (60, Agent.EXEC_MODE.SEQUENTIAL, ''), - } - - # Scenario to be executed - # "self do_stop_current_processing" - # AgentCmd.CMD_STATUS_CODE.CMD_EXECUTED - _TEST_COMMANDS_LIST = [ - # Format : ("self cmd_name cmd_args", timeout, "expected_result", expected_status), - (True, "self do_create_loadseq_1", 200, '', Agent.CMD_STATUS.CMD_EXECUTED), - (True, "self do_stop asap", 500, "STOPPING", Agent.CMD_STATUS.CMD_EXECUTED), - ] - - """ - ================================================================= - Methods running inside main thread - ================================================================= - """ - - def __init__(self, name:str=None,simulated_computer=None): - if name is None: - name = self.__class__.__name__ - super().__init__(simulated_computer=simulated_computer) - - def _init(self): - super()._init() - log.debug("end super init()") - log.info(f"self.TEST_MODE = {self.TEST_MODE}") - - # === Get the config object - self.config = self._oc['config'] - self.pconfig = self._oc['pyros_config'] - # === Get agent_alias - hostname = socket.gethostname() - log.info(f"{hostname=}") - log.info(f"{self.name=}") - agent_alias = self.config.get_agent_real_name(self.name, hostname) - log.info(f"{agent_alias=}") - # === Get self._path_data_root - self._path_data_root = self.config.get_agent_path_data_root(agent_alias) - # === Get self._home of current unit - self._home = self.config.getHome() - # === Get self._paths the directories for all data (images). See obsconfig_class.py to know keys - self._paths = self.config.get_agent_path_data_tree(agent_alias, True) - - # === Instanciate an object Ima to make image processing - self._ima = guitastro.Ima() - home = guitastro.Home(self._home) - - # === Instanciate an object Filenames to manage file names - self._filename_manager = guitastro.FileNames() - self._filename_manager.naming("PyROS.img.1") - - # === Set longitude to ima object to generate the night yyyymmdd and subdirectories yyyy/mm/dd - longitude = home.longitude - log.info(f"Longitude={longitude}") - self._ima.longitude(longitude) - log.info("Init done with success") - - # === Status of routine processing - self._routine_running = self.RUNNING_NOTHING - log.debug("end init()") - - # Note : calle d by _routine_process() in Agent - # @override - def _routine_process_iter_start_body(self): - log.debug("in routine_process_before_body()") - - # Note : called by _routine_process() in Agent - # @override - def _routine_process_iter_end_body(self): - log.debug("in routine_process_after_body()") - if self._routine_running == self.RUNNING_NOTHING: - # Get files to process - fitsfiles = self.glob_images_to_process() - n = len(fitsfiles) - log.info(f"There are {n} image{self._plural(n)} to process") - if n > 0: - # - We select the oldest image - fitsfile = fitsfiles[0] - log.info(f"Process the file {fitsfile}") - # - Thread TODO - self._routine_running = self.RUNNING_ONE_IMAGE_PROCESSING - self.process_one_image(fitsfile) - - """ - ================================================================= - Methods of specific commands - ================================================================= - """ - - def do_stop_current_processing(self): - pass - - def do_create_loadseq_1(self): - self._create_loadseq_1() - - def do_create_test_images_1(self): - self._create_test_images_1() - - def do_create_test_images_2(self): - self._create_test_images_2() - - """ - ================================================================= - Methods called by commands or routine. Overload these methods - ================================================================= - """ - def _create_loadseq_1(self): - self.pconfig.fn.fcontext = "pyros_seq" - main_folder_path = self.pconfig.fn.rootdir - nigth_id = "" - sequences = Sequence.objects.filter(night_id=nigth_id) - for sequence in sequences: - folder_path = main_folder_path + f"/P{sequence.period.id}/"+ f"{night_id}/" - file_name = folder_path + f"{sequence.id}.p" - if os.path.exists(file_name): - # if file exists, read it - seq_info = pickle.load(file_name) - target = seq_info["sequence"]["target_coords"] - ephem = seq_info.get("ephem") - # Sub folder per period PX (x is id of period) - # Sub folder per night - # File name is .p - - def glob_images_to_process(self): - - # - glob the incoming directory: - fitsfiles = glob.glob(f"{self._paths['ima_incoming']}/*.fit") - # - Please sort list of files in increasing dates (TODO) - return fitsfiles - - def bias_correction(self): - - # - Search the bias - path_bias = os.path.join( self._paths['ima_bias'], self._date_night ) - fitsbiasfiles = glob.glob(f"{path_bias}/*.fit") - log.info(f"fitsbiasfiles = {fitsbiasfiles}") - if len(fitsbiasfiles) > 0: - - # - Select the bias - pass - - def dark_correction(self): - - # - Search the dark - path_darks = os.path.join( self._paths['ima_darks'], self._date_night ) - fitsdarkfiles = glob.glob(f"{path_darks}/*.fit") - log.info(f"fitsdarkfiles = {fitsdarkfiles}") - if len(fitsdarkfiles) > 0: - - # - Select two darks and compute the therm using exposure - # - Correction of dark - pass - - def flat_correction(self): - - # - Search the flat - path_flats = os.path.join( self._paths['ima_flats'], self._date_night ) - fitsflatfiles = glob.glob(f"{path_flats}/*.fit") - log.info(f"fitsflatfiles = {fitsflatfiles}") - if len(fitsflatfiles) > 0: - - # - Select the flat (with the filter) - # - Correction of flat - pass - - def inversion_correction(self): - pass - - def cosmetic_correction(self): - pass - - def wcs_calibration(self): - return 0 - - def process_one_image(self, fitsfile: str): - """This is the general algorithm of processing - - The processing consists to make corrections of dark, flat, inversions, cosmetic - and perform WCS calibration. - - Args: - fitsfile: The file of the FITS file to process. - - """ - - # - Load file in memory - log.info("Load the file in memory") - #self.set_infos("Load the file in memory") - f = self._ima.genename(self._ima.load(fitsfile)) - # log.info(f"f={f}") - - # - Save as tmp - self._ima.path(self._paths['ima_tmp']) - log.info("Save the temporary file as tmp name") - self._ima.save("tmp") - - # - Load tmp and get infos - self._ima.load("tmp") - date_obs = self._ima.getkwd("DATE-OBS") - self._date_night = self._ima.get_night(date_obs) - log.info(f"Date_obs = {date_obs}") - log.info(f"Night = {self._date_night}") - exposure = self._ima.getkwd("EXPOSURE") - log.info(f"Exposure = {exposure}") - - # - Bias correction - self.bias_correction() - - # - Dark correction - self.dark_correction() - - # - Flat correction - self.flat_correction() - - # - Save tmp corrected by dark and flat - self._ima.path(self._paths['ima_tmp']) - self._ima.save("tmp") - - # - Inversion of mirrors or mirorxy - self.inversion_correction() - - # - Cosmetic correction - self.cosmetic_correction() - - # - WCS calibration - nmatched = self.wcs_calibration() - - # - Prepare the output file name - log.info("Decode the filename") - fgen_in = f['genename'] + f['sep'] + f['indexes'][0] + f['suffix'] - fext_in = f['file_extension'] - fext_out = ".fits" - - # - Save in processed - yyyy = self._date_night[0:4] - mm = self._date_night[4:6] - dd = self._date_night[6:8] - path_processed = os.path.join( self._paths['ima_processed'], yyyy, mm, dd ) - self._ima.path(path_processed) - fname_out = fgen_in + fext_out - fname = self._ima.save(fname_out) - log.info(f"Save the processed image {fname}") - - # - Delete the file in incoming directory - os.remove(fitsfile) - log.info(f"Delete the raw image {fitsfile}") - - # - Update the running state - self._routine_running = self.RUNNING_NOTHING - - time.sleep(5) - print("\n ...End of image calibration\n") - - """ - ================================================================= - Internal methods - ================================================================= - """ - def _create_test_loadseq_1(self): - try: - # === Define an image to test the processing and copy it in incoming directory - self._file_ima_test = os.path.join(self._path_data_root,"vendor/guitastro/tests/data/m57.fit") - file_in = self._file_ima_test - file_out = f"{self._paths['ima_incoming']}/m57.fit" - shutil.copyfile(file_in, file_out) - self._filename_manager.naming("") - except: - raise - - def _create_test_images_1(self): - try: - # === Define an image to test the processing and copy it in incoming directory - self._file_ima_test = os.path.join(self._path_data_root,"vendor/guitastro/tests/data/m57.fit") - file_in = self._file_ima_test - file_out = f"{self._paths['ima_incoming']}/m57.fit" - shutil.copyfile(file_in, file_out) - self._filename_manager.naming("") - except: - raise - - def _create_test_images_2(self): - try: - self._ima.etc.camera("Kepler 4040") - self._ima.etc.optics("Takahashi_180ED") - self._ima.etc.params("msky",18) - ra = 132.84583 - dec = 11.81333 - at = self._ima.simulation("GAIA", "PHOTOM", shutter_mode="closed", t=50, ra=ra, dec=dec) - file_out = os.path.join(self._paths['ima_tmp'], "m67.ecsv") - print(f"STEP TOTO 1 = {at}") - at.t.write(file_out, format='astrotable', overwrite=True) - print(f"STEP TOTO 2") - date_obs = self.getkwd("DATE-OBS") - except: - raise - - def _plural(self, n: int) -> str: - """Return "s" if n>1 for plurals. - - Args: - n: Number of entities - - Returns: - The string "s" or "" - """ - if n > 1: - s = "s" - else: - s = "" - return s - -if __name__ == "__main__": - args = parse_args(sys.argv[1:]) - #args = vars(parser.parse_args()) - agent = build_agent(A_ImagesProcessor, param_constr=args) - print(agent) - agent.run() diff --git a/src/core/pyros_django/utils/JDManipulator.py b/src/core/pyros_django/utils/JDManipulator.py deleted file mode 100644 index 103c475..0000000 --- a/src/core/pyros_django/utils/JDManipulator.py +++ /dev/null @@ -1,116 +0,0 @@ -from django.conf import settings -import datetime -import time -from decimal import * - -JD_VALUE = 86400 -TIMESTAMP_JD = 2440587.500000 -DAILY_SECOND = 1 / 86400 -SECOND_DIV = 86400 - -def getSimTime(): - current_time = datetime.datetime.now() - if current_time.minute == 59: - current_time = current_time.replace(hour=(current_time.hour + 1), minute=0, second=10) - else: - if current_time.second >= 50: - current_time = current_time.replace(minute=current_time.minute + 1, second=10) - else: - current_time = current_time.replace(second=(current_time.second + 10)) - - return (time.mktime(current_time.timetuple())) - - -SIM_TIME_START = getSimTime() - -def JulianSeconds(value): - return (Decimal(value) / SECOND_DIV) - -def getPreciseCurrentTime(): - return (Decimal(getCurrentTime())) - -def getPreciseNightStart(): - return (Decimal(getNightStart())) - -def getPreciseNightEnd(): - return (Decimal(getNightEnd())) - -def secondsToJulianDate(time_seconds): - return (time_seconds / 86400 + TIMESTAMP_JD) - -def secondsToPreciseJulianDate(time_seconds): - return (Decimal(time_seconds) / 86400 + Decimal(TIMESTAMP_JD)) - -def julianSecondsToSeconds(seconds_julian): - return seconds_julian * 86400 - -def julianDateToSeconds(time_julian): - return ((time_julian - TIMESTAMP_JD) * 86400) - -def getCurrentTime(): - current_time = datetime.datetime.now() - return (time.mktime(current_time.timetuple())) - -def getNextDefaultNightStart(): - current_time = datetime.datetime.now() - if (current_time.hour >= 18): - current_time += datetime.timedelta(days=1) - current_time = current_time.replace(hour=18, minute=0, second=0, microsecond=0) - return (time.mktime(current_time.timetuple())) - -def getNextDefaultNightEnd(): - current_time = datetime.datetime.now() - if (current_time.hour >= 18): - current_time += datetime.timedelta(days=2) - else: - current_time += datetime.timedelta(days=1) - current_time = current_time.replace(hour=6, minute=0, second=0, microsecond=0) - return (time.mktime(current_time.timetuple())) - -def getDefaultNightStart(): - current_time = datetime.datetime.now() - print("*********************") - print("*********************") - print("current time is", current_time) - print("SIM_TIME_START", SIM_TIME_START) - print("*********************") - print("*********************") - if settings.SIMULATOR: - if settings.SIMULATOR: - return SIM_TIME_START - if current_time.minute == 59: - current_time = current_time.replace(hour=(current_time.hour + 1), minute=0, second=10) - else: - if current_time.second > 50: - current_time = current_time.replace(minute=current_time.minute + 1, second=10) - else: - current_time = current_time.replace(second=(current_time.second + 10)) - else: - current_time = current_time.replace(hour=18, minute=0, second=0, microsecond=0) - return (time.mktime(current_time.timetuple())) - -def getDefaultNightEnd(): - current_time = datetime.datetime.now() - current_time += datetime.timedelta(days=1) - current_time = current_time.replace(hour=6, minute=0, second=0, microsecond=0) - return (time.mktime(current_time.timetuple())) - -def datetimeToJulianDate(current_time): - return (time.mktime(current_time.timetuple()) / JD_VALUE + TIMESTAMP_JD) - - -''' TODO ''' -def getNightStart(): - return (getDefaultNightStart()) - -''' TODO ''' -def getNightEnd(): - return (getDefaultNightEnd()) - -''' TODO ''' -def getNextNightStart(): - return (getNextDefaultNightStart()) - -''' TODO ''' -def getNextNightEnd(): - return (getNextNightEnd()) \ No newline at end of file diff --git a/src/core/pyros_django/utils/Logger.py b/src/core/pyros_django/utils/Logger.py deleted file mode 100644 index 4a3e87a..0000000 --- a/src/core/pyros_django/utils/Logger.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.conf import settings -import logging - -# If django project is in /src/ : -#RELATIVE_PATH_TO_LOG_DIR = '../logs/' -#logging.basicConfig(filename='%s/../logs/pyros.log'%(settings.BASE_DIR), format='-> At : [%(asctime)s]\n\t By module [%(module)s] logger : [%(name)s] : "%(message)s"', level=logging.DEBUG) -# If django project is in /src/core/pyros_django/ : -RELATIVE_PATH_TO_LOG_DIR = '../../../logs' -logging.basicConfig(filename = f'{settings.BASE_DIR}/{RELATIVE_PATH_TO_LOG_DIR}/pyros.log', - format = '-> At : [%(asctime)s]\n\t By module [%(module)s] logger : [%(name)s] : "%(message)s"', - level = logging.DEBUG) -#logging.basicConfig(filename='%s/../../../logs/pyros.log'%(settings.BASE_DIR), format='-> At : [%(asctime)s]\n\t By module [%(module)s] logger : [%(name)s] : "%(message)s"', level=logging.DEBUG) - -def setupLogger(logger_name, log_file, level=logging.INFO): - l = logging.getLogger(logger_name) - formatter = logging.Formatter('[%(message)s] at %(filename)s : %(lineno)s') - #fileHandler = logging.FileHandler('%s/../logs/%s.log'%(settings.BASE_DIR, log_file), mode='w') - fileHandler = logging.FileHandler(f'{settings.BASE_DIR}/{RELATIVE_PATH_TO_LOG_DIR}/{log_file}.log', mode='w') - fileHandler.setFormatter(formatter) - # streamHandler = logging.StreamHandler() - # streamHandler.setFormatter(formatter) - - l.setLevel(level) - l.addHandler(fileHandler) - # l.addHandler(streamHandler) - return (logging.getLogger(logger_name)) - - -class Logger: - def __init__(self, name: str, file: str): - super().__init__() - self.logger = setupLogger(name, file) - - def log(self, message): - if settings.DEBUG: - self.logger.info(message) - - def info(self, message: str): - if settings.DEBUG: - self.logger.info(message) - - def debug(self, message: str): - if settings.DEBUG: - self.logger.debug(message) diff --git a/src/core/pyros_django/utils/__init__.py b/src/core/pyros_django/utils/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/src/core/pyros_django/utils/__init__.py +++ /dev/null diff --git a/src/core/pyros_django/utils/highPrecision.py b/src/core/pyros_django/utils/highPrecision.py deleted file mode 100644 index 1361d5f..0000000 --- a/src/core/pyros_django/utils/highPrecision.py +++ /dev/null @@ -1,45 +0,0 @@ -from decimal import * - - -PRECISION = Decimal(0.0000000001) - -''' - Compare the two decimal, according to the given precision -''' - - -def is_nearby_equal(a: Decimal, b: Decimal, precision=PRECISION): - return (True if abs(b - a) < precision else False) - - -''' - Compare the two decimal, according to the given precision -''' - - -def is_nearby_sup_or_equal(a: Decimal, b: Decimal, precision=PRECISION): - if (a > b): - return True - return (True if abs(b - a) < precision else False) - - -''' - Compare the two decimal, according to the given precision -''' - - -def is_nearby_less_or_equal(a: Decimal, b: Decimal, precision=PRECISION): - if (a < b): - return True - return (True if abs(b - a) < precision else False) - - -''' - Check if decimal is between -''' - - -def is_between(a: Decimal, b: Decimal, c: Decimal, precision=PRECISION): - if is_nearby_less_or_equal(a, b) and is_nearby_less_or_equal(b, c): - return True - return False \ No newline at end of file diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_came.py b/src/core/pyros_django/utils/plc/guitalens_observatory/driver_came.py deleted file mode 100644 index 6a9bfd2..0000000 --- a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_came.py +++ /dev/null @@ -1,122 +0,0 @@ -# -*- coding: utf-8 -*- -import RPi.GPIO as io -import time - -def do_open_roof(pin_cmd_open_bcm=27, debug_level=0): - """Ouvre le toit avec un moteur de toit Came. - -Exemple: - -import driver_came ; driver_came.do_open_roof(27,2) -""" - - io.setwarnings(False) - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_cmd_open_bcm,io.OUT) # make pin an output (=arduino 27 open) - - io.output(pin_cmd_open_bcm,1) - time.sleep(3) - io.output(pin_cmd_open_bcm,0) - - err=0 - return err - -def do_stop_roof(pin_cmd_stop_bcm=4, debug_level=0): - """Stope le toit avec un moteur de toit Came. - -Exemple: - -import driver_came ; driver_came.do_stop_roof(4,2) -""" - - io.setwarnings(False) - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_cmd_stop_bcm,io.OUT) # make pin an output (=arduino 25 stop) - - io.output(pin_cmd_stop_bcm,1) - time.sleep(3) - io.output(pin_cmd_stop_bcm,0) - - err=0 - return err - -def do_close_roof(pin_cmd_close_bcm=23, debug_level=0): - """Ferme le toit avec un moteur de toit Came. - -Exemple: - -import driver_came ; driver_came.do_close_roof(23,2) -""" - - io.setwarnings(False) - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_cmd_close_bcm,io.OUT) # make pin an output (=arduino 29 close) - - io.output(pin_cmd_close_bcm,1) - time.sleep(3) - io.output(pin_cmd_close_bcm,0) - - err=0 - return err - -def get_data(pin_chk_power_bcm=26, pin_sw_manu_bcm=22, pin_sw_closed_bcm=5, pin_sw_opened_bcm=6, debug_level=0): - """Lecture des etats des switchs du moteur de toit Came. -Retourne un tuple, dans l'ordre: Un code de validité, - -Exemple: - -import driver_came ; driver_came.get_data(26,22,5,6,2) -""" - - io.setwarnings(False) - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_chk_power_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 48 24V) - io.setup(pin_sw_manu_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 31 manu/auto) - io.setup(pin_sw_closed_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 39 closed) - io.setup(pin_sw_opened_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 41 opened) - - pin48 = io.input(pin_chk_power_bcm) - pin31 = io.input(pin_sw_manu_bcm) - pin39 = io.input(pin_sw_closed_bcm) - pin41 = io.input(pin_sw_opened_bcm) - if (debug_level==2): - print("=== Bit states ===") - disp ="pin48,gpio26,power24V ="+str(pin48)+"pin31,gpio22,auto/manu ="+str(pin31)+" pin39,gpio5,closed ="+str(pin39)+" pin41,gpio6,opened ="+str(pin41) - print(disp) - - # === return - err = 0 - power_came = 0 - if ( pin48==0 ): - power_came_msg = "24Volts" - power_came = 1 - else: - power_came_msg = "0Volt" - err = err +1 - if ( pin31==1 ): - mode_came= 1 - mode_came_msg = "Auto" - else: - mode_came = 0 - mode_came_msg = "Manual" - roof_state = -1 - roof_state_msg = "Unknown" - if ( (pin39==1) and (pin41==1) ): - err = err + 2 - roof_state_msg = "NoPower" - elif ( (pin39==0) and (pin41==0) ): - roof_state = 2 - roof_state_msg = "Intermediate" - elif ( (pin39==1) and (pin41==0) ): - roof_state = 0 - roof_state_msg = "Closed" - elif ( (pin39==0) and (pin41==1) ): - roof_state = 1 - roof_state_msg = "Opened" - - if (debug_level>=1): - print("=== Came states ===") - print("power={} mode={} state={}".format(power_came_msg, mode_came_msg, roof_state_msg)); - - return err, power_came, mode_came, roof_state, power_came_msg, mode_came_msg, roof_state_msg, pin48, pin39, pin41,pin31 - diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_cv7.py b/src/core/pyros_django/utils/plc/guitalens_observatory/driver_cv7.py deleted file mode 100644 index 36482f3..0000000 --- a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_cv7.py +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: utf-8 -*- -# == pour donner les droits d'acces a /dev/ttS0 -# gedit /boot/cmdline.txt & -# effacer console=serial0,115200 -# == a priori il n'est pas necessaire de faire les deux lignes suivantes -# usermod -a -G tty pi -# chmod 777 /dev/ttyS0 - -import time -import serial -import RPi.GPIO as io - -def get_data(port="/dev/ttyS0",pin_vin_bcm=25, debug_level=0): - """Lecture d'une trame du capteur meteo CV7. -Retourne un tuple, dans l'ordre: Un code de validité, la vitesse du vent en m/s, la direction relative du vent en degre, la température en °C, la trame IIMWV lue, la trame WIXDR lue. Le code de validité =0 si la trame est valide, =1 si Vin n'est pas detecte, =2 si les trames ne sont pas valides. - -Exemple: - -import driver_cv7 ; driver_cv7.get_data("/dev/ttyS0", 25,2) -""" - - # === verify 12V power supply if it is possible - power_mife = 1 - if (pin_vin_bcm>0): - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_vin_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 35->34 SWO_T60 = Vin) - pin34 = io.input(pin_vin_bcm) - power_mife = 1-pin34 - if (debug_level==2): - print("=== Voltage intput ===") - disp ="pin34,35,gpio25,Vin="+str(pin34)+ " (0=12V 1=0V)" - print(disp) - err = 0 - if ( power_mife==1 ): - power_mife_msg = "12Volts" - power_mife = 1 - else: - power_mife_msg = "0Volt" - power_mife = 0 - err = err +1 - - # === get the raw frame - serialerror=0 - try: - ser = serial.Serial( - port=port, - baudrate = 4800, - parity=serial.PARITY_NONE, - stopbits=serial.STOPBITS_ONE, - bytesize=serial.EIGHTBITS, - timeout=0, - ) - if ser.isOpen(): - serialerror=0 - else: - serialerror=1 - except: - serialerror=2 - else: - if ser.isOpen(): - time.sleep(0.1) - ser.flush() - raw_str="" - for i in range(0,30000): - x=ser.read() - if (len(x)>0): - raw_str+= "{:c}".format(x[0]) - if (debug_level==2): - print("=== Raw frame ===") - print(raw_str) - ser.close() - - # === decode - valid=0b00 - wind_dir_deg = 0 - wind_dir_kt = 0 - wind_dir_ms = 0 - wind_tmp_degC = 0 - msg_wind = "" - msg_temp = "" - raw_list = raw_str.split() - if (debug_level==2): - print("=== Raw list ===") - print(raw_list) - for message in raw_list: - msg = str(message) - # $IIMWV,135.0,R,000.0,N,A*3A - key = "$IIMWV" - k = msg.find(key) - if ( (k==0) and (len(msg)>=27) ): - msg_list = msg.split(","); - if (debug_level==2): - print("=== IIMWV ===") - print(msg) - print(msg_list) - wind_dir_deg = float(msg_list[1]) - wind_speed_kt = float(msg_list[3]) - wind_speed_ms = wind_speed_kt*1.852/3.6 - valid = valid | 0b01 - msg_wind = msg - # $WIXDR,C,021.0,C,,*51 - key = "$WIXDR" - k = msg.find(key) - if ( (k==0) and (len(msg)>=21) ): - msg_list = msg.split(","); - if (debug_level==2): - print("=== WIXDR ===") - print(msg) - print(msg_list) - wind_tmp_degC = float(msg_list[2]) - valid = valid | 0b10 - msg_temp = msg - # === return - err = 0 - if (power_mife==0): - err += 1 - if (serialerror==1): - err += 2 - if (valid==0): - err += 4 - - return err, power_mife, wind_dir_deg, wind_speed_ms, wind_tmp_degC, power_mife_msg, msg_wind, msg_temp - diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_dht22.py b/src/core/pyros_django/utils/plc/guitalens_observatory/driver_dht22.py deleted file mode 100644 index a1bc81f..0000000 --- a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_dht22.py +++ /dev/null @@ -1,202 +0,0 @@ -# -*- coding: utf-8 -*- -from time import * -import RPi.GPIO as io - -def get_data(pin_data_bcm=13, debug_level=0): - if False: - # --- method perso pure python - err=0 - k=0 - sortie=False - while (sortie==False): - err_dht22, tmp, hum, seuil, data = get_data0(pin_data_bcm,debug_level) - if ((err_dht22==0) or (k>20)): - sortie=True - else: - sleep(0.1) - k+=1 - else: - # --- method lib python+C - import Adafruit_DHT - sensorDHT = Adafruit_DHT.DHT22 - hum, tmp = Adafruit_DHT.read_retry(sensorDHT, pin_data_bcm) - err_dht22 = 0 - seuil = 0 - data = "" - if (hum==None) or (tmp==None): - err_dht22 = 1 - hum = 0 - tmp = 0 - elif (hum>100): - err_dht22 = 2 - hum = 0 - tmp = 0 - return err_dht22, tmp, hum, seuil, data - -def get_data0(pin_data_bcm=13, debug_level=0): - """Lecture d'une trame du capteur meteo DHT22. -Retourne un tuple, dans l'ordre: Un code de validité, la température en °C, le % d'humidité, le seuil de binarisation, les bits de la trame lue. Le code de validité =0 si la trame est valide, =1 si le checksum est mauvais, =2 si le nombre de bits lu n'est pas égal à 40. -valide = 3 si la liste est vide -Exemple: - -import driver_dht22 ; driver_dht22.get_data(13,2) -""" - listetrame = [] #trame échantillonnée - data = [] #trame du capteur - tableN = [] #liste des nombres de 1 - - io.setwarnings(False) - io.setmode(io.BCM) - - # --- Pin GPIOxx for DHT data in mode OUT - io.setup(pin_data_bcm,io.OUT) - # --- Send HIGH->LOW(1ms)->HIGH to start an acquisition - io.output(pin_data_bcm,io.HIGH) - io.output(pin_data_bcm,io.LOW) - sleep(0.001) - io.output(pin_data_bcm,io.HIGH) - - # --- Pin GPIOxx for DHT data in mode IN - io.setup(pin_data_bcm,io.IN) - # --- Read continuously the GPIxx pin during few ms - for k in range (0,2500): - listetrame.append(io.input(pin_data_bcm)) #récupération de la trame suréchantillonnée - if (debug_level==3): - print("=== Raw data ===") - print(listetrame) - - if (debug_level==2): - print("=== Data -> 40 bits ===") - cpt1=0 #compteur des 1 - nb=1 #nombre du bit - t = len(listetrame) - for k in range(0,t-1) : #compte le nombre de 1 par bit - a = listetrame[k] - b = listetrame[k+1] - if (b==1) : - cpt1 = cpt1 + 1 - if ((b-a) ==-1) : - tableN.append(cpt1) #enregistrer le nombre de 1 dans tableN - if (debug_level==2): - print ("bit=",nb," len=",cpt1) - if (nb%8==0): - print() - nb=nb+1 - cpt1=0 - - try: - - seuil = (max(tableN)+min(tableN))/2 - except ValueError : - valide = 3 - seuil = 0 - return valide, 0, 0, 0 ,data - if (debug_level==2): - print("=== Threshold to binarize ===") - print ("seuil=",seuil) - - # --- autocorrection of the first bit - lent=len(tableN) - #print("lent A=",lent) - if (lent==41): - tableN = tableN[1:lent:1] - if (lent==39): - tableN.insert(0,0) - #print("tableN=",tableN) - lent=len(tableN) - #print("lent B=",lent) - - valide=0 - tmp=0 - hum=0 - for elem in tableN: - if elem > seuil: - d=1 - else: - d=0 - data.append(d) #on remplit data avec ses vraies valeurs binaires - - if lent != 40: - valide=2 - return valide, 0, 0, lent,data - - if (debug_level==2): - print("=== 40 Bits -> 16_hum 16_temp 8_chksum ===") - k=1 - bi_hum="0b" - bi_tmp="0b" - bi="0b" - sg_tmp=1 - chk=0; #check somme - for elem in tableN: - if elem > seuil: - d=1 - else: - d=0 - if (k>=1 and k<=16): - bi_hum=bi_hum+str(d) #on assemble le mot binaire de l'humidité - if (k==16): - hum=int(bi_hum,2)/10; #convertion du nombre binaire en décimal - if (debug_level==2): - print ("Binary humidity = ",bi_hum) - print ("Decimal humidity = ",hum) - if (k==17 and d==1): - sg_tmp=-1 - if (k>=18 and k<=32): - bi_tmp=bi_tmp+str(d) #on assemble le mot binaire de la température - # print ("le binaire de la temp vaut :",bi_tmp," (",k,")") - if (k==32): - tmp=sg_tmp*int(bi_tmp,2)/10; #convertion du nombre binaire en décimal - if (debug_level==2): - print ("Binary temperature = ",bi_tmp) - print ("Decimal temperature = ",tmp) - - #checksum - if (k>=1 and k<=8): - bi=bi+str(d) #premier octet - # print ("le binaire vaut :",bi," (",k,")") - if (k==8): - chk+=int(bi,2) #conversion du premier octet en décimal et addition du premier octet - bi="0b"; - if (k>=9 and k<=16): - bi=bi+str(d) #second octet - # print ("le binaire vaut :",bi," (",k,")") - if (k==16): - chk+=int(bi,2) #ajout du second octet - bi="0b"; - if (k>=17 and k<=24): - bi=bi+str(d) - # print ("le binaire vaut :",bi," (",k,")") - if (k==24): - chk+=int(bi,2) - bi="0b"; - if (k>=25 and k<=32): - bi=bi+str(d) - # print ("le binaire vaut :",bi," (",k,")") - if (k==32): - chk+=int(bi,2) - bi="0b"; - if (k>=33 and k<=40): - bi=bi+str(d) - # print ("le binaire vaut :",bi," (",k,")") - if (k==40): - if (debug_level==2): - print ("=== Checksum ===") - print ("Binary checksum data = ",bin(chk)) - print ("Decimal checksum data = ",chk) - chk=chk%256 #modulo 256 - if (debug_level==2): - print ("Decimal checksum data modulo = ",chk) - chksum=int(bi,2) - if (debug_level==2): - print ("Binary checksum frame modulo = ",bi) - print ("Decimal checksum frame modulo = ",chksum) - if (chksum==chk): - valide=0 - else: - valide=1 - - k+=1 - - return valide, tmp, hum, seuil, data - diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_mife.py b/src/core/pyros_django/utils/plc/guitalens_observatory/driver_mife.py deleted file mode 100644 index e9eb559..0000000 --- a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_mife.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -import RPi.GPIO as io -import time - -def do_led_green(pin_cmd_led_bcm=18, onoff=1): - """ - -Exemple: - -import driver_mife ; driver_mife.do_led_green(18,1) -""" - - io.setwarnings(False) - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_cmd_led_bcm,io.OUT) # make pin an output (=arduino 2 open) - - io.output(pin_cmd_led_bcm,onoff) - return onoff - -def do_led_red(pin_cmd_led_bcm=17, onoff=1): - """ - -Exemple: - -import driver_mife ; driver_mife.do_led_red(17,1) -""" - - io.setwarnings(False) - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_cmd_led_bcm,io.OUT) # make pin an output (=arduino 3 open) - - io.output(pin_cmd_led_bcm,onoff) - return onoff - - diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_mlx.py b/src/core/pyros_django/utils/plc/guitalens_observatory/driver_mlx.py deleted file mode 100644 index 527c627..0000000 --- a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_mlx.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*-coding: utf-8 -*- - -#import smbus -import time -import math -import subprocess -#subprocess.check_output(['i2cget', 'y 1 0x5a 0x06']) - -def get_data(debug_level=0): - """Lecture d'une trame du capteur MLX90614 -Retourne un tuple, dans l'ordre: Un code de validité, la température du ciel en °C, la température du boitier en °C, octet brut temperature du ciel,octet brut temperature du boitier -Exemple: - -import driver_mlx ; driver_mlx.get_data(2) -""" - add_i2c=0x5a - #bus = smbus.SMBus(1) - err=0 - k=0 - sortie=False - while (sortie==False): - err=0 - try : - #raw_data_ciel = bus.read_word_data(add_i2c,0x07) - #raw_data_boit = bus.read_word_data(add_i2c,0x06) - str_data_ciel = subprocess.check_output(['i2cget', '-y','1',str(add_i2c),'0x07','w']) - str_data_boit = subprocess.check_output(['i2cget', '-y','1',str(add_i2c),'0x06','w']) - raw_data_ciel = int(str_data_ciel[0:6],16) - raw_data_boit = int(str_data_boit[0:6],16) - #except IOError: - except: - err=1 - raw_data_ciel=0 - raw_data_boit=0 - if ((err==0) or (k>5)): - sortie=True - else: - time.sleep(0.1) - k+=1 - tmp_ciel = raw_data_ciel*0.02-273.15 - tmp_boit = raw_data_boit*0.02-273.15 - - if (debug_level==2): - print (" la valeur binaire de température ciel vaut : {}".format(raw_data_ciel)) - print (" la valeur binaire de température boitier vaut : {}".format(raw_data_boit)) - if (debug_level==1): - print ("la température de l'objet vaut : {}".format(tmp_ciel)); - print ("\n") - print ("la température du boitier vaut : {}".format(tmp_boit)); - if tmp_ciel < -16: - print ("Le ciel est clair") - else: - print ("le ciel est nuageux") - - return err,tmp_ciel,tmp_boit,raw_data_ciel,raw_data_boit - diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_rg11.py b/src/core/pyros_django/utils/plc/guitalens_observatory/driver_rg11.py deleted file mode 100644 index 9c1802c..0000000 --- a/src/core/pyros_django/utils/plc/guitalens_observatory/driver_rg11.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -import RPi.GPIO as io - -def get_data(pin_rain_bcm=19, pin_dry_bcm=20, pin_vin_bcm=25, debug_level=0): - """Lecture d'une trame du capteur meteo RG11. -Retourne un tuple, dans l'ordre: Un code de validité, etat (-1=unknown, 0=dry 1=rain), bit rain, bit dry. Le code de validité =0 si la trame est valide, =1 si Vin n'est pas detecte, =2 si les bits sont tous deux egaux a 0, =2 si les bits sont tous deux egaux à 1. - -Exemple: - -import driver_rg11 ; driver_rg11.get_data(19,20,25,2) -""" - - # === verify 12V power supply if it is possible - power_mife = 1 - if (pin_vin_bcm>0): - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_vin_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 35->34 SWO_T60 = Vin) - pin34 = io.input(pin_vin_bcm) - power_mife = 1-pin34 - if (debug_level==2): - print("=== Voltage intput ===") - disp ="pin34,35,gpio25,Vin="+str(pin34)+ " (0=12V 1=0V)" - print(disp) - err = 0 - if ( power_mife==1 ): - power_mife_msg = "12Volts" - power_mife = 1 - else: - power_mife_msg = "0Volt" - power_mife = 0 - err = err +1 - - io.setwarnings(False) - io.setmode(io.BCM) #set up GPIO using BCM numbering - io.setup(pin_rain_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 46->36 rain) - io.setup(pin_dry_bcm,io.IN, pull_up_down=io.PUD_DOWN) # make pin an input (=arduino 47->38 dry) - - pin36 = io.input(pin_rain_bcm) - pin38 = io.input(pin_dry_bcm) - if (debug_level==2): - print("=== Bit states ===") - disp ="pin36,46,gpio19,rain ="+str(pin36)+" pin38,47,gpio20,dry ="+str(pin38) - print(disp) - - # === return - err = 0 - rain_state_msg = "Unknown" - rain_state = 2 - if (power_mife==1): - if ( (pin36==0) and (pin38==0) ): - err = err + 2 - elif ( (pin36==1) and (pin38==1) ): - err = err + 4 - elif ( (pin36==0) and (pin38==1) ): - rain_state_msg = "Rain" - rain_state = 1 - elif ( (pin36==1) and (pin38==0) ): - rain_state_msg = "Dry" - rain_state = 0 - - if (debug_level>=1): - print("=== RG11 states ===") - disp = " Vin ="+power_mife_msg + " RG11 ="+rain_state_msg - print(disp) - - return err, power_mife, rain_state, rain_state, power_mife_msg, rain_state_msg, pin34, pin36, pin38 - diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/maintenance_guide.odp b/src/core/pyros_django/utils/plc/guitalens_observatory/maintenance_guide.odp deleted file mode 100644 index 7a7eaae..0000000 Binary files a/src/core/pyros_django/utils/plc/guitalens_observatory/maintenance_guide.odp and /dev/null differ diff --git a/src/core/pyros_django/utils/plc/guitalens_observatory/run_goc.py b/src/core/pyros_django/utils/plc/guitalens_observatory/run_goc.py deleted file mode 100644 index 60dcf35..0000000 --- a/src/core/pyros_django/utils/plc/guitalens_observatory/run_goc.py +++ /dev/null @@ -1,354 +0,0 @@ -# -*- coding: utf-8 -*- -import time -import socket -import struct -import sys -import os - -# --- Interaction with Raspberry GPIO -import fcntl -import driver_rg11 -import driver_cv7 -import driver_dht22 -import driver_mlx -import driver_came -import driver_mife - -# --- update the path of Python for util modules -py_path = os.sys.path -py_pwd = os.getcwd() -py_pwd = os.getcwd() + "/../.." -if (py_pwd not in py_path): - (os.sys.path).append(py_pwd) -import guitastro -import report - -# === Some debug states -roof_action = True -delay_roof_sec = 20 -oled_action = True - -# === Init OLED -if (oled_action == True): - import Adafruit_SSD1306 - from PIL import Image - from PIL import ImageDraw - from PIL import ImageFont - # Raspberry Pi pin configuration: - RST = 24 - # 128x64 display with hardware I2C: - disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) - # Initialize library. - disp.begin() - # Clear display. - disp.clear() - disp.display() - # Create blank image for drawing. - # Make sure to create image with mode '1' for 1-bit color. - width = disp.width - height = disp.height - panel1 = Image.new('1', (width, height)) - panel2 = Image.new('1', (width, height)) - #logo = Image.open("logo1.ppm").convert('1').resize((128,32),3) - #création d'un objet font - fontpath = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf" - font1 = ImageFont.truetype(fontpath,10) - # Get drawing object to draw on image. - draw1 = ImageDraw.Draw(panel1) - draw2 = ImageDraw.Draw(panel2) - # Draw a black filled box to clear the image. - draw1.rectangle((0,0,width,height), outline=0, fill=0) - #disp.image(logo) - #disp.display() - -# ======================================= -def valid_yesno (err_int): - if err_int==0: - return "yes" - else: - return "no" - -# ======================================= -def compute_error_code (err_int): - if err_int==0: - return "0" - else: - return "1" - -# ======================================= -def get_ip_address(ifname): - """Lecture de l'adresse IP du Raspberry. -Exemple: - -get_ip_address('eth0') -""" - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - return socket.inet_ntoa(fcntl.ioctl( - s.fileno(), - 0x8915, - struct.pack('256s', ifname[:15]) - )[20:24]) - -# ======================================= -def get_sunelev(): - date = guitastro.Date("now") - site = guitastro.Site("GPS 2 E 43 148") - skyobj= {'planet':'Sun'} - outputs = ['elev'] - target = guitastro.Target() - target.define(skyobj) - output0s = ['ra','dec'] - results = target.ephem(date,site,output0s) - ra = results['RA'] - dec = results['DEC'] - skyobj= {'RA':ra , 'DEC':dec } - target.define(skyobj) - results = target.ephem(date,site,outputs) - elev = results['ELEV'] - return elev - -# === print the current Python version -try: - print (sys.version) -except: - pass - -# === print the IP address -try: - print("IP = ",get_ip_address('eth0')) -except: - pass - -# === Configuration of security -delay_to_open_limit = 900 -wind_speed_ms_limit = 5/3.6 -tmp_cielcor_lim = -5 - -# === Main loop -greenled_state = 0 -t0 = time.time() -t0closing = time.time() - delay_to_open_limit -delay_to_open = 0 -t0file = 0 -t0wind = 0 -while True: - - # === Blink the green led - if greenled_state == 0: - driver_mife.do_led_green(18,1) - greenled_state = 1 - else: - driver_mife.do_led_green(18,0) - greenled_state = 0 - - # === Clear the OLED displays - try: - draw1.rectangle((0,0,width,height), outline=0, fill=0) - draw2.rectangle((0,0,width,height), outline=0, fill=0) - except: - pass - - # === Get Sun elevation - sunelev = get_sunelev(); - - # === Init the error supercode - err = 0 - - # === Get RG11 data - err_rg11, power_mife_rg11, rain_state, rain_state, power_mife_msg, rain_state_msg, pin34, pin36, pin38 = driver_rg11.get_data(19,20,25,0) - oled_rain = "RG11 : " - if (err_rg11>0): - print("RG11 err=",err_rg11) - err+=1 - oled_rain += "Err"+str(err_rg11) - else: - oled_rain += rain_state_msg - - # === Get CV7 data - err_cv7, power_mife_cv7, wind_dir_deg, wind_speed_ms, wind_tmp_degC, power_mife_msg, msg_wind, msg_temp = driver_cv7.get_data("/dev/ttyS0", 25,0) - oled_wind_speed = "Wind : " - oled_wind_dir = "Wind dir : " - if (err_cv7>0): - print("CV7 err=",err_cv7) - err+=2 - oled_wind_speed += "Err"+str(err_cv7) - oled_wind_dir += "Err"+str(err_cv7) - else: - oled_wind_speed += '{:.2f}'.format(wind_speed_ms)+" m/s" - oled_wind_dir += '{:3.0f}'.format(wind_dir_deg)+ " deg" - - # === Get DHT22 data - err_dht22, tmp, hum, seuil, data = driver_dht22.get_data(13,0) - oled_tmp = "Temp : " - oled_hum = "Humidity : " - if (err_dht22>0): - print("DHT22 err=",err_dht22) - err+=4 - oled_tmp += "Err"+str(err_dht22) - oled_hum += "Err"+str(err_dht22) - else: - oled_tmp += "{:.1f}".format(tmp) + " degC" - oled_hum += "{:.0f}".format(hum) + " %" - - # === Get MLX data - err_mlx, tmp_ciel, tmp_boit, raw_data_ciel, raw_data_boit =driver_mlx.get_data(0) - tmp_cielcor = tmp_ciel - tmp_boit * 0.7; - oled_skytmp = "Sky temp : " - if (err_mlx>0): - print("mlx err =",err_mlx) - err+=8 - oled_skytmp += "Err"+str(err_mlx) - else: - oled_skytmp += "{:.2f}".format(tmp_ciel)+" degC" - - # === Get Came data - err_came, power_came, mode_came, roof_state, power_came_msg, mode_came_msg, roof_state_msg, pin48, pin39, pin41,pin31 = driver_came.get_data(26,22,5,6,1) - oled_came1 = "Roof mode : " - oled_came2 = "Roof state : " - if (err_came>0): - oled_came1 += "Err"+str(err_mlx) - oled_came2 += "Err"+str(err_mlx) - else: - oled_came1 += mode_came_msg - oled_came2 += roof_state_msg - - # === Compute the meteo conditions - meteo_conditions = 0 - if (err_mlx==0): - if (tmp_cielcor > tmp_cielcor_lim): - meteo_conditions = meteo_conditions +1 - if (err_rg11==0) and (rain_state==1): - meteo_conditions = meteo_conditions +2 - if (err_cv7==0) and (wind_speed_ms>wind_speed_ms_limit): - meteo_conditions = meteo_conditions +4 - if (err_rg11==1): - # --- critical error - meteo_conditions = meteo_conditions +8 - - # === Json status - date = guitastro.Date("now") - date_iso_utc = date.iso(); - rep = report.Status_json() - rep.new_status("PLC","20181014_0854") - rep.append_entity("PLC_STATUS", "Raspberry", "20181014_0854", "Guitalens Observatory",date_iso_utc) - # --- Json device Came - rep.append_device("Came", "roof_controler", "S/N_A5EM", compute_error_code(err_came)) - rep.append_value( "Error_code", "int",str(err_came),"","","0=OK 1=PowerPB 2=SwitchPB") - rep.append_value( "Power_input", "int",str(power_came),"","","0=0Volt 1=24Volts") - rep.append_value( "Mode_came", "int",str(mode_came),"","","0=Manual 1=Auto") - rep.append_value( "Roof_state", "int",str(roof_state),"","","0=Closed 1=Opened 2=Intermediate") - rep.append_value( "Meteo_conditions", "int",str(meteo_conditions),"","","0=OK +1=Clouds +2=Rain +4=Wind +8=CriticalError") - rep.append_value( "Delay_to_open", "int","{:.0f}".format(delay_to_open),"s","","Current delay to open since the meteo became OK") - rep.append_value( "Security_delay_to_open", "int","{:.0f}".format(delay_to_open_limit),"s","","Limit delay to open since the meteo becomes OK") - rep.append_value( "SkyTemperatureCor_lim", "float","{:+.2f}".format(tmp_cielcor_lim),"degC","","Limit of the corrected temperature of the sky to close roof") - rep.append_value( "Wind_speed_lim", "float","{:.2f}".format(wind_speed_ms_limit),"m/s","","Limit of wind speed to close the roof") - rep.append_value( "Sun_elevation", "float","{:+.3f}".format(sunelev),"deg","","Local elevation of the Sun") - # --- Json device CV7 - rep.append_device("CV7", "weather_station", "S/N_09172419", compute_error_code(err_cv7)) - rep.append_value( "Error_code", "int",str(err_cv7),"","","0=OK 1=SerialPB 2=FramePB") - rep.append_value( "Power_input", "int",str(power_mife_cv7),"","","0=0Volt 1=12Volts (Power from MiFe board)") - rep.append_value( "Wind_dir", "float","{:.2f}".format(wind_dir_deg),"degrees","Wind_direction","0=North 90=East") - rep.append_value( "Wind_speed", "float","{:.2f}".format(wind_speed_ms),"m/s","Wind_speed","Wind speed from ultrasonic sensors") - rep.append_value( "OutsideTemperature", "float","{:+.2f}".format(wind_tmp_degC),"degC","Temperature_outside","Temperature of the anemometer") - # --- Json device DHT22 - rep.append_device("DHT22", "weather_station", "MiFe_DHT1_1", compute_error_code(err_dht22)) - rep.append_value( "Error_code", "int",str(err_dht22),"","","0=OK 1=CheksumPB 2=LengthPB 3=NodataPB") - rep.append_value( "Temperature", "float","{:+.0f}".format(tmp),"degC","Temperature_outside","Temperature inside PLC box") - rep.append_value( "Humidity", "float","{:.0f}".format(hum),"percent","Humidity_outside","Humidity inside PLC box") - # --- device RG11 - rep.append_device("RG11", "weather_station", "S/N_207588", compute_error_code(err_rg11)) - rep.append_value( "Error_code", "int",str(err_rg11),"","","0=OK +1=PowerPB +2=NopowerPB +4=AllonePB") - rep.append_value( "RainSate", "int",str(rain_state),"","Rain_boolean","0=Dry 1=Rain 2=Unknown") - # --- device MLX90614 - rep.append_device("MLX90614", "weather_station", "1", compute_error_code(err_mlx)) - rep.append_value( "Error_code", "int",str(err_mlx),"","","0=OK 1=DataPB") - rep.append_value( "SkyTemperature", "float","{:+5.2f}".format(tmp_ciel),"degC","","Temperature of the sky") - rep.append_value( "CanTemperature", "float","{:+5.2f}".format(tmp_boit),"degC","","Temperature of the TO can") - rep.append_value( "SkyTemperatureCor", "float","{:+5.2f}".format(tmp_cielcor),"degC","Temperature_sky","Corrected temperature of the sky") - # --- save the Json status report - rep.save_json("/var/www/html/meteo/plc_guitalens.json") - - # === String of results - date_jd_utc = date.jd(); - date_digits_utc = date.digits(0) - msg_gene = "{:13.5f} {} {:+6.2f} {:2d} {:1d} ".format(date_jd_utc, date_digits_utc, sunelev,err,meteo_conditions) - msg_came = "{:2d} {:1d} {:1d} {:1d} ".format(err_came, power_came, mode_came, roof_state) - msg_mlx = "{:2d} {:+6.2f} {:+6.2f} {:+6.2f} ".format(err_mlx, tmp_ciel, tmp_boit, tmp_cielcor) - msg_rg11 = "{:2d} {:1d} {:1d} ".format(err_rg11, power_mife_rg11, rain_state) - msg_dht22 = "{:2d} {:+3.0f} {:3.0f} ".format(err_dht22, tmp, hum) - msg_cv7 = "{:2d} {:1d} {:3.0f} {:6.2f} {:+3.0f} ".format(err_cv7, power_mife_cv7, wind_dir_deg, wind_speed_ms, wind_tmp_degC) - msg = msg_gene + msg_came + msg_mlx + msg_rg11 + msg_dht22 + msg_cv7 - print(msg) - - # === File for web site - try: - dt = time.time()-t0file; - if (dt>30): - dateymdhms= date.ymdhms() - fic = "/var/www/html/meteo/meteo_{:04d}{:02d}{:02d}.txt".format(dateymdhms[0],dateymdhms[1],dateymdhms[2]) - fichier = open(fic,"a") - fichier.write(msg) - fichier.write("\n") - fichier.close() - t0file = time.time() - except: - pass - - # === Display OLED - try: - dt = time.time()-t0; - if (dt<6): - draw1.text((0, 10),oled_came1, font=font1, fill=255) - draw1.text((0, 20),oled_skytmp, font=font1, fill=255) - draw1.text((0, 30),oled_tmp, font=font1, fill=255) - draw1.text((0, 40),oled_hum, font=font1, fill=255) - disp.image(panel1) - elif (dt<12): - draw2.text((0, 10),oled_came2, font=font1, fill=255) - draw2.text((0, 20),oled_wind_speed, font=font1, fill=255) - draw2.text((0, 30),oled_wind_dir, font=font1, fill=255) - draw2.text((0, 40),oled_rain, font=font1, fill=255) - disp.image(panel2) - else: - t0 = time.time() - disp.display() - except: - pass - - # === Roof action according security rules - delay_to_open = 0 - if (mode_came_msg=="Auto") and (err_came==0): - delay_to_open = time.time()-t0closing; - if (sunelev>0): - # --- Il fait jour - if (roof_state_msg != 'Closed'): - print("==> Il fait jour et le toit n'est pas ferme. On ferme.") - if roof_action == True: - driver_came.do_close_roof(23) - time.sleep(delay_roof_sec) - if (meteo_conditions>0): - t0closing = time.time() - else: - # --- Il fait nuit mais pas beau - if (meteo_conditions>0): - # --- Il ne fait pas beau - if (roof_state_msg != 'Closed'): - print("==> Il fait nuit, il ne fait pas beau {} et le toit n'est pas ferme. On ferme.".format(meteo_conditions)) - if roof_action == True: - driver_came.do_close_roof(23) - time.sleep(delay_roof_sec) - t0closing = time.time() - else: - # --- Il fait nuit et il fait beau - if (roof_state_msg != 'Opened'): - if (delay_to_open>delay_to_open_limit): - # --- Cela fait + de 600s que le toit avait ete prealablement ferme - print("==> Il fait nuit, il fait beau {} depuis +{}s et le toit n'est pas ouvert. On ouvre.".format(meteo_conditions,delay_to_open_limit)) - if roof_action == True: - driver_came.do_open_roof(27) - time.sleep(delay_roof_sec) - else: - print("==> Il fait nuit, il fait beau {} mais -{}s ({:.0f}) depuis la precedente fermeture.".format(meteo_conditions,delay_to_open_limit,delay_to_open)) - - # === Wait 1 seconds before the next read - time.sleep(1) diff --git a/src/core/pyros_django/utils/report/COPYING b/src/core/pyros_django/utils/report/COPYING deleted file mode 100644 index 7b90a6c..0000000 --- a/src/core/pyros_django/utils/report/COPYING +++ /dev/null @@ -1,18 +0,0 @@ -This file is part of the Report project -Copyright (C) 2018-2018 The Report Core Team - -Initial author : Alain KLOTZ - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/src/core/pyros_django/utils/report/PKG-INFO b/src/core/pyros_django/utils/report/PKG-INFO deleted file mode 100644 index 531a0bd..0000000 --- a/src/core/pyros_django/utils/report/PKG-INFO +++ /dev/null @@ -1,17 +0,0 @@ -Metadata-Version: 1.0 -Name: report -Version: 0.1 -Summary: Python for astronomy and robotic observatories -Home-page: -Author: Alain Klotz -Author-email: alain.klotz@free.fr -License: GNU General Public License -Description: Report - Python Pixel & Cassoulet package is a set of algorithms to drive - robotic astronomical observatories. -Platform: UNKNOWN -Classifier: Development Status :: Beta -Classifier: License :: GNU General Public License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Scientific/Engineering :: Astronomy diff --git a/src/core/pyros_django/utils/report/README b/src/core/pyros_django/utils/report/README deleted file mode 100644 index 8c3490a..0000000 --- a/src/core/pyros_django/utils/report/README +++ /dev/null @@ -1,17 +0,0 @@ -report -=========== - -A python module for driving a robotic observatory -Web Page: none -License: GNU General Public License - -Installation ------------- - -If you have numpy (http://numpy.scipy.org/) installed, just do - -python setup.py install - -On some linux distributions, this may need to be - -sudo python setup.py install diff --git a/src/core/pyros_django/utils/report/__init__.py b/src/core/pyros_django/utils/report/__init__.py deleted file mode 100644 index 1def4a0..0000000 --- a/src/core/pyros_django/utils/report/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import glob -import os - -from .status_json import Status_json - -# Now we can use: -# report = report.Status_json() -# report.init() diff --git a/src/core/pyros_django/utils/report/doc/user_guide_module_report.odt b/src/core/pyros_django/utils/report/doc/user_guide_module_report.odt deleted file mode 100644 index 01f91f9..0000000 Binary files a/src/core/pyros_django/utils/report/doc/user_guide_module_report.odt and /dev/null differ diff --git a/src/core/pyros_django/utils/report/setup.py b/src/core/pyros_django/utils/report/setup.py deleted file mode 100644 index 486d485..0000000 --- a/src/core/pyros_django/utils/report/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from distutils.core import setup - -long_desc = u"""Report -Python Pixel & Cassoulet package is a set of algorithms to drive -robotic astronomical observatories.""" - -setup(name='report', - version='0.1', - description='Python for astronomy and robotic observatories', - long_description = long_desc, - author='Alain Klotz', - author_email='alain.klotz@free.fr', - url='http://', - license='GNU General Public License', - packages=['report',], - classifiers=[ - 'Development Status :: Beta', - 'License :: GNU General Public License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Scientific/Engineering :: Astronomy' - ] - ) diff --git a/src/core/pyros_django/utils/report/status_json.py b/src/core/pyros_django/utils/report/status_json.py deleted file mode 100644 index 482c7c3..0000000 --- a/src/core/pyros_django/utils/report/status_json.py +++ /dev/null @@ -1,798 +0,0 @@ -#import math -import doctest -import json -import os -import sys - -# --- update the path of Python -py_path = os.sys.path -py_pwd = os.getcwd() -if (py_pwd not in py_path): - (os.sys.path).append(py_pwd) -py_pwd = os.getcwd() + "/.." -if (py_pwd not in py_path): - (os.sys.path).append(py_pwd) -py_pwd = os.getcwd() + "/../.." -if (py_pwd not in py_path): - (os.sys.path).append(py_pwd) - - -#import utils.celme as celme -#sys.path.append('..') -import vendor.guitastro.src.guitastro as guitastro - -# ======================================================== -# ======================================================== -# === Status_json -# ======================================================== -# ======================================================== - -class Status_json: - """ Class to manage Json file reports into python variables and vice versa - -Example a a very wimple Json file report contents: -{ - "frame_model": "1.3", - "producer_name": "PLC", - "producer_version": "20180909", - "entities": [ - { - "entity_name": "PLC_STATUS", - "origin": "Raspberry", - "version_firmware": "20180924A", - "site": "MyObservatory", - "date": "2019-01-10T20:20:20.738", - "devices": [ - { - "device_name": "DHT22", - "device_type": "meteo", - "serial_number": "1", - "error_code": "0", - "device_values": [ - { - "name": "OutsideTemperature", - "data_type": "float", - "value": "22", - "unit": "degC", - "monitoring_name": "Temperature_outside", - "comment": "Temperature", - "date_data": "2019-01-10T20:20:20.738" - } - ] - } - ] - } - ] -} - -A value is stored in a UFKI (Unique Four Key Identifier): -UFKI = entity_name device_name serial_number name - -No support for hjson. See the following link to do that: -https://github.com/hjson/hjson-py - - - Usage: - ------ - - First, instanciate an object from the class: - report = report.Status_json() - - Informations: - ------------- - - help(Status_json) - Status_json().infos("doctest") - Status_json().infos("doc_methods") - """ -# ======================================================== -# === attributes -# ======================================================== - - # --- multiplicators for units - _status = [] - _entity_name = "" - _device_name = "" - _serial_number = "" - -# ======================================================== -# === internal methods -# ======================================================== - - def _init(self,status=""): - """ Initialize internal attributes. - - Inputs: - ------- - status is a list of dictionnaries according a predefined format. - - Usage: - ------ - report = report.Status_json() - """ - self._status = status - self._entity_name = "" - self._device_name = "" - self._serial_number = "" - - def _is_number(self,s): - """ Return True if the string is a number else return False. - - Usage: - ------ - >>> report = report.Status_json() - >>> report._is_number("3e5") - True - >>> report._is_number("3a5") - False - """ - try: - float(s) - return True - except ValueError: - pass - try: - import unicodedata - unicodedata.numeric(s) - return True - except (TypeError, ValueError): - pass - return False - - #################################################################### - # To read a Status - #################################################################### - - def _get_indice_from_entities(self, entities, entity_name): - indice = 0 - found = -1 - for entity in entities: - #print("{} et {}".format(entity,entity_name)) - if entity == entity_name: - found = indice - break - indice += 1 - return found - - def _get_indice_from_devices(self, devices, device_name, serial_number): - indice = 0 - found = -1 - for device in devices: - cur_device_name = device['device_name'] - cur_serial_number = device['serial_number'] - #print("{} et {}".format(device,device_name)) - if (cur_device_name == device_name) and ( cur_serial_number == serial_number): - found = indice - break - indice += 1 - return found - - def _get_entity_names(self): - #entities = self._status['statuses'][0]['entities'] - entities = self._status['entities'] - entity_names = [] - for entity in entities: - entity_names.append(entity['entity_name']) - return entity_names - - def _get_device_nameserials(self, entity_name): - entities = self._get_entity_names() - indice = self._get_indice_from_entities(entities,entity_name) - if indice == -1: - return "" - #devices = self._status['statuses'][0]['entities'][indice]['devices'] - devices = self._status['entities'][indice]['devices'] - device_names = [] - for device in devices: - devs = {'device_name':device['device_name'], 'serial_number':device['serial_number']} - #print("devs={} ".format(devs)) - device_names.append(devs) - return device_names - - def _get_value_names(self, entity_name, device_name, serial_number): - entities = self._get_entity_names() - indicee = self._get_indice_from_entities(entities,entity_name) - if indicee == -1: - return "" - #devices = self._status['statuses'][0]['entities'][indicee]['devices'] - devices = self._status['entities'][indicee]['devices'] - indiced = self._get_indice_from_devices(devices, device_name, serial_number) - device = devices[indiced] - #print("device={} ".format(device)) - values = device['device_values'] - value_names = [] - for value in values: - #print("value={} ".format(value)) - value_names.append(value['name']) - return value_names - - def _get_value_name_values(self, entity_name, device_name, serial_number, value_name): - entities = self._get_entity_names() - indicee = self._get_indice_from_entities(entities,entity_name) - if indicee == -1: - return "" - #devices = self._status['statuses'][0]['entities'][indicee]['devices'] - devices = self._status['entities'][indicee]['devices'] - indiced = self._get_indice_from_devices(devices, device_name, serial_number) - device = devices[indiced] - #print("device={} ".format(device)) - values = device['device_values'] - for value in values: - if value_name == value['name']: - return value - return "" - - def _set_value_name_values(self, entity_name, device_name, serial_number, value_name, dico): - entities = self._get_entity_names() - indicee = self._get_indice_from_entities(entities,entity_name) - if indicee == -1: - return "" - #devices = self._status['statuses'][0]['entities'][indicee]['devices'] - devices = self._status['entities'][indicee]['devices'] - indiced = self._get_indice_from_devices(devices, device_name, serial_number) - device = devices[indiced] - #print("device={} ".format(device)) - values = device['device_values'] - indicev = 0 - for value in values: - if value_name == value['name']: - #self._status['statuses'][0]['entities'][indicee]['devices'][indiced]['device_values'][indicev] = dico - self._status['entities'][indicee]['devices'][indiced]['device_values'][indicev] = dico - break - indicev += 1 - return "" - - #################################################################### - # To create a Status - #################################################################### - - def _status_new(self, producer_name, producer_version): - status_header = {'frame_model':'1.3', 'producer_name':producer_name, 'producer_version':producer_version, 'entities':[]} - #self._status = { 'statuses':[] } - #self._status['statuses'].append(status_header) - self._status = status_header - - def _status_new_entity(self, entity_name, theorigin, version_firmware, site, date=""): - if date=="": - date = (guitastro.Date("now")).iso() - entity= {'entity_name':entity_name, 'origin':theorigin, 'version_firmware':version_firmware, 'site':site, 'date':date, 'devices':[]} - #self._status['statuses'][0]['entities'].append(entity); - self._status['entities'].append(entity); - - def _status_entity_new_device(self, entity_name, device_name, device_type, serial_number, error_code): - entities = self._get_entity_names() - indicee = self._get_indice_from_entities(entities,entity_name) - if indicee == -1: - return "" - device = {'device_name':device_name, 'device_type':device_type, 'serial_number':serial_number, 'error_code':error_code, 'device_values':[]} - #self._status['statuses'][0]['entities'][indicee]['devices'].append(device) - self._status['entities'][indicee]['devices'].append(device) - - def _status_entity_device_new_value(self, entity_name, device_name, serial_number, name, data_type, value, unit="", monitoring_name="", comment="", date_data=""): - entities = self._get_entity_names() - indicee = self._get_indice_from_entities(entities,entity_name) - if indicee == -1: - return "" - #devices = self._status['statuses'][0]['entities'][indicee]['devices'] - devices = self._status['entities'][indicee]['devices'] - indiced = self._get_indice_from_devices(devices, device_name, serial_number) - if indiced == -1: - return "" - if date_data=="": - date_data = (guitastro.Date("now")).iso() - else: - date_data = (guitastro.Date(date_data)).iso() - dico = {'name':name, 'data_type':data_type, 'value':value, 'unit':unit, 'monitoring_name':monitoring_name, 'comment':comment, 'date_data':date_data} - #self._status['statuses'][0]['entities'][indicee]['devices'][indiced]['device_values'].append(dico) - self._status['entities'][indicee]['devices'][indiced]['device_values'].append(dico) - -# ======================================================== -# === status_json methods -# ======================================================== - - def new_status(self, producer_name, producer_version): - """ Initialize a new status - - Inputs: - ------- - Dictionary keys of the creator. - - Usage: - ------ - >>> report = report.Status_json() - >>> report.new_status("PLC","20180909") - - Related topics: - --------------- - Method append_entity - """ - self._init() - self._status_new(producer_name, producer_version) - - def append_entity(self, entity_name, theorigin, version_firmware, site, date=""): - """ Append a new entity to a creator - - Inputs: - ------- - Dictionary keys of the entity. - - Usage: - ------ - >>> report = report.Status_json() - >>> report.new_status("PLC","20180909") - >>> rep.append_entity("PLC_STATUS", "Raspberry", "20180924A", "MyObservatory") - - Related topics: - --------------- - Methods append_device, get_entities - """ - self._status_new_entity(entity_name, theorigin, version_firmware, site, date) - self._entity_name = entity_name - - def append_device(self, device_name, device_type, serial_number, error_code): - """ Append a new device to an entity - - Inputs: - ------- - Dictionary keys of the device. - - Usage: - ------ - >>> report = report.Status_json() - >>> report.new_status("PLC","20180909") - >>> rep.append_entity("PLC_STATUS", "Raspberry", "20180924A", "MyObservatory") - >>> rep.append_device("DHT22", "meteo", "1", "0") - - Related topics: - --------------- - Methods append_value, get_devices - """ - entity_name = self._entity_name - self._status_entity_new_device(entity_name, device_name, device_type, serial_number, error_code) - self._device_name = device_name - self._serial_number = serial_number - - def append_value(self, name, data_type, value, unit="", monitoring_name="", comment="", date_data=""): - """ Append a new value to a device - - Inputs: - ------- - Dictionary keys of the device_value. - - Usage: - ------ - >>> report = report.Status_json() - >>> report.new_status("PLC","20180909") - >>> rep.append_entity("PLC_STATUS", "Raspberry", "20180924A", "MyObservatory") - >>> rep.append_device("DHT22", "meteo", "1", "0") - >>> rep.append_value( "OutsideTemperature", "float","22","degC","temperature","Temperature","") - - Related topics: - --------------- - Methods append_value, get_devices - """ - entity_name = self._entity_name - device_name = self._device_name - serial_number = self._serial_number - self._status_entity_device_new_value(entity_name, device_name, serial_number, name, data_type, value, unit, monitoring_name, comment, date_data) - - def load_json(self, full_filename): - """ Load a Json file as an object - - Inputs: - ------- - full_filename is the path + file name of the Json file - - Usage: - ------ - >>> report = report.Status_json() - >>> report.load_json("") - - Related topics: - --------------- - The Json file does not have any comment - """ - if (full_filename != ""): - with open(full_filename, "r") as read_file: - self._status = json.load(read_file) - - def save_json(self, full_filename): - """ Save a Json file from an object - - Inputs: - ------- - full_filename is the path + file name of the Json file - - Usage: - ------ - >>> report = report.Status_json() - >>> report.create_a_simple_report_for_tests() - >>> report.save_json("") - - Related topics: - --------------- - The Json file will not have any comment - """ - if (full_filename != "") and (self._status != ""): - json_string = json.dumps(self._status, indent=2) - with open(full_filename, "w") as write_file: - write_file.write(json_string) - - def create_a_simple_report_for_tests(self): - """ Create a simple report for tests - - Inputs: - ------- - None. - - Usage: - ------ - >>> report = report.Status_json() - >>> report.create_a_simple_report_for_tests() - - Related topics: - --------------- - The Json file will not have any comment - """ - self.new_status("PLC","20180909") - self.append_entity("PLC_STATUS", "Raspberry", "20180924A", "MyObservatory") - self.append_device("DHT22", "meteo", "1", "0") - self.append_value( "OutsideTemperature", "float","22","degC","temperature","Temperature") - #full_filename = "test.json" - #self.save_json(full_filename) - -# ======================================================== -# === get/set methods -# ======================================================== - - def get_error_message(self, error_code): - """ Get the message of a given error code - - Inputs: - ------- - integer number corresponding to an error code. - - Outputs: - ------- - The string message of the error code. - - Usage: - ------ - >>> rep.get_error_message(102) - >>> 'Disk full' - - Related topics: - --------------- - """ - errs = [] - errs.append( {'code':0, 'message':"No error", 'version':"1.0"} ) - # errors - errs.append( {'code':1 , 'message':"Unreferenced error", 'version':"1.2"} ) - errs.append( {'code':2 , 'message':"System error", 'version':"1.2"} ) - errs.append( {'code':3 , 'message':"Device temperature too high", 'version':"1.2"} ) - errs.append( {'code':4 , 'message':"Device temperature too low", 'version':"1.2"} ) - errs.append( {'code':101 , 'message':"Disk not found", 'version':"1.2"} ) - errs.append( {'code':102 , 'message':"Disk full", 'version':"1.2"} ) - errs.append( {'code':111 , 'message':"File not found", 'version':"1.2"} ) - errs.append( {'code':112 , 'message':"File opening failure", 'version':"1.2"} ) - errs.append( {'code':113 , 'message':"File reading error", 'version':"1.2"} ) - errs.append( {'code':114 , 'message':"File writing error", 'version':"1.2"} ) - errs.append( {'code':1001 , 'message':"Power supply off", 'version':"1.2"} ) - errs.append( {'code':1002 , 'message':"Power supply over voltage", 'version':"1.2"} ) - errs.append( {'code':2001 , 'message':"Data connection failed", 'version':"1.2"} ) - errs.append( {'code':2002 , 'message':"Data checksum error", 'version':"1.2"} ) - errs.append( {'code':2003 , 'message':"Data value out of range", 'version':"1.2"} ) - errs.append( {'code':2004 , 'message':"No data", 'version':"1.2"} ) - errs.append( {'code':2005 , 'message':"No response after timeout", 'version':"1.2"} ) - errs.append( {'code':2006 , 'message':"Data raw frame error", 'version':"1.2"} ) - # warnings - errs.append( {'code':-3 , 'message':"Device temperature reaching high limit", 'version':"1.2"} ) - errs.append( {'code':-4 , 'message':"Device temperature reaching low limit", 'version':"1.2"} ) - errs.append( {'code':-102 , 'message':"Disk almost full", 'version':"1.2"} ) - errs.append( {'code':-2003, 'message':"Data value not consistent", 'version':"1.2"} ) - # find the message - messages = [err['message'] for err in errs if err['code']==error_code] - return messages[0] - - def get_monitoring_names(self, monitoring_name=""): - """ Get the list of available monitoring names - - Inputs: - ------- - Optional: A particular monitoring name - - Outputs: - ------- - List of dictionaries of available monitoring names. - If the optional particular monitoring name is specified as input then - return only the dictionary of that monitoring name. - - Usage: - ------ - >>> rep.get_monitoring_names("Wind_speed") - >>> [{'monitoring_name': 'Wind_speed', 'section': 'weather', 'description': '', 'version': '1.1'}] - - Related topics: - --------------- - """ - monitors = [] - # Weather - monitors .append( {'monitoring_name':"Temperature_outside", 'section':"weather", 'description':"Ambiant temperature", 'version':"1.1"} ) - monitors .append( {'monitoring_name':"Temperature_sky", 'section':"weather", 'description':"Cloud coverage", 'version':"1.1"} ) - monitors .append( {'monitoring_name':"Humidity_outside", 'section':"weather", 'description':"Ambiant humidity", 'version':"1.1"} ) - monitors .append( {'monitoring_name':"Pressure_outside", 'section':"weather", 'description':"Ambiant pressure (not corrected to sea level)", 'version':"1.1"} ) - monitors .append( {'monitoring_name':"Wind_speed", 'section':"weather", 'description':"", 'version':"1.1"} ) - monitors .append( {'monitoring_name':"Wind_direction", 'section':"weather", 'description':"0=N, 90=E", 'version':"1.1"} ) - monitors .append( {'monitoring_name':"Rain_boolean", 'section':"weather", 'description':"0=No rain, 1=Rain", 'version':"1.1"} ) - # Housing - monitors .append( {'monitoring_name':"State_dome_shutter_east", 'section':"housing", 'description':'0=Closed 1=Opened 2=Intermediate3=Closing, 4=Opening, 5=Undefined', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"State_dome_shutter_west", 'section':"housing", 'description':'0=Closed 1=Opened 2=Intermediate3=Closing, 4=Opening, 5=Undefined', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"Direction_dome_shutter", 'section':"housing", 'description':'0=N, 90=E', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"State_roof", 'section':"housing", 'description':'0=Closed 1=Opened 2=Intermediate 3=Closing, 4=Opening, 5=Undefined', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"State_roof_north", 'section':"housing", 'description':'0=Closed 1=Opened 2=Intermediate 3=Closing, 4=Opening, 5=Undefined', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"State_roof_south", 'section':"housing", 'description':'0=Closed 1=Opened 2=Intermediate 3=Closing, 4=Opening, 5=Undefined', 'version':"1.2"} ) - # Power supply - monitors .append( {'monitoring_name':"Voltage_input", 'section':"powersupply", 'description':'', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"Voltage_output", 'section':"powersupply", 'description':'', 'version':"1.2"} ) - # Instruments - monitors .append( {'monitoring_name':"Temperature_mirror", 'section':"Instruments", 'description':'Mirrors temperatures (M1, M2, etc)', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"Position_filterwheel", 'section':"Instruments", 'description':'', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"Position_focuser", 'section':"Instruments", 'description':'Positions of focusers (M2, channel1, etc.)', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"Temperature_sensor", 'section':"Instruments", 'description':'', 'version':"1.2"} ) - # Image quality - monitors .append( {'monitoring_name':"PSF_FWHM", 'section':"Imagequality", 'description':'Image quality', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"ZeroMag", 'section':"Imagequality", 'description':'Transparency', 'version':"1.2"} ) - monitors .append( {'monitoring_name':"SkyMag", 'section':"Imagequality", 'description':'Background brightness', 'version':"1.2"} ) - if monitoring_name!="": - # find the message - print("Etape 1") - dico = [monitor for monitor in monitors if monitor['monitoring_name']==monitoring_name] - return dico - return monitors - - def get_entities(self): - """ Get the current entities - - Inputs: - ------- - None. - - Usage: - ------ - >>> report = report.Status_json() - >>> print("{}",format(report.get_entities())) - - Related topics: - --------------- - """ - entities = [] - if self._status != "": - entities = self._get_entity_names() - return entities - - def get_devices(self, only_entity_name=""): - """ Get the current devices - - Inputs: - ------- - None or a device name to check if exists. - - Usage: - ------ - >>> report = report.Status_json() - >>> print("{}",format(report.get_devices())) - - Related topics: - --------------- - """ - res = [] - if self._status != "": - entities = self._get_entity_names() - for entity_name in entities: - devices = [] - if (only_entity_name==""): - devices = self._get_device_nameserials(entity_name) - else: - if (only_entity_name==entity_name): - devices = self._get_device_nameserials(entity_name) - for device in devices: - re = [entity_name, device['device_name'], device['serial_number']] - res.append(re) - return res - - def get_ufkis(self, only_device_name="", only_serial_number="", getvalue=False): - """ Get the current values - - Inputs: - ------- - None or a device name + serial number + value to check if exists. - - Usage: - ------ - >>> report = report.Status_json() - >>> print("{}",format(report.get_devices())) - >>> print("{}",format(report.get_ufkis("","",True)) - - Related topics: - --------------- - """ - res = [] - if self._status != "": - entities = self._get_entity_names() - for entity_name in entities: - devices = self._get_device_nameserials(entity_name) - for device in devices: - device_name = device['device_name'] - serial_number = device['serial_number'] - value_names = [] - if (only_device_name=="") or (only_serial_number==""): - value_names = self._get_value_names(entity_name, device_name, serial_number) - else: - if (only_device_name==device_name) or (only_serial_number==serial_number): - value_names = self._get_value_names(entity_name, device_name, serial_number) - for value_name in value_names: - if getvalue==False: - re = [entity_name, device_name, serial_number, value_name] - else: - val = self._get_value_name_values(entity_name, device_name, serial_number, value_name) - re = [entity_name, device_name, serial_number, value_name, val] - res.append(re) - return res - - def get_sensors(self, only_device_name="", only_serial_number="", getvalue=False): - """ Get the current values. Alias of get_ufkis. - """ - return self.get_ufkis(only_device_name, only_serial_number, getvalue); - - def get_values(self, only_device_name="", only_serial_number="", getvalue=False): - """ Get the current values. Alias of get_ufkis. - """ - return self.get_ufkis(only_device_name, only_serial_number, getvalue); - - -# ======================================================== -# === debug methods -# ======================================================== - - def infos(self, action) -> None: - """ To get informations about this class - - :param action: A command to run a debug action (see examples). - :type action: string - - :Example: - - Status_json().infos("doctest") - Status_json().infos("doc_methods") - Status_json().infos("internal_attributes") - Status_json().infos("public_methods") - """ - if (action == "doc_methods"): - publics = [x for x in dir(self) if x[0]!="_"] - for public in publics: - varname = "{}".format(public) - if (callable(getattr(self,varname))==True): - print("\n{:=^40}".format(" method "+varname+" ")) - t = "Angle()."+varname+".__doc__" - tt =eval(t) - print(tt) - if (action == "doctest"): - if __name__ == "__main__": - print("\n{:~^40}".format("doctest")) - #doctest.testmod(verbose=True, extraglobs={'objangle': Angle()}) - doctest.testmod(verbose=True) - if (action == "internal_attributes"): - internals = [x for x in dir(self) if x[0]=="_" and x[1]!="_"] - for internal in internals: - varname = "{}".format(internal) - #if (hasattr(self,varname)==True): - if (callable(getattr(self,varname))==False): - print(varname + "=" + str(getattr(self,varname))) - if (action == "public_methods"): - publics = [x for x in dir(self) if x[0]!="_"] - for public in publics: - varname = "{}".format(public) - if (callable(getattr(self,varname))==True): - print(varname) - - -# ======================================================== -# === special methods -# ======================================================== - - def __init__(self, status=""): - """ Object initialization where angle is the input in any format. - - :param angle : An angle in any supported format (cf. help(Angle)) - :type angle : string - - """ - self._init(status) - -# ======================================================== -# ======================================================== -# ======================================================== - -# Examples of execution - -if __name__ == "__main__": - - # --- update the path of Python if necessary - - import report - - # =============================== - # --- Write a very sipmle Json - # =============================== - print("Make a new report") - rep = report.Status_json() - rep.new_status("PLC","20180909") - rep.append_entity("PLC_STATUS", "Raspberry", "20180924A", "MyObservatory") - # --- one device with one value - rep.append_device("DHT22", "meteo", "1", "0") - rep.append_value( "OutsideTemperature", "float","22","degC","Temperature_outside","Temperature","now") - # --- List the UFKIs - ufkis = rep.get_ufkis("","",False) - print(" List of all UFKIs:") - for ufki in ufkis: - print(" UFKI = {}".format(ufki)) - # --- save the Json file - rep.save_json("plc_verysimple.json") - - # =============================== - # --- Write a more complex Json - # =============================== - print("Make a new report") - rep = report.Status_json() - rep.new_status("PLC","20180909") - rep.append_entity("PLC_STATUS", "Raspberry", "20180924A", "Guitalens Observatory") - # --- device Came - rep.append_device("Came", "roof_controler", "124", "0") - rep.append_value( "Error_code", "int","0","","","0=OK 1=PowerPB 2=SwitchPB","now") - rep.append_value( "Power_input", "int","0","","","0=0Volt 1=24Volts","now") - rep.append_value( "Mode_came", "int","0","","","0=Manual 1=Auto","now") - rep.append_value( "Roof_state", "int","0","","","0=Closed 1=Opened 2=Intermediate","now") - # --- device CV7 - rep.append_device("CV7", "weather_station", "RET6789", "0") - rep.append_value( "Error_code", "int","0","","","0=OK 1=SerialPB 2=FramePB","now") - rep.append_value( "Power_input", "int","0","","","0=0Volt 1=12Volts (Power from MiFe board)","now") - rep.append_value( "Wind_dir", "float","0","degrees","Wind_direction","0=North 90=East","now") - rep.append_value( "Wind_speed", "float","0","m/s","Wind_spped","Wind speed from ultrasonic sensors","now") - rep.append_value( "OutsideTemperature", "float","0","degC","Temperature_outside","Temperature of the anemometer","now") - # --- device DHT22 - rep.append_device("DHT22", "weather_station", "123", "0") - rep.append_value( "Error_code", "int","0","","","0=OK 1=CheksumPB 2=LengthPB 3=NodataPB","now") - rep.append_value( "Temperature", "float","21","degC","temperature","Temperature inside PLX box","now") - rep.append_value( "Humidity", "float","77","percent","humidity","Humidity inside PLX box","now") - # --- device RG11 - rep.append_device("RG11", "weather_station", "TY67", "0") - rep.append_value( "Error_code", "int","0","","","0=OK +1=PowerPB +2=NopowerPB +4=AllonePB","now") - rep.append_value( "RainSate", "int","0","","rain","0=Dry 1=Rain 2=Unknown","now") - # --- device MLX90614 - rep.append_device("MLX90614", "weather_station", "1", "0") - rep.append_value( "Error_code", "int","0","","","0=OK 1=DataPB","now") - rep.append_value( "SkyTemperature", "float","-15.67","degC","Temperature_sky","Temperature of the sky","now") - rep.append_value( "CanTemperature", "float","22.47","degC","","Temperature of the TO can","now") - # --- List the UFKIs - ufkis = rep.get_ufkis("","",False) - print(" List of all UFKIs:") - for ufki in ufkis: - print(" UFKI = {}".format(ufki)) - # --- save the Json file - rep.save_json("plc_guitalens.json") - - # =============================== - # --- Read an existing Json - # =============================== - rep = report.Status_json() - path_filename = "plc_verysimple.json" - print("Analysis of the file {}:".format(path_filename)) - rep.load_json(path_filename) - res = rep.get_entities() - print(" entities = {}".format(res)) - res = rep.get_devices() - print(" devices = {}".format(res)) - print(" List of all UFKIs:") - ufkis = rep.get_ufkis("","",True) - for ufki in ufkis: - print(" UFKI = {}".format(ufki)) -- libgit2 0.21.2