TempSensorSim/TempSensor_max31865's temperature() now stores its reading on self.temp, so ATemperatureSensor's inherited AttributeChange (previously never triggered by anything) actually fires. TempSensorTask no longer keeps its own shadow copy of the reading - it registers its websocket-push callback on self.sensor directly and just drives the read each tick; server/brewpi.py's TC-feeding registration moved from sensor_task to sensor for the same reason. Priming read happens before registering the callback (not after) since all tasks are built synchronously at module level, before the asyncio event loop starts - registering first would fire on_temp_changed's asyncio.create_task() with no running loop. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GpePKZiEZWbGo9HrfuML6U
130 lines
2.4 KiB
Python
Executable File
130 lines
2.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import time
|
|
from components import ATemperatureSensor, TemperatureSensorException
|
|
import spidev
|
|
|
|
|
|
class TempSensor_max31865(ATemperatureSensor):
|
|
def name(self):
|
|
return "Max31865"
|
|
|
|
def __init__(self, temp_offset=0, **kwargs):
|
|
ATemperatureSensor.__init__(self)
|
|
# Open SPI bus
|
|
self.spi = spidev.SpiDev()
|
|
self.spi.open(0, 0)
|
|
self.spi.max_speed_hz = 50000
|
|
self.spi.mode = 0b01
|
|
self.temp_offset = temp_offset
|
|
self.write_reg(0x00, 0xA3)
|
|
|
|
def read_reg(self, addr):
|
|
reg = self.spi.xfer([addr, 0xFF])
|
|
|
|
return reg[1]
|
|
|
|
def write_reg(self, addr, data):
|
|
self.spi.xfer([addr+0x80, data])
|
|
|
|
def read_digits(self):
|
|
for i in range(0, 10):
|
|
reg = self.read_reg(0x00)
|
|
if (0x20 & reg) == 0:
|
|
break
|
|
time.sleep(0.01)
|
|
|
|
digits = 0
|
|
msb = self.read_reg(0x01)
|
|
lsb = self.read_reg(0x02)
|
|
self.write_reg(0x00, 0xA3)
|
|
if lsb & 0x01 == 0x00:
|
|
digits = (256*msb + lsb) >> 1
|
|
else:
|
|
raise TemperatureSensorException("Could not read sensor!")
|
|
|
|
return digits
|
|
|
|
|
|
def temperature(self):
|
|
digits = self.read_digits()
|
|
self.temp = self.temp_offset + self.to_temperature(digits)
|
|
return self.temp
|
|
|
|
@staticmethod
|
|
def to_temperature(digits):
|
|
T = 0
|
|
R = __class__.calc_R(430, digits)
|
|
T = __class__.vanDusen_temp(R)
|
|
|
|
return T
|
|
|
|
@staticmethod
|
|
def calc_R(Rref, digits):
|
|
k = float(digits) / 32768
|
|
R = k*Rref
|
|
|
|
return R
|
|
|
|
@staticmethod
|
|
def vanDusen_temp(Rmeas):
|
|
RLut, TLut = __class__.vanDusenLut(100, -150, +500, 1.0)
|
|
|
|
# Find candidate
|
|
i = 0
|
|
for R in RLut:
|
|
if R > Rmeas:
|
|
break
|
|
i += 1
|
|
|
|
# Linear interpolation
|
|
R0 = RLut[i-1]
|
|
R1 = RLut[i]
|
|
T0 = TLut[i-1]
|
|
T1 = TLut[i]
|
|
|
|
dR = R1 - R0
|
|
dT = T1 - T0
|
|
|
|
k = (Rmeas-R0)/dR
|
|
T = T0 + dT*k
|
|
|
|
return T
|
|
|
|
@staticmethod
|
|
def vanDusenLut (R0, Tmin, Tmax, dT):
|
|
a = +3.90830e-03
|
|
b = -5.77500e-07
|
|
c = -4.18301e-12
|
|
|
|
Rv = []
|
|
Tv = []
|
|
T = Tmin
|
|
while T <= Tmax:
|
|
R = R0*(1 + a*T + b*T**2)
|
|
|
|
if T < 0.0:
|
|
R += R0*c*(T - 100)*T**3
|
|
|
|
Rv.append(R)
|
|
Tv.append(T)
|
|
T += dT
|
|
|
|
return Rv, Tv
|
|
|
|
# Main
|
|
if __name__ == '__main__':
|
|
|
|
|
|
sensor = TempSensor_max31865()
|
|
for k in range (0, 100):
|
|
for i in range (0, 8):
|
|
print("Reg[0x{}]: 0x{:02X}".format(i, sensor.read_reg(i)))
|
|
|
|
digits = sensor.read_digits()
|
|
print("Digits = {:04X}".format(digits))
|
|
print("Temperature = {:0.2f} °C".format(TempSensor_max31865.to_temperature(digits)))
|
|
time.sleep(0.5)
|
|
|
|
print("End of program")
|
|
|