/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include "sht21.h"
#include "driver/i2c.h"
#include "../core/kv/kv.h"
#include "../core/log/log.h"
#include "../core/i2c/i2c.h"
#include "../box/box.h"
#define TRIGGER_TEMP_MEASURE_NOHOLD 0xF3
#define TRIGGER_HUMD_MEASURE_NOHOLD 0xF5
#define SHT21_ADDR 0x40
#define ACK_CHECK_EN 0x1
#define ACK_VAL 0x0
#define NACK_VAL 0x1
static uint16_t read_sht21(int i2cId);
void init_sht21(int i2cId) {
ESP_LOGI(SGO_LOG_NOSEND, "@SHT21 Initializing sht21 i2c device");
// TODO: write you setup code here
}
static bool send_sht21_cmd(int i2cId, uint8_t cmd_b) {
int port = get_i2c_port(i2cId);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, SHT21_ADDR << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN);
i2c_master_write_byte(cmd, cmd_b, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGW(SGO_LOG_NOSEND, "@SHT21_%d Write bus is busy", i2cId);
return false;
} else if (ret != ESP_OK) {
//ESP_LOGI(SGO_LOG_NOSEND, "@SHT21_%d Write failed", i2cId);
return false;
}
return true;
}
static bool crc_checksum(uint8_t data[], uint8_t no_of_bytes, uint8_t checksum);
static uint16_t read_sht21(int i2cId) {
uint8_t v[3] = {0};
int port = get_i2c_port(i2cId);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, SHT21_ADDR << 1 | I2C_MASTER_READ, ACK_CHECK_EN);
i2c_master_read_byte(cmd, &v[0], ACK_VAL);
i2c_master_read_byte(cmd, &v[1], ACK_VAL);
i2c_master_read_byte(cmd, &v[2], NACK_VAL);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGW(SGO_LOG_NOSEND, "@SHT21_%d Read bus is busy", i2cId);
return 255;
} else if (ret != ESP_OK) {
ESP_LOGW(SGO_LOG_NOSEND, "@SHT21_%d Read failed", i2cId);
return 255;
}
if(!crc_checksum(v, 2, v[2])) {
//reset();
ESP_LOGW(SGO_LOG_NOSEND, "@SHT21_%d Wrong crc", i2cId);
return 255;
}
return (v[0] << 8) | v[1];
}
void loop_sht21(int i2cId) {
int temp = 0;
int humi = 0;
start_i2c(i2cId);
{
if (!send_sht21_cmd(i2cId, TRIGGER_TEMP_MEASURE_NOHOLD)) {
set_sht21_present(i2cId, 0);
stop_i2c(i2cId);
return;
}
vTaskDelay(100 / portTICK_RATE_MS);
int16_t v = read_sht21(i2cId);
if (v != 255) {
v &= ~0x0003;
float vd = -46.85 + 175.72 * (float)(v) / 65536.0;
set_sht21_temp(i2cId, vd);
set_sht21_present(i2cId, 1);
temp = vd;
}
}
vTaskDelay(500 / portTICK_RATE_MS);
{
if (!send_sht21_cmd(i2cId, TRIGGER_HUMD_MEASURE_NOHOLD)) {
set_sht21_present(i2cId, 0);
stop_i2c(i2cId);
return;
}
vTaskDelay(100 / portTICK_RATE_MS);
uint16_t v = read_sht21(i2cId);
if (v != 255) {
v &= ~0x0003;
float vd = -6.0 + 125.0 * (float)(v) / 65536.0;
set_sht21_humi(i2cId, vd);
set_sht21_present(i2cId, 1);
humi = vd;
}
}
stop_i2c(i2cId);
float asvp = 610.78 * powf(2.71828, (float)temp / (float)(temp + 238.3) * 17.2694);
float leaf_temp_offset = (float)get_sht21_vpd_leaf_offset(i2cId) / 10.0f;
float ltemp = (float)temp + leaf_temp_offset;
float lsvp = 610.78 * powf(2.71828, ltemp / (ltemp + 238.3) * 17.2694);
float vpd = lsvp - (asvp * (float)humi / 100.0);
if (round(vpd / 10.0f) > 255) {
set_sht21_vpd(i2cId, 255);
} else {
set_sht21_vpd(i2cId, round(vpd / 10.0f));
}
}
const uint16_t POLYNOMIAL = 0x131;
static bool crc_checksum(uint8_t data[], uint8_t no_of_bytes, uint8_t checksum) {
uint8_t crc = 0;
uint8_t byteCtr;
for (byteCtr = 0; byteCtr < no_of_bytes; ++byteCtr)
{ crc ^= (data[byteCtr]);
for (uint8_t bit = 8; bit > 0; --bit)
{ if (crc & 0x80) crc = (crc << 1) ^ POLYNOMIAL;
else crc = (crc << 1);
}
}
return crc == checksum;
}