forked from M-Labs/thermostat
Compare commits
11 Commits
57d366e4d7
...
ff718ffdef
Author | SHA1 | Date | |
---|---|---|---|
ff718ffdef | |||
dd9e5fe195 | |||
a5c40f706a | |||
c8af8cb61f | |||
23ce99d6d8 | |||
d594c93166 | |||
e3abe9384a | |||
33ef98c5a8 | |||
9305d766d1 | |||
1f406fad38 | |||
e8b217d0fc |
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -99,15 +99,15 @@ dependencies = [
|
|||||||
"aligned",
|
"aligned",
|
||||||
"bare-metal 0.2.5",
|
"bare-metal 0.2.5",
|
||||||
"bitfield",
|
"bitfield",
|
||||||
"cortex-m 0.7.4",
|
"cortex-m 0.7.7",
|
||||||
"volatile-register",
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cortex-m"
|
name = "cortex-m"
|
||||||
version = "0.7.4"
|
version = "0.7.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37ff967e867ca14eba0c34ac25cd71ea98c678e741e3915d923999bb2fe7c826"
|
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bare-metal 0.2.5",
|
"bare-metal 0.2.5",
|
||||||
"bitfield",
|
"bitfield",
|
||||||
@ -173,7 +173,7 @@ version = "0.3.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc"
|
checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m 0.7.4",
|
"cortex-m 0.6.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -371,7 +371,7 @@ version = "0.5.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3d55dedd501dfd02514646e0af4d7016ce36bc12ae177ef52056989966a1eec"
|
checksum = "c3d55dedd501dfd02514646e0af4d7016ce36bc12ae177ef52056989966a1eec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m 0.7.4",
|
"cortex-m 0.6.7",
|
||||||
"cortex-m-semihosting",
|
"cortex-m-semihosting",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -520,7 +520,7 @@ version = "0.2.0"
|
|||||||
source = "git+https://github.com/stm32-rs/stm32-eth.git?rev=3759c5c9#3759c5c99c0ab69bb71759030766bc0fba0b6cde"
|
source = "git+https://github.com/stm32-rs/stm32-eth.git?rev=3759c5c9#3759c5c99c0ab69bb71759030766bc0fba0b6cde"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aligned",
|
"aligned",
|
||||||
"cortex-m 0.7.4",
|
"cortex-m 0.7.7",
|
||||||
"smoltcp",
|
"smoltcp",
|
||||||
"stm32f4xx-hal",
|
"stm32f4xx-hal",
|
||||||
"volatile-register",
|
"volatile-register",
|
||||||
@ -533,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "da3d56009c8f32e4f208dbea17df72484154d1040a8969b75d8c73eb7b18fe8f"
|
checksum = "da3d56009c8f32e4f208dbea17df72484154d1040a8969b75d8c73eb7b18fe8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bare-metal 0.2.5",
|
"bare-metal 0.2.5",
|
||||||
"cortex-m 0.7.4",
|
"cortex-m 0.6.7",
|
||||||
"cortex-m-rt 0.6.13",
|
"cortex-m-rt 0.6.13",
|
||||||
"vcell",
|
"vcell",
|
||||||
]
|
]
|
||||||
@ -546,7 +546,7 @@ checksum = "3a06fde2dd27c0ba934c9e69b62af66eb1c20dbb6d741b187a763912e9892d13"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bare-metal 1.0.0",
|
"bare-metal 1.0.0",
|
||||||
"cast",
|
"cast",
|
||||||
"cortex-m 0.7.4",
|
"cortex-m 0.7.7",
|
||||||
"cortex-m-rt 0.7.1",
|
"cortex-m-rt 0.7.1",
|
||||||
"embedded-dma",
|
"embedded-dma",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
@ -587,7 +587,7 @@ dependencies = [
|
|||||||
"bare-metal 1.0.0",
|
"bare-metal 1.0.0",
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"cortex-m 0.6.7",
|
"cortex-m 0.7.7",
|
||||||
"cortex-m-log",
|
"cortex-m-log",
|
||||||
"cortex-m-rt 0.6.13",
|
"cortex-m-rt 0.6.13",
|
||||||
"eeprom24x",
|
"eeprom24x",
|
||||||
|
@ -18,7 +18,7 @@ panic-halt = "1.0"
|
|||||||
panic-semihosting = { version = "0.5", optional = true }
|
panic-semihosting = { version = "0.5", optional = true }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
bare-metal = "1"
|
bare-metal = "1"
|
||||||
cortex-m = "0.6"
|
cortex-m = "0.7"
|
||||||
cortex-m-rt = { version = "0.6", features = ["device"] }
|
cortex-m-rt = { version = "0.6", features = ["device"] }
|
||||||
cortex-m-log = { version = "0.6", features = ["log-integration"] }
|
cortex-m-log = { version = "0.6", features = ["log-integration"] }
|
||||||
stm32f4xx-hal = { version = "=0.10.1", features = ["rt", "stm32f427", "usb_fs"] }
|
stm32f4xx-hal = { version = "=0.10.1", features = ["rt", "stm32f427", "usb_fs"] }
|
||||||
|
@ -71,11 +71,11 @@ openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program target/thumbv
|
|||||||
|
|
||||||
A GUI has been developed for easy configuration and plotting of key parameters.
|
A GUI has been developed for easy configuration and plotting of key parameters.
|
||||||
|
|
||||||
The Python GUI program is located at pythermostat/pythermostat/thermostat_qt.py, and is developed based on the Python libraries PyQt and PyQtGraph. The GUI can be configured and
|
The Python GUI program is located at pythermostat/pythermostat/control_panel.py, and is developed based on the Python libraries PyQt and PyQtGraph. The GUI can be configured and
|
||||||
launched automatically by running:
|
launched automatically by running:
|
||||||
|
|
||||||
```
|
```
|
||||||
nix run .#thermostat_gui
|
nix run .#control_panel
|
||||||
```
|
```
|
||||||
|
|
||||||
## Command Line Usage
|
## Command Line Usage
|
||||||
@ -109,7 +109,7 @@ formatted as line-delimited JSON.
|
|||||||
| `output` | Show current output settings |
|
| `output` | Show current output settings |
|
||||||
| `output <0/1> max_i_pos <amp>` | Set maximum positive output current, clamped to [0, 2] |
|
| `output <0/1> max_i_pos <amp>` | Set maximum positive output current, clamped to [0, 2] |
|
||||||
| `output <0/1> max_i_neg <amp>` | Set maximum negative output current, clamped to [0, 2] |
|
| `output <0/1> max_i_neg <amp>` | Set maximum negative output current, clamped to [0, 2] |
|
||||||
| `output <0/1> max_v <volt>` | Set maximum output voltage, clamped to [0, 4] |
|
| `output <0/1> max_v <volt>` | Set maximum output voltage, clamped to [0, 4.3] |
|
||||||
| `output <0/1> i_set <amp>` | Disengage PID, set fixed output current, clamped to [-2, 2] |
|
| `output <0/1> i_set <amp>` | Disengage PID, set fixed output current, clamped to [-2, 2] |
|
||||||
| `output <0/1> polarity <normal/reversed>` | Set output current polarity, with 'normal' being the front panel polarity |
|
| `output <0/1> polarity <normal/reversed>` | Set output current polarity, with 'normal' being the front panel polarity |
|
||||||
| `output <0/1> pid` | Let output current to be controlled by the PID |
|
| `output <0/1> pid` | Let output current to be controlled by the PID |
|
||||||
|
14
flake.lock
generated
14
flake.lock
generated
@ -2,16 +2,16 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1722791413,
|
"lastModified": 1740865531,
|
||||||
"narHash": "sha256-rCTrlCWvHzMCNcKxPE3Z/mMK2gDZ+BvvpEVyRM4tKmU=",
|
"narHash": "sha256-h00vGIh/jxcGl8aWdfnVRD74KuLpyY3mZgMFMy7iKIc=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "8b5b6723aca5a51edf075936439d9cd3947b7b2c",
|
"rev": "5ef6c425980847c78a80d759abc476e941a9bf42",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-24.05",
|
"ref": "nixos-24.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@ -29,11 +29,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1719281921,
|
"lastModified": 1740969088,
|
||||||
"narHash": "sha256-LIBMfhM9pMOlEvBI757GOK5l0R58SRi6YpwfYMbf4yc=",
|
"narHash": "sha256-BajboqzFnDhxVT0SXTDKVJCKtFP96lZXccBlT/43mao=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "b6032d3a404d8a52ecfc8571ff0c26dfbe221d07",
|
"rev": "20fdb02098fdda9a25a2939b975abdd7bc03f62d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
13
flake.nix
13
flake.nix
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
description = "Firmware for the Sinara 8451 Thermostat";
|
description = "Firmware for the Sinara 8451 Thermostat";
|
||||||
|
|
||||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
|
||||||
inputs.rust-overlay = {
|
inputs.rust-overlay = {
|
||||||
url = "github:oxalica/rust-overlay";
|
url = "github:oxalica/rust-overlay";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
@ -64,7 +64,10 @@
|
|||||||
format = "pyproject";
|
format = "pyproject";
|
||||||
src = "${self}/pythermostat";
|
src = "${self}/pythermostat";
|
||||||
|
|
||||||
nativeBuildInputs = [ pkgs.qt6.wrapQtAppsHook ];
|
nativeBuildInputs = [
|
||||||
|
pkgs.python3Packages.setuptools
|
||||||
|
pkgs.qt6.wrapQtAppsHook
|
||||||
|
];
|
||||||
propagatedBuildInputs =
|
propagatedBuildInputs =
|
||||||
[ pkgs.qt6.qtbase ]
|
[ pkgs.qt6.qtbase ]
|
||||||
++ (with pkgs.python3Packages; [
|
++ (with pkgs.python3Packages; [
|
||||||
@ -78,7 +81,7 @@
|
|||||||
|
|
||||||
dontWrapQtApps = true;
|
dontWrapQtApps = true;
|
||||||
postFixup = ''
|
postFixup = ''
|
||||||
wrapQtApp "$out/bin/thermostat_qt"
|
wrapQtApp "$out/bin/thermostat_control_panel"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,9 +106,9 @@
|
|||||||
default = thermostat;
|
default = thermostat;
|
||||||
};
|
};
|
||||||
|
|
||||||
apps.x86_64-linux.thermostat_gui = {
|
apps.x86_64-linux.control_panel = {
|
||||||
type = "app";
|
type = "app";
|
||||||
program = "${self.packages.x86_64-linux.pythermostat}/bin/thermostat_qt";
|
program = "${pythermostat}/bin/thermostat_control_panel";
|
||||||
};
|
};
|
||||||
|
|
||||||
hydraJobs = {
|
hydraJobs = {
|
||||||
|
@ -20,7 +20,7 @@ dependencies = [
|
|||||||
|
|
||||||
[project.gui-scripts]
|
[project.gui-scripts]
|
||||||
thermostat_plot = "pythermostat.plot:main"
|
thermostat_plot = "pythermostat.plot:main"
|
||||||
thermostat_qt = "pythermostat.thermostat_qt:main"
|
thermostat_control_panel = "pythermostat.control_panel:main"
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
thermostat_autotune = "pythermostat.autotune:main"
|
thermostat_autotune = "pythermostat.autotune:main"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"""GUI for the Sinara 8451 Thermostat"""
|
"""GUI Control Panel for the Sinara 8451 Thermostat"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
@ -84,15 +84,15 @@ class CtrlPanel(QObject):
|
|||||||
self.params[i].setValue = self._setValue
|
self.params[i].setValue = self._setValue
|
||||||
self.params[i].sigTreeStateChanged.connect(self.send_command)
|
self.params[i].sigTreeStateChanged.connect(self.send_command)
|
||||||
|
|
||||||
self.params[i].child("Save to flash").sigActivated.connect(
|
self.params[i].child("save").sigActivated.connect(
|
||||||
partial(self.save_settings, i)
|
partial(self.save_settings, i)
|
||||||
)
|
)
|
||||||
self.params[i].child("Load from flash").sigActivated.connect(
|
self.params[i].child("load").sigActivated.connect(
|
||||||
partial(self.load_settings, i)
|
partial(self.load_settings, i)
|
||||||
)
|
)
|
||||||
self.params[i].child(
|
self.params[i].child("pid", "pid_autotune", "run_pid").sigActivated.connect(
|
||||||
"PID Config", "PID Auto Tune", "Run"
|
partial(self.pid_auto_tune_request, i)
|
||||||
).sigActivated.connect(partial(self.pid_auto_tune_request, i))
|
)
|
||||||
|
|
||||||
self.thermostat.pid_update.connect(self.update_pid)
|
self.thermostat.pid_update.connect(self.update_pid)
|
||||||
self.thermostat.report_update.connect(self.update_report)
|
self.thermostat.report_update.connect(self.update_report)
|
||||||
@ -146,13 +146,13 @@ class CtrlPanel(QObject):
|
|||||||
|
|
||||||
# Handle thermostat command irregularities
|
# Handle thermostat command irregularities
|
||||||
match inner_param.name(), new_value:
|
match inner_param.name(), new_value:
|
||||||
case "Postfilter Rate", None:
|
case "rate", None:
|
||||||
thermostat_param = thermostat_param.copy()
|
thermostat_param = thermostat_param.copy()
|
||||||
thermostat_param["field"] = "off"
|
thermostat_param["field"] = "off"
|
||||||
new_value = ""
|
new_value = ""
|
||||||
case "Control Method", "Constant Current":
|
case "control_method", "constant_current":
|
||||||
return
|
return
|
||||||
case "Control Method", "Temperature PID":
|
case "control_method", "temperature_pid":
|
||||||
new_value = ""
|
new_value = ""
|
||||||
|
|
||||||
inner_param.setOpts(lock=True)
|
inner_param.setOpts(lock=True)
|
||||||
@ -170,23 +170,23 @@ class CtrlPanel(QObject):
|
|||||||
for settings in pid_settings:
|
for settings in pid_settings:
|
||||||
channel = settings["channel"]
|
channel = settings["channel"]
|
||||||
with QSignalBlocker(self.params[channel]):
|
with QSignalBlocker(self.params[channel]):
|
||||||
self.params[channel].child("PID Config", "Kp").setValue(
|
self.params[channel].child("pid", "kp").setValue(
|
||||||
settings["parameters"]["kp"]
|
settings["parameters"]["kp"]
|
||||||
)
|
)
|
||||||
self.params[channel].child("PID Config", "Ki").setValue(
|
self.params[channel].child("pid", "ki").setValue(
|
||||||
settings["parameters"]["ki"]
|
settings["parameters"]["ki"]
|
||||||
)
|
)
|
||||||
self.params[channel].child("PID Config", "Kd").setValue(
|
self.params[channel].child("pid", "kd").setValue(
|
||||||
settings["parameters"]["kd"]
|
settings["parameters"]["kd"]
|
||||||
)
|
)
|
||||||
self.params[channel].child(
|
self.params[channel].child(
|
||||||
"PID Config", "PID Output Clamping", "Minimum"
|
"pid", "pid_output_clamping", "output_min"
|
||||||
).setValue(settings["parameters"]["output_min"] * 1000)
|
).setValue(settings["parameters"]["output_min"] * 1000)
|
||||||
self.params[channel].child(
|
self.params[channel].child(
|
||||||
"PID Config", "PID Output Clamping", "Maximum"
|
"pid", "pid_output_clamping", "output_max"
|
||||||
).setValue(settings["parameters"]["output_max"] * 1000)
|
).setValue(settings["parameters"]["output_max"] * 1000)
|
||||||
self.params[channel].child(
|
self.params[channel].child(
|
||||||
"Output Config", "Control Method", "Set Temperature"
|
"output", "control_method", "target"
|
||||||
).setValue(settings["target"])
|
).setValue(settings["target"])
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@pyqtSlot(list)
|
||||||
@ -194,18 +194,18 @@ class CtrlPanel(QObject):
|
|||||||
for settings in report_data:
|
for settings in report_data:
|
||||||
channel = settings["channel"]
|
channel = settings["channel"]
|
||||||
with QSignalBlocker(self.params[channel]):
|
with QSignalBlocker(self.params[channel]):
|
||||||
self.params[channel].child("Output Config", "Control Method").setValue(
|
self.params[channel].child("output", "control_method").setValue(
|
||||||
"Temperature PID" if settings["pid_engaged"] else "Constant Current"
|
"temperature_pid" if settings["pid_engaged"] else "constant_current"
|
||||||
)
|
)
|
||||||
self.params[channel].child(
|
self.params[channel].child(
|
||||||
"Output Config", "Control Method", "Set Current"
|
"output", "control_method", "i_set"
|
||||||
).setValue(settings["i_set"] * 1000)
|
).setValue(settings["i_set"] * 1000)
|
||||||
if settings["temperature"] is not None:
|
if settings["temperature"] is not None:
|
||||||
self.params[channel].child("Temperature").setValue(
|
self.params[channel].child("readings", "temperature").setValue(
|
||||||
settings["temperature"]
|
settings["temperature"]
|
||||||
)
|
)
|
||||||
if settings["tec_i"] is not None:
|
if settings["tec_i"] is not None:
|
||||||
self.params[channel].child("Current through TEC").setValue(
|
self.params[channel].child("readings", "tec_i").setValue(
|
||||||
settings["tec_i"] * 1000
|
settings["tec_i"] * 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -214,13 +214,13 @@ class CtrlPanel(QObject):
|
|||||||
for sh_param in sh_data:
|
for sh_param in sh_data:
|
||||||
channel = sh_param["channel"]
|
channel = sh_param["channel"]
|
||||||
with QSignalBlocker(self.params[channel]):
|
with QSignalBlocker(self.params[channel]):
|
||||||
self.params[channel].child("Thermistor Config", "T₀").setValue(
|
self.params[channel].child("thermistor", "t0").setValue(
|
||||||
sh_param["params"]["t0"] - 273.15
|
sh_param["params"]["t0"] - 273.15
|
||||||
)
|
)
|
||||||
self.params[channel].child("Thermistor Config", "R₀").setValue(
|
self.params[channel].child("thermistor", "r0").setValue(
|
||||||
sh_param["params"]["r0"]
|
sh_param["params"]["r0"]
|
||||||
)
|
)
|
||||||
self.params[channel].child("Thermistor Config", "B").setValue(
|
self.params[channel].child("thermistor", "b").setValue(
|
||||||
sh_param["params"]["b"]
|
sh_param["params"]["b"]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -229,39 +229,35 @@ class CtrlPanel(QObject):
|
|||||||
for output_params in output_data:
|
for output_params in output_data:
|
||||||
channel = output_params["channel"]
|
channel = output_params["channel"]
|
||||||
with QSignalBlocker(self.params[channel]):
|
with QSignalBlocker(self.params[channel]):
|
||||||
self.params[channel].child(
|
self.params[channel].child("output", "limits", "max_v").setValue(
|
||||||
"Output Config", "Limits", "Max Voltage Difference"
|
output_params["max_v"]
|
||||||
).setValue(output_params["max_v"])
|
)
|
||||||
self.params[channel].child(
|
self.params[channel].child("output", "limits", "max_i_pos").setValue(
|
||||||
"Output Config", "Limits", "Max Cooling Current"
|
output_params["max_i_pos"] * 1000
|
||||||
).setValue(output_params["max_i_pos"] * 1000)
|
)
|
||||||
self.params[channel].child(
|
self.params[channel].child("output", "limits", "max_i_neg").setValue(
|
||||||
"Output Config", "Limits", "Max Heating Current"
|
output_params["max_i_neg"] * 1000
|
||||||
).setValue(output_params["max_i_neg"] * 1000)
|
)
|
||||||
|
|
||||||
@pyqtSlot(list)
|
@pyqtSlot(list)
|
||||||
def update_postfilter(self, postfilter_data):
|
def update_postfilter(self, postfilter_data):
|
||||||
for postfilter_params in postfilter_data:
|
for postfilter_params in postfilter_data:
|
||||||
channel = postfilter_params["channel"]
|
channel = postfilter_params["channel"]
|
||||||
with QSignalBlocker(self.params[channel]):
|
with QSignalBlocker(self.params[channel]):
|
||||||
self.params[channel].child(
|
self.params[channel].child("thermistor", "rate").setValue(
|
||||||
"Thermistor Config", "Postfilter Rate"
|
postfilter_params["rate"]
|
||||||
).setValue(postfilter_params["rate"])
|
)
|
||||||
|
|
||||||
def update_pid_autotune(self, ch, state):
|
def update_pid_autotune(self, ch, state):
|
||||||
match state:
|
match state:
|
||||||
case PIDAutotuneState.OFF:
|
case PIDAutotuneState.OFF:
|
||||||
self.change_params_title(
|
self.change_params_title(ch, ("pid", "pid_autotune", "run_pid"), "Run")
|
||||||
ch, ("PID Config", "PID Auto Tune", "Run"), "Run"
|
|
||||||
)
|
|
||||||
case (
|
case (
|
||||||
PIDAutotuneState.READY
|
PIDAutotuneState.READY
|
||||||
| PIDAutotuneState.RELAY_STEP_UP
|
| PIDAutotuneState.RELAY_STEP_UP
|
||||||
| PIDAutotuneState.RELAY_STEP_DOWN
|
| PIDAutotuneState.RELAY_STEP_DOWN
|
||||||
):
|
):
|
||||||
self.change_params_title(
|
self.change_params_title(ch, ("pid", "pid_autotune", "run_pid"), "Stop")
|
||||||
ch, ("PID Config", "PID Auto Tune", "Run"), "Stop"
|
|
||||||
)
|
|
||||||
case PIDAutotuneState.SUCCEEDED:
|
case PIDAutotuneState.SUCCEEDED:
|
||||||
self.info_box.display_info_box(
|
self.info_box.display_info_box(
|
||||||
"PID Autotune Success",
|
"PID Autotune Success",
|
||||||
|
@ -1,38 +1,50 @@
|
|||||||
{
|
{
|
||||||
"ctrl_panel": [
|
"ctrl_panel": [
|
||||||
{
|
{
|
||||||
"name": "Temperature",
|
"name": "readings",
|
||||||
"type": "float",
|
"title": "Readings",
|
||||||
"format": "{value:.4f} °C",
|
"type": "group",
|
||||||
"readonly": true
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "temperature",
|
||||||
|
"title": "Temperature",
|
||||||
|
"type": "float",
|
||||||
|
"format": "{value:.4f} °C",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tec_i",
|
||||||
|
"title": "Current through TEC",
|
||||||
|
"type": "float",
|
||||||
|
"suffix": "mA",
|
||||||
|
"decimals": 6,
|
||||||
|
"readonly": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Current through TEC",
|
"name": "output",
|
||||||
"type": "float",
|
"title": "Output Config",
|
||||||
"suffix": "mA",
|
|
||||||
"decimals": 6,
|
|
||||||
"readonly": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Output Config",
|
|
||||||
"expanded": true,
|
"expanded": true,
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "Control Method",
|
"name": "control_method",
|
||||||
|
"title": "Control Method",
|
||||||
"type": "mutex",
|
"type": "mutex",
|
||||||
"limits": [
|
"limits": {
|
||||||
"Constant Current",
|
"Constant Current": "constant_current",
|
||||||
"Temperature PID"
|
"Temperature PID": "temperature_pid"
|
||||||
],
|
},
|
||||||
"value": "Constant Current",
|
"value": "constant_current",
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "output",
|
"topic": "output",
|
||||||
"field": "pid"
|
"field": "pid"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "Set Current",
|
"name": "i_set",
|
||||||
|
"title": "Set Current",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"step": 100,
|
"step": 100,
|
||||||
@ -43,6 +55,7 @@
|
|||||||
"triggerOnShow": true,
|
"triggerOnShow": true,
|
||||||
"decimals": 6,
|
"decimals": 6,
|
||||||
"suffix": "mA",
|
"suffix": "mA",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "output",
|
"topic": "output",
|
||||||
"field": "i_set"
|
"field": "i_set"
|
||||||
@ -50,7 +63,8 @@
|
|||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Set Temperature",
|
"name": "target",
|
||||||
|
"title": "Set Temperature",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 25,
|
"value": 25,
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
@ -59,6 +73,7 @@
|
|||||||
300
|
300
|
||||||
],
|
],
|
||||||
"format": "{value:.4f} °C",
|
"format": "{value:.4f} °C",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "pid",
|
"topic": "pid",
|
||||||
"field": "target"
|
"field": "target"
|
||||||
@ -68,12 +83,14 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Limits",
|
"name": "limits",
|
||||||
|
"title": "Limits",
|
||||||
"expanded": true,
|
"expanded": true,
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "Max Cooling Current",
|
"name": "max_i_pos",
|
||||||
|
"title": "Max Cooling Current",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"step": 100,
|
"step": 100,
|
||||||
@ -83,6 +100,7 @@
|
|||||||
2000
|
2000
|
||||||
],
|
],
|
||||||
"suffix": "mA",
|
"suffix": "mA",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "output",
|
"topic": "output",
|
||||||
"field": "max_i_pos"
|
"field": "max_i_pos"
|
||||||
@ -90,7 +108,8 @@
|
|||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Max Heating Current",
|
"name": "max_i_neg",
|
||||||
|
"title": "Max Heating Current",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"step": 100,
|
"step": 100,
|
||||||
@ -100,6 +119,7 @@
|
|||||||
2000
|
2000
|
||||||
],
|
],
|
||||||
"suffix": "mA",
|
"suffix": "mA",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "output",
|
"topic": "output",
|
||||||
"field": "max_i_neg"
|
"field": "max_i_neg"
|
||||||
@ -107,16 +127,18 @@
|
|||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Max Voltage Difference",
|
"name": "max_v",
|
||||||
|
"title": "Max Voltage Difference",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
|
"decimals": 3,
|
||||||
"limits": [
|
"limits": [
|
||||||
0,
|
0,
|
||||||
5
|
4.3
|
||||||
],
|
],
|
||||||
"siPrefix": true,
|
|
||||||
"suffix": "V",
|
"suffix": "V",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "output",
|
"topic": "output",
|
||||||
"field": "max_v"
|
"field": "max_v"
|
||||||
@ -128,12 +150,14 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Thermistor Config",
|
"name": "thermistor",
|
||||||
|
"title": "Thermistor Config",
|
||||||
"expanded": true,
|
"expanded": true,
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "T₀",
|
"name": "t0",
|
||||||
|
"title": "T₀",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 25,
|
"value": 25,
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
@ -142,40 +166,46 @@
|
|||||||
100
|
100
|
||||||
],
|
],
|
||||||
"format": "{value:.4f} °C",
|
"format": "{value:.4f} °C",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "s-h",
|
"topic": "b-p",
|
||||||
"field": "t0"
|
"field": "t0"
|
||||||
},
|
},
|
||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "R₀",
|
"name": "r0",
|
||||||
|
"title": "R₀",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 10000,
|
"value": 10000,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"siPrefix": true,
|
"siPrefix": true,
|
||||||
"suffix": "Ω",
|
"suffix": "Ω",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "s-h",
|
"topic": "b-p",
|
||||||
"field": "r0"
|
"field": "r0"
|
||||||
},
|
},
|
||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "B",
|
"name": "b",
|
||||||
|
"title": "B",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 3950,
|
"value": 3950,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"suffix": "K",
|
"suffix": "K",
|
||||||
"decimals": 4,
|
"decimals": 4,
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "s-h",
|
"topic": "b-p",
|
||||||
"field": "b"
|
"field": "b"
|
||||||
},
|
},
|
||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Postfilter Rate",
|
"name": "rate",
|
||||||
|
"title": "Postfilter Rate",
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"value": 16.67,
|
"value": 16.67,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
@ -194,15 +224,18 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "PID Config",
|
"name": "pid",
|
||||||
|
"title": "PID Config",
|
||||||
"expanded": true,
|
"expanded": true,
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "Kp",
|
"name": "kp",
|
||||||
|
"title": "Kp",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"suffix": "",
|
"suffix": "",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "pid",
|
"topic": "pid",
|
||||||
"field": "kp"
|
"field": "kp"
|
||||||
@ -210,10 +243,12 @@
|
|||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Ki",
|
"name": "ki",
|
||||||
|
"title": "Ki",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"suffix": "Hz",
|
"suffix": "Hz",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "pid",
|
"topic": "pid",
|
||||||
"field": "ki"
|
"field": "ki"
|
||||||
@ -221,10 +256,12 @@
|
|||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Kd",
|
"name": "kd",
|
||||||
|
"title": "Kd",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"suffix": "s",
|
"suffix": "s",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "pid",
|
"topic": "pid",
|
||||||
"field": "kd"
|
"field": "kd"
|
||||||
@ -232,12 +269,14 @@
|
|||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "PID Output Clamping",
|
"name": "pid_output_clamping",
|
||||||
|
"title": "PID Output Clamping",
|
||||||
"expanded": true,
|
"expanded": true,
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "Minimum",
|
"name": "output_min",
|
||||||
|
"title": "Minimum",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"step": 100,
|
"step": 100,
|
||||||
"limits": [
|
"limits": [
|
||||||
@ -246,6 +285,7 @@
|
|||||||
],
|
],
|
||||||
"decimals": 6,
|
"decimals": 6,
|
||||||
"suffix": "mA",
|
"suffix": "mA",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "pid",
|
"topic": "pid",
|
||||||
"field": "output_min"
|
"field": "output_min"
|
||||||
@ -253,7 +293,8 @@
|
|||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Maximum",
|
"name": "output_max",
|
||||||
|
"title": "Maximum",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"step": 100,
|
"step": 100,
|
||||||
"limits": [
|
"limits": [
|
||||||
@ -262,6 +303,7 @@
|
|||||||
],
|
],
|
||||||
"decimals": 6,
|
"decimals": 6,
|
||||||
"suffix": "mA",
|
"suffix": "mA",
|
||||||
|
"compactHeight": false,
|
||||||
"thermostat:set_param": {
|
"thermostat:set_param": {
|
||||||
"topic": "pid",
|
"topic": "pid",
|
||||||
"field": "output_max"
|
"field": "output_max"
|
||||||
@ -271,20 +313,24 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "PID Auto Tune",
|
"name": "pid_autotune",
|
||||||
|
"title": "PID Auto Tune",
|
||||||
"expanded": false,
|
"expanded": false,
|
||||||
"type": "group",
|
"type": "group",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "Target Temperature",
|
"name": "target_temp",
|
||||||
|
"title": "Target Temperature",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 20,
|
"value": 20,
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"format": "{value:.4f} °C",
|
"format": "{value:.4f} °C",
|
||||||
|
"compactHeight": false,
|
||||||
"pid_autotune": "target_temp"
|
"pid_autotune": "target_temp"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Test Current",
|
"name": "test_current",
|
||||||
|
"title": "Test Current",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"decimals": 6,
|
"decimals": 6,
|
||||||
@ -294,27 +340,33 @@
|
|||||||
2000
|
2000
|
||||||
],
|
],
|
||||||
"suffix": "mA",
|
"suffix": "mA",
|
||||||
|
"compactHeight": false,
|
||||||
"pid_autotune": "test_current"
|
"pid_autotune": "test_current"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Temperature Swing",
|
"name": "temp_swing",
|
||||||
|
"title": "Temperature Swing",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 1.5,
|
"value": 1.5,
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"prefix": "±",
|
"prefix": "±",
|
||||||
"format": "{value:.4f} °C",
|
"format": "{value:.4f} °C",
|
||||||
|
"compactHeight": false,
|
||||||
"pid_autotune": "temp_swing"
|
"pid_autotune": "temp_swing"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Lookback",
|
"name": "lookback",
|
||||||
|
"title": "Lookback",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": 3.0,
|
"value": 3.0,
|
||||||
"step": 0.1,
|
"step": 0.1,
|
||||||
"format": "{value:.4f} s",
|
"format": "{value:.4f} s",
|
||||||
|
"compactHeight": false,
|
||||||
"pid_autotune": "lookback"
|
"pid_autotune": "lookback"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Run",
|
"name": "run_pid",
|
||||||
|
"title": "Run",
|
||||||
"type": "action",
|
"type": "action",
|
||||||
"tip": "Run"
|
"tip": "Run"
|
||||||
}
|
}
|
||||||
@ -323,12 +375,14 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Save to flash",
|
"name": "save",
|
||||||
|
"title": "Save to flash",
|
||||||
"type": "action",
|
"type": "action",
|
||||||
"tip": "Save config to thermostat, applies on reset"
|
"tip": "Save config to thermostat, applies on reset"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Load from flash",
|
"name": "load",
|
||||||
|
"title": "Load from flash",
|
||||||
"type": "action",
|
"type": "action",
|
||||||
"tip": "Load config from flash"
|
"tip": "Load config from flash"
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ pub const MAX_TEC_I: ElectricCurrent = ElectricCurrent {
|
|||||||
pub const MAX_TEC_V: ElectricPotential = ElectricPotential {
|
pub const MAX_TEC_V: ElectricPotential = ElectricPotential {
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
units: PhantomData,
|
units: PhantomData,
|
||||||
value: 4.0,
|
value: 4.3,
|
||||||
};
|
};
|
||||||
// DAC chip outputs 0-5v, which is then passed through a resistor dividor to provide 0-3v range
|
// DAC chip outputs 0-5v, which is then passed through a resistor dividor to provide 0-3v range
|
||||||
const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential {
|
const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user