Commit 199002a4ee6541f4698ae81f74aea7a13192e374

Authored by aklotz
1 parent f479d1ab
Exists in dev

Premier commit du rearangement des fichiers config.

config/__init__.py renamed to config/old_config/__init__.py
config/appels_wrappers.py renamed to config/old_config/appels_wrappers.py
config/config.yml renamed to config/old_config/config.yml
config/config_base.py renamed to config/old_config/config_base.py
config/config_dev.py renamed to config/old_config/config_dev.py
config/config_prod.py renamed to config/old_config/config_prod.py
config/config_test.py renamed to config/old_config/config_test.py
config/config_unit_simulunit1.xml renamed to config/old_config/config_unit_simulunit1.xml
config/configpyros.py renamed to config/old_config/configpyros.py
config/configpyros_v2.py renamed to config/old_config/configpyros_v2.py
config/minimal_config.txt renamed to config/old_config/minimal_config.txt
config/schema.yaml renamed to config/old_config/schema.yaml
config/socket_config.ini renamed to config/old_config/socket_config.ini
config/test_config_xml1.py renamed to config/old_config/test_config_xml1.py
config/test_yaml.py renamed to config/old_config/test_yaml.py
1   -# -*- coding: utf-8 -*-
2   -
3   -from pykwalify.core import Core
4   -from pykwalify.errors import SchemaError
5   -
6   -"""
7   -Read yaml file :
8   -import yaml
9   -with open("C:/srv/develop/pyros/config/config.yml", 'r') as stream:
10   - try:
11   - a = yaml.safe_load(stream)
12   - print(a)
13   - except yaml.YAMLError as exc:
14   - print(exc)
15   -
16   -# Write YAML file
17   -with open('C:/srv/develop/pyros/config/config2.yml', 'w', encoding='utf8') as outfile:
18   - yaml.dump(a, outfile, default_flow_style=False, allow_unicode=True)
19   -"""
20   -
21   -"""
22   -import yaml
23   -with open("config.yml", 'r') as stream:
24   - try:
25   - a = yaml.safe_load(stream)
26   - print(a)
27   - except yaml.YAMLError as exc:
28   - print(exc)
29   -
30   - """
31   -
32   -def check_and_return_config(yaml_file:str,schema_file:str)->dict:
33   - """
34   - Check if yaml_file is valid for the schema_file
35   -
36   - Args:
37   - yaml_file (str): Path to the config_file to be validated
38   - schema_file (str): Path to the schema file
39   -
40   - Returns:
41   - dict: Dictionnary of the config file (with values)
42   - """
43   - try:
44   -
45   - c = Core(source_file=yaml_file, schema_files=[schema_file])
46   - return c.validate(raise_exception=True)
47   - except SchemaError as error:
48   - #TODO : find a way to retrieve message with path to error
49   - print(error.path)
50   -
51   -
  1 +# -*- coding: utf-8 -*-
  2 +
  3 +from pykwalify.core import Core
  4 +from pykwalify.errors import SchemaError
  5 +
  6 +"""
  7 +Read yaml file :
  8 +import yaml
  9 +with open("C:/srv/develop/pyros/config/config.yml", 'r') as stream:
  10 + try:
  11 + a = yaml.safe_load(stream)
  12 + print(a)
  13 + except yaml.YAMLError as exc:
  14 + print(exc)
  15 +
  16 +# Write YAML file
  17 +with open('C:/srv/develop/pyros/config/config2.yml', 'w', encoding='utf8') as outfile:
  18 + yaml.dump(a, outfile, default_flow_style=False, allow_unicode=True)
  19 +"""
  20 +
  21 +"""
  22 +import yaml
  23 +with open("config.yml", 'r') as stream:
  24 + try:
  25 + a = yaml.safe_load(stream)
  26 + print(a)
  27 + except yaml.YAMLError as exc:
  28 + print(exc)
  29 +
  30 + """
  31 +
  32 +def check_and_return_config(yaml_file:str,schema_file:str)->dict:
  33 + """
  34 + Check if yaml_file is valid for the schema_file
  35 +
  36 + Args:
  37 + yaml_file (str): Path to the config_file to be validated
  38 + schema_file (str): Path to the schema file
  39 +
  40 + Returns:
  41 + dict: Dictionnary of the config file (with values)
  42 + """
  43 + try:
  44 +
  45 + c = Core(source_file=yaml_file, schema_files=[schema_file])
  46 + return c.validate(raise_exception=True)
  47 + except SchemaError as error:
  48 + #TODO : find a way to retrieve message with path to error
  49 + print(error.path)
  50 +
  51 +
