diff --git a/README.md b/README.md index 8b1c306..465d8e3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ regardless of their components and control mechanisms. This software will grow over time to support additional components and control mechanisms. Currently, this API provides a general abstract Preselector class that uses an rf_path array to describe the available combinations of calibration sources, filters, -and amplifiers. A simple set_rf_path method allows users to specify the rf path by index or name. +and amplifiers. A simple set_state method allows users to specify the state of the preselector +by the state key specified in the preselector config. Finally, different switching control mechanisms are supported by extending the base Preseelctor class. Currently, this repository provides an implementation for a WebRelayPreselector that includes an [x310 WebRelay](https://www.controlbyweb.com/x310/). See below for additional details on using the WebRelayPreslector. @@ -19,11 +20,11 @@ To install this Python package, clone the repository and enter the directory of ``` Windows: py –m build -py -m pip install dist/its-preselector-2.0.0.tar.gz +py -m pip install dist/its-preselector-2.0.1.tar.gz Linux: python3 -m build -Python3 –m pip install dist/its-preselector-2.0.0.tar.gz +Python3 –m pip install dist/its-preselector-2.0.1.tar.gz ``` # WebRelayPreselector Configuration @@ -31,7 +32,7 @@ The WebRelayPreselector requires a [SigMF metadata file](https://Github.com/NTIA metadata and for any other desired sources. Below is an example config file for the WebRelayPreselector to describe how it works: ``` { - "base_url" : "http://192.168.130.32/state.xml?relay", + "base_url" : "http://192.168.130.32/state.xml", "noise_diode_on" : "1State=1,2State=1,3State=0,4State=0", "noise_diode_off" : "1State=0,2State=1,3State=0,4State=0", "antenna" : "1State=0,2State=0,3State=0,4State=0" @@ -62,6 +63,7 @@ with open('config/config.json') as config_file: preselector_config = json.load(config_file) preselector = WebRelayPreselector(sensor_def, preselector_config) +preselector.set_state('antenna') ``` # Preselector Interactions @@ -84,7 +86,7 @@ preselector = WebRelayPreselector(sensor_def, preselector_config) ## Control: # License diff --git a/config/config.json b/config/config.json index 81adf82..f3f966e 100644 --- a/config/config.json +++ b/config/config.json @@ -1,9 +1,8 @@ { - "base_url" : "http://192.168.130.32/state.xml?relay", + "base_url" : "http://192.168.1.2/state.xml", "noise_diode_on" : "1State=1,2State=1,3State=0,4State=0", - "noise_diode_off" : "1State=0,2State=1,3State=0,4State=0", - "antenna" : "1State=0,2State=0,3State=0,4State=0", - "1" : "1State=0,2State=1,3State=0,4State=0" + "noise_diode_off" : "1State=1,2State=0,3State=0,4State=0", + "antenna" : "1State=0,2State=0,3State=0,4State=0" } diff --git a/setup.cfg b/setup.cfg index 32a8e69..18262e5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = its-preselector -version = 2.0.0 +version = 2.0.1 author = ITS author_email = dboulware@ntia.gov description = A package to control the ITS web relay based preselector @@ -19,7 +19,7 @@ package_dir = = src packages = its_preselector -python_requires = >=3.6 +python_requires = >=3.7 install_requires = requests>=2.25.1 diff --git a/src/its_preselector/preselector.py b/src/its_preselector/preselector.py index 46cb18c..9dded99 100644 --- a/src/its_preselector/preselector.py +++ b/src/its_preselector/preselector.py @@ -116,7 +116,7 @@ def get_amplifier_noise_figure(self, rf_path_index): return None @abstractmethod - def set_rf_path(self, i): + def set_state(self, i): pass def __get_filter(self, filter_id): @@ -135,5 +135,7 @@ def __get_amplifier(self, amp_id): return None - + @abstractmethod + def get_sensor_value(sensor): + pass diff --git a/src/its_preselector/test/test_web_relay_preselector.py b/src/its_preselector/test/test_web_relay_preselector.py new file mode 100644 index 0000000..746b57d --- /dev/null +++ b/src/its_preselector/test/test_web_relay_preselector.py @@ -0,0 +1,36 @@ +import unittest +import json + +from its_preselector.web_relay_preselector import WebRelayPreselector + + +class MyTestCase(unittest.TestCase): + + @classmethod + def setUpClass(cls): + file = open('test_metadata.sigmf-meta') + cls.sensor_def = json.load(file) + file.close() + + def test_blank_base_url(self): + preselector = WebRelayPreselector(self.sensor_def, {'base_url': '', 'antenna' : '1State=0,2State=0,3State=0,4State=0' }) + with self.assertRaises(Exception): + preselector.set_state('antenna') + + def test_none_base_url(self): + preselector = WebRelayPreselector(self.sensor_def, {'base_url': None, 'antenna' : '1State=0,2State=0,3State=0,4State=0' }) + with self.assertRaises(Exception): + preselector.set_state('antenna') + + def test_invalid_base_url(self): + preselector = WebRelayPreselector(self.sensor_def, {'base_url': 'http://badpreselector.gov', 'antenna' : '1State=0,2State=0,3State=0,4State=0' }) + with self.assertRaises(Exception): + preselector.set_state('antenna') + + def test_healthy_false(self): + preselector = WebRelayPreselector(self.sensor_def, {'base_url': 'http://bad_preselector.gov', + 'antenna': '1State=0,2State=0,3State=0,4State=0'}) + self.assertFalse(preselector.healthy()) + +if __name__ == '__main__': + unittest.main() diff --git a/src/its_preselector/web_relay_preselector.py b/src/its_preselector/web_relay_preselector.py index c48a8f1..fa23ffc 100644 --- a/src/its_preselector/web_relay_preselector.py +++ b/src/its_preselector/web_relay_preselector.py @@ -1,5 +1,9 @@ +import logging from its_preselector.preselector import Preselector import requests +import xml.etree.ElementTree as ET + +logger = logging.getLogger(__name__) class WebRelayPreselector(Preselector): @@ -9,14 +13,34 @@ def __init__(self, sigmf, config): if 'base_url' in config: self.base_url = config['base_url'] - def set_rf_path(self, i): + def set_state(self, i): key = str(i) if key in self.config: switches = self.config[str(i)].split(',') - if self.base_url: + if self.base_url and self.base_url != '': for i in range(len(switches)): - command = self.base_url + switches[i] - print(command) - requests.get(command) + command = self.base_url + '?relay' + switches[i] + logger.debug(command) + response = requests.get(command) + if response.status_code != requests.codes.ok: + raise Exception('Unable to set preselector state. Verify configuration and connectivity.') + else: + raise Exception('base_url is None or blank') else: raise Exception("RF path " + key + " configuration does not exist.") + + def get_sensor_value(self, sensor_num): + sensor_num_string = str(sensor_num) + response = requests.get(self.base_url + '?sensor' + sensor_num_string) + sensor_tag = 'sensor' + sensor_num_string + root = ET.fromstring(response.text) + sensor = root.find(sensor_tag) + return sensor.text + + def healthy(self): + try: + response = requests.get(self.base_url) + return response.status_code == requests.codes.ok + except: + logger.error("Unable to connect to preselector") + return False