mirror of
https://github.com/esphome/esphome.git
synced 2025-09-08 14:22:21 +01:00
Merge remote-tracking branch 'upstream/dev' into integration
This commit is contained in:
@@ -29,6 +29,19 @@ static const int8_t SEN5X_INDEX_SCALE_FACTOR = 10; //
|
|||||||
static const int8_t SEN5X_MIN_INDEX_VALUE = 1 * SEN5X_INDEX_SCALE_FACTOR; // must be adjusted by the scale factor
|
static const int8_t SEN5X_MIN_INDEX_VALUE = 1 * SEN5X_INDEX_SCALE_FACTOR; // must be adjusted by the scale factor
|
||||||
static const int16_t SEN5X_MAX_INDEX_VALUE = 500 * SEN5X_INDEX_SCALE_FACTOR; // must be adjusted by the scale factor
|
static const int16_t SEN5X_MAX_INDEX_VALUE = 500 * SEN5X_INDEX_SCALE_FACTOR; // must be adjusted by the scale factor
|
||||||
|
|
||||||
|
static const LogString *rht_accel_mode_to_string(RhtAccelerationMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case LOW_ACCELERATION:
|
||||||
|
return LOG_STR("LOW");
|
||||||
|
case MEDIUM_ACCELERATION:
|
||||||
|
return LOG_STR("MEDIUM");
|
||||||
|
case HIGH_ACCELERATION:
|
||||||
|
return LOG_STR("HIGH");
|
||||||
|
default:
|
||||||
|
return LOG_STR("UNKNOWN");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SEN5XComponent::setup() {
|
void SEN5XComponent::setup() {
|
||||||
// the sensor needs 1000 ms to enter the idle state
|
// the sensor needs 1000 ms to enter the idle state
|
||||||
this->set_timeout(1000, [this]() {
|
this->set_timeout(1000, [this]() {
|
||||||
@@ -50,7 +63,7 @@ void SEN5XComponent::setup() {
|
|||||||
uint32_t stop_measurement_delay = 0;
|
uint32_t stop_measurement_delay = 0;
|
||||||
// In order to query the device periodic measurement must be ceased
|
// In order to query the device periodic measurement must be ceased
|
||||||
if (raw_read_status) {
|
if (raw_read_status) {
|
||||||
ESP_LOGD(TAG, "Sensor has data available, stopping periodic measurement");
|
ESP_LOGD(TAG, "Data is available; stopping periodic measurement");
|
||||||
if (!this->write_command(SEN5X_CMD_STOP_MEASUREMENTS)) {
|
if (!this->write_command(SEN5X_CMD_STOP_MEASUREMENTS)) {
|
||||||
ESP_LOGE(TAG, "Failed to stop measurements");
|
ESP_LOGE(TAG, "Failed to stop measurements");
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
@@ -71,7 +84,8 @@ void SEN5XComponent::setup() {
|
|||||||
this->serial_number_[0] = static_cast<bool>(uint16_t(raw_serial_number[0]) & 0xFF);
|
this->serial_number_[0] = static_cast<bool>(uint16_t(raw_serial_number[0]) & 0xFF);
|
||||||
this->serial_number_[1] = static_cast<uint16_t>(raw_serial_number[0] & 0xFF);
|
this->serial_number_[1] = static_cast<uint16_t>(raw_serial_number[0] & 0xFF);
|
||||||
this->serial_number_[2] = static_cast<uint16_t>(raw_serial_number[1] >> 8);
|
this->serial_number_[2] = static_cast<uint16_t>(raw_serial_number[1] >> 8);
|
||||||
ESP_LOGD(TAG, "Serial number %02d.%02d.%02d", serial_number_[0], serial_number_[1], serial_number_[2]);
|
ESP_LOGV(TAG, "Serial number %02d.%02d.%02d", this->serial_number_[0], this->serial_number_[1],
|
||||||
|
this->serial_number_[2]);
|
||||||
|
|
||||||
uint16_t raw_product_name[16];
|
uint16_t raw_product_name[16];
|
||||||
if (!this->get_register(SEN5X_CMD_GET_PRODUCT_NAME, raw_product_name, 16, 20)) {
|
if (!this->get_register(SEN5X_CMD_GET_PRODUCT_NAME, raw_product_name, 16, 20)) {
|
||||||
@@ -88,45 +102,43 @@ void SEN5XComponent::setup() {
|
|||||||
// first char
|
// first char
|
||||||
current_char = *current_int >> 8;
|
current_char = *current_int >> 8;
|
||||||
if (current_char) {
|
if (current_char) {
|
||||||
product_name_.push_back(current_char);
|
this->product_name_.push_back(current_char);
|
||||||
// second char
|
// second char
|
||||||
current_char = *current_int & 0xFF;
|
current_char = *current_int & 0xFF;
|
||||||
if (current_char) {
|
if (current_char) {
|
||||||
product_name_.push_back(current_char);
|
this->product_name_.push_back(current_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_int++;
|
current_int++;
|
||||||
} while (current_char && --max);
|
} while (current_char && --max);
|
||||||
|
|
||||||
Sen5xType sen5x_type = UNKNOWN;
|
Sen5xType sen5x_type = UNKNOWN;
|
||||||
if (product_name_ == "SEN50") {
|
if (this->product_name_ == "SEN50") {
|
||||||
sen5x_type = SEN50;
|
sen5x_type = SEN50;
|
||||||
} else {
|
} else {
|
||||||
if (product_name_ == "SEN54") {
|
if (this->product_name_ == "SEN54") {
|
||||||
sen5x_type = SEN54;
|
sen5x_type = SEN54;
|
||||||
} else {
|
} else {
|
||||||
if (product_name_ == "SEN55") {
|
if (this->product_name_ == "SEN55") {
|
||||||
sen5x_type = SEN55;
|
sen5x_type = SEN55;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGD(TAG, "Productname %s", product_name_.c_str());
|
ESP_LOGD(TAG, "Product name: %s", this->product_name_.c_str());
|
||||||
}
|
}
|
||||||
if (this->humidity_sensor_ && sen5x_type == SEN50) {
|
if (this->humidity_sensor_ && sen5x_type == SEN50) {
|
||||||
ESP_LOGE(TAG, "For Relative humidity a SEN54 OR SEN55 is required. You are using a <%s> sensor",
|
ESP_LOGE(TAG, "Relative humidity requires a SEN54 or SEN55");
|
||||||
this->product_name_.c_str());
|
|
||||||
this->humidity_sensor_ = nullptr; // mark as not used
|
this->humidity_sensor_ = nullptr; // mark as not used
|
||||||
}
|
}
|
||||||
if (this->temperature_sensor_ && sen5x_type == SEN50) {
|
if (this->temperature_sensor_ && sen5x_type == SEN50) {
|
||||||
ESP_LOGE(TAG, "For Temperature a SEN54 OR SEN55 is required. You are using a <%s> sensor",
|
ESP_LOGE(TAG, "Temperature requires a SEN54 or SEN55");
|
||||||
this->product_name_.c_str());
|
|
||||||
this->temperature_sensor_ = nullptr; // mark as not used
|
this->temperature_sensor_ = nullptr; // mark as not used
|
||||||
}
|
}
|
||||||
if (this->voc_sensor_ && sen5x_type == SEN50) {
|
if (this->voc_sensor_ && sen5x_type == SEN50) {
|
||||||
ESP_LOGE(TAG, "For VOC a SEN54 OR SEN55 is required. You are using a <%s> sensor", this->product_name_.c_str());
|
ESP_LOGE(TAG, "VOC requires a SEN54 or SEN55");
|
||||||
this->voc_sensor_ = nullptr; // mark as not used
|
this->voc_sensor_ = nullptr; // mark as not used
|
||||||
}
|
}
|
||||||
if (this->nox_sensor_ && sen5x_type != SEN55) {
|
if (this->nox_sensor_ && sen5x_type != SEN55) {
|
||||||
ESP_LOGE(TAG, "For NOx a SEN55 is required. You are using a <%s> sensor", this->product_name_.c_str());
|
ESP_LOGE(TAG, "NOx requires a SEN55");
|
||||||
this->nox_sensor_ = nullptr; // mark as not used
|
this->nox_sensor_ = nullptr; // mark as not used
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +149,7 @@ void SEN5XComponent::setup() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->firmware_version_ >>= 8;
|
this->firmware_version_ >>= 8;
|
||||||
ESP_LOGD(TAG, "Firmware version %d", this->firmware_version_);
|
ESP_LOGV(TAG, "Firmware version %d", this->firmware_version_);
|
||||||
|
|
||||||
if (this->voc_sensor_ && this->store_baseline_) {
|
if (this->voc_sensor_ && this->store_baseline_) {
|
||||||
uint32_t combined_serial =
|
uint32_t combined_serial =
|
||||||
@@ -150,7 +162,7 @@ void SEN5XComponent::setup() {
|
|||||||
|
|
||||||
if (this->pref_.load(&this->voc_baselines_storage_)) {
|
if (this->pref_.load(&this->voc_baselines_storage_)) {
|
||||||
ESP_LOGI(TAG, "Loaded VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
ESP_LOGI(TAG, "Loaded VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
||||||
this->voc_baselines_storage_.state0, voc_baselines_storage_.state1);
|
this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize storage timestamp
|
// Initialize storage timestamp
|
||||||
@@ -158,13 +170,13 @@ void SEN5XComponent::setup() {
|
|||||||
|
|
||||||
if (this->voc_baselines_storage_.state0 > 0 && this->voc_baselines_storage_.state1 > 0) {
|
if (this->voc_baselines_storage_.state0 > 0 && this->voc_baselines_storage_.state1 > 0) {
|
||||||
ESP_LOGI(TAG, "Setting VOC baseline from save state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
ESP_LOGI(TAG, "Setting VOC baseline from save state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
||||||
this->voc_baselines_storage_.state0, voc_baselines_storage_.state1);
|
this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1);
|
||||||
uint16_t states[4];
|
uint16_t states[4];
|
||||||
|
|
||||||
states[0] = voc_baselines_storage_.state0 >> 16;
|
states[0] = this->voc_baselines_storage_.state0 >> 16;
|
||||||
states[1] = voc_baselines_storage_.state0 & 0xFFFF;
|
states[1] = this->voc_baselines_storage_.state0 & 0xFFFF;
|
||||||
states[2] = voc_baselines_storage_.state1 >> 16;
|
states[2] = this->voc_baselines_storage_.state1 >> 16;
|
||||||
states[3] = voc_baselines_storage_.state1 & 0xFFFF;
|
states[3] = this->voc_baselines_storage_.state1 & 0xFFFF;
|
||||||
|
|
||||||
if (!this->write_command(SEN5X_CMD_VOC_ALGORITHM_STATE, states, 4)) {
|
if (!this->write_command(SEN5X_CMD_VOC_ALGORITHM_STATE, states, 4)) {
|
||||||
ESP_LOGE(TAG, "Failed to set VOC baseline from saved state");
|
ESP_LOGE(TAG, "Failed to set VOC baseline from saved state");
|
||||||
@@ -182,11 +194,11 @@ void SEN5XComponent::setup() {
|
|||||||
delay(20);
|
delay(20);
|
||||||
uint16_t secs[2];
|
uint16_t secs[2];
|
||||||
if (this->read_data(secs, 2)) {
|
if (this->read_data(secs, 2)) {
|
||||||
auto_cleaning_interval_ = secs[0] << 16 | secs[1];
|
this->auto_cleaning_interval_ = secs[0] << 16 | secs[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (acceleration_mode_.has_value()) {
|
if (this->acceleration_mode_.has_value()) {
|
||||||
result = this->write_command(SEN5X_CMD_RHT_ACCELERATION_MODE, acceleration_mode_.value());
|
result = this->write_command(SEN5X_CMD_RHT_ACCELERATION_MODE, this->acceleration_mode_.value());
|
||||||
} else {
|
} else {
|
||||||
result = this->write_command(SEN5X_CMD_RHT_ACCELERATION_MODE);
|
result = this->write_command(SEN5X_CMD_RHT_ACCELERATION_MODE);
|
||||||
}
|
}
|
||||||
@@ -197,7 +209,7 @@ void SEN5XComponent::setup() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delay(20);
|
delay(20);
|
||||||
if (!acceleration_mode_.has_value()) {
|
if (!this->acceleration_mode_.has_value()) {
|
||||||
uint16_t mode;
|
uint16_t mode;
|
||||||
if (this->read_data(mode)) {
|
if (this->read_data(mode)) {
|
||||||
this->acceleration_mode_ = RhtAccelerationMode(mode);
|
this->acceleration_mode_ = RhtAccelerationMode(mode);
|
||||||
@@ -227,19 +239,18 @@ void SEN5XComponent::setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this->write_command(cmd)) {
|
if (!this->write_command(cmd)) {
|
||||||
ESP_LOGE(TAG, "Error starting continuous measurements.");
|
ESP_LOGE(TAG, "Error starting continuous measurements");
|
||||||
this->error_code_ = MEASUREMENT_INIT_FAILED;
|
this->error_code_ = MEASUREMENT_INIT_FAILED;
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initialized_ = true;
|
this->initialized_ = true;
|
||||||
ESP_LOGD(TAG, "Sensor initialized");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SEN5XComponent::dump_config() {
|
void SEN5XComponent::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "sen5x:");
|
ESP_LOGCONFIG(TAG, "SEN5X:");
|
||||||
LOG_I2C_DEVICE(this);
|
LOG_I2C_DEVICE(this);
|
||||||
if (this->is_failed()) {
|
if (this->is_failed()) {
|
||||||
switch (this->error_code_) {
|
switch (this->error_code_) {
|
||||||
@@ -247,16 +258,16 @@ void SEN5XComponent::dump_config() {
|
|||||||
ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
|
ESP_LOGW(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||||
break;
|
break;
|
||||||
case MEASUREMENT_INIT_FAILED:
|
case MEASUREMENT_INIT_FAILED:
|
||||||
ESP_LOGW(TAG, "Measurement Initialization failed");
|
ESP_LOGW(TAG, "Measurement initialization failed");
|
||||||
break;
|
break;
|
||||||
case SERIAL_NUMBER_IDENTIFICATION_FAILED:
|
case SERIAL_NUMBER_IDENTIFICATION_FAILED:
|
||||||
ESP_LOGW(TAG, "Unable to read sensor serial id");
|
ESP_LOGW(TAG, "Unable to read serial ID");
|
||||||
break;
|
break;
|
||||||
case PRODUCT_NAME_FAILED:
|
case PRODUCT_NAME_FAILED:
|
||||||
ESP_LOGW(TAG, "Unable to read product name");
|
ESP_LOGW(TAG, "Unable to read product name");
|
||||||
break;
|
break;
|
||||||
case FIRMWARE_FAILED:
|
case FIRMWARE_FAILED:
|
||||||
ESP_LOGW(TAG, "Unable to read sensor firmware version");
|
ESP_LOGW(TAG, "Unable to read firmware version");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGW(TAG, "Unknown setup error");
|
ESP_LOGW(TAG, "Unknown setup error");
|
||||||
@@ -264,26 +275,17 @@ void SEN5XComponent::dump_config() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGCONFIG(TAG,
|
ESP_LOGCONFIG(TAG,
|
||||||
" Productname: %s\n"
|
" Product name: %s\n"
|
||||||
" Firmware version: %d\n"
|
" Firmware version: %d\n"
|
||||||
" Serial number %02d.%02d.%02d",
|
" Serial number %02d.%02d.%02d",
|
||||||
this->product_name_.c_str(), this->firmware_version_, serial_number_[0], serial_number_[1],
|
this->product_name_.c_str(), this->firmware_version_, this->serial_number_[0], this->serial_number_[1],
|
||||||
serial_number_[2]);
|
this->serial_number_[2]);
|
||||||
if (this->auto_cleaning_interval_.has_value()) {
|
if (this->auto_cleaning_interval_.has_value()) {
|
||||||
ESP_LOGCONFIG(TAG, " Auto cleaning interval %" PRId32 " seconds", auto_cleaning_interval_.value());
|
ESP_LOGCONFIG(TAG, " Auto cleaning interval: %" PRId32 "s", this->auto_cleaning_interval_.value());
|
||||||
}
|
}
|
||||||
if (this->acceleration_mode_.has_value()) {
|
if (this->acceleration_mode_.has_value()) {
|
||||||
switch (this->acceleration_mode_.value()) {
|
ESP_LOGCONFIG(TAG, " RH/T acceleration mode: %s",
|
||||||
case LOW_ACCELERATION:
|
LOG_STR_ARG(rht_accel_mode_to_string(this->acceleration_mode_.value())));
|
||||||
ESP_LOGCONFIG(TAG, " Low RH/T acceleration mode");
|
|
||||||
break;
|
|
||||||
case MEDIUM_ACCELERATION:
|
|
||||||
ESP_LOGCONFIG(TAG, " Medium RH/T acceleration mode");
|
|
||||||
break;
|
|
||||||
case HIGH_ACCELERATION:
|
|
||||||
ESP_LOGCONFIG(TAG, " High RH/T acceleration mode");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
LOG_SENSOR(" ", "PM 1.0", this->pm_1_0_sensor_);
|
LOG_SENSOR(" ", "PM 1.0", this->pm_1_0_sensor_);
|
||||||
@@ -297,7 +299,7 @@ void SEN5XComponent::dump_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SEN5XComponent::update() {
|
void SEN5XComponent::update() {
|
||||||
if (!initialized_) {
|
if (!this->initialized_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,8 +322,8 @@ void SEN5XComponent::update() {
|
|||||||
this->voc_baselines_storage_.state1 = state1;
|
this->voc_baselines_storage_.state1 = state1;
|
||||||
|
|
||||||
if (this->pref_.save(&this->voc_baselines_storage_)) {
|
if (this->pref_.save(&this->voc_baselines_storage_)) {
|
||||||
ESP_LOGI(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 " ,state1: 0x%04" PRIX32,
|
ESP_LOGI(TAG, "Stored VOC baseline state0: 0x%04" PRIX32 ", state1: 0x%04" PRIX32,
|
||||||
this->voc_baselines_storage_.state0, voc_baselines_storage_.state1);
|
this->voc_baselines_storage_.state0, this->voc_baselines_storage_.state1);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "Could not store VOC baselines");
|
ESP_LOGW(TAG, "Could not store VOC baselines");
|
||||||
}
|
}
|
||||||
@@ -333,7 +335,7 @@ void SEN5XComponent::update() {
|
|||||||
|
|
||||||
if (!this->write_command(SEN5X_CMD_READ_MEASUREMENT)) {
|
if (!this->write_command(SEN5X_CMD_READ_MEASUREMENT)) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
ESP_LOGD(TAG, "write error read measurement (%d)", this->last_error_);
|
ESP_LOGD(TAG, "Write error: read measurement (%d)", this->last_error_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->set_timeout(20, [this]() {
|
this->set_timeout(20, [this]() {
|
||||||
@@ -341,7 +343,7 @@ void SEN5XComponent::update() {
|
|||||||
|
|
||||||
if (!this->read_data(measurements, 8)) {
|
if (!this->read_data(measurements, 8)) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
ESP_LOGD(TAG, "read data error (%d)", this->last_error_);
|
ESP_LOGD(TAG, "Read data error (%d)", this->last_error_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +415,7 @@ bool SEN5XComponent::write_tuning_parameters_(uint16_t i2c_command, const GasTun
|
|||||||
params[5] = tuning.gain_factor;
|
params[5] = tuning.gain_factor;
|
||||||
auto result = write_command(i2c_command, params, 6);
|
auto result = write_command(i2c_command, params, 6);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
ESP_LOGE(TAG, "set tuning parameters failed. i2c command=%0xX, err=%d", i2c_command, this->last_error_);
|
ESP_LOGE(TAG, "Set tuning parameters failed (command=%0xX, err=%d)", i2c_command, this->last_error_);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -424,7 +426,7 @@ bool SEN5XComponent::write_temperature_compensation_(const TemperatureCompensati
|
|||||||
params[1] = compensation.normalized_offset_slope;
|
params[1] = compensation.normalized_offset_slope;
|
||||||
params[2] = compensation.time_constant;
|
params[2] = compensation.time_constant;
|
||||||
if (!write_command(SEN5X_CMD_TEMPERATURE_COMPENSATION, params, 3)) {
|
if (!write_command(SEN5X_CMD_TEMPERATURE_COMPENSATION, params, 3)) {
|
||||||
ESP_LOGE(TAG, "set temperature_compensation failed. Err=%d", this->last_error_);
|
ESP_LOGE(TAG, "Set temperature_compensation failed (%d)", this->last_error_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -433,7 +435,7 @@ bool SEN5XComponent::write_temperature_compensation_(const TemperatureCompensati
|
|||||||
bool SEN5XComponent::start_fan_cleaning() {
|
bool SEN5XComponent::start_fan_cleaning() {
|
||||||
if (!write_command(SEN5X_CMD_START_CLEANING_FAN)) {
|
if (!write_command(SEN5X_CMD_START_CLEANING_FAN)) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
ESP_LOGE(TAG, "write error start fan (%d)", this->last_error_);
|
ESP_LOGE(TAG, "Start fan cleaning failed (%d)", this->last_error_);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "Fan auto clean started");
|
ESP_LOGD(TAG, "Fan auto clean started");
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace sen5x {
|
namespace sen5x {
|
||||||
|
|
||||||
enum ERRORCODE {
|
enum ERRORCODE : uint8_t {
|
||||||
COMMUNICATION_FAILED,
|
COMMUNICATION_FAILED,
|
||||||
SERIAL_NUMBER_IDENTIFICATION_FAILED,
|
SERIAL_NUMBER_IDENTIFICATION_FAILED,
|
||||||
MEASUREMENT_INIT_FAILED,
|
MEASUREMENT_INIT_FAILED,
|
||||||
@@ -18,19 +18,17 @@ enum ERRORCODE {
|
|||||||
UNKNOWN
|
UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
// Shortest time interval of 3H for storing baseline values.
|
enum RhtAccelerationMode : uint16_t {
|
||||||
// Prevents wear of the flash because of too many write operations
|
LOW_ACCELERATION = 0,
|
||||||
const uint32_t SHORTEST_BASELINE_STORE_INTERVAL = 10800;
|
MEDIUM_ACCELERATION = 1,
|
||||||
// Store anyway if the baseline difference exceeds the max storage diff value
|
HIGH_ACCELERATION = 2,
|
||||||
const uint32_t MAXIMUM_STORAGE_DIFF = 50;
|
};
|
||||||
|
|
||||||
struct Sen5xBaselines {
|
struct Sen5xBaselines {
|
||||||
int32_t state0;
|
int32_t state0;
|
||||||
int32_t state1;
|
int32_t state1;
|
||||||
} PACKED; // NOLINT
|
} PACKED; // NOLINT
|
||||||
|
|
||||||
enum RhtAccelerationMode : uint16_t { LOW_ACCELERATION = 0, MEDIUM_ACCELERATION = 1, HIGH_ACCELERATION = 2 };
|
|
||||||
|
|
||||||
struct GasTuning {
|
struct GasTuning {
|
||||||
uint16_t index_offset;
|
uint16_t index_offset;
|
||||||
uint16_t learning_time_offset_hours;
|
uint16_t learning_time_offset_hours;
|
||||||
@@ -46,6 +44,12 @@ struct TemperatureCompensation {
|
|||||||
uint16_t time_constant;
|
uint16_t time_constant;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Shortest time interval of 3H for storing baseline values.
|
||||||
|
// Prevents wear of the flash because of too many write operations
|
||||||
|
static const uint32_t SHORTEST_BASELINE_STORE_INTERVAL = 10800;
|
||||||
|
// Store anyway if the baseline difference exceeds the max storage diff value
|
||||||
|
static const uint32_t MAXIMUM_STORAGE_DIFF = 50;
|
||||||
|
|
||||||
class SEN5XComponent : public PollingComponent, public sensirion_common::SensirionI2CDevice {
|
class SEN5XComponent : public PollingComponent, public sensirion_common::SensirionI2CDevice {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
@@ -102,8 +106,14 @@ class SEN5XComponent : public PollingComponent, public sensirion_common::Sensiri
|
|||||||
protected:
|
protected:
|
||||||
bool write_tuning_parameters_(uint16_t i2c_command, const GasTuning &tuning);
|
bool write_tuning_parameters_(uint16_t i2c_command, const GasTuning &tuning);
|
||||||
bool write_temperature_compensation_(const TemperatureCompensation &compensation);
|
bool write_temperature_compensation_(const TemperatureCompensation &compensation);
|
||||||
|
|
||||||
|
uint32_t seconds_since_last_store_;
|
||||||
|
uint16_t firmware_version_;
|
||||||
ERRORCODE error_code_;
|
ERRORCODE error_code_;
|
||||||
|
uint8_t serial_number_[4];
|
||||||
bool initialized_{false};
|
bool initialized_{false};
|
||||||
|
bool store_baseline_;
|
||||||
|
|
||||||
sensor::Sensor *pm_1_0_sensor_{nullptr};
|
sensor::Sensor *pm_1_0_sensor_{nullptr};
|
||||||
sensor::Sensor *pm_2_5_sensor_{nullptr};
|
sensor::Sensor *pm_2_5_sensor_{nullptr};
|
||||||
sensor::Sensor *pm_4_0_sensor_{nullptr};
|
sensor::Sensor *pm_4_0_sensor_{nullptr};
|
||||||
@@ -115,18 +125,14 @@ class SEN5XComponent : public PollingComponent, public sensirion_common::Sensiri
|
|||||||
// SEN55 only
|
// SEN55 only
|
||||||
sensor::Sensor *nox_sensor_{nullptr};
|
sensor::Sensor *nox_sensor_{nullptr};
|
||||||
|
|
||||||
std::string product_name_;
|
|
||||||
uint8_t serial_number_[4];
|
|
||||||
uint16_t firmware_version_;
|
|
||||||
Sen5xBaselines voc_baselines_storage_;
|
|
||||||
bool store_baseline_;
|
|
||||||
uint32_t seconds_since_last_store_;
|
|
||||||
ESPPreferenceObject pref_;
|
|
||||||
optional<RhtAccelerationMode> acceleration_mode_;
|
optional<RhtAccelerationMode> acceleration_mode_;
|
||||||
optional<uint32_t> auto_cleaning_interval_;
|
optional<uint32_t> auto_cleaning_interval_;
|
||||||
optional<GasTuning> voc_tuning_params_;
|
optional<GasTuning> voc_tuning_params_;
|
||||||
optional<GasTuning> nox_tuning_params_;
|
optional<GasTuning> nox_tuning_params_;
|
||||||
optional<TemperatureCompensation> temperature_compensation_;
|
optional<TemperatureCompensation> temperature_compensation_;
|
||||||
|
ESPPreferenceObject pref_;
|
||||||
|
std::string product_name_;
|
||||||
|
Sen5xBaselines voc_baselines_storage_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sen5x
|
} // namespace sen5x
|
||||||
|
@@ -11,21 +11,22 @@ static const char *const TAG = "sensirion_i2c";
|
|||||||
// To avoid memory allocations for small writes a stack buffer is used
|
// To avoid memory allocations for small writes a stack buffer is used
|
||||||
static const size_t BUFFER_STACK_SIZE = 16;
|
static const size_t BUFFER_STACK_SIZE = 16;
|
||||||
|
|
||||||
bool SensirionI2CDevice::read_data(uint16_t *data, uint8_t len) {
|
bool SensirionI2CDevice::read_data(uint16_t *data, const uint8_t len) {
|
||||||
const uint8_t num_bytes = len * 3;
|
const uint8_t num_bytes = len * 3;
|
||||||
std::vector<uint8_t> buf(num_bytes);
|
uint8_t buf[num_bytes];
|
||||||
|
|
||||||
last_error_ = this->read(buf.data(), num_bytes);
|
this->last_error_ = this->read(buf, num_bytes);
|
||||||
if (last_error_ != i2c::ERROR_OK) {
|
if (this->last_error_ != i2c::ERROR_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t i = 0; i < len; i++) {
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
const uint8_t j = 3 * i;
|
const uint8_t j = 3 * i;
|
||||||
uint8_t crc = sht_crc_(buf[j], buf[j + 1]);
|
// Use MSB first since Sensirion devices use CRC-8 with MSB first
|
||||||
|
uint8_t crc = crc8(&buf[j], 2, 0xFF, CRC_POLYNOMIAL, true);
|
||||||
if (crc != buf[j + 2]) {
|
if (crc != buf[j + 2]) {
|
||||||
ESP_LOGE(TAG, "CRC8 Checksum invalid at pos %d! 0x%02X != 0x%02X", i, buf[j + 2], crc);
|
ESP_LOGE(TAG, "CRC invalid @ %d! 0x%02X != 0x%02X", i, buf[j + 2], crc);
|
||||||
last_error_ = i2c::ERROR_CRC;
|
this->last_error_ = i2c::ERROR_CRC;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
data[i] = encode_uint16(buf[j], buf[j + 1]);
|
data[i] = encode_uint16(buf[j], buf[j + 1]);
|
||||||
@@ -34,10 +35,10 @@ bool SensirionI2CDevice::read_data(uint16_t *data, uint8_t len) {
|
|||||||
}
|
}
|
||||||
/***
|
/***
|
||||||
* write command with parameters and insert crc
|
* write command with parameters and insert crc
|
||||||
* use stack array for less than 4 parameters. Most sensirion i2c commands have less parameters
|
* use stack array for less than 4 parameters. Most Sensirion I2C commands have less parameters
|
||||||
*/
|
*/
|
||||||
bool SensirionI2CDevice::write_command_(uint16_t command, CommandLen command_len, const uint16_t *data,
|
bool SensirionI2CDevice::write_command_(uint16_t command, CommandLen command_len, const uint16_t *data,
|
||||||
uint8_t data_len) {
|
const uint8_t data_len) {
|
||||||
uint8_t temp_stack[BUFFER_STACK_SIZE];
|
uint8_t temp_stack[BUFFER_STACK_SIZE];
|
||||||
std::unique_ptr<uint8_t[]> temp_heap;
|
std::unique_ptr<uint8_t[]> temp_heap;
|
||||||
uint8_t *temp;
|
uint8_t *temp;
|
||||||
@@ -74,56 +75,26 @@ bool SensirionI2CDevice::write_command_(uint16_t command, CommandLen command_len
|
|||||||
temp[raw_idx++] = data[i] & 0xFF;
|
temp[raw_idx++] = data[i] & 0xFF;
|
||||||
temp[raw_idx++] = data[i] >> 8;
|
temp[raw_idx++] = data[i] >> 8;
|
||||||
#endif
|
#endif
|
||||||
temp[raw_idx++] = sht_crc_(data[i]);
|
// Use MSB first since Sensirion devices use CRC-8 with MSB first
|
||||||
|
temp[raw_idx++] = crc8(&temp[raw_idx - 2], 2, 0xFF, CRC_POLYNOMIAL, true);
|
||||||
}
|
}
|
||||||
last_error_ = this->write(temp, raw_idx);
|
this->last_error_ = this->write(temp, raw_idx);
|
||||||
return last_error_ == i2c::ERROR_OK;
|
return this->last_error_ == i2c::ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SensirionI2CDevice::get_register_(uint16_t reg, CommandLen command_len, uint16_t *data, uint8_t len,
|
bool SensirionI2CDevice::get_register_(uint16_t reg, CommandLen command_len, uint16_t *data, const uint8_t len,
|
||||||
uint8_t delay_ms) {
|
const uint8_t delay_ms) {
|
||||||
if (!this->write_command_(reg, command_len, nullptr, 0)) {
|
if (!this->write_command_(reg, command_len, nullptr, 0)) {
|
||||||
ESP_LOGE(TAG, "Failed to write i2c register=0x%X (%d) err=%d,", reg, command_len, this->last_error_);
|
ESP_LOGE(TAG, "Write failed: reg=0x%X (%d) err=%d,", reg, command_len, this->last_error_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(delay_ms);
|
delay(delay_ms);
|
||||||
bool result = this->read_data(data, len);
|
bool result = this->read_data(data, len);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
ESP_LOGE(TAG, "Failed to read data from register=0x%X err=%d,", reg, this->last_error_);
|
ESP_LOGE(TAG, "Read failed: reg=0x%X err=%d,", reg, this->last_error_);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The 8-bit CRC checksum is transmitted after each data word
|
|
||||||
uint8_t SensirionI2CDevice::sht_crc_(uint16_t data) {
|
|
||||||
uint8_t bit;
|
|
||||||
uint8_t crc = 0xFF;
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
crc ^= data >> 8;
|
|
||||||
#else
|
|
||||||
crc ^= data & 0xFF;
|
|
||||||
#endif
|
|
||||||
for (bit = 8; bit > 0; --bit) {
|
|
||||||
if (crc & 0x80) {
|
|
||||||
crc = (crc << 1) ^ crc_polynomial_;
|
|
||||||
} else {
|
|
||||||
crc = (crc << 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
||||||
crc ^= data & 0xFF;
|
|
||||||
#else
|
|
||||||
crc ^= data >> 8;
|
|
||||||
#endif
|
|
||||||
for (bit = 8; bit > 0; --bit) {
|
|
||||||
if (crc & 0x80) {
|
|
||||||
crc = (crc << 1) ^ crc_polynomial_;
|
|
||||||
} else {
|
|
||||||
crc = (crc << 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sensirion_common
|
} // namespace sensirion_common
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@@ -8,10 +8,10 @@ namespace esphome {
|
|||||||
namespace sensirion_common {
|
namespace sensirion_common {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of a i2c functions for Sensirion sensors
|
* Implementation of I2C functions for Sensirion sensors
|
||||||
* Sensirion data requires crc checking.
|
* Sensirion data requires CRC checking.
|
||||||
* Each 16 bit word is/must be followed 8 bit CRC code
|
* Each 16 bit word is/must be followed 8 bit CRC code
|
||||||
* (Applies to read and write - note the i2c command code doesn't need a CRC)
|
* (Applies to read and write - note the I2C command code doesn't need a CRC)
|
||||||
* Format:
|
* Format:
|
||||||
* | 16 Bit Command Code | 16 bit Data word 1 | CRC of DW 1 | 16 bit Data word 1 | CRC of DW 2 | ..
|
* | 16 Bit Command Code | 16 bit Data word 1 | CRC of DW 1 | 16 bit Data word 1 | CRC of DW 2 | ..
|
||||||
*/
|
*/
|
||||||
@@ -21,79 +21,79 @@ class SensirionI2CDevice : public i2c::I2CDevice {
|
|||||||
public:
|
public:
|
||||||
enum CommandLen : uint8_t { ADDR_8_BIT = 1, ADDR_16_BIT = 2 };
|
enum CommandLen : uint8_t { ADDR_8_BIT = 1, ADDR_16_BIT = 2 };
|
||||||
|
|
||||||
/** Read data words from i2c device.
|
/** Read data words from I2C device.
|
||||||
* handles crc check used by Sensirion sensors
|
* handles CRC check used by Sensirion sensors
|
||||||
* @param data pointer to raw result
|
* @param data pointer to raw result
|
||||||
* @param len number of words to read
|
* @param len number of words to read
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool read_data(uint16_t *data, uint8_t len);
|
bool read_data(uint16_t *data, uint8_t len);
|
||||||
|
|
||||||
/** Read 1 data word from i2c device.
|
/** Read 1 data word from I2C device.
|
||||||
* @param data reference to raw result
|
* @param data reference to raw result
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool read_data(uint16_t &data) { return this->read_data(&data, 1); }
|
bool read_data(uint16_t &data) { return this->read_data(&data, 1); }
|
||||||
|
|
||||||
/** get data words from i2c register.
|
/** get data words from I2C register.
|
||||||
* handles crc check used by Sensirion sensors
|
* handles CRC check used by Sensirion sensors
|
||||||
* @param i2c register
|
* @param I2C register
|
||||||
* @param data pointer to raw result
|
* @param data pointer to raw result
|
||||||
* @param len number of words to read
|
* @param len number of words to read
|
||||||
* @param delay milliseconds to to wait between sending the i2c command and reading the result
|
* @param delay milliseconds to to wait between sending the I2C command and reading the result
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool get_register(uint16_t command, uint16_t *data, uint8_t len, uint8_t delay = 0) {
|
bool get_register(uint16_t command, uint16_t *data, uint8_t len, uint8_t delay = 0) {
|
||||||
return get_register_(command, ADDR_16_BIT, data, len, delay);
|
return get_register_(command, ADDR_16_BIT, data, len, delay);
|
||||||
}
|
}
|
||||||
/** Read 1 data word from 16 bit i2c register.
|
/** Read 1 data word from 16 bit I2C register.
|
||||||
* @param i2c register
|
* @param I2C register
|
||||||
* @param data reference to raw result
|
* @param data reference to raw result
|
||||||
* @param delay milliseconds to to wait between sending the i2c command and reading the result
|
* @param delay milliseconds to to wait between sending the I2C command and reading the result
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool get_register(uint16_t i2c_register, uint16_t &data, uint8_t delay = 0) {
|
bool get_register(uint16_t i2c_register, uint16_t &data, uint8_t delay = 0) {
|
||||||
return this->get_register_(i2c_register, ADDR_16_BIT, &data, 1, delay);
|
return this->get_register_(i2c_register, ADDR_16_BIT, &data, 1, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get data words from i2c register.
|
/** get data words from I2C register.
|
||||||
* handles crc check used by Sensirion sensors
|
* handles CRC check used by Sensirion sensors
|
||||||
* @param i2c register
|
* @param I2C register
|
||||||
* @param data pointer to raw result
|
* @param data pointer to raw result
|
||||||
* @param len number of words to read
|
* @param len number of words to read
|
||||||
* @param delay milliseconds to to wait between sending the i2c command and reading the result
|
* @param delay milliseconds to to wait between sending the I2C command and reading the result
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool get_8bit_register(uint8_t i2c_register, uint16_t *data, uint8_t len, uint8_t delay = 0) {
|
bool get_8bit_register(uint8_t i2c_register, uint16_t *data, uint8_t len, uint8_t delay = 0) {
|
||||||
return get_register_(i2c_register, ADDR_8_BIT, data, len, delay);
|
return get_register_(i2c_register, ADDR_8_BIT, data, len, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read 1 data word from 8 bit i2c register.
|
/** Read 1 data word from 8 bit I2C register.
|
||||||
* @param i2c register
|
* @param I2C register
|
||||||
* @param data reference to raw result
|
* @param data reference to raw result
|
||||||
* @param delay milliseconds to to wait between sending the i2c command and reading the result
|
* @param delay milliseconds to to wait between sending the I2C command and reading the result
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool get_8bit_register(uint8_t i2c_register, uint16_t &data, uint8_t delay = 0) {
|
bool get_8bit_register(uint8_t i2c_register, uint16_t &data, uint8_t delay = 0) {
|
||||||
return this->get_register_(i2c_register, ADDR_8_BIT, &data, 1, delay);
|
return this->get_register_(i2c_register, ADDR_8_BIT, &data, 1, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write a command to the i2c device.
|
/** Write a command to the I2C device.
|
||||||
* @param command i2c command to send
|
* @param command I2C command to send
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
template<class T> bool write_command(T i2c_register) { return write_command(i2c_register, nullptr, 0); }
|
template<class T> bool write_command(T i2c_register) { return write_command(i2c_register, nullptr, 0); }
|
||||||
|
|
||||||
/** Write a command and one data word to the i2c device .
|
/** Write a command and one data word to the I2C device .
|
||||||
* @param command i2c command to send
|
* @param command I2C command to send
|
||||||
* @param data argument for the i2c command
|
* @param data argument for the I2C command
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
template<class T> bool write_command(T i2c_register, uint16_t data) { return write_command(i2c_register, &data, 1); }
|
template<class T> bool write_command(T i2c_register, uint16_t data) { return write_command(i2c_register, &data, 1); }
|
||||||
|
|
||||||
/** Write a command with arguments as words
|
/** Write a command with arguments as words
|
||||||
* @param i2c_register i2c command to send - an be uint8_t or uint16_t
|
* @param i2c_register I2C command to send - an be uint8_t or uint16_t
|
||||||
* @param data vector<uint16> arguments for the i2c command
|
* @param data vector<uint16> arguments for the I2C command
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
template<class T> bool write_command(T i2c_register, const std::vector<uint16_t> &data) {
|
template<class T> bool write_command(T i2c_register, const std::vector<uint16_t> &data) {
|
||||||
@@ -101,57 +101,39 @@ class SensirionI2CDevice : public i2c::I2CDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Write a command with arguments as words
|
/** Write a command with arguments as words
|
||||||
* @param i2c_register i2c command to send - an be uint8_t or uint16_t
|
* @param i2c_register I2C command to send - an be uint8_t or uint16_t
|
||||||
* @param data arguments for the i2c command
|
* @param data arguments for the I2C command
|
||||||
* @param len number of arguments (words)
|
* @param len number of arguments (words)
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
template<class T> bool write_command(T i2c_register, const uint16_t *data, uint8_t len) {
|
template<class T> bool write_command(T i2c_register, const uint16_t *data, uint8_t len) {
|
||||||
// limit to 8 or 16 bit only
|
// limit to 8 or 16 bit only
|
||||||
static_assert(sizeof(i2c_register) == 1 || sizeof(i2c_register) == 2,
|
static_assert(sizeof(i2c_register) == 1 || sizeof(i2c_register) == 2, "Only 8 or 16 bit command types supported");
|
||||||
"only 8 or 16 bit command types are supported.");
|
|
||||||
return write_command_(i2c_register, CommandLen(sizeof(T)), data, len);
|
return write_command_(i2c_register, CommandLen(sizeof(T)), data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint8_t crc_polynomial_{0x31u}; // default for sensirion
|
|
||||||
/** Write a command with arguments as words
|
/** Write a command with arguments as words
|
||||||
* @param command i2c command to send can be uint8_t or uint16_t
|
* @param command I2C command to send can be uint8_t or uint16_t
|
||||||
* @param command_len either 1 for short 8 bit command or 2 for 16 bit command codes
|
* @param command_len either 1 for short 8 bit command or 2 for 16 bit command codes
|
||||||
* @param data arguments for the i2c command
|
* @param data arguments for the I2C command
|
||||||
* @param data_len number of arguments (words)
|
* @param data_len number of arguments (words)
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool write_command_(uint16_t command, CommandLen command_len, const uint16_t *data, uint8_t data_len);
|
bool write_command_(uint16_t command, CommandLen command_len, const uint16_t *data, uint8_t data_len);
|
||||||
|
|
||||||
/** get data words from i2c register.
|
/** get data words from I2C register.
|
||||||
* handles crc check used by Sensirion sensors
|
* handles CRC check used by Sensirion sensors
|
||||||
* @param i2c register
|
* @param I2C register
|
||||||
* @param command_len either 1 for short 8 bit command or 2 for 16 bit command codes
|
* @param command_len either 1 for short 8 bit command or 2 for 16 bit command codes
|
||||||
* @param data pointer to raw result
|
* @param data pointer to raw result
|
||||||
* @param len number of words to read
|
* @param len number of words to read
|
||||||
* @param delay milliseconds to to wait between sending the i2c command and reading the result
|
* @param delay milliseconds to to wait between sending the I2C command and reading the result
|
||||||
* @return true if reading succeeded
|
* @return true if reading succeeded
|
||||||
*/
|
*/
|
||||||
bool get_register_(uint16_t reg, CommandLen command_len, uint16_t *data, uint8_t len, uint8_t delay);
|
bool get_register_(uint16_t reg, CommandLen command_len, uint16_t *data, uint8_t len, uint8_t delay);
|
||||||
|
|
||||||
/** 8-bit CRC checksum that is transmitted after each data word for read and write operation
|
/** last error code from I2C operation
|
||||||
* @param command i2c command to send
|
|
||||||
* @param data data word for which the crc8 checksum is calculated
|
|
||||||
* @param len number of arguments (words)
|
|
||||||
* @return 8 Bit CRC
|
|
||||||
*/
|
|
||||||
uint8_t sht_crc_(uint16_t data);
|
|
||||||
|
|
||||||
/** 8-bit CRC checksum that is transmitted after each data word for read and write operation
|
|
||||||
* @param command i2c command to send
|
|
||||||
* @param data1 high byte of data word
|
|
||||||
* @param data2 low byte of data word
|
|
||||||
* @return 8 Bit CRC
|
|
||||||
*/
|
|
||||||
uint8_t sht_crc_(uint8_t data1, uint8_t data2) { return sht_crc_(encode_uint16(data1, data2)); }
|
|
||||||
|
|
||||||
/** last error code from i2c operation
|
|
||||||
*/
|
*/
|
||||||
i2c::ErrorCode last_error_;
|
i2c::ErrorCode last_error_;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user