Public Access
160 lines
5.6 KiB
Python
160 lines
5.6 KiB
Python
# -*- coding: iso-8859-1 -*-
|
|
"""
|
|
Temperature monitoring thread.
|
|
|
|
This module provides a thread that periodically reads temperature from a controller
|
|
and stores it in a TemperatureResult object.
|
|
"""
|
|
|
|
import threading
|
|
import time
|
|
import datetime
|
|
|
|
from damaris.data import TemperatureResult
|
|
from damaris.tools.temperature import TemperatureController
|
|
|
|
|
|
class TemperatureMonitor(threading.Thread):
|
|
"""
|
|
Thread that periodically reads temperature from a controller
|
|
and stores it in a TemperatureResult object.
|
|
|
|
This thread runs independently and can be configured with any
|
|
TemperatureController implementation (Eurotherm, Lakeshore, etc.).
|
|
|
|
Attributes:
|
|
controller: The TemperatureController instance to read from.
|
|
interval: Polling interval in seconds.
|
|
result: The TemperatureResult object storing collected data.
|
|
quit_flag: Event to signal the thread to stop.
|
|
data_pool: Optional DataPool to store results.
|
|
data_key: Key to use when storing in data_pool.
|
|
"""
|
|
|
|
def __init__(self, controller: TemperatureController,
|
|
interval: float = 1.0,
|
|
data_pool=None,
|
|
data_key: str = "temperature"):
|
|
"""
|
|
Initialize the temperature monitor.
|
|
|
|
Args:
|
|
controller: TemperatureController implementation (Eurotherm, etc.)
|
|
interval: Polling interval in seconds (default: 1.0)
|
|
data_pool: Optional DataPool to store results (default: None)
|
|
data_key: Key to use when storing in data_pool (default: "temperature")
|
|
"""
|
|
threading.Thread.__init__(self, name="TemperatureMonitor")
|
|
self.controller = controller
|
|
self.interval = float(interval)
|
|
self.data_pool = data_pool
|
|
self.data_key = data_key
|
|
self.quit_flag = threading.Event()
|
|
self.result = TemperatureResult()
|
|
self._running = False
|
|
self._lock = threading.RLock()
|
|
|
|
# Initialize the result with metadata
|
|
self.result.xlabel = "Time (s)"
|
|
self.result.ylabel = "Temperature (C)"
|
|
self.result.description = {"type": "temperature_monitoring"}
|
|
|
|
def run(self):
|
|
"""
|
|
Main thread loop: periodically reads temperature and stores it.
|
|
"""
|
|
self._running = True
|
|
start_time = time.time()
|
|
|
|
while not self.quit_flag.is_set() and self._running:
|
|
try:
|
|
# Read temperature and setpoint
|
|
timestamp = time.time() - start_time
|
|
current_temp = self.controller.get_temperature()
|
|
setpoint = self.controller.get_setpoint()
|
|
|
|
# Store in result
|
|
with self._lock:
|
|
if not hasattr(self.result, 'x'):
|
|
self.result.x = []
|
|
self.result.y = []
|
|
self.result.setpoint = []
|
|
|
|
self.result.x.append(timestamp)
|
|
self.result.y.append(current_temp)
|
|
self.result.setpoint.append(setpoint)
|
|
|
|
# Update job metadata on first sample
|
|
if len(self.result.x) == 1:
|
|
self.result.job_date = datetime.datetime.now()
|
|
self.result.job_id = id(self)
|
|
|
|
# Optional: store in data_pool
|
|
if self.data_pool is not None:
|
|
with self._lock:
|
|
self.data_pool[self.data_key] = self.result
|
|
|
|
except Exception as e:
|
|
print(f"TemperatureMonitor error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
# Sleep in small increments for responsive shutdown
|
|
sleep_remaining = self.interval
|
|
while sleep_remaining > 0 and not self.quit_flag.is_set() and self._running:
|
|
sleep_time = min(0.1, sleep_remaining)
|
|
self.quit_flag.wait(sleep_time)
|
|
sleep_remaining -= sleep_time
|
|
|
|
def stop(self):
|
|
"""
|
|
Graceful shutdown: signal the thread to stop and wait for it.
|
|
"""
|
|
self._running = False
|
|
self.quit_flag.set()
|
|
# Wait for the thread to finish its current iteration
|
|
self.join(timeout=self.interval + 0.5)
|
|
|
|
def reset(self):
|
|
"""
|
|
Clear the collected data and start fresh.
|
|
"""
|
|
with self._lock:
|
|
self.result = TemperatureResult()
|
|
self.result.xlabel = "Time (s)"
|
|
self.result.ylabel = "Temperature (C)"
|
|
self.result.description = {"type": "temperature_monitoring"}
|
|
|
|
def get_current_temperature(self) -> float:
|
|
"""
|
|
Get the latest temperature reading.
|
|
|
|
Returns:
|
|
float: Latest temperature in Celsius, or 0.0 if no data.
|
|
"""
|
|
with self._lock:
|
|
if hasattr(self.result, 'y') and len(self.result.y) > 0:
|
|
return self.result.y[-1]
|
|
return 0.0
|
|
|
|
def get_current_setpoint(self) -> float:
|
|
"""
|
|
Get the latest setpoint reading.
|
|
|
|
Returns:
|
|
float: Latest setpoint in Celsius, or 0.0 if no data.
|
|
"""
|
|
with self._lock:
|
|
if hasattr(self.result, 'setpoint') and len(self.result.setpoint) > 0:
|
|
return self.result.setpoint[-1]
|
|
return 0.0
|
|
|
|
def is_running(self) -> bool:
|
|
"""
|
|
Check if the monitor is currently running.
|
|
|
|
Returns:
|
|
bool: True if the monitor thread is active.
|
|
"""
|
|
return self._running and not self.quit_flag.is_set()
|