52 52 print(check_and_return_config("config.yml","schema.yaml"))
53 53 \ No newline at end of file
... ...
privatedev/config/definitions.txt
... ... @@ -86,3 +86,84 @@ Appels depuis un agent PyROS
86 86 res = config.get_agent(channel = "OpticalChannel-up", component = "DetectorSensor")
87 87 res should be 'camera_up'
88 88  
  89 +================================================================================================================================
  90 +
  91 +==========================
  92 +schema_observaotry-2.0.yml
  93 +--------------------------
  94 +
  95 +schema;schema_DATABASE:
  96 +schema;schema_AGENT_DEVICE:
  97 +schema;schema_AGENT:
  98 +schema;schema_GROUP:
  99 +schema;schema_CHANNEL_GROUPS:
  100 + GROUPS:
  101 + type: seq
  102 + sequence:
  103 + - include: schema_GROUP
  104 +schema;schema_MOUNT:
  105 +
  106 +schema;schema_CHANNEL:
  107 +
  108 +schema;schema_SECURITY:
  109 +
  110 +schema;schema_TOPOLOGY:
  111 + SECURITY:
  112 + include: schema_SECURITY
  113 + MOUNT:
  114 + include: schema_MOUNT
  115 + CHANNELS:
  116 + include: schema_CHANNELS
  117 + CHANNEL_GROUPS:
  118 + include: schema_CHANNEL_GROUPS
  119 +
  120 +schema;schema_COMPUTER:
  121 +
  122 +schema;schema_AGENTS:
  123 + AGENT_DEVICE:
  124 + include: schema_AGENT_DEVICE
  125 + AGENT:
  126 + include: schema_AGENT
  127 +
  128 +schema;schema_COMPUTERS:
  129 + COMPUTER:
  130 + include: schema_COMPUTER
  131 +
  132 +schema;schema_UNIT:
  133 + DATABASE:
  134 + include: schema_DATABASE
  135 + AGENTS:
  136 + include: schema_AGENTS
  137 + TOPOLOGY:
  138 + include: schema_TOPOLOGY
  139 +
  140 +
  141 +schema;schema_UNITS:
  142 + UNIT:
  143 + include: schema_UNIT
  144 +
  145 +
  146 +
  147 +schema;schema_CHANNELS:
  148 + CHANNEL:
  149 + include: schema_CHANNEL
  150 +
  151 +
  152 +
  153 +schema;schema_DEVICE:
  154 +
  155 +schema;schema_DEVICES:
  156 + DEVICE:
  157 + include: schema_DEVICE
  158 +
  159 +
  160 +schema;schema_OBSERVATORY:
  161 + DEVICES:
  162 + include: schema_DEVICES
  163 + COMPUTERS:
  164 + include: schema_COMPUTERS
  165 + UNITS:
  166 + include: schema_UNITS
  167 +
  168 + OBSERVATORY:
  169 + include: schema_OBSERVATORY
... ...
privatedev/config/device_Raspberry_MiFe_sn004.yml
... ... @@ -13,9 +13,14 @@ DEVICE:
13 13 _voltage: 220
14 14 _intensity: 1
15 15 _socket: "CEE 7/7 2P+T"
16   -
  16 +
  17 + _hostname: ""
  18 + _virtual_machine: False
17 19 _os: Linux
18 20 _os_version: Raspbian
  21 + _network_interfaces:
  22 + - B8:27:EB:8B:99:BE # RJ45
  23 + - b8:27:eb:de:cc:eb # Wifi
