Add support for SHT4X (#1512)

This commit is contained in:
Stephen Tierney 2021-04-28 18:22:46 +10:00 committed by GitHub
parent cc43e01e34
commit 7fb116d87d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 234 additions and 0 deletions

View file

@ -80,6 +80,7 @@ esphome/components/rtttl/* @glmnet
esphome/components/script/* @esphome/core esphome/components/script/* @esphome/core
esphome/components/sensor/* @esphome/core esphome/components/sensor/* @esphome/core
esphome/components/sgp40/* @SenexCrenshaw esphome/components/sgp40/* @SenexCrenshaw
esphome/components/sht4x/* @sjtrny
esphome/components/shutdown/* @esphome/core esphome/components/shutdown/* @esphome/core
esphome/components/sim800l/* @glmnet esphome/components/sim800l/* @glmnet
esphome/components/spi/* @esphome/core esphome/components/spi/* @esphome/core

View file

View file

@ -0,0 +1,92 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ID,
CONF_TEMPERATURE,
CONF_HUMIDITY,
UNIT_CELSIUS,
UNIT_PERCENT,
ICON_THERMOMETER,
ICON_WATER_PERCENT,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_HUMIDITY,
)
CODEOWNERS = ["@sjtrny"]
DEPENDENCIES = ["i2c"]
sht4x_ns = cg.esphome_ns.namespace("sht4x")
SHT4XComponent = sht4x_ns.class_("SHT4XComponent", cg.PollingComponent, i2c.I2CDevice)
CONF_PRECISION = "precision"
SHT4XPRECISION = sht4x_ns.enum("SHT4XPRECISION")
PRECISION_OPTIONS = {
"High": SHT4XPRECISION.SHT4X_PRECISION_HIGH,
"Med": SHT4XPRECISION.SHT4X_PRECISION_MED,
"Low": SHT4XPRECISION.SHT4X_PRECISION_LOW,
}
CONF_HEATER_POWER = "heater_power"
SHT4XHEATERPOWER = sht4x_ns.enum("SHT4XHEATERPOWER")
HEATER_POWER_OPTIONS = {
"High": SHT4XHEATERPOWER.SHT4X_HEATERPOWER_HIGH,
"Med": SHT4XHEATERPOWER.SHT4X_HEATERPOWER_MED,
"Low": SHT4XHEATERPOWER.SHT4X_HEATERPOWER_LOW,
}
CONF_HEATER_TIME = "heater_time"
SHT4XHEATERTIME = sht4x_ns.enum("SHT4XHEATERTIME")
HEATER_TIME_OPTIONS = {
"Long": SHT4XHEATERTIME.SHT4X_HEATERTIME_LONG,
"Short": SHT4XHEATERTIME.SHT4X_HEATERTIME_SHORT,
}
CONF_HEATER_MAX_DUTY = "heater_max_duty"
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(SHT4XComponent),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
UNIT_CELSIUS, ICON_THERMOMETER, 2, DEVICE_CLASS_TEMPERATURE
),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
UNIT_PERCENT, ICON_WATER_PERCENT, 2, DEVICE_CLASS_HUMIDITY
),
cv.Optional(CONF_PRECISION, default="High"): cv.enum(PRECISION_OPTIONS),
cv.Optional(CONF_HEATER_POWER, default="High"): cv.enum(
HEATER_POWER_OPTIONS
),
cv.Optional(CONF_HEATER_TIME, default="Long"): cv.enum(HEATER_TIME_OPTIONS),
cv.Optional(CONF_HEATER_MAX_DUTY, default=0.0): cv.float_range(
min=0.0, max=0.05
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x44))
)
TYPES = {
CONF_TEMPERATURE: "set_temp_sensor",
CONF_HUMIDITY: "set_humidity_sensor",
}
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
cg.add(var.set_precision_value(config[CONF_PRECISION]))
cg.add(var.set_heater_power_value(config[CONF_HEATER_POWER]))
cg.add(var.set_heater_time_value(config[CONF_HEATER_TIME]))
cg.add(var.set_heater_duty_value(config[CONF_HEATER_MAX_DUTY]))
for key, funcName in TYPES.items():
if key in config:
sens = yield sensor.new_sensor(config[key])
cg.add(getattr(var, funcName)(sens))

View file

@ -0,0 +1,89 @@
#include "sht4x.h"
#include "esphome/core/log.h"
namespace esphome {
namespace sht4x {
static const char *TAG = "sht4x";
static const uint8_t MEASURECOMMANDS[] = {0xFD, 0xF6, 0xE0};
void SHT4XComponent::start_heater_() {
uint8_t cmd[] = {MEASURECOMMANDS[this->heater_command_]};
ESP_LOGD(TAG, "Heater turning on");
this->write_bytes_raw(cmd, 1);
}
void SHT4XComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up sht4x...");
if (this->duty_cycle_ > 0.0) {
uint32_t heater_interval = (uint32_t)(this->heater_time_ / this->duty_cycle_);
ESP_LOGD(TAG, "Heater interval: %i", heater_interval);
if (this->heater_power_ == SHT4X_HEATERPOWER_HIGH) {
if (this->heater_time_ == SHT4X_HEATERTIME_LONG) {
this->heater_command_ = 0x39;
} else {
this->heater_command_ = 0x32;
}
} else if (this->heater_power_ == SHT4X_HEATERPOWER_MED) {
if (this->heater_time_ == SHT4X_HEATERTIME_LONG) {
this->heater_command_ = 0x2F;
} else {
this->heater_command_ = 0x24;
}
} else {
if (this->heater_time_ == SHT4X_HEATERTIME_LONG) {
this->heater_command_ = 0x1E;
} else {
this->heater_command_ = 0x15;
}
}
ESP_LOGD(TAG, "Heater command: %x", this->heater_command_);
this->set_interval(heater_interval, std::bind(&SHT4XComponent::start_heater_, this));
}
}
void SHT4XComponent::dump_config() { LOG_I2C_DEVICE(this); }
void SHT4XComponent::update() {
uint8_t cmd[] = {MEASURECOMMANDS[this->precision_]};
// Send command
this->write_bytes_raw(cmd, 1);
this->set_timeout(10, [this]() {
const uint8_t num_bytes = 6;
uint8_t buffer[num_bytes];
// Read measurement
bool read_status = this->read_bytes_raw(buffer, num_bytes);
if (read_status) {
// Evaluate and publish measurements
if (this->temp_sensor_ != nullptr) {
// Temp is contained in the first 16 bits
float sensor_value_temp = (buffer[0] << 8) + buffer[1];
float temp = -45 + 175 * sensor_value_temp / 65535;
this->temp_sensor_->publish_state(temp);
}
if (this->humidity_sensor_ != nullptr) {
// Relative humidity is in the last 16 bits
float sensor_value_rh = (buffer[3] << 8) + buffer[4];
float rh = -6 + 125 * sensor_value_rh / 65535;
this->humidity_sensor_->publish_state(rh);
}
} else {
ESP_LOGD(TAG, "Sensor read failed");
}
});
}
} // namespace sht4x
} // namespace esphome

View file

@ -0,0 +1,45 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace sht4x {
enum SHT4XPRECISION { SHT4X_PRECISION_HIGH = 0, SHT4X_PRECISION_MED, SHT4X_PRECISION_LOW };
enum SHT4XHEATERPOWER { SHT4X_HEATERPOWER_HIGH, SHT4X_HEATERPOWER_MED, SHT4X_HEATERPOWER_LOW };
enum SHT4XHEATERTIME { SHT4X_HEATERTIME_LONG = 1100, SHT4X_HEATERTIME_SHORT = 110 };
class SHT4XComponent : public PollingComponent, public i2c::I2CDevice {
public:
float get_setup_priority() const override { return setup_priority::DATA; }
void setup() override;
void dump_config() override;
void update() override;
void set_precision_value(SHT4XPRECISION precision) { this->precision_ = precision; };
void set_heater_power_value(SHT4XHEATERPOWER heater_power) { this->heater_power_ = heater_power; };
void set_heater_time_value(SHT4XHEATERTIME heater_time) { this->heater_time_ = heater_time; };
void set_heater_duty_value(float duty_cycle) { this->duty_cycle_ = duty_cycle; };
void set_temp_sensor(sensor::Sensor *temp_sensor) { this->temp_sensor_ = temp_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
protected:
SHT4XPRECISION precision_;
SHT4XHEATERPOWER heater_power_;
SHT4XHEATERTIME heater_time_;
float duty_cycle_;
void start_heater_();
uint8_t heater_command_;
sensor::Sensor *temp_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace sht4x
} // namespace esphome

View file

@ -741,6 +741,13 @@ sensor:
id: 'workshop_PMC_10_0' id: 'workshop_PMC_10_0'
address: 0x69 address: 0x69
update_interval: 10s update_interval: 10s
- platform: sht4x
temperature:
name: 'SHT4X Temperature'
humidity:
name: 'SHT4X Humidity'
address: 0x44
update_interval: 15s
- platform: shtcx - platform: shtcx
temperature: temperature:
name: 'Living Room Temperature 10' name: 'Living Room Temperature 10'