Files
2025-07-10 21:59:56 +07:00

440 lines
12 KiB
Python

import time
import struct
I2C_ADDR = 0x49
STATUS_REG = 0x00
WRITE_REG = 0x01
READ_REG = 0x02
TX_VALID = 0x02
RX_VALID = 0x01
#Register addresses
HW_VERSION_HIGH = 0x00
HW_VERSION_LOW = 0x01
FW_VERSION_HIGH = 0x02
FW_VERSION_LOW = 0x03
CONFIG = 0x04
INTEGRATION_TIME = 0x05
DEVICE_TEMP = 0x06
LED_CONFIG = 0x07
#Raw channel registers
R_G_A = 0x08
S_H_B = 0x0a
T_I_C = 0x0c
U_J_D = 0x0e
V_K_E = 0x10
W_L_F = 0x12
#Calibrated channel registers
R_G_A_CAL = 0x14
S_H_B_CAL = 0x18
T_I_C_CAL = 0x1c
U_J_D_CAL = 0x20
V_K_E_CAL = 0x24
W_L_F_CAL = 0x28
DEV_SELECT_CONTROL = 0x4F
COEF_DATA_0 = 0x50
COEF_DATA_1 = 0x51
COEF_DATA_2 = 0x52
COEF_DATA_3 = 0x52
COEF_DATA_READ = 0x54
COEF_DATA_WRITE = 0x55
#Settings
POLLING_DELAY = 0.01
NIR = 0x00
VISIBLE = 0x01
UV = 0x02
LED_WHITE = 0x00
LED_IR = 0x01
LED_UV = 0x02
LED_CURRENT_LIMIT_12_5MA = 0b00
LED_CURRENT_LIMIT_25MA = 0b01
LED_CURRENT_LIMIT_50MA = 0b10
LED_CURRENT_LIMIT_100MA = 0b11
INDICATOR_CURRENT_LIMIT_1MA = 0b00
INDICATOR_CURRENT_LIMIT_2MA = 0b01
INDICATOR_CURRENT_LIMIT_4MA = 0b10
INDICATOR_CURRENT_LIMIT_8MA = 0b11
GAIN_1X = 0b00
GAIN_37X = 0b01
GAIN_16X = 0b10
GAIN_64X = 0b11
MEASUREMENT_MODE_4CHAN = 0b00
MEASUREMENT_MODE_4CHAN_2 = 0b01
MEASUREMENT_MODE_6CHAN_CONTINUOUS = 0b10
MEASUREMENT_MODE_6CHAN_ONE_SHOT = 0b11
class AS7265X():
def __init__(self, i2c_bus):
self._bus = i2c_bus
def begin(self):
if not self.isConnected():
return False
value = self.virtualReadRegister(DEV_SELECT_CONTROL)
if (value & 0b00110000) == 0:
return False
self.setBulbCurrent(LED_CURRENT_LIMIT_12_5MA, LED_WHITE)
self.setBulbCurrent(LED_CURRENT_LIMIT_12_5MA, LED_IR)
self.setBulbCurrent(LED_CURRENT_LIMIT_12_5MA, LED_UV)
self.disableBulb(LED_WHITE)
self.disableBulb(LED_IR)
self.disableBulb(LED_UV)
self.setIndicatorCurrent(INDICATOR_CURRENT_LIMIT_8MA)
self.enableIndicator()
self.setIntegrationCycles(49) #50 * 2.8ms = 140ms.
self.setGain(GAIN_64X)
self.setMeasurementMode(MEASUREMENT_MODE_6CHAN_ONE_SHOT)
self.enableInterrupt()
return True
def getDeviceType(self):
return self.virtualReadRegister(HW_VERSION_HIGH)
def getHardwareVersion(self):
return self.virtualReadRegister(HW_VERSION_LOW)
def getMajorFirmwareVersion(self):
self.virtualWriteRegister(FW_VERSION_HIGH, 0x01)
self.virtualWriteRegister(FW_VERSION_LOW, 0x01)
return self.virtualReadRegister(FW_VERSION_LOW)
def getPatchFirmwareVersion(self):
self.virtualWriteRegister(FW_VERSION_HIGH, 0x02)
self.virtualWriteRegister(FW_VERSION_LOW, 0x02)
return self.virtualReadRegister(FW_VERSION_LOW)
def getBuildFirmwareVersion(self):
self.virtualWriteRegister(FW_VERSION_HIGH, 0x03)
self.virtualWriteRegister(FW_VERSION_LOW, 0x03)
return self.virtualReadRegister(FW_VERSION_LOW)
def isConnected(self):
try:
self._bus.read_byte_data(I2C_ADDR, STATUS_REG)
return True
except:
return False
def takeMeasurements(self):
self.setMeasurementMode(MEASUREMENT_MODE_6CHAN_ONE_SHOT)
while not self.dataAvailable():
time.sleep(POLLING_DELAY)
def takeMeasurementsWithBulb(self):
self.enableBulb(LED_WHITE)
self.enableBulb(LED_IR)
self.enableBulb(LED_UV)
self.takeMeasurements()
self.disableBulb(LED_WHITE)
self.disableBulb(LED_IR)
self.disableBulb(LED_UV)
#Get the various color readings
def getG(self):
return self.getChannel(R_G_A, VISIBLE)
def getH(self):
return self.getChannel(S_H_B, VISIBLE)
def getI(self):
return self.getChannel(T_I_C, VISIBLE)
def getJ(self):
return self.getChannel(U_J_D, VISIBLE)
def getK(self):
return self.getChannel(V_K_E, VISIBLE)
def getL(self):
return self.getChannel(W_L_F, VISIBLE)
#Get the various NIR readings
def getR(self):
return self.getChannel(R_G_A, NIR)
def getS(self):
return self.getChannel(S_H_B, NIR)
def getT(self):
return self.getChannel(T_I_C, NIR)
def getU(self):
return self.getChannel(U_J_D, NIR)
def getV(self):
return self.getChannel(V_K_E, NIR)
def getW(self):
return self.getChannel(W_L_F, NIR)
#Get the various UV readings
def getA(self):
return self.getChannel(R_G_A, UV)
def getB(self):
return self.getChannel(S_H_B, UV)
def getC(self):
return self.getChannel(T_I_C, UV)
def getD(self):
return self.getChannel(U_J_D, UV)
def getE(self):
return self.getChannel(V_K_E, UV)
def getF(self):
return self.getChannel(W_L_F, UV)
def getChannel(self, channelRegister, device):
self.selectDevice(device)
colorData = self.virtualReadRegister(channelRegister) << 8
colorData |= self.virtualReadRegister(channelRegister + 1)
return colorData
#Returns the various calibration data
def getCalibratedA(self):
return self.getCalibratedValue(R_G_A_CAL, UV)
def getCalibratedB(self):
return self.getCalibratedValue(S_H_B_CAL, UV)
def getCalibratedC(self):
return self.getCalibratedValue(T_I_C_CAL, UV)
def getCalibratedD(self):
return self.getCalibratedValue(U_J_D_CAL, UV)
def getCalibratedE(self):
return self.getCalibratedValue(V_K_E_CAL, UV)
def getCalibratedF(self):
return self.getCalibratedValue(W_L_F_CAL, UV)
#Returns the various calibration data
def getCalibratedG(self):
return self.getCalibratedValue(R_G_A_CAL, VISIBLE)
def getCalibratedH(self):
return self.getCalibratedValue(S_H_B_CAL, VISIBLE)
def getCalibratedI(self):
return self.getCalibratedValue(T_I_C_CAL, VISIBLE)
def getCalibratedJ(self):
return self.getCalibratedValue(U_J_D_CAL, VISIBLE)
def getCalibratedK(self):
return self.getCalibratedValue(V_K_E_CAL, VISIBLE)
def getCalibratedL(self):
return self.getCalibratedValue(W_L_F_CAL, VISIBLE)
#Returns the various calibration data
def getCalibratedR(self):
return self.getCalibratedValue(R_G_A_CAL, NIR)
def getCalibratedS(self):
return self.getCalibratedValue(S_H_B_CAL, NIR)
def getCalibratedT(self):
return self.getCalibratedValue(T_I_C_CAL, NIR)
def getCalibratedU(self):
return self.getCalibratedValue(U_J_D_CAL, NIR)
def getCalibratedV(self):
return self.getCalibratedValue(V_K_E_CAL, NIR)
def getCalibratedW(self):
return self.getCalibratedValue(W_L_F_CAL, NIR)
#Given an address, read four bytes and return the floating point calibrated value
def getCalibratedValue(self, calAddress, device):
self.selectDevice(device)
b0 = self.virtualReadRegister(calAddress + 0)
b1 = self.virtualReadRegister(calAddress + 1)
b2 = self.virtualReadRegister(calAddress + 2)
b3 = self.virtualReadRegister(calAddress + 3)
#Channel calibrated values are stored big-endian
calBytes = 0
calBytes |= (b0 << (8 * 3))
calBytes |= (b1 << (8 * 2))
calBytes |= (b2 << (8 * 1))
calBytes |= (b3 << (8 * 0))
return self.convertBytesToFloat(calBytes)
#Given 4 bytes returns the floating point value
def convertBytesToFloat(self, value):
b = struct.pack('=L', value)
f = struct.unpack('f', b)
return f[0]
def setMeasurementMode(self, mode):
mode = 0b11 if mode > 0b11 else mode
value = self.virtualReadRegister(CONFIG)
value &= 0b11110011
value |= (mode << 2)
self.virtualWriteRegister(CONFIG, value)
def setGain(self, gain):
gain = 0b11 if gain > 0b11 else gain
value = self.virtualReadRegister(CONFIG)
value &= 0b11001111
value |= (gain << 4)
self.virtualWriteRegister(CONFIG, value)
def setIntegrationCycles(self, cycleValue):
self.virtualWriteRegister(INTEGRATION_TIME, cycleValue)
def enableInterrupt(self):
value = self.virtualReadRegister(CONFIG)
value |= 0b01000000
self.virtualWriteRegister(CONFIG, value)
def disableInterrupt(self):
value = self.virtualReadRegister(CONFIG)
value &= 0b10111111
self.virtualWriteRegister(CONFIG, value)
def dataAvailable(self):
value = self.virtualReadRegister(CONFIG)
return value & 0x02
def enableBulb(self, device):
self.selectDevice(device)
value = self.virtualReadRegister(LED_CONFIG)
value |= 0b00001000
self.virtualWriteRegister(LED_CONFIG, value)
def disableBulb(self, device):
self.selectDevice(device)
value = self.virtualReadRegister(LED_CONFIG)
value &= 0b11110111
self.virtualWriteRegister(LED_CONFIG, value)
def setBulbCurrent(self, current, device):
self.selectDevice(device)
current = 0b11 if current > 0b11 else current
value = self.virtualReadRegister(LED_CONFIG)
value &= 0b11001111
value |= (current << 4)
self.virtualWriteRegister(LED_CONFIG, value)
def selectDevice(self, device):
self.virtualWriteRegister(DEV_SELECT_CONTROL, device)
def enableIndicator(self):
value = self.virtualReadRegister(LED_CONFIG)
value |= 0b00000001
self.selectDevice(NIR)
self.virtualWriteRegister(LED_CONFIG, value)
def disableIndicator(self):
value = self.virtualReadRegister(LED_CONFIG)
value &= 0b11111110
self.selectDevice(NIR)
self.virtualWriteRegister(LED_CONFIG, value)
def setIndicatorCurrent(self, current):
current = 0b11 if current > 0b11 else current
value = self.virtualReadRegister(LED_CONFIG)
value &= 0b11111001
value |= (current << 1)
self.selectDevice(NIR)
self.virtualWriteRegister(LED_CONFIG, value)
def getTemperature(self, deviceNumber):
self.selectDevice(deviceNumber)
return self.virtualReadRegister(DEVICE_TEMP)
def getTemperatureAverage(self):
average = 0
for x in range(3):
average += self.getTemperature(x)
return float(average) / 3
def softReset(self):
value = self.virtualReadRegister(CONFIG)
value |= 0x80
self.virtualWriteRegister(CONFIG, value)
def virtualReadRegister(self, virtualAddr):
status = self.readRegister(STATUS_REG)
if (status & RX_VALID) != 0:
incoming = self.readRegister(READ_REG)
while(1):
status = self.readRegister(STATUS_REG)
if (status & TX_VALID) == 0:
break
time.sleep(POLLING_DELAY)
self.writeRegister(WRITE_REG, virtualAddr)
while(1):
status = self.readRegister(STATUS_REG)
if (status & RX_VALID) != 0:
break
time.sleep(POLLING_DELAY)
incoming = self.readRegister(READ_REG)
return incoming
def virtualWriteRegister(self, virtualAddr, dataToWrite):
while(1):
status = self.readRegister(STATUS_REG)
if (status & TX_VALID) == 0:
break
time.sleep(POLLING_DELAY)
self.writeRegister(WRITE_REG, virtualAddr | 0x80)
while(1):
status = self.readRegister(STATUS_REG)
if (status & TX_VALID) == 0:
break
time.sleep(POLLING_DELAY)
self.writeRegister(WRITE_REG, dataToWrite)
def readRegister(self, addr):
return self._bus.read_byte_data(I2C_ADDR, addr)
def writeRegister(self, addr, val):
return self._bus.write_byte_data(I2C_ADDR, addr, val)