19 24 _protocol:
20 25 _transport: TCP
21 26 _langage: Json
... ...
privatedev/config/device_SkyWatcher_L80_snxx1.yml
... ... @@ -22,14 +22,19 @@ DEVICE:
22 22  
23 23 - CAPABILITY:
24 24 component: OpticImager
25   - # Total tranmission
26   - _transmissions:
27   - # m
28   - _wavelengths: [379e-9, 380e-9, 1100e-9, 1101e-9]
29   - _transmission: [0.0, 0.9, 0.9, 0.0]
30   - # Equivalent focal length (m)
31   - _foclen: 0.503
32   - # Equivalent apperture diameter (m)
33   - _appdiam: 0.08
34   - # mean sigma value of a Gaussian model of the psf (m)
35   - _psf_sigma: 10.0e-6
  25 +
  26 + attributes:
  27 +
  28 + - attribute:
  29 + key: _foclen
  30 + value: 0.503
  31 +
  32 + - attribute:
  33 + key: _transmissions
  34 + value:
  35 + _wavelengths: [379e-9, 380e-9, 1100e-9, 1101e-9]
  36 + _transmission: [0.0, 0.9, 0.9, 0.0]
  37 +
  38 + - attribute:
  39 + key: _appdiam
  40 + value: 0.08
... ...
privatedev/config/device_ZWO_ASI1600MM_snxx1.yml
... ... @@ -22,35 +22,90 @@ DEVICE:
22 22  
23 23 - CAPABILITY:
24 24 component: DetectorSensor
25   - _manufacturer: Panasonic
26   - _model: MN34230
27   - _type: CMOS # Enum: CCD, CMOS
28   - _celldimx: 3.8e-6 # (m)
29   - _celldimy: 3.8e-6 # (m)
30   - _cellnbx: 4656
31   - _cellnby: 3520
32   - _color: None # Enum: None, bayerCFA
33   - _dqe_wavelengths: [379e-9, 380e-9, 1100e-9, 1101e-9] # (m)
34   - _dqe_response: [0.0, 0.6, 0.6, 0.0] # (electron/photon)
35   - _exposuretime:
36   - _exposuretimes: []
37   - _liminf : 0.001
38   - _limsup : 600
39   - _binnings:
40   - _binxy: [ [1,1], [2,2], [3,3], [4,4] ] # form
41   - _readouttime: [ 6, 4, 3, 1 ]
42   - _electronic:
43   - _gain_manufacturer: [0, 1, 20]
44   - _gain_eadu: [1.0, 2.0, 5.0] # form
45   - _readout_noise: [2.0, 2.0, 2.0]
46   - _readout_signal: [250, 250, 250]
47   - _saturation_level: [65535, 65535, 65535]
  25 +
  26 + attributes:
  27 +
  28 + - attribute:
  29 + key: manufacturer
  30 + value: Panasonic
  31 +
  32 + - attribute:
  33 + key: _model
  34 + value: MN34230
  35 +
  36 + - attribute:
  37 + key: _type
  38 + value: CMOS
  39 +
  40 + - attribute:
  41 + key: _exposuretime
  42 + value: 1.0
  43 + liminf: 0.001
  44 + limsup: 600
  45 + is_editable: True
  46 +
  47 + - attribute:
  48 + key: binnings
  49 + value:
  50 + _binxy: [ [1,1], [2,2], [3,3], [4,4] ] # form
  51 + _readouttime: [ 6, 4, 3, 1 ]
  52 + is_editable: True
  53 +
  54 + - attribute:
  55 + key: _celldimx
  56 + value: 3.8e-6
  57 + - attribute:
  58 + key: _celldimy
  59 + value: 3.8e-6
  60 +
  61 + - attribute:
  62 + key: _cellnbx
  63 + value: 4656
  64 + - attribute:
  65 + key: _cellnby
  66 + value: 3520
  67 +
  68 + - attribute:
  69 + key: _color
  70 + value: None
  71 +
  72 + - attribute:
  73 + key: _qdes
  74 + value:
  75 + _wavelengths: [379e-9, 380e-9, 1100e-9, 1101e-9]
  76 + _qde: [0.0, 0.9, 0.9, 0.0]
  77 +
  78 + - attribute:
  79 + key: _cellnbx
  80 + value: 4656
  81 +
  82 + - attribute:
  83 + key: electronic
  84 + value:
  85 + _gain_manufacturer: [0, 1, 20]
  86 + _gain_eadu: [1.0, 2.0, 5.0] # form
  87 + _readout_noise: [2.0, 2.0, 2.0]
  88 + _readout_signal: [250, 250, 250]
  89 + _saturation_level: [65535, 65535, 65535]
