Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions src/devices/eeprom.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ def __init__(self):
The constructor function for the EEPROM class
"""
self._google_sheet_interval = 20
self._heat = bool(True)
self._kd_value = 36.0
self._ki_value = 28.0
self._kp_value = 20.0
self._tank_id = 1
self._thermal_correction = 12

def get_google_sheet_interval(self, default):
"""
Expand All @@ -28,14 +26,6 @@ def get_google_sheet_interval(self, default):
return default
return self._google_sheet_interval

def get_heat(self, default):
"""
Get the heat setting from EEPROM
"""
if self._heat is None:
return default
return self._heat

def get_kd(self, default):
"""
Get the Kd value from EEPROM
Expand Down Expand Up @@ -68,26 +58,12 @@ def get_tank_id(self, default):
return default
return self._tank_id

def get_thermal_correction(self, default):
"""
Get the thermal correction value from EEPROM
"""
if self._thermal_correction is None:
return default
return float(self._thermal_correction)

def set_google_sheet_interval(self, value):
"""
Set the google sheet interval in EEPROM
"""
self._google_sheet_interval = value

def set_heat(self, value):
"""
Set the heat setting in EEPROM
"""
self._heat = value

def set_kd(self, value):
"""
Set the Kd value in EEPROM
Expand Down
163 changes: 163 additions & 0 deletions src/devices/thermal_control.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
"""
A file for the ThermalControl class
"""

import time


class ThermalControl:
"""
The class for the ThermalControl
"""

FLAT_TYPE = 0
RAMP_TYPE = 1
SINE_TYPE = 2

def __init__(self, titrator):
"""
The constructor function for the ThermalControl class
"""
self.titrator = titrator
self._heat = bool(True)
self._base_thermal_target = 78
self._current_thermal_target = 67
self._thermal_function_type = ThermalControl.FLAT_TYPE
self._ramp_time_start_seconds = 0
self._ramp_time_end_seconds = 0
self._ramp_initial_value = 0.0
self._amplitude = 0.0
self._period_in_seconds = 0

def get_amplitude(self):
"""
Get the amplitude for the pH function.
"""
return self._amplitude

def get_base_thermal_target(self):
"""
Get the base thermal target
"""
return self._base_thermal_target

def get_current_thermal_target(self):
"""
Get the current thermal target
"""
return self._current_thermal_target

def get_heat(self, default):
"""
Get the heat setting from EEPROM
"""
if self._heat is None:
return default
return self._heat

def get_period_in_seconds(self):
"""
Get the period in seconds for the pH function.
"""
return self._period_in_seconds

def get_ramp_time_end(self):
"""
Get the ramp time end in seconds.
"""
return (
self._ramp_time_end_seconds
if self._thermal_function_type != ThermalControl.FLAT_TYPE
else 0
)

def get_ramp_time_start(self):
"""
Get the ramp time start in seconds.
"""
return (
self._ramp_time_start_seconds
if self._thermal_function_type != ThermalControl.FLAT_TYPE
else 0
)

def get_thermal_function_type(self):
"""
Get the current thermal function type.
"""
return self._thermal_function_type

def set_amplitude(self, amplitude):
"""
Set the amplitude for the pH function.
"""
self._amplitude = amplitude

def set_base_thermal_target(self, value):
"""
Set the base thermal target
"""
self._base_thermal_target = value

def set_current_thermal_target(self, value):
"""
Set the current thermal target
"""
self._current_thermal_target = value

def set_heat(self, value):
"""
Set the heat setting in EEPROM
"""
self._heat = value

def set_ramp_duration_hours(self, new_ph_ramp_duration):
"""
Set the ramp duration in hours. If the duration is greater than 0, configure ramp parameters;
otherwise, set the function type to FLAT_TYPE.
"""
if new_ph_ramp_duration > 0:
current_ramp_time = (
self._ramp_time_end_seconds - self._ramp_time_start_seconds
)
current_ramp_time_str = f"{current_ramp_time:.3f}"
new_ramp_duration_str = f"{new_ph_ramp_duration:.3f}"
print(
f"Change ramp time from {current_ramp_time_str} to {new_ramp_duration_str}"
)

self._ramp_time_start_seconds = int(time.monotonic())
self._ramp_time_end_seconds = self._ramp_time_start_seconds + int(
new_ph_ramp_duration * 3600
)

self._ramp_initial_value = self.titrator.thermal_probe.get_running_average()
self._thermal_function_type = ThermalControl.RAMP_TYPE
else:
self._ramp_time_end_seconds = 0
self._thermal_function_type = ThermalControl.FLAT_TYPE
print("Set ramp time to 0")

def set_sine_amplitude_and_hours(self, amplitude, period_in_hours):
"""
Set the amplitude and period (in hours) for the sine wave pH function.
"""
if amplitude > 0 and period_in_hours > 0:
self._amplitude = amplitude
self._period_in_seconds = int(period_in_hours * 3600)
self._thermal_function_type = ThermalControl.SINE_TYPE
else:
raise ValueError("Amp and period !> than 0.")

