#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 { namespace 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 : 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 acceleration_mode_; optional auto_cleaning_interval_; optional voc_tuning_params_; optional nox_tuning_params_; optional temperature_compensation_; ESPPreferenceObject pref_; }; } // namespace sen5x } // namespace esphome