summaryrefslogtreecommitdiff
path: root/daq_system/devices/temperature.py
diff options
context:
space:
mode:
authorChristian Kolset <christian.kolset@gmail.com>2026-04-13 14:36:55 -0600
committerChristian Kolset <christian.kolset@gmail.com>2026-04-13 14:36:55 -0600
commit8d6acf3a8ea4b37f86b321dbf430be5be01b1267 (patch)
tree923251b7ee88c7b5c89500883154bad32a2ecca5 /daq_system/devices/temperature.py
init
Diffstat (limited to 'daq_system/devices/temperature.py')
-rw-r--r--daq_system/devices/temperature.py115
1 files changed, 115 insertions, 0 deletions
diff --git a/daq_system/devices/temperature.py b/daq_system/devices/temperature.py
new file mode 100644
index 0000000..5427cf6
--- /dev/null
+++ b/daq_system/devices/temperature.py
@@ -0,0 +1,115 @@
+"""
+devices/temperature.py
+
+Temperature sensor module — thermocouple / RTD / thermistor inputs.
+"""
+
+import math
+import random
+import time
+from typing import Any, Dict
+
+from PyQt6.QtWidgets import (
+ QWidget, QVBoxLayout, QFormLayout, QGroupBox,
+ QComboBox, QDoubleSpinBox, QLabel, QCheckBox
+)
+from devices.base_device import BaseDevice, ChannelConfig, DeviceInfo, DeviceStatus
+
+TEMP_COLORS = ["#ff6b35", "#ffcc00", "#c77dff", "#ff4d6d"]
+
+
+class TemperatureDevice(BaseDevice):
+ DEVICE_TYPE = "temperature"
+ ICON = "🌡"
+
+ def __init__(self, device_id: str = "temp_0", num_channels: int = 4,
+ simulate: bool = True, sensor_type: str = "thermocouple"):
+ channels = [
+ ChannelConfig(
+ channel_id=f"tc{i}", name=f"TC {i}",
+ unit="°C", min_value=-200.0, max_value=1200.0,
+ alarm_low=0.0, alarm_high=100.0,
+ color=TEMP_COLORS[i % len(TEMP_COLORS)]
+ )
+ for i in range(num_channels)
+ ]
+ info = DeviceInfo(
+ device_id=device_id, name="Temperature",
+ device_type=self.DEVICE_TYPE,
+ description=f"{sensor_type.title()} temperature input",
+ icon=self.ICON, channels=channels
+ )
+ super().__init__(info)
+ self.simulate = simulate
+ self.sensor_type = sensor_type
+ self._start = time.time()
+ # Simulate slow thermal drift
+ self._targets = [20.0 + i * 5 for i in range(num_channels)]
+ self._currents = [20.0 + i * 5 for i in range(num_channels)]
+
+ def connect(self) -> bool:
+ self._start = time.time()
+ self.status = DeviceStatus.SIMULATED if self.simulate else DeviceStatus.ERROR
+ return self.simulate
+
+ def disconnect(self) -> None:
+ self.status = DeviceStatus.DISCONNECTED
+
+ def read_channels(self) -> Dict[str, float]:
+ result = {}
+ for i, ch in enumerate(self.info.channels):
+ if not ch.enabled:
+ continue
+ # Slow drift toward target with noise
+ diff = self._targets[i] - self._currents[i]
+ self._currents[i] += diff * 0.05 + random.gauss(0, 0.02)
+ # Occasionally shift target
+ if random.random() < 0.01:
+ self._targets[i] += random.gauss(0, 2.0)
+ self._targets[i] = max(10.0, min(200.0, self._targets[i]))
+ result[ch.channel_id] = round(self._currents[i], 2)
+ return result
+
+ def write_channel(self, channel_id: str, value: Any) -> bool:
+ return False # Read-only
+
+ def get_config_widget(self) -> QWidget:
+ w = QWidget()
+ layout = QVBoxLayout(w)
+ grp = QGroupBox("Sensor Configuration")
+ form = QFormLayout(grp)
+
+ sensor_cb = QComboBox()
+ sensor_cb.addItems(["thermocouple", "rtd", "thermistor", "ic_sensor"])
+ sensor_cb.setCurrentText(self.sensor_type)
+ form.addRow("Sensor Type:", sensor_cb)
+
+ tc_type = QComboBox()
+ tc_type.addItems(["K", "J", "T", "E", "N", "R", "S", "B"])
+ form.addRow("TC Type:", tc_type)
+
+ unit_cb = QComboBox()
+ unit_cb.addItems(["°C", "°F", "K"])
+ form.addRow("Units:", unit_cb)
+
+ layout.addWidget(grp)
+
+ # Alarm config per channel
+ alarm_grp = QGroupBox("Alarm Setpoints")
+ alarm_layout = QVBoxLayout(alarm_grp)
+ for ch in self.info.channels:
+ row_layout = QFormLayout()
+ lo = QDoubleSpinBox()
+ lo.setRange(-200, 1200)
+ lo.setValue(ch.alarm_low or 0.0)
+ lo.setSuffix(" °C")
+ hi = QDoubleSpinBox()
+ hi.setRange(-200, 1200)
+ hi.setValue(ch.alarm_high or 100.0)
+ hi.setSuffix(" °C")
+ row_layout.addRow(f"{ch.name} Low:", lo)
+ row_layout.addRow(f"{ch.name} High:", hi)
+ alarm_layout.addLayout(row_layout)
+ layout.addWidget(alarm_grp)
+ layout.addStretch()
+ return w