def set_thermal_function_type(self, function_type):
"""
Set the current thermal function type.
"""
if function_type in (
ThermalControl.FLAT_TYPE,
ThermalControl.RAMP_TYPE,
ThermalControl.SINE_TYPE,
):
self._thermal_function_type = function_type
else:
raise ValueError("Invalid thermal function type")
71 changes: 70 additions & 1 deletion src/devices/thermal_probe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,85 @@
The file for the ThermalProbe class
"""

import time


class ThermalProbe:
"""
The class for the ThermalProbe
"""

HISTORY_SIZE = 10

def __init__(self, eeprom):
"""
The constructor function for the ThermalProbe class
"""
self.eeprom = eeprom

self.correction = self.eeprom.get_thermal_correction(0.0)
self._correction = 12

self.history = [0.0] * self.HISTORY_SIZE
self.history_index = 0
self.first_time = True
self.last_time = 0

def clear_thermal_correction(self):
"""
Clear the thermal correction value in EEPROM
"""
self._correction = 0

def get_raw_temperature(self):
"""
Simulate reading the raw temperature from a sensor.
In a real implementation, this method would interface with hardware.
"""
# Placeholder for actual sensor reading logic
return 25.0 # return thermo.temperature(RTDnominal, refResistor);

def get_running_average(self):
"""
Return the corrected running average within the range of 00.00-99.99
"""
temperature = self.get_uncorrected_running_average() + self._correction
if temperature < 0.0:
temperature = 0.0
elif temperature > 99.99:
temperature = 99.99
return temperature

def get_thermal_correction(self):
"""
Get the thermal correction value from EEPROM
"""
return float(self._correction)

def get_uncorrected_running_average(self):
"""
Calculate the uncorrected running average of temperature readings.
"""
current_time = time.time()
if (
self.first_time or self.last_time + 1 <= current_time
): # Check if 1 second has passed
temperature = self.get_raw_temperature()
if self.first_time:
# Initialize the history buffer with the first temperature reading
self.history = [temperature] * self.HISTORY_SIZE
self.first_time = False

# Update the history buffer with the new temperature reading
self.history_index = (self.history_index + 1) % self.HISTORY_SIZE
self.history[self.history_index] = temperature
self.last_time = current_time

# Calculate the average of the history buffer, ignoring unused slots
valid_readings = self.history[: self.history_index + 1]
return sum(valid_readings) / len(valid_readings)

def set_thermal_correction(self, value):
"""
Set the thermal correction value in EEPROM
"""
self._correction = value
4 changes: 4 additions & 0 deletions src/titrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from src.devices.ph_control import PHControl
from src.devices.pid import PID
from src.devices.sd import SD
from src.devices.thermal_control import ThermalControl
from src.devices.thermal_probe import ThermalProbe
from src.ui_state.main_menu import MainMenu
from src.version import VERSION
Expand Down Expand Up @@ -51,6 +52,9 @@ def __init__(self):
# Initialize PH Control
self.ph_control = PHControl()

# Initialize Thermal Control
self.thermal_control = ThermalControl(self)

# Initialize Thermal Probe
self.thermal_probe = ThermalProbe(self.eeprom)

Expand Down
27 changes: 26 additions & 1 deletion src/ui_state/main_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
The file for the MainMenu class
"""

import time

from src.devices.library import Keypad
from src.ui_state.set_menu.set_chill_or_heat import SetChillOrHeat
from src.ui_state.set_menu.set_google_mins import SetGoogleSheetInterval
Expand Down Expand Up @@ -31,6 +33,7 @@
from src.ui_state.view_menu.view_ph_calibration import ViewPHCalibration
from src.ui_state.view_menu.view_pid_constants import ViewPIDConstants
from src.ui_state.view_menu.view_tank_id import ViewTankID
from src.ui_state.view_menu.view_thermal import ViewThermal
from src.ui_state.view_menu.view_thermal_correction import (
ViewThermalCorrection,
)
Expand Down Expand Up @@ -59,6 +62,7 @@ def __init__(self, titrator):
"View pH slope",
"View PID",
"View tank ID",
"View temp",
"View temp cal",
"View time",
"View version",
Expand Down Expand Up @@ -93,6 +97,7 @@ def __init__(self, titrator):
ViewPHCalibration, # View pH slope
ViewPIDConstants, # View PID constants
ViewTankID, # View Tank ID
ViewThermal, # View Temperature
ViewThermalCorrection, # View Thermal Correction
ViewTime, # View Time
ViewVersion, # View Version
Expand Down Expand Up @@ -220,7 +225,27 @@ def idle(self):
"""
lcd = self.titrator.lcd
lcd.print("Idle Line 1", line=1)
lcd.print("Idle Line 2", line=2)

thermal_control = self.titrator.thermal_control
temperature = self.titrator.thermal_probe.get_running_average()
status = "h" if thermal_control.get_heat(True) else "c"

output = [" "] * 20
output[0] = "T"
output[1] = "=" if int(time.monotonic()) % 2 == 0 else " "

buffer = f"{temperature:5.2f}"
output[2:7] = list(buffer[:5])

output[7] = " "
output[8] = status
output[9] = " "

thermal_target = thermal_control.get_current_thermal_target()
buffer = f"{thermal_target:5.2f}"
output[10:15] = list(buffer[:5])

self.titrator.lcd.print("".join(output), line=2)

def loop(self):
"""
Expand Down
Loading