MicroPython Driver for AHT30 Sensor

AHT30 Driver Code for micro:bit

Download as zip file

'''
AHT30 (humidity and temperature sensors)
MicroPython driver for micro:bit

CREDIT for CRC calculation:
    SOURCE: AHT30 Datasheet, 3.CRCcheck, page 11.
    Function: unsigned char Calc_CRC8()
    Translated from C++
    to MicroPython for the micro:bit.

AUTHOR: fredscave.com
DATE  : 2024/11
VERSION : 1.00
'''

from microbit import i2c, sleep
from micropython import const

ADDR = const(0x38)
CMD_MEASURE = [0xAC, 0x33, 0x00]
CRC_INIT = const(0xFF)
CRC_POLY = const(0x31)
MASK_BUSY = const(0b10000000)
MASK_MODE = const(0b01100000)
MASK_CRC_FLAG = const(0b00010000)
MASK_CALIBRATION = const(0b00001000)
MASK_CMP_INTERRUPT = const(0b00000100)

class AHT30():
    def __init__(self, addr=ADDR):
        sleep(10)
        self.addr = addr
        self.IsChecksum = False

    def Read_Status(self):
        buf = i2c.read(self.addr, 1)
        return buf[0]

    def Busy(self):
        x = self.Read_Status() & MASK_BUSY
        return bool(x)

    def Mode(self):
        x = self.Read_Status() & MASK_MODE
        x = x >> 5
        if x == 0b00:
            return 'NOR'
        elif x == 0b01:
            return 'CYC'
        else:
            return 'CMD'

    def CRC_Flag(self):
        x = self.Read_Status() & MASK_CRC_FLAG
        return bool(x)

    def Calibrated(self):
        x = self.Read_Status() & MASK_CALIBRATION
        return bool(x)

    def CMP_Interrupt(self):
        x = self.Read_Status() & MASK_CMP_INTERRUPT
        return bool(x)

    def Is_Checksum(self):
        return self.IsChecksum

    def Read(self):
        i2c.write(self.addr, bytearray(CMD_MEASURE))
        sleep(80)
        busy = True
        while self.Busy():
            sleep(10)
            #busy = self.Read_Status() & 0b10000000
        buf = i2c.read(self.addr, 7)
        measurements = self._Convert(buf)
        return measurements

    def T(self):
        measurements = self.Read()
        return round(measurements[1], 1)

    def RH(self):
        measurements = self.Read()
        return int(measurements[0] + 0.5)

    def _Convert(self, buf):
        RawRH = ((buf[1] << 16) | (buf[2] << 8) | buf[3]) >> 4
        RH = RawRH * 100 / 0x100000
        RawT = ((buf[3] & 0x0F) << 16) | (buf[4] << 8) | buf[5]
        T = ((RawT * 200) / 0x100000) - 50
        self.IsChecksum = self._Compare_Checksum(buf)
        return (RH, T, self.IsChecksum)

    def _Compare_Checksum(self, buf):
        check = bytearray(1)
        check[0] = CRC_INIT
        for byte in buf[:6]:
            check[0] ^= byte
            for x in range(8):
                if check[0] & 0b10000000:
                    check[0] = (check[0] << 1) ^ CRC_POLY
                else:
                    check[0] = check[0] << 1
        return check[0] == buf[6]