diff --git a/socs/agents/starcam_lat/__init__.py b/socs/agents/starcam_lat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/socs/agents/starcam_lat/agent.py b/socs/agents/starcam_lat/agent.py index 2fa45d623..588d00c7e 100644 --- a/socs/agents/starcam_lat/agent.py +++ b/socs/agents/starcam_lat/agent.py @@ -1,6 +1,4 @@ import argparse -import socket -import struct import time from os import environ @@ -8,127 +6,7 @@ from ocs import ocs_agent, site_config from ocs.ocs_twisted import TimeoutLock - -class StarcamHelper: - """Functions to control and retrieve data from the starcam. - - Parameters - ---------- - ip_addres: str - IP address of the starcam computer. - port: int - Port of the starcam computer. - timeout: float - Socket connection timeout in seconds. Defaults to 10 seconds. - - """ - - def __init__(self, ip_address, port, timeout=10): - self.ip = ip_address - self.port = port - self.server_addr = (self.ip, self.port) - self.comm = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.comm.connect(self.server_addr) - self.comm.settimeout(timeout) - - def pack_and_send_cmds(self): - """Packs commands and parameters to be sent to the starcam and sends. - - Returns: - list: Values sent to the starcam. - - """ - logodds = 1e8 - latitude = -22.9586 - longitude = -67.7875 - height = 5200.0 - exposure = 700 - timelimit = 1 - set_focus_to_amount = 0 - auto_focus_bool = 1 - start_focus = 0 - end_focus = 0 - step_size = 5 - photos_per_focus = 3 - infinity_focus_bool = 0 - set_aperture_steps = 0 - max_aperture_bool = 0 - make_HP_bool = 0 - use_HP_bool = 0 - spike_limit_value = 3 - dynamic_hot_pixels_bool = 1 - r_smooth_value = 2 - high_pass_filter_bool = 0 - r_high_pass_filter_value = 10 - centroid_search_border_value = 1 - filter_return_image_bool = 0 - n_sigma_value = 2 - star_spacing_value = 15 - values = [logodds, - latitude, - longitude, - height, - exposure, - timelimit, - set_focus_to_amount, - auto_focus_bool, - start_focus, - end_focus, - step_size, - photos_per_focus, - infinity_focus_bool, - set_aperture_steps, - max_aperture_bool, - make_HP_bool, - use_HP_bool, - spike_limit_value, - dynamic_hot_pixels_bool, - r_smooth_value, - high_pass_filter_bool, - r_high_pass_filter_value, - centroid_search_border_value, - filter_return_image_bool, - n_sigma_value, - star_spacing_value] - # Pack values into the command for the camera - self.cmds_for_camera = struct.pack('ddddddfiiiiiiiiiifffffffff', - *values) - # send commands to the camera - self.comm.sendto(self.cmds_for_camera, (self.ip, self.port)) - print("Commands sent to camera.") - # Return the list of values - return values - - def get_astrom_data(self): - """Receives and unpacks data from the starcam. - - Returns: - dict: Dictionary of unpacked data. - """ - (scdata_raw, _) = self.comm.recvfrom(256) - data = struct.unpack_from("dddddddddddddiiiiiiiiddiiiiiiiiiiiiiifiii", - scdata_raw) - keys = ['c_time', - 'gmt', - 'blob_num', - 'obs_ra', - 'astrom_ra', - 'obs_dec', - 'fr', - 'ps', - 'alt', - 'az', - 'ir', - 'astrom_solve_time', - 'camera_time'] - # Create a dictionary of the unpacked data - astrom_data = [data[i] for i in range(len(keys))] - astrom_data_dict = {keys[i]: astrom_data[i] for i in range(len(keys))} - return astrom_data_dict - - def close(self): - """Closes the socket connection.""" - self.comm.close() +from socs.agents.starcam_lat.drivers import StarcamHelper class StarcamAgent: @@ -159,14 +37,11 @@ def __init__(self, agent, ip_address, port): self.log = agent.log self.take_data = False self.lock = TimeoutLock() + self.starcam = StarcamHelper(ip_address, port) + agg_params = {'frame_length': 60} self.agent.register_feed("starcamera", record=True, agg_params=agg_params, buffer_time=1) - try: - self.starcam = StarcamHelper(ip_address, port) - except socket.timeout: - self.log.error("Starcam connection has timed out.") - return False, "Timeout" @ocs_agent.param('_') def send_commands(self, session, params=None): @@ -182,7 +57,8 @@ def send_commands(self, session, params=None): f"{self.lock.job} is already running.") return False, "Could not acquire lock." self.log.info("Sending commands.") - self.starcam.pack_and_send_cmds() + self.starcam.send_cmds() + self.log.info("Commands sent to camera.") return True, "Sent commands to the starcam." @ocs_agent.param('_') @@ -231,8 +107,16 @@ def acq(self, session, params=None): 'block_name': 'astrometry', 'data': {} } - # get astrometry data - astrom_data_dict = self.starcam.get_astrom_data() + try: + astrom_data_dict = self.starcam.get_astrom_data() + if session.degraded: + self.log.info("Connection re-established.") + session.degraded = False + except ConnectionError: + self.log.error("Failed to get data from star camera. Check network connection.") + session.degraded = True + time.sleep(1) + continue # update the data dictionary+session and publish data['data'].update(astrom_data_dict) session.data.update(data['data']) diff --git a/socs/agents/starcam_lat/drivers.py b/socs/agents/starcam_lat/drivers.py new file mode 100644 index 000000000..6039c6d41 --- /dev/null +++ b/socs/agents/starcam_lat/drivers.py @@ -0,0 +1,123 @@ +import struct + +from socs.tcp import TCPInterface + + +class StarcamHelper(TCPInterface): + """Functions to control and retrieve data from the starcam. + + Parameters + ---------- + ip_addres: str + IP address of the starcam computer. + port: int + Port of the starcam computer. + timeout: float + Socket connection timeout in seconds. Defaults to 10 seconds. + + """ + + def __init__(self, ip_address, port, timeout=10): + # Set up the TCP Interface + super().__init__(ip_address, port, timeout) + + def send_cmds(self): + """Send commands and parameters to the starcam.""" + cmds = self._pack_cmds() + self.comm.send(cmds) + + @staticmethod + def _pack_cmds(): + """Packs commands and parameters to be sent to the starcam. + + Returns: + bytes: Packed bytes object to send to the starcam. + + """ + logodds = 1e8 + latitude = -22.9586 + longitude = -67.7875 + height = 5200.0 + exposure = 700 + timelimit = 1 + set_focus_to_amount = 0 + auto_focus_bool = 1 + start_focus = 0 + end_focus = 0 + step_size = 5 + photos_per_focus = 3 + infinity_focus_bool = 0 + set_aperture_steps = 0 + max_aperture_bool = 0 + make_HP_bool = 0 + use_HP_bool = 0 + spike_limit_value = 3 + dynamic_hot_pixels_bool = 1 + r_smooth_value = 2 + high_pass_filter_bool = 0 + r_high_pass_filter_value = 10 + centroid_search_border_value = 1 + filter_return_image_bool = 0 + n_sigma_value = 2 + star_spacing_value = 15 + values = [logodds, + latitude, + longitude, + height, + exposure, + timelimit, + set_focus_to_amount, + auto_focus_bool, + start_focus, + end_focus, + step_size, + photos_per_focus, + infinity_focus_bool, + set_aperture_steps, + max_aperture_bool, + make_HP_bool, + use_HP_bool, + spike_limit_value, + dynamic_hot_pixels_bool, + r_smooth_value, + high_pass_filter_bool, + r_high_pass_filter_value, + centroid_search_border_value, + filter_return_image_bool, + n_sigma_value, + star_spacing_value] + + # Pack values into the command for the camera + return struct.pack('ddddddfiiiiiiiiiifffffffff', *values) + + def get_astrom_data(self): + """Receives and unpacks data from the starcam. + + Returns: + dict: Dictionary of unpacked data. + """ + scdata_raw = self.comm.recv(256) + return self._unpack_response(scdata_raw) + + @staticmethod + def _unpack_response(response): + data = struct.unpack_from("dddddddddddddiiiiiiiiddiiiiiiiiiiiiiifiii", + response) + keys = ['c_time', + 'gmt', + 'blob_num', + 'obs_ra', + 'astrom_ra', + 'obs_dec', + 'fr', + 'ps', + 'alt', + 'az', + 'ir', + 'astrom_solve_time', + 'camera_time'] + + # Create a dictionary of the unpacked data + astrom_data = [data[i] for i in range(len(keys))] + astrom_data_dict = {keys[i]: astrom_data[i] for i in range(len(keys))} + return astrom_data_dict diff --git a/tests/agents/test_starcam_lat_agent.py b/tests/agents/test_starcam_lat_agent.py new file mode 100644 index 000000000..356fcdfbf --- /dev/null +++ b/tests/agents/test_starcam_lat_agent.py @@ -0,0 +1,6 @@ +from socs.agents.starcam_lat.drivers import StarcamHelper # noqa: F401 + + +def test__pack_cmds(): + cmds = StarcamHelper._pack_cmds() + assert cmds == b'\x00\x00\x00\x00\x84\xd7\x97A\x13\xf2A\xcff\xf56\xc0fffff\xf2P\xc0\x00\x00\x00\x00\x00P\xb4@\x00\x00\x00\x00\x00\xe0\x85@\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@@\x00\x00\x80?\x00\x00\x00@\x00\x00\x00\x00\x00\x00 A\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00@\x00\x00pA'