48 90  
49 91 - CAPABILITY:
50 92 component: DetectorShutter
51   - _manufacturer: None
52   - _model: None
53   - _types: ['rolling'] # list of Enum: none, mechanical, rolling
54   - _modes: ['opened'] # list of Enum: closed, opened, synchro
55   - _delayopening: 0 # (s)
56   - _delayclosing: 0 # (s)
  93 +
  94 + attributes:
  95 +
  96 + - attribute:
  97 + key: manufacturer
  98 + value: None
  99 +
  100 + - attribute:
  101 + key: _model
  102 + value: None
  103 +
  104 + - attribute:
  105 + key: _type
  106 + value: ['rolling']
  107 +
  108 + - attribute:
  109 + key: _modes
  110 + value: ["opened"]
  111 + is_editable: False
... ...
privatedev/config/observatory_guitalens.yml
... ... @@ -29,9 +29,21 @@ OBSERVATORY:
29 29 _file: device_SkyWatcher_L80_snxx1.yml
30 30  
31 31 - DEVICE:
  32 + _name: Celestron-C11
  33 + _file: device_Celestron_C11_sn974234.yml
  34 +
  35 + - DEVICE:
32 36 _name: ZWO-ASI1600MMPro
33 37 _file: device_ZWO_ASI1600MM_snxx1.yml
34 38  
  39 + - DEVICE:
  40 + _name: FLI-Kepler4040
  41 + _file: device_FLI_Kepler4040_sn2821221.yml
  42 +
  43 + - DEVICE:
  44 + _name: FLI-KeplerGPS
  45 + _file: device_FLI_KITS_sn0x1.yml
  46 +
35 47 # === Inventory of available computers
36 48 # A computer is a hardware of a virtual machine.
37 49 # As a computer can be shared with various units, it is defined at the observatory level.
... ... @@ -79,13 +91,13 @@ OBSERVATORY:
79 91 _computer: None
80 92 _name: optic_up
81 93 _path: ~
82   - _device: SkyWatcher-refractor
  94 + _device: Celestron-C11
83 95  
84 96 - AGENT_DEVICE:
85 97 _computer: MainComputer
86 98 _name: camera_up
87 99 _path: private/plugin/agent_devices
88   - _device: ZWO-ASI1600MMPro
  100 + _device: FLI-Kepler4040
89 101 _protocol: private/plugin/agent_devices/camera_protocol.py
90 102  
91 103 - AGENT:
... ... @@ -114,6 +126,7 @@ OBSERVATORY:
114 126 - OpticImager: optic_up
115 127 - DetectorSensor: camera_up
116 128 - DetectorShutter: camera_up
  129 + - DetectorTimer: camera_up
117 130  
118 131 CHANNEL_GROUPS:
119 132  
... ...
privatedev/config/schema_device-2.0.yml
1   -schema;schema_capability:
  1 +schema;schema_component_attributes:
2 2 type: map
3 3 required: True
4 4 mapping:
5   - component:
  5 + key:
