forked from M-Labs/thermostat
Compare commits
88 Commits
3f32c9a4a2
...
70627342f3
Author | SHA1 | Date | |
---|---|---|---|
70627342f3 | |||
ffa0783cff | |||
ba6b24fe95 | |||
2e0ecd9758 | |||
199aeb3609 | |||
1e81641169 | |||
2c95bd9d09 | |||
d83c4ed4f6 | |||
637d8d029a | |||
671004703b | |||
10873933f4 | |||
ec1fffecd1 | |||
36c063d917 | |||
65b9202cea | |||
a72a0606f1 | |||
81f09a9f0f | |||
f768ea5d4f | |||
e849610658 | |||
bbe9a60824 | |||
cd07cdeddd | |||
fe3a22a599 | |||
2b35bf57f9 | |||
8a83bbc1d1 | |||
82315d65b2 | |||
dfe08546fe | |||
c4309c5ba0 | |||
3387ad67f7 | |||
903f9f8767 | |||
aadf8a2595 | |||
49561a2f5a | |||
b32b38d830 | |||
fcda46d1f3 | |||
89e9da4499 | |||
87ca0694cd | |||
03233386d0 | |||
242a2b2e69 | |||
b84af82722 | |||
7997ef2472 | |||
911b4c680f | |||
19677c2251 | |||
5f30f12875 | |||
3283b126b8 | |||
59ba8c692d | |||
e3ef9115a5 | |||
c5c311ae14 | |||
6699458939 | |||
8a4a963f9b | |||
2f10ad8056 | |||
3731282146 | |||
50ac1c2078 | |||
0eebc0a6df | |||
78ba799d56 | |||
f9c0f140fa | |||
93d96401b9 | |||
881bf6ff6c | |||
7e0dd61f79 | |||
ed34eb9e03 | |||
387d1226c5 | |||
058e597ef0 | |||
80975f50b1 | |||
86afa19085 | |||
4b6dfdf478 | |||
85cb2027a8 | |||
4fedb14727 | |||
863920f922 | |||
96b57f199d | |||
f2da457860 | |||
066c75fc21 | |||
60b05ddfeb | |||
6a78a2069d | |||
6eb5b7298e | |||
4a292c19db | |||
0b115b3394 | |||
2e904cb498 | |||
d3f378f058 | |||
d0273cd41b | |||
0988ed24d6 | |||
ab3b26a2a4 | |||
000b97398b | |||
e162bcf210 | |||
c3d7804898 | |||
9c0977262c | |||
017206bd34 | |||
f46bd2b50e | |||
5b48fb2793 | |||
358403e651 | |||
4a48379923 | |||
b766e949e8 |
@ -1,7 +1,19 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
from contextlib import suppress
|
||||||
from pytec.aioclient import AsyncioClient
|
from pytec.aioclient import AsyncioClient
|
||||||
|
|
||||||
|
|
||||||
|
async def poll_for_info(tec):
|
||||||
|
while True:
|
||||||
|
print(tec.get_pwm())
|
||||||
|
print(tec.get_steinhart_hart())
|
||||||
|
print(tec.get_pid())
|
||||||
|
print(tec.get_postfilter())
|
||||||
|
print(tec.get_fan())
|
||||||
|
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
tec = AsyncioClient()
|
tec = AsyncioClient()
|
||||||
await tec.connect() # (host="192.168.1.26", port=23)
|
await tec.connect() # (host="192.168.1.26", port=23)
|
||||||
@ -11,8 +23,14 @@ async def main():
|
|||||||
print(await tec.get_pwm())
|
print(await tec.get_pwm())
|
||||||
print(await tec.get_postfilter())
|
print(await tec.get_postfilter())
|
||||||
print(await tec.get_steinhart_hart())
|
print(await tec.get_steinhart_hart())
|
||||||
|
|
||||||
|
polling_task = asyncio.create_task(poll_for_info(tec))
|
||||||
|
|
||||||
async for data in tec.report_mode():
|
async for data in tec.report_mode():
|
||||||
print(data)
|
print(data)
|
||||||
|
|
||||||
|
polling_task.cancel()
|
||||||
|
with suppress(asyncio.CancelledError):
|
||||||
|
await polling_task
|
||||||
|
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
@ -11,7 +11,6 @@ class PIDAutoTuner(QObject):
|
|||||||
|
|
||||||
self._thermostat = thermostat
|
self._thermostat = thermostat
|
||||||
self._thermostat.report_update.connect(self.tick)
|
self._thermostat.report_update.connect(self.tick)
|
||||||
self._thermostat.interval_update.connect(self.update_sampling_interval)
|
|
||||||
|
|
||||||
self.autotuners = [PIDAutotune(25) for _ in range(num_of_channel)]
|
self.autotuners = [PIDAutotune(25) for _ in range(num_of_channel)]
|
||||||
self.target_temp = [20.0 for _ in range(num_of_channel)]
|
self.target_temp = [20.0 for _ in range(num_of_channel)]
|
||||||
@ -20,10 +19,6 @@ class PIDAutoTuner(QObject):
|
|||||||
self.lookback = [3.0 for _ in range(num_of_channel)]
|
self.lookback = [3.0 for _ in range(num_of_channel)]
|
||||||
self.sampling_interval = [1 / 16.67 for _ in range(num_of_channel)]
|
self.sampling_interval = [1 / 16.67 for _ in range(num_of_channel)]
|
||||||
|
|
||||||
@pyqtSlot(list)
|
|
||||||
def update_sampling_interval(self, interval):
|
|
||||||
self.sampling_interval = interval
|
|
||||||
|
|
||||||
def set_params(self, params_name, ch, val):
|
def set_params(self, params_name, ch, val):
|
||||||
getattr(self, params_name)[ch] = val
|
getattr(self, params_name)[ch] = val
|
||||||
|
|
||||||
@ -50,11 +45,14 @@ class PIDAutoTuner(QObject):
|
|||||||
@asyncSlot(list)
|
@asyncSlot(list)
|
||||||
async def tick(self, report):
|
async def tick(self, report):
|
||||||
for channel_report in report:
|
for channel_report in report:
|
||||||
|
ch = channel_report["channel"]
|
||||||
|
|
||||||
|
self.sampling_interval[ch] = channel_report["interval"]
|
||||||
|
|
||||||
# TODO: Skip when PID Autotune or emit error message if NTC is not connected
|
# TODO: Skip when PID Autotune or emit error message if NTC is not connected
|
||||||
if channel_report["temperature"] is None:
|
if channel_report["temperature"] is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ch = channel_report["channel"]
|
|
||||||
match self.autotuners[ch].state():
|
match self.autotuners[ch].state():
|
||||||
case (
|
case (
|
||||||
PIDAutotuneState.STATE_READY
|
PIDAutotuneState.STATE_READY
|
||||||
|
@ -20,7 +20,6 @@ class Thermostat(QObject, metaclass=PropertyMeta):
|
|||||||
pid = Property(list)
|
pid = Property(list)
|
||||||
pwm = Property(list)
|
pwm = Property(list)
|
||||||
postfilter = Property(list)
|
postfilter = Property(list)
|
||||||
interval = Property(list)
|
|
||||||
report = Property(list)
|
report = Property(list)
|
||||||
|
|
||||||
connection_error = pyqtSignal()
|
connection_error = pyqtSignal()
|
||||||
@ -54,36 +53,45 @@ class Thermostat(QObject, metaclass=PropertyMeta):
|
|||||||
"Encountered an error while polling for information from Thermostat.",
|
"Encountered an error while polling for information from Thermostat.",
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
self.handle_connection_error()
|
await self.handle_connection_error()
|
||||||
return
|
return
|
||||||
self._update_params_task = asyncio.create_task(self.update_params())
|
self._update_params_task = asyncio.create_task(self.update_params())
|
||||||
await asyncio.sleep(self._update_s)
|
await asyncio.sleep(self._update_s)
|
||||||
|
|
||||||
def handle_connection_error(self):
|
async def handle_connection_error(self):
|
||||||
self.end_session()
|
await self.end_session()
|
||||||
self.connection_error.emit()
|
self.connection_error.emit()
|
||||||
|
|
||||||
async def get_hw_rev(self):
|
async def get_hw_rev(self):
|
||||||
return await self._client.hw_rev()
|
return await self._client.hw_rev()
|
||||||
|
|
||||||
async def update_params(self):
|
async def update_params(self):
|
||||||
fan_task = asyncio.create_task(self._client.get_fan())
|
|
||||||
pwm_task = asyncio.create_task(self._client.get_pwm())
|
|
||||||
pid_task = asyncio.create_task(self._client.get_pid())
|
|
||||||
report_task = asyncio.create_task(self._client.report())
|
|
||||||
thermistor_task = asyncio.create_task(self._client.get_steinhart_hart())
|
|
||||||
postfilter_task = asyncio.create_task(self._client.get_postfilter())
|
|
||||||
|
|
||||||
self.fan = await fan_task
|
|
||||||
self.pwm = await pwm_task
|
|
||||||
if self._poll_for_report:
|
if self._poll_for_report:
|
||||||
self.report = await report_task
|
(
|
||||||
self.interval = [
|
self.fan,
|
||||||
self.report[i]["interval"] for i in range(len(self.report))
|
self.pwm,
|
||||||
]
|
self.report,
|
||||||
self.pid = await pid_task
|
self.pid,
|
||||||
self.thermistor = await thermistor_task
|
self.thermistor,
|
||||||
self.postfilter = await postfilter_task
|
self.postfilter,
|
||||||
|
) = await asyncio.gather(
|
||||||
|
self._client.get_fan(),
|
||||||
|
self._client.get_pwm(),
|
||||||
|
self._client.report(),
|
||||||
|
self._client.get_pid(),
|
||||||
|
self._client.get_steinhart_hart(),
|
||||||
|
self._client.get_postfilter(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.fan, self.pwm, self.pid, self.thermistor, self.postfilter = (
|
||||||
|
await asyncio.gather(
|
||||||
|
self._client.get_fan(),
|
||||||
|
self._client.get_pwm(),
|
||||||
|
self._client.get_pid(),
|
||||||
|
self._client.get_steinhart_hart(),
|
||||||
|
self._client.get_postfilter(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def connected(self):
|
def connected(self):
|
||||||
return self._client.connected()
|
return self._client.connected()
|
||||||
@ -110,9 +118,6 @@ class Thermostat(QObject, metaclass=PropertyMeta):
|
|||||||
async def report_mode(self):
|
async def report_mode(self):
|
||||||
async for report in self._client.report_mode():
|
async for report in self._client.report_mode():
|
||||||
self.report_update.emit(report)
|
self.report_update.emit(report)
|
||||||
self.interval = [
|
|
||||||
self.report[i]["interval"] for i in range(len(self.report))
|
|
||||||
]
|
|
||||||
|
|
||||||
@asyncSlot()
|
@asyncSlot()
|
||||||
async def end_session(self):
|
async def end_session(self):
|
||||||
|
@ -285,19 +285,6 @@ class CtrlPanel(QObject):
|
|||||||
f"Channel {ch} PID Autotune has failed.",
|
f"Channel {ch} PID Autotune has failed.",
|
||||||
)
|
)
|
||||||
|
|
||||||
@asyncSlot()
|
|
||||||
async def pid_auto_tune_request(self, ch):
|
|
||||||
match self.autotuners.get_state(ch):
|
|
||||||
case PIDAutotuneState.STATE_OFF | PIDAutotuneState.STATE_FAILED:
|
|
||||||
self.autotuners.load_params_and_set_ready(ch)
|
|
||||||
|
|
||||||
case (
|
|
||||||
PIDAutotuneState.STATE_READY
|
|
||||||
| PIDAutotuneState.STATE_RELAY_STEP_UP
|
|
||||||
| PIDAutotuneState.STATE_RELAY_STEP_DOWN
|
|
||||||
):
|
|
||||||
await self.autotuners.stop_pid_from_running(ch)
|
|
||||||
|
|
||||||
@asyncSlot(int)
|
@asyncSlot(int)
|
||||||
async def load_settings(self, ch):
|
async def load_settings(self, ch):
|
||||||
await self.thermostat.load_cfg(ch)
|
await self.thermostat.load_cfg(ch)
|
||||||
@ -316,3 +303,17 @@ class CtrlPanel(QObject):
|
|||||||
f"Channel {ch} settings has been saved to flash.\n"
|
f"Channel {ch} settings has been saved to flash.\n"
|
||||||
"It will be loaded on Thermostat reset, or when settings are explicitly loaded.",
|
"It will be loaded on Thermostat reset, or when settings are explicitly loaded.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@asyncSlot()
|
||||||
|
async def pid_auto_tune_request(self, ch=0):
|
||||||
|
match self.autotuners.get_state(ch):
|
||||||
|
case PIDAutotuneState.STATE_OFF | PIDAutotuneState.STATE_FAILED:
|
||||||
|
self.autotuners.load_params_and_set_ready(ch)
|
||||||
|
|
||||||
|
case (
|
||||||
|
PIDAutotuneState.STATE_READY
|
||||||
|
| PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||||
|
| PIDAutotuneState.STATE_RELAY_STEP_DOWN
|
||||||
|
):
|
||||||
|
await self.autotuners.stop_pid_from_running(ch)
|
||||||
|
|
||||||
|
@ -59,9 +59,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.info_box = InfoBox()
|
self.info_box = InfoBox()
|
||||||
|
|
||||||
# Models
|
# Models
|
||||||
self.thermostat = Thermostat(
|
self.thermostat = Thermostat(self, self.report_refresh_spin.value())
|
||||||
self, self.report_refresh_spin.value()
|
|
||||||
)
|
|
||||||
self._connecting_task = None
|
self._connecting_task = None
|
||||||
self.thermostat.connection_state_changed.connect(self._on_connection_changed)
|
self.thermostat.connection_state_changed.connect(self._on_connection_changed)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user