ELEC60013-ES-CW1/RPi/tmp006.py
2022-03-07 23:30:18 +00:00

124 lines
4.8 KiB
Python

"""Library for interacting with TMP006 Thermopile (IR Temperature) Sensor."""
import smbus2
from time import sleep
# Pointer Register Locations
_REG_VOBJ = bytes([0x00])
_REG_TAMB = bytes([0x01])
_REG_CNFG = bytes([0x02])
_REG_M_ID = bytes([0xFE])
_REG_D_ID = bytes([0xFF])
# Configuration Flags
_MODE_ON = bytes([0x70])
SAMPLERATE_4HZ = bytes([0x00])
SAMPLERATE_2HZ = bytes([0x02])
SAMPLERATE_1HZ = bytes([0x04])
SAMPLERATE_0_5HZ = bytes([0x06])
SAMPLERATE_0_25HZ = bytes([0x08])
_DRDY_EN = bytes([0x01])
class TMP006:
def __init__(self, i2cBus, i2cAddress=0x40, samplerate=SAMPLERATE_1HZ):
self.i2c = i2cBus
self.addr = i2cAddress
self.samplerate = samplerate
i2cBus.pec = True # enable smbus2 Packet Error Checking
self.config = bytes([0x00, 0x00])
self.config = bytes(
[self.config[0] | samplerate[0] | _MODE_ON[0] | _DRDY_EN[0], self.config[1]]
)
ptrConfig = smbus2.i2c_msg.write(self.addr, _REG_CNFG)
writeConfig = smbus2.i2c_msg.write(self.addr, self.config)
self.i2c.i2c_rdwr(ptrConfig, writeConfig)
@property
def temperature(self) -> float:
"""Measured temperature in degrees Celsius, to 2 decimel places"""
Vobj = self.vObject()
Tdie = self.tAmbient()
# Values for Calculations
S0 = 6.4e-14 # Calibration Factor TODO: Calibrate
a1 = 1.75e-3
a2 = -1.678e-5
Tref = 298.15
b0 = -2.94e-5
b1 = -5.7e-7
b2 = 4.63e-9
c2 = 13.4
# Calculate Sensitivity of Thermopile
S = S0 * (1 + a1 * (Tdie - Tref) + a2 * ((Tdie - Tref) ** 2))
# Calculate Coltage offset due to package thermal resistance
Voffset = b0 + b1 * (Tdie - Tref) + b2 * ((Tdie - Tref) ** 2)
# Calculate Seebeck coefficients
fVobj = (Vobj - Voffset) + c2 * ((Vobj - Voffset) ** 2)
# Calculate object temperature in Kelvin
Tobj = (Tdie**4 + (fVobj / S)) ** 0.25
# Convert from Kelvin to Celsius
return round(Tobj - 273.15, 2)
@property
def active(self) -> bool:
"""Check if Sensor is powered on."""
ptrPower = smbus2.i2c_msg.write(self.addr, _REG_CNFG)
power = smbus2.i2c_msg.read(self.addr, 2)
self.i2c.i2c_rdwr(ptrPower, power)
return power.buf[0][0] & _MODE_ON[0] != 0
@active.setter
def active(self, value: bool):
"""Set the sensor to active or inactive."""
if value:
ptrPower = smbus2.i2c_msg.write(self.addr, _REG_CNFG)
power = smbus2.i2c_msg.read(self.addr, 2)
self.i2c.i2c_rdwr(ptrPower, power)
newPower = bytes([power.buf[0][0] | _MODE_ON[0], power.buf[1][0]])
updatePower = smbus2.i2c_msg.write(self.addr, newPower)
self.i2c.i2c_rdwr(ptrPower, updatePower)
else:
ptrPower = smbus2.i2c_msg.write(self.addr, _REG_CNFG)
power = smbus2.i2c_msg.read(self.addr, 2)
self.i2c.i2c_rdwr(ptrPower, power)
newPower = bytes([power.buf[0][0] & ~_MODE_ON[0], power.buf[1][0]])
updatePower = smbus2.i2c_msg.write(self.addr, newPower)
self.i2c.i2c_rdwr(ptrPower, updatePower)
def vObject(self) -> float:
"""Reading from Sensor Voltage Register in Volts"""
ptrVobject = smbus2.i2c_msg.write(self.addr, _REG_VOBJ)
readVobject = smbus2.i2c_msg.read(self.addr, 2)
self.i2c.i2c_rdwr(ptrVobject, readVobject)
scaledVoltage = int.from_bytes(
readVobject.buf[0] + readVobject.buf[1], byteorder="big", signed=True
)
return round(scaledVoltage * 156.25e-9, 1)
# convert to Volts (156.25nV per LSB * 1e-9 for scaling from nV to Volts)
def tAmbient(self) -> float:
"""Reading from Ambient Temperature Register in Degrees Celsius"""
ptrTambient = smbus2.i2c_msg.write(self.addr, _REG_TAMB)
readTambient = smbus2.i2c_msg.read(self.addr, 2)
self.i2c.i2c_rdwr(ptrTambient, readTambient)
scaledTemp = int.from_bytes(
readTambient.buf[0] + readTambient.buf[1], byteorder="big", signed=True
)
return round(scaledTemp * 0.0078125, 1)
# convert to degrees Celsius (1/32 for scaling * 1/4 for 2 bit shift)
@property
def manID(self) -> bytes:
"""Sensor manufacturer ID"""
ptrManID = smbus2.i2c_msg.write(self.addr, _REG_M_ID)
readManID = smbus2.i2c_msg.read(self.addr, 2)
self.i2c.i2c_rdwr(ptrManID, readManID)
return readManID.buf[0] + readManID.buf[1]
@property
def devID(self) -> bytes:
"""Sensor device ID"""
ptrDevID = smbus2.i2c_msg.write(self.addr, _REG_D_ID)
readDevID = smbus2.i2c_msg.read(self.addr, 2)
self.i2c.i2c_rdwr(ptrDevID, readDevID)
return readDevID.buf[0] + readDevID.buf[1]