Public Access
make temperature proxy host and port configurable in the configuration tab
This commit is contained in:
1 parent
f562255c75
commit
5f558e4f03
4 files changed
+62
-12
No files matched your search
+3
-2
@@ -51,12 +51,13 @@ Following is a short description of the options:
|
|||||||
10. Filename of the data pool file
|
10. Filename of the data pool file
|
||||||
11. Write interval after which the data pool is rewritten
|
11. Write interval after which the data pool is rewritten
|
||||||
12. Compression settings
|
12. Compression settings
|
||||||
13. Authors, License and version numbers of used components
|
13. Host and port of the temperature proxy service
|
||||||
|
14. Authors, License and version numbers of used components
|
||||||
|
|
||||||
Temperature History
|
Temperature History
|
||||||
===================
|
===================
|
||||||
|
|
||||||
DAMARIS automatically retrieves one temperature history for the complete experiment from the local ``tempproxy`` service at ``http://localhost:8000/v1/readings`` after the experiment finishes. The proxy controls the temperature device; no controller, serial device, or polling interval needs to be configured in DAMARIS. Successful readings are stored under the ``temperature`` DataPool key with elapsed seconds on the x-axis and the proxy's ``pv`` values unchanged on the y-axis, so units depend on the configured controller. If the proxy is unavailable or has no readings for the experiment, the history is omitted and the experiment's other data is still saved.
|
DAMARIS automatically retrieves one temperature history for the complete experiment from the ``tempproxy`` service at ``http://<host>:<port>/v1/readings`` after the experiment finishes. Host and port are configured in the Configuration tab, the defaults are ``127.0.0.1`` and ``18007``. The proxy controls the temperature device; no controller, serial device, or polling interval needs to be configured in DAMARIS. Successful readings are stored under the ``temperature`` DataPool key with elapsed seconds on the x-axis and the proxy's ``pv`` values unchanged on the y-axis, so units depend on the configured controller. If the proxy is unavailable or has no readings for the experiment, the history is omitted and the experiment's other data is still saved.
|
||||||
|
|
||||||
Experiment Script
|
Experiment Script
|
||||||
=================
|
=================
|
||||||
|
|||||||
@@ -871,7 +871,10 @@ class DamarisGUI:
|
|||||||
temperature_history_start = self.temperature_history_start
|
temperature_history_start = self.temperature_history_start
|
||||||
self.temperature_history_start = None
|
self.temperature_history_start = None
|
||||||
self.data.pop("temperature", None)
|
self.data.pop("temperature", None)
|
||||||
temperature = TemperatureProxyClient().get_history(
|
proxy_config = self.config.get( )
|
||||||
|
temperature = TemperatureProxyClient(
|
||||||
|
host=proxy_config["tempproxy_host"],
|
||||||
|
port=proxy_config["tempproxy_port"]).get_history(
|
||||||
temperature_history_start, time.time())
|
temperature_history_start, time.time())
|
||||||
if temperature is not None:
|
if temperature is not None:
|
||||||
self.data["temperature"] = temperature
|
self.data["temperature"] = temperature
|
||||||
@@ -2379,6 +2382,27 @@ class ConfigTab:
|
|||||||
backend_vbox.pack_start(self.config_adc_bit_depth_hbox, False, False, 0)
|
backend_vbox.pack_start(self.config_adc_bit_depth_hbox, False, False, 0)
|
||||||
self.config_adc_bit_depth_hbox.show_all()
|
self.config_adc_bit_depth_hbox.show_all()
|
||||||
|
|
||||||
|
# temperature proxy settings
|
||||||
|
self.config_tempproxy_hbox = gtk.Box(orientation=gtk.Orientation.HORIZONTAL, spacing=6)
|
||||||
|
self.config_tempproxy_host_label = gtk.Label(label="Temp proxy host:")
|
||||||
|
self.config_tempproxy_host_entry = gtk.Entry()
|
||||||
|
self.config_tempproxy_host_entry.set_text("127.0.0.1")
|
||||||
|
self.config_tempproxy_host_entry.set_tooltip_text("Host of the tempproxy service reading the temperature controller")
|
||||||
|
self.config_tempproxy_host_entry.connect("key-press-event", self.config_keypress)
|
||||||
|
self.config_tempproxy_port_label = gtk.Label(label="port:")
|
||||||
|
self.config_tempproxy_port_spinbutton = gtk.SpinButton.new_with_range(1, 65535, 1)
|
||||||
|
self.config_tempproxy_port_spinbutton.set_value(18007)
|
||||||
|
self.config_tempproxy_port_spinbutton.set_tooltip_text("Port of the tempproxy service, /v1/readings is requested there")
|
||||||
|
self.config_tempproxy_port_spinbutton.connect("key-press-event", self.config_keypress)
|
||||||
|
self.config_tempproxy_hbox.pack_start(self.config_tempproxy_host_label, False, False, 0)
|
||||||
|
self.config_tempproxy_hbox.pack_start(self.config_tempproxy_host_entry, False, False, 0)
|
||||||
|
self.config_tempproxy_hbox.pack_start(self.config_tempproxy_port_label, False, False, 0)
|
||||||
|
self.config_tempproxy_hbox.pack_start(self.config_tempproxy_port_spinbutton, False, False, 0)
|
||||||
|
frontend_vbox = self.xml_gui.get_object("vbox7")
|
||||||
|
if frontend_vbox:
|
||||||
|
frontend_vbox.pack_start(self.config_tempproxy_hbox, False, False, 0)
|
||||||
|
self.config_tempproxy_hbox.show_all()
|
||||||
|
|
||||||
# insert version informations
|
# insert version informations
|
||||||
components_text = """
|
components_text = """
|
||||||
operating system %(os)s
|
operating system %(os)s
|
||||||
@@ -2485,7 +2509,9 @@ pygobject version %(pygobject)s
|
|||||||
"data_pool_complib": complib,
|
"data_pool_complib": complib,
|
||||||
"data_pool_comprate": self.config_data_pool_comprate.get_value_as_int( ),
|
"data_pool_comprate": self.config_data_pool_comprate.get_value_as_int( ),
|
||||||
"script_font": self.config_script_font_button.get_font_name( ),
|
"script_font": self.config_script_font_button.get_font_name( ),
|
||||||
"adc_bit_depth": self.config_adc_bit_depth_spinbutton.get_value_as_int()
|
"adc_bit_depth": self.config_adc_bit_depth_spinbutton.get_value_as_int(),
|
||||||
|
"tempproxy_host": self.config_tempproxy_host_entry.get_text( ),
|
||||||
|
"tempproxy_port": self.config_tempproxy_port_spinbutton.get_value_as_int( )
|
||||||
}
|
}
|
||||||
ADC_Result.default_bit_depth = actual_config["adc_bit_depth"]
|
ADC_Result.default_bit_depth = actual_config["adc_bit_depth"]
|
||||||
return actual_config
|
return actual_config
|
||||||
@@ -2520,6 +2546,10 @@ pygobject version %(pygobject)s
|
|||||||
ADC_Result.default_bit_depth = int(config["adc_bit_depth"])
|
ADC_Result.default_bit_depth = int(config["adc_bit_depth"])
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
if "tempproxy_host" in config:
|
||||||
|
self.config_tempproxy_host_entry.set_text( str( config[ "tempproxy_host" ] ) )
|
||||||
|
if "tempproxy_port" in config:
|
||||||
|
self.config_tempproxy_port_spinbutton.set_value( float( config[ "tempproxy_port" ] ) )
|
||||||
|
|
||||||
if "data_pool_complib" in config:
|
if "data_pool_complib" in config:
|
||||||
# find combo-box entry and make it active...
|
# find combo-box entry and make it active...
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Read experiment temperature history from the local tempproxy service.
|
"""Read experiment temperature history from the tempproxy service.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
client = TemperatureProxyClient()
|
client = TemperatureProxyClient() # defaults to http://127.0.0.1:18007
|
||||||
temperature = client.get_history(start_epoch, end_epoch)
|
temperature = client.get_history(start_epoch, end_epoch)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -18,11 +18,18 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class TemperatureProxyClient:
|
class TemperatureProxyClient:
|
||||||
"""Retrieve experiment-bounded readings from ``localhost:8000``."""
|
"""Retrieve experiment-bounded readings from a configurable tempproxy host/port."""
|
||||||
|
|
||||||
URL = "http://localhost:8000/v1/readings"
|
|
||||||
TIMEOUT = 5
|
TIMEOUT = 5
|
||||||
|
|
||||||
|
def __init__(self, host: str = "127.0.0.1", port: int = 18007):
|
||||||
|
"""Create a client for ``http://<host>:<port>/v1/readings``.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
client = TemperatureProxyClient(host="192.168.1.5", port=18007)
|
||||||
|
"""
|
||||||
|
self.url = f"http://{host}:{port}/v1/readings"
|
||||||
|
|
||||||
def get_history(self, start_epoch: float, end_epoch: float) -> TemperatureResult | None:
|
def get_history(self, start_epoch: float, end_epoch: float) -> TemperatureResult | None:
|
||||||
"""Return temperature history relative to the experiment start, or ``None``.
|
"""Return temperature history relative to the experiment start, or ``None``.
|
||||||
|
|
||||||
@@ -33,7 +40,7 @@ class TemperatureProxyClient:
|
|||||||
temperature = TemperatureProxyClient().get_history(1000.0, 1060.0)
|
temperature = TemperatureProxyClient().get_history(1000.0, 1060.0)
|
||||||
"""
|
"""
|
||||||
query = urlencode({"start": start_epoch, "end": end_epoch})
|
query = urlencode({"start": start_epoch, "end": end_epoch})
|
||||||
url = f"{self.URL}?{query}"
|
url = f"{self.url}?{query}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with urlopen(url, timeout=self.TIMEOUT) as response:
|
with urlopen(url, timeout=self.TIMEOUT) as response:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class TestTemperatureProxyClient(unittest.TestCase):
|
|||||||
return io.BytesIO(json.dumps(payload).encode("utf-8"))
|
return io.BytesIO(json.dumps(payload).encode("utf-8"))
|
||||||
|
|
||||||
@patch("damaris.gui.TemperatureProxyClient.urlopen")
|
@patch("damaris.gui.TemperatureProxyClient.urlopen")
|
||||||
def test_get_history_uses_fixed_endpoint_and_converts_readings(self, mock_urlopen):
|
def test_get_history_uses_default_endpoint_and_converts_readings(self, mock_urlopen):
|
||||||
mock_urlopen.return_value = self.response({
|
mock_urlopen.return_value = self.response({
|
||||||
"readings": [
|
"readings": [
|
||||||
{"t": 101.5, "pv": 293.15},
|
{"t": 101.5, "pv": 293.15},
|
||||||
@@ -35,13 +35,25 @@ class TestTemperatureProxyClient(unittest.TestCase):
|
|||||||
args, kwargs = mock_urlopen.call_args
|
args, kwargs = mock_urlopen.call_args
|
||||||
parsed_url = urlparse(args[0])
|
parsed_url = urlparse(args[0])
|
||||||
self.assertEqual(parsed_url.scheme, "http")
|
self.assertEqual(parsed_url.scheme, "http")
|
||||||
self.assertEqual(parsed_url.netloc, "localhost:8000")
|
self.assertEqual(parsed_url.netloc, "127.0.0.1:18007")
|
||||||
self.assertEqual(parsed_url.path, "/v1/readings")
|
self.assertEqual(parsed_url.path, "/v1/readings")
|
||||||
self.assertEqual(parse_qs(parsed_url.query), {"start": ["100.0"], "end": ["110.0"]})
|
self.assertEqual(parse_qs(parsed_url.query), {"start": ["100.0"], "end": ["110.0"]})
|
||||||
self.assertEqual(kwargs, {"timeout": TemperatureProxyClient.TIMEOUT})
|
self.assertEqual(kwargs, {"timeout": TemperatureProxyClient.TIMEOUT})
|
||||||
self.assertEqual(result.x, [1.5, 4.0])
|
self.assertEqual(result.x, [1.5, 4.0])
|
||||||
self.assertEqual(result.y, [293.15, 294.25])
|
self.assertEqual(result.y, [293.15, 294.25])
|
||||||
|
|
||||||
|
@patch("damaris.gui.TemperatureProxyClient.urlopen")
|
||||||
|
def test_custom_host_and_port_are_used(self, mock_urlopen):
|
||||||
|
mock_urlopen.return_value = self.response({"readings": [{"t": 101.0, "pv": 293.0}]})
|
||||||
|
|
||||||
|
client = TemperatureProxyClient(host="proxy.example.org", port=9000)
|
||||||
|
client.get_history(100.0, 110.0)
|
||||||
|
|
||||||
|
args, _ = mock_urlopen.call_args
|
||||||
|
parsed_url = urlparse(args[0])
|
||||||
|
self.assertEqual(parsed_url.netloc, "proxy.example.org:9000")
|
||||||
|
self.assertEqual(parsed_url.path, "/v1/readings")
|
||||||
|
|
||||||
@patch("damaris.gui.TemperatureProxyClient.urlopen")
|
@patch("damaris.gui.TemperatureProxyClient.urlopen")
|
||||||
def test_empty_readings_return_none(self, mock_urlopen):
|
def test_empty_readings_return_none(self, mock_urlopen):
|
||||||
mock_urlopen.return_value = self.response({"readings": []})
|
mock_urlopen.return_value = self.response({"readings": []})
|
||||||
@@ -62,7 +74,7 @@ class TestTemperatureProxyClient(unittest.TestCase):
|
|||||||
OSError("connection refused"),
|
OSError("connection refused"),
|
||||||
TimeoutError("request timed out"),
|
TimeoutError("request timed out"),
|
||||||
http.client.BadStatusLine("not an HTTP response"),
|
http.client.BadStatusLine("not an HTTP response"),
|
||||||
HTTPError(TemperatureProxyClient.URL, 500, "server error", {}, None),
|
HTTPError(self.client.url, 500, "server error", {}, None),
|
||||||
)
|
)
|
||||||
for failure in failures:
|
for failure in failures:
|
||||||
with self.subTest(failure=failure):
|
with self.subTest(failure=failure):
|
||||||
|
|||||||
Reference in new issue
Block a user