Files
esphome/esphome/components/sen5x/sen5x.h
Jesse Hills ebe867b1f9 Mark user-configurable classes as final (part 15/21)
Add the C++ `final` specifier to leaf, user-configurable component classes and
automation action/trigger/condition primitives so that classes meant to be
terminal cannot be subclassed by external components. Only classes never used as
a base anywhere in the tree are marked. Part 15 of 21, split alphabetically by
component (script .. slow_pwm).
2026-06-15 13:21:46 +12:00

133 lines
5.2 KiB
C++

#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/sensirion_common/i2c_sensirion.h"
#include "esphome/core/application.h"
#include "esphome/core/preferences.h"
namespace esphome::sen5x {
enum ERRORCODE : uint8_t {
COMMUNICATION_FAILED,
SERIAL_NUMBER_IDENTIFICATION_FAILED,
MEASUREMENT_INIT_FAILED,
PRODUCT_NAME_FAILED,
FIRMWARE_FAILED,
UNKNOWN
};
enum RhtAccelerationMode : uint16_t {
LOW_ACCELERATION = 0,
MEDIUM_ACCELERATION = 1,
HIGH_ACCELERATION = 2,
};
enum class Sen5xType : uint8_t { SEN50, SEN54, SEN55, UNKNOWN };
struct GasTuning {
uint16_t index_offset;
uint16_t learning_time_offset_hours;
uint16_t learning_time_gain_hours;
uint16_t gating_max_duration_minutes;
uint16_t std_initial;
uint16_t gain_factor;
};
struct TemperatureCompensation {
int16_t offset;
int16_t normalized_offset_slope;
uint16_t time_constant;
};
// Shortest time interval of 2H (in milliseconds) for storing baseline values.
// Prevents wear of the flash because of too many write operations
static const uint32_t SHORTEST_BASELINE_STORE_INTERVAL = 2 * 60 * 60 * 1000;
class SEN5XComponent final : public PollingComponent, public sensirion_common::SensirionI2CDevice {
public:
void setup() override;
void dump_config() override;
void update() override;
void set_pm_1_0_sensor(sensor::Sensor *pm_1_0) { this->pm_1_0_sensor_ = pm_1_0; }
void set_pm_2_5_sensor(sensor::Sensor *pm_2_5) { this->pm_2_5_sensor_ = pm_2_5; }
void set_pm_4_0_sensor(sensor::Sensor *pm_4_0) { this->pm_4_0_sensor_ = pm_4_0; }
void set_pm_10_0_sensor(sensor::Sensor *pm_10_0) { this->pm_10_0_sensor_ = pm_10_0; }
void set_voc_sensor(sensor::Sensor *voc_sensor) { this->voc_sensor_ = voc_sensor; }
void set_nox_sensor(sensor::Sensor *nox_sensor) { this->nox_sensor_ = nox_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
void set_store_baseline(bool store_baseline) { this->store_baseline_ = store_baseline; }
void set_acceleration_mode(RhtAccelerationMode mode) { this->acceleration_mode_ = mode; }
void set_auto_cleaning_interval(uint32_t auto_cleaning_interval) {
this->auto_cleaning_interval_ = auto_cleaning_interval;
}
void set_voc_algorithm_tuning(uint16_t index_offset, uint16_t learning_time_offset_hours,
uint16_t learning_time_gain_hours, uint16_t gating_max_duration_minutes,
uint16_t std_initial, uint16_t gain_factor) {
GasTuning tuning_params;
tuning_params.index_offset = index_offset;
tuning_params.learning_time_offset_hours = learning_time_offset_hours;
tuning_params.learning_time_gain_hours = learning_time_gain_hours;
tuning_params.gating_max_duration_minutes = gating_max_duration_minutes;
tuning_params.std_initial = std_initial;
tuning_params.gain_factor = gain_factor;
this->voc_tuning_params_ = tuning_params;
}
void set_nox_algorithm_tuning(uint16_t index_offset, uint16_t learning_time_offset_hours,
uint16_t learning_time_gain_hours, uint16_t gating_max_duration_minutes,
uint16_t gain_factor) {
GasTuning tuning_params;
tuning_params.index_offset = index_offset;
tuning_params.learning_time_offset_hours = learning_time_offset_hours;
tuning_params.learning_time_gain_hours = learning_time_gain_hours;
tuning_params.gating_max_duration_minutes = gating_max_duration_minutes;
tuning_params.std_initial = 50;
tuning_params.gain_factor = gain_factor;
this->nox_tuning_params_ = tuning_params;
}
void set_temperature_compensation(float offset, float normalized_offset_slope, uint16_t time_constant) {
TemperatureCompensation temp_comp;
temp_comp.offset = offset * 200;
temp_comp.normalized_offset_slope = normalized_offset_slope * 10000;
temp_comp.time_constant = time_constant;
this->temperature_compensation_ = temp_comp;
}
bool start_fan_cleaning();
protected:
bool write_tuning_parameters_(uint16_t i2c_command, const GasTuning &tuning);
bool write_temperature_compensation_(const TemperatureCompensation &compensation);
char serial_number_[17] = "UNKNOWN";
uint16_t voc_baseline_state_[4]{0};
uint32_t voc_baseline_time_{0};
uint16_t firmware_version_{0};
Sen5xType type_{Sen5xType::UNKNOWN};
ERRORCODE error_code_{ERRORCODE::UNKNOWN};
bool initialized_{false};
bool store_baseline_{false};
sensor::Sensor *pm_1_0_sensor_{nullptr};
sensor::Sensor *pm_2_5_sensor_{nullptr};
sensor::Sensor *pm_4_0_sensor_{nullptr};
sensor::Sensor *pm_10_0_sensor_{nullptr};
// SEN54 and SEN55 only
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
sensor::Sensor *voc_sensor_{nullptr};
// SEN55 only
sensor::Sensor *nox_sensor_{nullptr};
optional<RhtAccelerationMode> acceleration_mode_;
optional<uint32_t> auto_cleaning_interval_;
optional<GasTuning> voc_tuning_params_;
optional<GasTuning> nox_tuning_params_;
optional<TemperatureCompensation> temperature_compensation_;
ESPPreferenceObject pref_;
};
} // namespace esphome::sen5x