6 6 type: str
7 7 required: True
8   - _type_cover:
9   - type: str
10   - enum: ["None","RollingRoof",ClamShell","Dome"]
11   - _manufacturer:
12   - type: str
13   - _model:
14   - type: str
15   - _orientation_type:
16   - type: str
17   - _velocity_profile:
18   - type: str
19   - _home:
20   - type: str
21   - _connect_real_mount:
  8 + # is_* are False by default
  9 + is_editable:
22 10 type: bool
23   - _transmissions:
24   - type: map
25   - mapping:
26   - _wavelengths:
27   - type: seq
28   - sequence:
29   - # scientific notation isn't supported by the library
30   - - type: any
31   - _transmission:
32   - type: seq
33   - sequence:
34   - - type: float
35   - _appdiam:
36   - type: float
37   - _foclen:
38   - type: float
39   - _psf_sigma:
40   - type: any
41   - _type:
42   - type: str
43   - enum: ["CCD","CMOS"]
44   - _celldimx:
45   - type: any
46   - _celldimy:
  11 + is_container:
  12 + type: bool
  13 + is_enum:
  14 + type: bool
  15 + value:
47 16 type: any
48   - _cellnbx:
  17 + required: True
  18 + liminf:
  19 + type: number
  20 + limsup:
  21 + type: number
  22 + label:
49 23 type: any
50   - _cellnby:
  24 + unit:
51 25 type: any
52   - _color:
  26 +
  27 +schema;schema_capability:
  28 + type: map
  29 + required: True
  30 + mapping:
  31 + component:
53 32 type: str
54   - enum: ["None","bayerCFA"]
55   - _dqe_wavelengths:
56   - type: seq
57   - sequence:
58   - - type: any
59   - _dqe_response:
60   - type: seq
61   - sequence:
62   - - type: float
63   - _exposuretime:
64   - type: map
65   - mapping:
66   - _exposuretimes:
67   - type: seq
68   - sequence:
69   - - type: any
70   - _liminf :
71   - type: float
72   - _limsup :
73   - type: float
74   - _binnings:
75   - type: map
76   - mapping:
77   - _binxy:
78   - type: seq
79   - sequence:
80   - - type: seq
81   - sequence:
82   - - type: int
83   - _readouttime:
84   - type: seq
85   - sequence:
86   - - type: int
87   - _electronic:
88   - type: map
89   - mapping:
90   - _gain_manufacturer:
91   - type: seq
92   - sequence:
93   - - type: int
94   - _gain_eadu:
95   - type: seq
96   - sequence:
97   - - type: float
98   - _readout_noise:
99   - type: seq
100   - sequence:
101   - - type: float
102   - _readout_signal:
103   - type: seq
104   - sequence:
105   - - type: int
106   - _saturation_level:
107   - type: seq
108   - sequence:
109   - - type: int
110   - _types:
111   - type: seq
112   - sequence:
113   - - type: str
114   - enum: ["None","mechanical","rolling"]
115   - _modes:
  33 + required: True
  34 + attributes:
116 35 type: seq
117   - sequence:
118   - - type: str
119   - enum: ["closed","opened","synchro"]
120   - _delayopening:
121   - type: int
122   - _delayclosing:
123   - type: int
  36 + required: False # True if we're not using default values
  37 + seq:
  38 + - include : schema_component_attributes
124 39  
  40 +# old version
  41 +# schema;schema_capability:
  42 +# type: map
  43 +# required: True
  44 +# mapping:
  45 +
125 46 schema;schema_capabilities:
126 47 type: seq
127 48 sequence:
... ...
src/core/pyros_django/obsconfig/configpyros_v2.py 0 โ†’ 100644
... ... @@ -0,0 +1,415 @@
  1 +import pykwalify.core
  2 +import yaml,sys,logging,os
  3 +from pykwalify.errors import PyKwalifyException,SchemaError
  4 +
  5 +class ConfigPyrosV2:
  6 + # (AKo) : Config file path is checked on the settings file, if the file isn't valid (i.e not found) the error will be launched by the settings file when starting the application
  7 +
  8 + def check_and_return_config(self,yaml_file:str,schema_file:str)->dict:
  9 + """
  10 + Check if yaml_file is valid for the schema_file and return an dictionary of the config file
  11 +
  12 + Args:
  13 + yaml_file (str): Path to the config_file to be validated
  14 + schema_file (str): Path to the schema file
  15 +
  16 + Returns:
  17 + dict: dictionary of the config file (with values)
  18 + """
  19 + # disable pykwalify error to clean the output
  20 + logging.disable(logging.ERROR)
  21 + try:
  22 + c = pykwalify.core.Core(source_file=yaml_file, schema_files=[schema_file])
  23 + return c.validate(raise_exception=True)
  24 + except SchemaError:
  25 + for error in c.errors:
  26 + print("Error :",str(error).split(". Path")[0])
  27 + print("Path to error :",error.path)
  28 + return None
  29 +
  30 + def read_and_check_config_file(self,yaml_file:str)->dict:
  31 + """
  32 + Read the schema key of the config file to retrieve schema name and proceed to the checking of that config file
  33 + Call check_and_return_config function and print its return.
  34 +
  35 + Args:
  36 + yaml_file (str): path to the config file
  37 + Returns:
  38 + dict: Dictionary of the config file (with values)
  39 + """
  40 + try:
  41 + with open(yaml_file, 'r') as stream:
  42 + config_file = yaml.safe_load(stream)
  43 +
  44 + self.CONFIG_PATH = yaml_file.split("config/")[0]+"config/"
  45 +
  46 + result = self.check_and_return_config(yaml_file,self.CONFIG_PATH+config_file["schema"])
  47 + if result is None:
  48 + print("Error when reading and validating config file, please check the errors right above")
  49 + return result
  50 + except yaml.YAMLError as exc:
  51 + print(exc)
  52 + except:
  53 + return None
  54 +
  55 + def __init__(self,config_file_name:str) -> None:
  56 + """
  57 + Initiate class with the config file
  58 + set content attribute to a dictionary containing all values from the config file
  59 +
  60 + Args:
  61 + config_file_name (str): path to the config file
  62 + """
  63 + obs_config = self.read_and_check_config_file(config_file_name)
  64 + if obs_config is None:
  65 + print(f"Error when trying to read config file (path of config file : {config_file_name}")
  66 +
  67 + self.content = obs_config
  68 +
  69 +
  70 + def get_obs_name(self)->str:
  71 + """
  72 + Return name of the observatory
  73 +
  74 + Returns:
  75 + str: Name of the observatory
  76 + """
  77 + return self.content["OBSERVATORY"]["_name"]
  78 +
  79 + def get_channels(self,unit)->dict:
  80 + """
  81 + return dictionary of channels
  82 +
  83 + Returns:
  84 + dict: [description]
  85 + """
  86 + channels = {}
  87 +
  88 + for channel_id in range(len(unit["TOPOLOGY"]["CHANNELS"])):
  89 + channel = unit["TOPOLOGY"]["CHANNELS"][channel_id]["CHANNEL"]
  90 + channels[channel["_name"]] = channel
  91 + return channels
  92 +
  93 + def get_computers(self)->dict:
  94 + """
  95 + return dictionary of computers
  96 +
  97 + Returns:
  98 + dict: [description]
  99 + """
  100 + computers = {}
  101 + for computer_id in range(len(self.content["OBSERVATORY"]["COMPUTERS"])):
  102 + computer = self.content["OBSERVATORY"]["COMPUTERS"][computer_id]["COMPUTER"]
  103 + if( "_file" in computer.keys() ):
  104 + computer["computer_config"]= self.read_and_check_config_file(self.CONFIG_PATH+computer["_file"])["COMPUTER"]
  105 + computers[computer["_name"]] = computer
  106 + return computers
  107 +
  108 + def get_devices(self)->dict:
  109 + """
  110 + return dictionary of devices
  111 +
  112 + Returns:
  113 + dict: [description]
  114 + """
  115 + devices = {}
  116 + for device_id in range(len(self.content["OBSERVATORY"]["DEVICES"])):
  117 + device = self.content["OBSERVATORY"]["DEVICES"][device_id]["DEVICE"]
  118 + if( "_file" in device.keys() ):
  119 + device["device_config"] = self.read_and_check_config_file(self.CONFIG_PATH+device["_file"])["DEVICE"]
  120 + devices[device["_name"]] = device
  121 + return devices
  122 +
  123 + def get_agents(self,unit)->dict:
  124 + """
  125 + return dictionary of agents
  126 +
  127 + Returns:
  128 + dict: dictionary of agents. For each agents tell the name, computer, device, protocole, etc...
  129 + """
  130 + agents = {}
  131 +
  132 +
  133 + for agent_id in range(len(unit["AGENTS"])):
  134 + # Agents is a list containing dictionary that have only one key
  135 + key = list(unit["AGENTS"][agent_id].keys())[0]
  136 + agent = unit["AGENTS"][agent_id][key]
  137 + agents[agent["_name"]] = agent
  138 + return agents
  139 +
  140 + def get_channel_groups(self,unit:dict)->dict:
  141 + """
  142 + Return dictionary of channel groups, tell the logic between groups of channels and within a group of channels
  143 +
  144 + Args:
  145 + unit (dict): dictonary contaning all values of a unit
  146 + Returns:
  147 + dict: dictionary of channel groups (tell the logic and groups of channels)
  148 + """
  149 + info = {}
  150 + info["global_groups_logic"] = unit["TOPOLOGY"]["CHANNEL_GROUPS"]["_logic"]
  151 + info["groups"] = {}
  152 + for group_id in range(len(unit["TOPOLOGY"]["CHANNEL_GROUPS"]["GROUPS"])):
  153 + group = unit["TOPOLOGY"]["CHANNEL_GROUPS"]["GROUPS"][group_id]["GROUP"]
  154 + info["groups"][group_id] = group
  155 + return info
  156 +
  157 + def get_channel_information(self,unit:dict,channel_name:str)->dict:
  158 + """
  159 + Return information of the given channel name of a unit
  160 +
  161 + Args:
  162 + unit (dict): dictionary representing the unit
  163 + channel_name (str): name of the channel
  164 +
  165 + Returns:
  166 + dict: dictionary containing all values that define this channel
  167 + """
  168 + channels = self.get_channels(unit)
  169 + return channels[channel_name]
  170 +
  171 + def get_topology(self,unit:dict)->dict:
  172 + """
  173 + Return dictionary of the topology of the observatory
  174 +
  175 + Args:
  176 + unit (dict): dictionary representing the unit
  177 + Returns:
  178 + dict: dictionary representing the topology of an unit (security, mount, channels, channel_groups)
  179 + """
  180 + topology = {}
  181 + for key in unit["TOPOLOGY"].keys():
  182 + branch = unit["TOPOLOGY"][key]
  183 + if key == "CHANNELS":
  184 + topology[key] = self.get_channels(unit)
  185 + elif key == "CHANNEL_GROUPS":
  186 + topology[key] = self.get_channel_groups(unit)
  187 + else:
  188 + topology[key] = branch
  189 + return topology
  190 +
  191 + def get_active_agents(self,unit:dict)->list:
  192 + """
  193 + Return the list of active agents (i.e. agents that have an association with a device)
  194 +
  195 + Args:
  196 + unit (dict): dictionary representing the unit
  197 +
  198 + Returns:
  199 + list: kist of the name of active agents
  200 + """
  201 + return list(self.get_agents(unit).keys())
  202 +
  203 + def get_units(self)->dict:
  204 + """
  205 + Return all units sort by name defined in the config file
  206 +
  207 + Returns:
  208 + dict: dictionary giving for a unit_name, his content (name,database,topology,agents,...)
  209 + """
  210 + result = {}
  211 + units = self.content["OBSERVATORY"]["UNITS"]
  212 + for unit in units:
  213 + unit = unit["UNIT"]
  214 + result[unit["_name"]] = unit
  215 + return result
  216 +
  217 + def get_components_agents(self,unit:dict)->dict:
  218 + """
  219 + Return dictionary of component_agents of the given unit
  220 +
  221 + Args:
  222 + unit (dict): dictionary representing the unit
  223 +
  224 + Returns:
  225 + dict: dictionary sort by component name giving the associated agent (agent name)
  226 + """
  227 + components_agents = {}
  228 + topology = self.get_topology(unit)
  229 + for element in topology:
  230 + if element in ("SECURITY","MOUNT","CHANNELS"):
  231 + if(element != "CHANNELS"):
  232 + for component_agent in topology[element]["COMPONENT_AGENTS"]:
  233 + component_name = list(component_agent.keys())[0]
  234 + components_agents[component_name] = component_agent[component_name]
  235 + else:
  236 + for channel in topology[element]:
  237 + for component_agent in topology[element][channel]["COMPONENT_AGENTS"]:
  238 + component_name = list(component_agent.keys())[0]
  239 + components_agents[component_name] = component_agent[component_name]
  240 + return components_agents
  241 +
  242 + def get_units_name(self)->list:
  243 + """
  244 + Return list of units names
  245 +
  246 + Returns:
  247 + [list]: names of units
  248 + """
  249 + return list(self.get_units().keys())
  250 +
  251 + def get_unit_by_name(self,name:str)->dict:
  252 + """
  253 + Return dictionary containing definition of the unit that match the given name
  254 +
  255 + Args:
  256 + name (str): name of the unit
  257 +
  258 + Returns:
  259 + dict: dictonary representing the unit
  260 + """
  261 + return self.get_units()[name]
  262 +
  263 + def get_agents_per_computer(self,unit:dict)->dict:
  264 + """
  265 + Return dictionary that give for each computer, what are the associated agents to it as a list
  266 +
  267 + Args:
  268 + unit (dict): dictonary representing the unit
  269 +
  270 + Returns:
  271 + dict: dictionary that give for each computer, what are the associated agents to it as a list
  272 +
  273 + """
  274 + agents_per_computer = {}
  275 + agents = self.get_agents(unit)
  276 + for agent in agents:
  277 + computer_name = agents[agent]["_computer"]
  278 + if(agents[agent]["_computer"] not in agents_per_computer.keys()):
  279 + agents_per_computer[computer_name] = [agent]
  280 + else:
  281 + agents_per_computer[computer_name].append(agent)
  282 + return agents_per_computer
  283 +
  284 +
  285 + def get_agents_per_device(self,unit:dict)->dict:
  286 + """
  287 + Return dictionary that give for each device, what are the associated agents to it as a list
  288 +
  289 + Args:
  290 + unit (dict): dictonary representing the unit
  291 +
  292 + Returns:
  293 + dict: dictionary that give for each device, what are the associated agents to it as a list
  294 +
  295 + """
  296 + agents_per_device = {}
  297 + agents = self.get_agents(unit)
  298 + for agent in agents:
  299 + if("_device" in agents[agent].keys()):
  300 + device_name = agents[agent]["_device"]
  301 + if(agents[agent]["_device"] not in agents_per_device.keys()):
  302 + agents_per_device[device_name] = [agent]
  303 + else:
  304 + agents_per_device[device_name].append(agent)
  305 + return agents_per_device
  306 +
  307 + def get_active_devices(self)->list:
  308 + """
  309 + Return a list of active device names
  310 +
  311 + Returns:
  312 + list: list of active device names
  313 + """
  314 + active_devices = []
  315 + for unit_name in self.get_units():
  316 + unit = self.get_unit_by_name(unit_name)
  317 + for device in self.get_agents_per_device(unit):
  318 + active_devices.append(device)
  319 + return active_devices
  320 +
  321 + def get_active_computers(self)->list:
  322 + """
  323 + Return a list of active computer names
  324 +
  325 + Returns:
  326 + list: list of active computer names
  327 + """
  328 + active_computers = []
  329 + for unit_name in self.get_units():
  330 + unit = self.get_unit_by_name(unit_name)
  331 + for computer in self.get_agents_per_computer(unit):
  332 + active_computers.append(computer)
  333 + return active_computers
  334 +
  335 + def get_agent_information(self,unit:dict,agent_name:str)->dict:
  336 + """
  337 + Give the dictionary of attributes of the agent for an unit.
  338 +
  339 + Args:
  340 + unit (dict): dictonary representing the unit
  341 + agent_name (str): agent name
  342 +
  343 + Returns:
  344 + dict: dictionary containing attributes of the agent
  345 + """
  346 + return self.get_agents(unit)[agent_name]
  347 +
  348 + def get_device_information(self,device_name:str)->dict:
  349 + """
  350 + Give the dictionary of the attributes of the device
  351 +
  352 + Args:
  353 + device_name (str): device name
  354 +
  355 + Returns:
  356 + dict: dictionary containing attributes of the device
  357 + """
  358 + return self.get_devices()[device_name]
  359 +
  360 + def get_database_for_unit(self,unit_name:str)->dict:
  361 + """
  362 + Return dictionary of attributes of the database for an unit
  363 +
  364 + Args:
  365 + unit_name (str): unit name
  366 +
  367 + Returns:
  368 + dict: dictionary of attributes of the database for an unit
  369 + """
  370 + return self.get_unit_by_name(unit_name)["DATABASE"]
  371 +
  372 + def get_device_for_agent(self,unit:dict,agent_name:str)->str:
  373 + """
  374 + Return device name associated to the agent
  375 +
  376 + Args:
  377 + unit (dict): dictonary representing the unit
  378 + agent_name (str): agent name
  379 +
  380 + Returns:
  381 + str: device name associated to this agent
  382 + """
  383 + agents_per_device = self.get_agents_per_device(unit)
  384 + for device in agents_per_device:
  385 + if agent_name in agents_per_device[device]:
  386 + return self.get_device_information(device)
  387 + def get_unit_of_computer(self,computer_name:str)->str:
  388 + """
  389 + Return the name of the unit where the computer is used
  390 +
  391 + Args:
  392 + computer_name (str): computer name
  393 +
  394 + Returns:
  395 + str: unit name
  396 + """
  397 + for unit_name in self.get_units():
  398 + unit = self.get_unit_by_name(unit_name)
  399 + if(computer_name in self.get_agents_per_computer(unit)):
  400 + return unit_name
  401 +
  402 + def get_unit_of_device(self,device_name:str)->str:
  403 + """
  404 + Return the name of the unit where the device is used
  405 +
  406 + Args:
  407 + device_name (str): device name
  408 +
  409 + Returns:
  410 + str: unit name
  411 + """
  412 + for unit_name in self.get_units():
  413 + unit = self.get_unit_by_name(unit_name)
  414 + if(device_name in self.get_agents_per_device(unit)):
  415 + return unit_name
... ...