summaryrefslogtreecommitdiff
path: root/daq_system/devices/temperature.py
blob: 5427cf6fa937d407d99185aefc6373a8211cfadd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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