+#include <stdio.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include "esp-aht30.h"
+
+static const uint8_t aht30_update_seq[] = { 0xac, 0x33, 0x00 };
+
+static uint8_t crc8(uint8_t *msg, size_t n) {
+ uint8_t crc = 0xff;
+ uint8_t *end = msg + n;
+
+ while (msg < end) {
+ crc ^= *msg++;
+ for (int i=0;i<8;i++) {
+ if (crc & 0x80)
+ crc = (crc << 1) ^ 0x31;
+ else
+ crc = (crc << 1);
+ }
+ }
+
+ return crc;
+}
+
+esp_err_t aht30_init(i2c_master_bus_handle_t bus, const aht30_config_t *config, aht30_handle_t *aht) {
+ i2c_device_config_t i2c_dev_conf = {
+ .dev_addr_length = I2C_ADDR_BIT_LEN_7,
+ .device_address = AHT30_ADDR,
+ .scl_speed_hz = config ? config->scl_speed_hz : 400000,
+ .scl_wait_us = config ? config->scl_wait_us : 20000,
+ };
+
+ return i2c_master_bus_add_device(bus, &i2c_dev_conf, &aht->dev);
+}
+
+esp_err_t aht30_delete(aht30_handle_t *aht) {
+ return i2c_master_bus_rm_device(aht->dev);
+}
+
+esp_err_t aht30_read(aht30_handle_t *aht, aht30_reading_t *res) {
+ uint8_t data[7];
+
+ // request sensor update
+ ESP_ERROR_CHECK(i2c_master_transmit(aht->dev, aht30_update_seq, sizeof(aht30_update_seq), 500));
+
+ // delay required 80ms
+ vTaskDelay(80 / portTICK_PERIOD_MS);
+
+ // poll result
+ ESP_ERROR_CHECK(i2c_master_receive(aht->dev, data, 7, 500));
+
+ res->status = data[0];
+ res->valid = crc8(data, 6) == data[6];
+ res->humidity = (data[1] << 12 | data[2] << 4 | data[3] >> 4) * 100;
+ res->temperature = ((data[3] << 16 | data[4] << 8 | data[5]) & 0xfffff) * 200 - (50 << 20);
+
+ return 0;
+}