Skip to content

Commit

Permalink
Fixes and features
Browse files Browse the repository at this point in the history
  • Loading branch information
gnthibault committed Aug 11, 2023
1 parent 416d8c0 commit 5e9e405
Show file tree
Hide file tree
Showing 21 changed files with 276 additions and 172 deletions.
38 changes: 32 additions & 6 deletions Manager/Manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ def __init__(self, *args, **kwargs):
"""
Base.__init__(self)

self.is_initialized = False
self.independant_services = None
self.is_initialized = False
self.serv_time = None
self.serv_weather = None
self.vizualization_service = None
self.webmanager_client = None

##########################################################################
# Properties
##########################################################################
Expand Down Expand Up @@ -95,6 +101,9 @@ def initialize(self):
self.logger.info('\tSetting up main image directory')
self._setup_image_directory()

# Reset indi webmanager client
self._setup_indi_web_manager_client()

# setup various services
self.logger.info('\tSetting up web services')
self._setup_services()
Expand Down Expand Up @@ -128,9 +137,9 @@ def initialize(self):
self._setup_scheduler()

# Setup vizualization service
self.logger.info('\tSetting up vizualization service')
self._setup_vizualization_service()
self.logger.info('\t Observatory initialized')
# self.logger.info('\tSetting up vizualization service')
# self._setup_vizualization_service()
# self.logger.info('\t Observatory initialized')
self.is_initialized = True
# self.logger.debug("Initializing mount")
# self.mount.initialize()
Expand Down Expand Up @@ -531,9 +540,23 @@ def close_observatory(self):

def unpark(self):
try:

# Reset indi server
#TODO TN This needs to be setup properly with splitted webmanager clients
if self.serv_weather is not None:
self.logger.debug("Waiting for weather server to stop")
self.serv_weather.stop()
if self.vizualization_service is not None:
self.logger.debug("Waiting for vizualization server to stop")
self.vizualization_service.stop()

for _, indi_client in IndiClient._instances.items():
#indi_client.stop() # This is working properly in debug but not in normal runtime
del indi_client
IndiClient._instances = {}

self.observatory.reset_config()
self.webmanager_client.reset_server()
self._setup_weather_service()

# unpark the observatory
self.observatory.power_on_all_equipments()
Expand All @@ -551,6 +574,9 @@ def unpark(self):
self.guider.launch_server()
self.guider.connect_server()
# self.guider.connect_profile()

self._setup_weather_service()
self._setup_vizualization_service()
return True
except Exception as e:
self.logger.error(f"Problem unparking: {e}")
Expand Down Expand Up @@ -591,7 +617,7 @@ def _setup_services(self):
setup various services that are supposed to provide infos/data
"""
try:
self._setup_indi_web_manager_client()
# TODO TN, I need to properly split observatory related webmanager and services related
self._setup_time_service()
self._setup_weather_service()
self._setup_messaging()
Expand Down
2 changes: 1 addition & 1 deletion Mount/IndiG11.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,4 @@ def set_park_settings(self, mode='HOME'):
def set_coord(self, coord):
IndiMount.set_coord(self, coord)
# Wait for the mount/tube to damper vibrations
time.sleep(2)
time.sleep(5)
45 changes: 24 additions & 21 deletions ObservationPlanner/ObservationPlanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Astropy stuff
from astropy.coordinates import get_moon
from astropy.coordinates import get_sun
from astropy import units as AU
from astropy import units as u
from astropy.coordinates import AltAz
from astropy.coordinates import EarthLocation
from astropy.coordinates import SkyCoord
Expand All @@ -23,8 +23,9 @@
from astroplan import ObservingBlock
from astroplan.constraints import AtNightConstraint
from astroplan.constraints import AirmassConstraint
from astroplan.constraints import TimeConstraint
from astroplan.constraints import AltitudeConstraint
from astroplan.constraints import MoonSeparationConstraint
from astroplan.constraints import TimeConstraint
from astroplan.plots import plot_sky
from astroplan.scheduling import PriorityScheduler
from astroplan.scheduling import SequentialScheduler
Expand Down Expand Up @@ -121,14 +122,16 @@ def gen_constraints(self):
#
return [AirmassConstraint(max=3, boolean_constraint=True),
AtNightConstraint.twilight_astronomical(),
MoonSeparationConstraint(min=45*AU.deg),
MoonSeparationConstraint(min=45*u.deg),
LocalHorizonConstraint(horizon=self.obs.get_horizon(),
boolean_constraint=True)]
boolean_constraint=True),
AltitudeConstraint(max=self.obs.max_altitude_degree*u.deg,
boolean_constraint=True)]

