diff --git a/README.md b/README.md index d6236d97..84f2efe7 100644 --- a/README.md +++ b/README.md @@ -311,8 +311,7 @@ The following signals are currently offered: - `measurement_action_completed` - signal expects task_id, data, and metadata - `location_action_completed` - signal expects latitude and longitude -- `monitor_action_completed` - signal expects boolean indicating if the signal analyzer -is healthy +- `trigger_api_restart` - triggers a restart of the API docker container (where scos-sensor runs) New signals can be added. However, corresponding signal handlers must be added to scos-sensor to receive the signals and process the results. diff --git a/scos_actions/__init__.py b/scos_actions/__init__.py index 064c0b35..ba7be38e 100644 --- a/scos_actions/__init__.py +++ b/scos_actions/__init__.py @@ -1 +1 @@ -__version__ = "4.0.2" +__version__ = "5.0.0" diff --git a/scos_actions/actions/monitor_sigan.py b/scos_actions/actions/monitor_sigan.py index f470dcb0..8bfaa5a7 100644 --- a/scos_actions/actions/monitor_sigan.py +++ b/scos_actions/actions/monitor_sigan.py @@ -4,7 +4,7 @@ from scos_actions.actions.interfaces.action import Action from scos_actions.hardware.mocks.mock_gps import MockGPS -from scos_actions.signals import monitor_action_completed +from scos_actions.signals import trigger_api_restart logger = logging.getLogger(__name__) @@ -20,16 +20,10 @@ def __init__(self, sigan, parameters={"name": "monitor_sigan"}, gps=None): def __call__(self, schedule_entry_json, task_id): logger.debug("Performing signal analyzer health check") - healthy = True - - if not self.sigan.is_available: - healthy = False - else: - healthy = self.sigan.healthy + healthy = self.sigan.healthy() if healthy: - monitor_action_completed.send(sender=self.__class__, sigan_healthy=True) logger.info("signal analyzer healthy") else: logger.warning("signal analyzer unhealthy") - monitor_action_completed.send(sender=self.__class__, sigan_healthy=False) + trigger_api_restart.send(sender=self.__class__) diff --git a/scos_actions/actions/tests/test_monitor_radio.py b/scos_actions/actions/tests/test_monitor_sigan.py similarity index 55% rename from scos_actions/actions/tests/test_monitor_radio.py rename to scos_actions/actions/tests/test_monitor_sigan.py index e46f1b5c..3cd2e737 100644 --- a/scos_actions/actions/tests/test_monitor_radio.py +++ b/scos_actions/actions/tests/test_monitor_sigan.py @@ -1,5 +1,5 @@ from scos_actions.discover import test_actions as actions -from scos_actions.signals import monitor_action_completed +from scos_actions.signals import trigger_api_restart MONITOR_SIGAN_SCHEDULE = { "name": "test_monitor", @@ -11,48 +11,47 @@ def test_monitor_sigan_not_available(): - _sigan_healthy = None + _api_restart_triggered = False def callback(sender, **kwargs): - nonlocal _sigan_healthy - _sigan_healthy = kwargs["sigan_healthy"] + nonlocal _api_restart_triggered + _api_restart_triggered = True - monitor_action_completed.connect(callback) + trigger_api_restart.connect(callback) action = actions["test_monitor_sigan"] sigan = action.sigan sigan._is_available = False action(MONITOR_SIGAN_SCHEDULE, 1) - assert _sigan_healthy == False + assert _api_restart_triggered == True # signal sent sigan._is_available = True def test_monitor_sigan_not_healthy(): - _sigan_healthy = None + _api_restart_triggered = False def callback(sender, **kwargs): - nonlocal _sigan_healthy - _sigan_healthy = kwargs["sigan_healthy"] + nonlocal _api_restart_triggered + _api_restart_triggered = True - monitor_action_completed.connect(callback) + trigger_api_restart.connect(callback) action = actions["test_monitor_sigan"] sigan = action.sigan - sigan._healthy = False + sigan.times_to_fail_recv = 6 action(MONITOR_SIGAN_SCHEDULE, 1) - assert _sigan_healthy == False - sigan._healthy = True + assert _api_restart_triggered == True # signal sent def test_monitor_sigan_healthy(): - _sigan_healthy = None + _api_restart_triggered = False def callback(sender, **kwargs): - nonlocal _sigan_healthy - _sigan_healthy = kwargs["sigan_healthy"] + nonlocal _api_restart_triggered + _api_restart_triggered = True - monitor_action_completed.connect(callback) + trigger_api_restart.connect(callback) action = actions["test_monitor_sigan"] sigan = action.sigan sigan._is_available = True sigan.set_times_to_fail_recv(0) action(MONITOR_SIGAN_SCHEDULE, 1) - assert _sigan_healthy == True + assert _api_restart_triggered == False # signal not sent diff --git a/scos_actions/hardware/mocks/mock_sigan.py b/scos_actions/hardware/mocks/mock_sigan.py index 1277a9ff..11c60d66 100644 --- a/scos_actions/hardware/mocks/mock_sigan.py +++ b/scos_actions/hardware/mocks/mock_sigan.py @@ -33,7 +33,6 @@ def __init__(self, randomize_values=False): self._overload = False self._capture_time = None self._is_available = True - self._healthy = True # Simulate returning less than the requested number of samples from # self.recv_num_samps @@ -144,9 +143,5 @@ def set_times_to_fail_recv(self, n): def last_calibration_time(self): return get_datetime_str_now() - @property - def healthy(self): - return self._healthy - def update_calibration(self, params): pass diff --git a/scos_actions/hardware/sigan_iface.py b/scos_actions/hardware/sigan_iface.py index 5de48a12..69682195 100644 --- a/scos_actions/hardware/sigan_iface.py +++ b/scos_actions/hardware/sigan_iface.py @@ -81,11 +81,25 @@ def connect(self) -> None: """ pass - @property - @abstractmethod - def healthy(self) -> bool: - """Perform a health check by collecting IQ samples.""" - pass + def healthy(self, num_samples=56000): + """Perform health check by collecting IQ samples.""" + logger.debug("Performing health check.") + if not self.is_available: + return False + try: + measurement_result = self.acquire_time_domain_samples( + num_samples, gain_adjust=False + ) + data = measurement_result["data"] + except Exception as e: + logger.exception("Unable to acquire samples from device.") + return False + + if not len(data) == num_samples: + logger.error("Data length doesn't match request.") + return False + + return True def power_cycle_and_connect(self, sleep_time: float = 2.0) -> None: """ @@ -137,4 +151,4 @@ def get_status(self): raise KeyError except KeyError: sigan_model = str(self.__class__) - return {"model": sigan_model, "healthy": self.healthy} + return {"model": sigan_model, "healthy": self.healthy()} diff --git a/scos_actions/signals.py b/scos_actions/signals.py index 5a247896..36baaf3b 100644 --- a/scos_actions/signals.py +++ b/scos_actions/signals.py @@ -6,8 +6,7 @@ # Provides arguments: 'latitude', 'longitude' location_action_completed = Signal() -# Provides arguments: 'sigan_healthy' -monitor_action_completed = Signal() +trigger_api_restart = Signal() # Provides argument: 'component' register_component_with_status = Signal()