Skip to content

Commit

Permalink
Merge pull request #6 from NTIA/updates
Browse files Browse the repository at this point in the history
Add healthy check and raise exception when base_url is misconfigured
  • Loading branch information
dboulware committed May 13, 2022
2 parents 7ef7a18 + 8d65307 commit ee275a6
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 18 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -19,19 +20,19 @@ 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
The WebRelayPreselector requires a [SigMF metadata file](https://Github.com/NTIA/sigmf-ns-ntia) that describes the Sensor preselector and a config file to describe the x310 settings for the rf paths specified in the
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"
Expand Down Expand Up @@ -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
Expand All @@ -84,7 +86,7 @@ preselector = WebRelayPreselector(sensor_def, preselector_config)

## Control:
<ul>
<li>preselector.set_rf_path(rf_path_name)</li>
<li>preselector.set_state(rf_path_name)</li>
</ul>

# License
Expand Down
7 changes: 3 additions & 4 deletions config/config.json
Original file line number Diff line number Diff line change
@@ -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"
}


Expand Down
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -19,7 +19,7 @@ package_dir =
= src
packages =
its_preselector
python_requires = >=3.6
python_requires = >=3.7
install_requires =
requests>=2.25.1

Expand Down
6 changes: 4 additions & 2 deletions src/its_preselector/preselector.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -135,5 +135,7 @@ def __get_amplifier(self, amp_id):

return None


@abstractmethod
def get_sensor_value(sensor):
pass

36 changes: 36 additions & 0 deletions src/its_preselector/test/test_web_relay_preselector.py
Original file line number Diff line number Diff line change
@@ -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()
34 changes: 29 additions & 5 deletions src/its_preselector/web_relay_preselector.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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

0 comments on commit ee275a6

Please sign in to comment.