def gen_obs_blocks(self, constraint):

#TODO TN readout time, get that info from camera
camera_time = 1*AU.second
camera_time = 1*u.second
# Create ObservingBlocks for each filter and target with our time
# constraint, and durations determined by the exposures needed

Expand All @@ -140,15 +143,15 @@ def gen_obs_blocks(self, constraint):
SkyCoord.from_name(target_name,
frame="icrs"),
equinox=Time('J2000')))
#target = FixedTarget(SkyCoord(239*AU.deg, 49*AU.deg))
#target = FixedTarget(SkyCoord(239*u.deg, 49*u.deg))
for filter_name, acq_config in config.items():
# We split big observing blocks into smaller blocks for better
# granularity
(count, temperature, gain, exp_time_sec) = [acq_config[k] for k in ["count", "temperature", "gain", "exp_time_sec"]]
while count > 0:
l_count = max(1, min(count,
self.MaximumSlotDurationSec//exp_time_sec))
exp_time = exp_time_sec*AU.second
exp_time = exp_time_sec*u.second

#TODO TN retrieve priority from the file
priority = 0 if (filter_name=='Luminance') else 1
Expand All @@ -166,9 +169,9 @@ def gen_scheduler(self, constraint):
# Initialize a transitioner object with the slew rate and/or the
# duration of other transitions (e.g. filter changes)
# TODO TN do that from mount or filterwheel info
slew_rate = 1.5*AU.deg/AU.second
slew_rate = 1.5*u.deg/u.second
transitions = Transitioner(slew_rate,
{'filter':{'default': 10*AU.second}})
{'filter':{'default': 10*u.second}})

# Initialize the priority scheduler with constraints and transitioner
return PriorityScheduler(
Expand All @@ -180,9 +183,9 @@ def gen_schedule(self, obs_blocks, scheduler, start_time=None,
duration_hour=None):
""" start_time can either be a precise datetime or a datetime.date """
if duration_hour is None:
duration_hour = self.tmh * 2 * AU.hour
duration_hour = self.tmh * 2 * u.hour
else:
duration_hour = duration_hour * AU.hour
duration_hour = duration_hour * u.hour

if start_time is None or (isinstance(start_time, datetime.date) and not
isinstance(start_time, datetime.datetime)):
Expand All @@ -208,9 +211,9 @@ def showObservationPlan(self, start_time=None, duration_hour=None,
show_airmass=True, afig=None, pfig=None):
""" start_time can either be a precise datetime or a datetime.date """
if duration_hour is None:
duration_hour = self.tmh * 2 * AU.hour
duration_hour = self.tmh * 2 * u.hour
else:
duration_hour = duration_hour * AU.hour
duration_hour = duration_hour * u.hour

if start_time is None or (isinstance(start_time, datetime.date) and not
isinstance(start_time, datetime.datetime)):
Expand All @@ -219,13 +222,13 @@ def showObservationPlan(self, start_time=None, duration_hour=None,
else:
target_date = start_time
midnight = self.ntpServ.get_next_local_midnight_in_utc(target_date)
d_h = float(duration_hour/AU.hour)
d_h = float(duration_hour/u.hour)
start_time = midnight - datetime.timedelta(hours=d_h/2)
else:
target_date = start_time.date()

#Time margin, in hour
tmh_range = int(np.ceil(float(duration_hour/AU.hour)))
tmh_range = int(np.ceil(float(duration_hour/u.hour)))
#tmh_range = np.arange(tmh_range, dtype=float) - tmh_range//2
date_font_size = 8
resolution = 400
Expand All @@ -239,7 +242,7 @@ def showObservationPlan(self, start_time=None, duration_hour=None,
#Astropy ranges (everything in UTC)
start_time = Time(start_time)
relative_time_frame = np.linspace(0, tmh_range,
resolution) * AU.hour
resolution) * u.hour
absolute_time_frame = start_time + relative_time_frame
altaz_frame = AltAz(obstime=absolute_time_frame,
location=self.obs.getAstropyEarthLocation())
Expand Down Expand Up @@ -273,18 +276,18 @@ def showObservationPlan(self, start_time=None, duration_hour=None,
color='silver', label=moon_label)

#grey sky when sun lower than -0 deg
grey_sun_range = sun_altazs.alt < -0*AU.deg
grey_sun_range = sun_altazs.alt < -0*u.deg
self.alt_ax.fill_between(matplotlib.dates.date2num(
absolute_time_frame.to_datetime()), 0, 90,
grey_sun_range, color='0.5', zorder=0)
#Dark sky when sun is below -18 deg
dark_sun_range = sun_altazs.alt < -18*AU.deg
dark_sun_range = sun_altazs.alt < -18*u.deg
self.alt_ax.fill_between(matplotlib.dates.date2num(
absolute_time_frame.to_datetime()), 0, 90,
dark_sun_range, color='0', zorder=0)
#grey sky when sun is low (<18deg) but moon has risen
grey_moon_range = np.logical_and(moon_altazs.alt > -5*AU.deg,
sun_altazs.alt < -18*AU.deg)
grey_moon_range = np.logical_and(moon_altazs.alt > -5*u.deg,
sun_altazs.alt < -18*u.deg)
grey_moon_intensity = 0.0025*moon_ill_perc #hence 0.25 for 100%
self.alt_ax.fill_between(matplotlib.dates.date2num(
absolute_time_frame.to_datetime()), 0, 90,
Expand Down Expand Up @@ -360,7 +363,7 @@ def showObservationPlan(self, start_time=None, duration_hour=None,
for (target_name, imaging_program), color in zip(
self.targetList.items(), colors):
target_coord = SkyCoord(SkyCoord.from_name(target_name, frame="icrs"), equinox=Time('J2000'))
#target_coord = SkyCoord(239*AU.deg, 49*AU.deg)
#target_coord = SkyCoord(239*u.deg, 49*u.deg)

# Compute altazs for target
target_altazs = target_coord.transform_to(altaz_frame)
Expand Down
35 changes: 26 additions & 9 deletions Observatory/AggregatedCustomScopeController.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def initialize(self):
self.initialize_adjustable_power_source()
self.initialize_all_dew_outputs()
self.set_auto_dew_aggressivity()
time.sleep(1) # this is a very specific case, see https://github.com/indilib/indi-3rdparty/issues/822
self.initialize_all_usb()
self.initialize_usb_hub()

Expand Down Expand Up @@ -300,6 +301,7 @@ def power_on_arduino_control_box(self):
# 5V adjustable power source
self.set_number('ADJUSTABLE_VOLTAGE', {'ADJUSTABLE_VOLTAGE_VALUE': self.adjustable_voltage_value})

def switch_on_arduino_control_box_usb(self):
# Now setup USB
on_switches = [f"PORT_{i}" for i in range(1, 7) if self.usb_labels[f"USB_LABEL_{i}"] == "ARDUINO_CONTROL_BOX"]
self.set_switch("USB_PORT_CONTROL", on_switches=on_switches)
Expand Down Expand Up @@ -585,40 +587,55 @@ def __init__(self, config=None, connect_on_create=False):
# Finished configuring
self.logger.debug('configured successfully')

def power_on_all_equipments(self):
def reset_config(self):
# initialize upbv2
self.start_upbv2_driver()
self.upbv2.initialize()
self.upbv2.initialize() # This force to put to zero power and usb usually before an indiserver reset

def power_on_all_equipments(self):
self.upbv2.connect(connect_device=True)
self.logger.debug(f'1#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
# Power servo controller
self.upbv2.power_on_arduino_control_box()
self.logger.debug(f'2#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
time.sleep(self._indi_driver_connect_delay_s)
self.upbv2.switch_on_arduino_control_box_usb()
self.logger.debug(f'3#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
time.sleep(self._indi_driver_connect_delay_s)
self.logger.debug(f'3.5#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
# Power acquisition instruments: this is a very specific case, see https://github.com/indilib/indi-3rdparty/issues/822
self.switch_on_acquisition_equipments_usb()
self.upbv2.switch_on_acquisition_equipments_usb()
self.logger.debug(f'4#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
time.sleep(self._indi_driver_connect_delay_s)
# Power mount
self.switch_on_mount()

self.logger.debug(f'5#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
# Wait for the os serial port to be created, and stuff like that
time.sleep(self._indi_driver_connect_delay_s)

# Power acquisition instruments: this is a very specific case, see https://github.com/indilib/indi-3rdparty/issues/822
self.power_on_acquisition_equipments()

self.upbv2.power_on_acquisition_equipments()
self.logger.debug(f'6#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
time.sleep(self._indi_driver_connect_delay_s)
# start or restart drivers if needed
self.start_all_drivers()
# Now we need to wait a bit before trying to connect driver
# but _indi_driver_connect_delay_s was already waited for at previous step
for driver_name, device_name in self._indi_resetable_instruments_driver_map.items():
if not self.probe_device_driver_connection(driver_name=driver_name, device_name=device_name):
self.logger.debug(f"Device {device_name} doesn't seems to have its driver properly started - restarting")
self.restart_driver(driver_name)
# Now we need to wait a bit before trying to connect driver
if not self.probe_device_driver_connection(driver_name=self._indi_mount_driver_name,
device_name=self._indi_mount_device_name):
self.restart_driver(self._indi_mount_driver_name)

# Initialize dependent device
self.logger.debug(f'7#################################### {self.upbv2.get_switch("USB_PORT_CONTROL")["PORT_4"]}')
self.arduino_servo_controller.initialize()

self.is_initialized = True
exit()

def power_off_all_equipments(self):
"""
Expand All @@ -628,10 +645,10 @@ def power_off_all_equipments(self):
self.logger.debug("Deinitializing AggregatedCustomScopeController")

self.switch_off_mount()
self.power_off_acquisition_equipments()
self.upbv2.power_off_acquisition_equipments()
# Power acquisition instruments: this is a very specific case, see https://github.com/indilib/indi-3rdparty/issues/822
time.sleep(1)
self.switch_off_acquisition_equipments_usb()
self.upbv2.switch_off_acquisition_equipments_usb()

# Deinitialize arduino servo first (as it relies on upb power)
self.arduino_servo_controller.deinitialize()
Expand Down Expand Up @@ -691,7 +708,7 @@ def get_running_driver(self):
f"{self._indi_webserver_port}"
req = f"{base_url}/api/server/drivers"
response = requests.get(req)
self.logger.debug(f"get_running_driver - url {req} - code {response.status_code} - response:{response.text}")
# self.logger.debug(f"get_running_driver - url {req} - code {response.status_code} - response :{response.text}")
assert response.status_code == 200
running_driver_list = json.loads(response.text)
except json.JSONDecodeError as e:
Expand Down
3 changes: 3 additions & 0 deletions Observatory/DummyScopeController.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def power_on_all_equipments(self):
def power_off_all_equipments(self):
self.logger.debug("Shutting down all equipements")

def reset_config(self):
pass

def deinitialize(self):
self.logger.debug("Deinitializing DummyScopeController")

Expand Down
4 changes: 4 additions & 0 deletions Observatory/IndiDomeController.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Basic stuff
import logging
import time

# Indi stuff
from helper.IndiDevice import IndiDevice
Expand Down Expand Up @@ -27,6 +28,9 @@ def __init__(self, config=None, connect_on_create=True):
# Finished configuring
self.logger.debug('Indi dome configured successfully')

def power_on(self):
self.connect(connect_device=True)

def initialize(self):
self._is_initialized = True
self.logger.debug("Initializing dome, not doing much actually")
Expand Down
7 changes: 7 additions & 0 deletions Observatory/Observatory.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def __init__(self, serv_weather=None, config=None):
longitude=config['longitude'])
self.altitude_meter = config['elevation']
self.horizon = config['horizon']
self.max_altitude_degree = config.get("max_altitude_degree", 90)
self.investigator = config['investigator']

# Now find the timezone from the gps coordinate
Expand Down Expand Up @@ -156,8 +157,14 @@ def unpark(self):
self.logger.debug('Observatory: unparking')
self.open_everything()

def reset_config(self):
if self.has_scope:
self.scope_controller.reset_config()

def power_on_all_equipments(self):
self.logger.debug('Observatory: powering all scope equipments')
if self.has_dome:
self.dome_controller.power_on()
if self.has_scope:
self.scope_controller.power_on_all_equipments()

Expand Down
Loading

0 comments on commit 5e9e405

Please sign in to comment.