ESPHome 2025.9.0-dev
Loading...
Searching...
No Matches
bme68x_bsec2.cpp
Go to the documentation of this file.
2#include "esphome/core/hal.h"
4#include "esphome/core/log.h"
5
6#ifdef USE_BSEC2
7#include "bme68x_bsec2.h"
8
9#include <string>
10
11namespace esphome {
12namespace bme68x_bsec2 {
13
14#define BME68X_BSEC2_ALGORITHM_OUTPUT_LOG(a) (a == ALGORITHM_OUTPUT_CLASSIFICATION ? "Classification" : "Regression")
15#define BME68X_BSEC2_OPERATING_AGE_LOG(o) (o == OPERATING_AGE_4D ? "4 days" : "28 days")
16#define BME68X_BSEC2_SAMPLE_RATE_LOG(r) (r == SAMPLE_RATE_DEFAULT ? "Default" : (r == SAMPLE_RATE_ULP ? "ULP" : "LP"))
17#define BME68X_BSEC2_VOLTAGE_LOG(v) (v == VOLTAGE_3_3V ? "3.3V" : "1.8V")
18
19static const char *const TAG = "bme68x_bsec2.sensor";
20
21static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
22
24 this->bsec_status_ = bsec_init_m(&this->bsec_instance_);
25 if (this->bsec_status_ != BSEC_OK) {
26 this->mark_failed();
27 ESP_LOGE(TAG, "bsec_init_m failed: status %d", this->bsec_status_);
28 return;
29 }
30
31 bsec_get_version_m(&this->bsec_instance_, &this->version_);
32
33 this->bme68x_status_ = bme68x_init(&this->bme68x_);
34 if (this->bme68x_status_ != BME68X_OK) {
35 this->mark_failed();
36 ESP_LOGE(TAG, "bme68x_init failed: status %d", this->bme68x_status_);
37 return;
38 }
39 if (this->bsec2_configuration_ != nullptr && this->bsec2_configuration_length_) {
41 if (this->bsec_status_ != BSEC_OK) {
42 this->mark_failed();
43 ESP_LOGE(TAG, "bsec_set_configuration_m failed: status %d", this->bsec_status_);
44 return;
45 }
46 }
47
49 if (this->bsec_status_ != BSEC_OK) {
50 this->mark_failed();
51 ESP_LOGE(TAG, "bsec_update_subscription_m failed: status %d", this->bsec_status_);
52 return;
53 }
54
55 this->load_state_();
56}
57
59 ESP_LOGCONFIG(TAG,
60 "BME68X via BSEC2:\n"
61 " BSEC2 version: %d.%d.%d.%d\n"
62 " BSEC2 configuration blob:\n"
63 " Configured: %s",
64 this->version_.major, this->version_.minor, this->version_.major_bugfix, this->version_.minor_bugfix,
65 YESNO(this->bsec2_blob_configured_));
66 if (this->bsec2_configuration_ != nullptr && this->bsec2_configuration_length_) {
67 ESP_LOGCONFIG(TAG, " Size: %" PRIu32, this->bsec2_configuration_length_);
68 }
69
70 if (this->is_failed()) {
71 ESP_LOGE(TAG, "Communication failed (BSEC2 status: %d, BME68X status: %d)", this->bsec_status_,
72 this->bme68x_status_);
73 }
74
76 ESP_LOGCONFIG(TAG, " Algorithm output: %s", BME68X_BSEC2_ALGORITHM_OUTPUT_LOG(this->algorithm_output_));
77 }
78 ESP_LOGCONFIG(TAG,
79 " Operating age: %s\n"
80 " Sample rate: %s\n"
81 " Voltage: %s\n"
82 " State save interval: %ims\n"
83 " Temperature offset: %.2f",
84 BME68X_BSEC2_OPERATING_AGE_LOG(this->operating_age_), BME68X_BSEC2_SAMPLE_RATE_LOG(this->sample_rate_),
85 BME68X_BSEC2_VOLTAGE_LOG(this->voltage_), this->state_save_interval_ms_, this->temperature_offset_);
86
87#ifdef USE_SENSOR
88 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
89 ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->temperature_sample_rate_));
90 LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
91 ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->pressure_sample_rate_));
92 LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
93 ESP_LOGCONFIG(TAG, " Sample rate: %s", BME68X_BSEC2_SAMPLE_RATE_LOG(this->humidity_sample_rate_));
94 LOG_SENSOR(" ", "Gas resistance", this->gas_resistance_sensor_);
95 LOG_SENSOR(" ", "CO2 equivalent", this->co2_equivalent_sensor_);
96 LOG_SENSOR(" ", "Breath VOC equivalent", this->breath_voc_equivalent_sensor_);
97 LOG_SENSOR(" ", "IAQ", this->iaq_sensor_);
98 LOG_SENSOR(" ", "IAQ static", this->iaq_static_sensor_);
99 LOG_SENSOR(" ", "Numeric IAQ accuracy", this->iaq_accuracy_sensor_);
100#endif
101#ifdef USE_TEXT_SENSOR
102 LOG_TEXT_SENSOR(" ", "IAQ accuracy", this->iaq_accuracy_text_sensor_);
103#endif
104}
105
107
109 this->run_();
110
112 this->status_set_error();
113 } else {
114 this->status_clear_error();
115 }
116 if (this->bsec_status_ > BSEC_OK || this->bme68x_status_ > BME68X_OK) {
117 this->status_set_warning();
118 } else {
119 this->status_clear_warning();
120 }
121 // Process a single action from the queue. These are primarily sensor state publishes
122 // that in totality take too long to send in a single call.
123 if (this->queue_.size()) {
124 auto action = std::move(this->queue_.front());
125 this->queue_.pop();
126 action();
127 }
128}
129
130void BME68xBSEC2Component::set_config_(const uint8_t *config, uint32_t len) {
131 if (len > BSEC_MAX_PROPERTY_BLOB_SIZE) {
132 ESP_LOGE(TAG, "Configuration is larger than BSEC_MAX_PROPERTY_BLOB_SIZE");
133 this->mark_failed();
134 return;
135 }
136 uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
137 this->bsec_status_ = bsec_set_configuration_m(&this->bsec_instance_, config, len, work_buffer, sizeof(work_buffer));
138 if (this->bsec_status_ == BSEC_OK) {
139 this->bsec2_blob_configured_ = true;
140 }
141}
142
144 if (sample_rate == SAMPLE_RATE_DEFAULT) {
145 sample_rate = this->sample_rate_;
146 }
147 return sample_rate == SAMPLE_RATE_ULP ? BSEC_SAMPLE_RATE_ULP : BSEC_SAMPLE_RATE_LP;
148}
149
151 bsec_sensor_configuration_t virtual_sensors[BSEC_NUMBER_OUTPUTS];
152 uint8_t num_virtual_sensors = 0;
153#ifdef USE_SENSOR
154 if (this->iaq_sensor_) {
155 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_IAQ;
156 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
157 num_virtual_sensors++;
158 }
159
160 if (this->iaq_static_sensor_) {
161 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_STATIC_IAQ;
162 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
163 num_virtual_sensors++;
164 }
165
166 if (this->co2_equivalent_sensor_) {
167 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT;
168 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
169 num_virtual_sensors++;
170 }
171
173 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_BREATH_VOC_EQUIVALENT;
174 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
175 num_virtual_sensors++;
176 }
177
178 if (this->pressure_sensor_) {
179 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
180 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->pressure_sample_rate_);
181 num_virtual_sensors++;
182 }
183
184 if (this->gas_resistance_sensor_) {
185 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_RAW_GAS;
186 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(SAMPLE_RATE_DEFAULT);
187 num_virtual_sensors++;
188 }
189
190 if (this->temperature_sensor_) {
191 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
192 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->temperature_sample_rate_);
193 num_virtual_sensors++;
194 }
195
196 if (this->humidity_sensor_) {
197 virtual_sensors[num_virtual_sensors].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
198 virtual_sensors[num_virtual_sensors].sample_rate = this->calc_sensor_sample_rate_(this->humidity_sample_rate_);
199 num_virtual_sensors++;
200 }
201#endif
202 bsec_sensor_configuration_t sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
203 uint8_t num_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
204 this->bsec_status_ = bsec_update_subscription_m(&this->bsec_instance_, virtual_sensors, num_virtual_sensors,
205 sensor_settings, &num_sensor_settings);
206}
207
209 this->op_mode_ = this->bsec_settings_.op_mode;
210 int64_t curr_time_ns = this->get_time_ns_();
211 if (curr_time_ns < this->bsec_settings_.next_call) {
212 return;
213 }
214 uint8_t status;
215
216 ESP_LOGV(TAG, "Performing sensor run");
217
218 struct bme68x_conf bme68x_conf;
219 this->bsec_status_ = bsec_sensor_control_m(&this->bsec_instance_, curr_time_ns, &this->bsec_settings_);
220 if (this->bsec_status_ < BSEC_OK) {
221 ESP_LOGW(TAG, "Failed to fetch sensor control settings (BSEC2 error code %d)", this->bsec_status_);
222 return;
223 }
224
225 switch (this->bsec_settings_.op_mode) {
226 case BME68X_FORCED_MODE:
227 bme68x_get_conf(&bme68x_conf, &this->bme68x_);
228
229 bme68x_conf.os_hum = this->bsec_settings_.humidity_oversampling;
230 bme68x_conf.os_temp = this->bsec_settings_.temperature_oversampling;
231 bme68x_conf.os_pres = this->bsec_settings_.pressure_oversampling;
232 bme68x_set_conf(&bme68x_conf, &this->bme68x_);
233 this->bme68x_heatr_conf_.enable = BME68X_ENABLE;
234 this->bme68x_heatr_conf_.heatr_temp = this->bsec_settings_.heater_temperature;
235 this->bme68x_heatr_conf_.heatr_dur = this->bsec_settings_.heater_duration;
236
237 // status = bme68x_set_op_mode(this->bsec_settings_.op_mode, &this->bme68x_);
238 status = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &this->bme68x_heatr_conf_, &this->bme68x_);
239 status = bme68x_set_op_mode(BME68X_FORCED_MODE, &this->bme68x_);
240 this->op_mode_ = BME68X_FORCED_MODE;
241 ESP_LOGV(TAG, "Using forced mode");
242
243 break;
244 case BME68X_PARALLEL_MODE:
245 if (this->op_mode_ != this->bsec_settings_.op_mode) {
246 bme68x_get_conf(&bme68x_conf, &this->bme68x_);
247
248 bme68x_conf.os_hum = this->bsec_settings_.humidity_oversampling;
249 bme68x_conf.os_temp = this->bsec_settings_.temperature_oversampling;
250 bme68x_conf.os_pres = this->bsec_settings_.pressure_oversampling;
251 bme68x_set_conf(&bme68x_conf, &this->bme68x_);
252
253 this->bme68x_heatr_conf_.enable = BME68X_ENABLE;
254 this->bme68x_heatr_conf_.heatr_temp_prof = this->bsec_settings_.heater_temperature_profile;
255 this->bme68x_heatr_conf_.heatr_dur_prof = this->bsec_settings_.heater_duration_profile;
256 this->bme68x_heatr_conf_.profile_len = this->bsec_settings_.heater_profile_len;
257 this->bme68x_heatr_conf_.shared_heatr_dur =
258 BSEC_TOTAL_HEAT_DUR -
259 (bme68x_get_meas_dur(BME68X_PARALLEL_MODE, &bme68x_conf, &this->bme68x_) / INT64_C(1000));
260
261 status = bme68x_set_heatr_conf(BME68X_PARALLEL_MODE, &this->bme68x_heatr_conf_, &this->bme68x_);
262
263 status = bme68x_set_op_mode(BME68X_PARALLEL_MODE, &this->bme68x_);
264 this->op_mode_ = BME68X_PARALLEL_MODE;
265 ESP_LOGV(TAG, "Using parallel mode");
266 }
267 break;
268 case BME68X_SLEEP_MODE:
269 if (this->op_mode_ != this->bsec_settings_.op_mode) {
270 bme68x_set_op_mode(BME68X_SLEEP_MODE, &this->bme68x_);
271 this->op_mode_ = BME68X_SLEEP_MODE;
272 ESP_LOGV(TAG, "Using sleep mode");
273 }
274 break;
275 }
276
277 if (this->bsec_settings_.trigger_measurement && this->bsec_settings_.op_mode != BME68X_SLEEP_MODE) {
278 uint32_t meas_dur = 0;
279 meas_dur = bme68x_get_meas_dur(this->op_mode_, &bme68x_conf, &this->bme68x_);
280 ESP_LOGV(TAG, "Queueing read in %uus", meas_dur);
281 this->set_timeout("read", meas_dur / 1000, [this, curr_time_ns]() { this->read_(curr_time_ns); });
282 } else {
283 ESP_LOGV(TAG, "Measurement not required");
284 this->read_(curr_time_ns);
285 }
286}
287
288void BME68xBSEC2Component::read_(int64_t trigger_time_ns) {
289 ESP_LOGV(TAG, "Reading data");
290
291 if (this->bsec_settings_.trigger_measurement) {
292 uint8_t current_op_mode;
293 this->bme68x_status_ = bme68x_get_op_mode(&current_op_mode, &this->bme68x_);
294
295 if (current_op_mode == BME68X_SLEEP_MODE) {
296 ESP_LOGV(TAG, "Still in sleep mode, doing nothing");
297 return;
298 }
299 }
300
301 if (!this->bsec_settings_.process_data) {
302 ESP_LOGV(TAG, "Data processing not required");
303 return;
304 }
305
306 struct bme68x_data data[3];
307 uint8_t nFields = 0;
308 this->bme68x_status_ = bme68x_get_data(this->op_mode_, &data[0], &nFields, &this->bme68x_);
309
310 if (this->bme68x_status_ != BME68X_OK) {
311 ESP_LOGW(TAG, "Failed to get sensor data (BME68X error code %d)", this->bme68x_status_);
312 return;
313 }
314 if (nFields < 1) {
315 ESP_LOGD(TAG, "BME68X did not provide new data");
316 return;
317 }
318
319 for (uint8_t i = 0; i < nFields; i++) {
320 bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance
321 uint8_t num_inputs = 0;
322
323 if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_TEMPERATURE)) {
324 inputs[num_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
325 inputs[num_inputs].signal = data[i].temperature;
326 inputs[num_inputs].time_stamp = trigger_time_ns;
327 num_inputs++;
328 }
329 if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_HEATSOURCE)) {
330 inputs[num_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
331 inputs[num_inputs].signal = this->temperature_offset_;
332 inputs[num_inputs].time_stamp = trigger_time_ns;
333 num_inputs++;
334 }
335 if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_HUMIDITY)) {
336 inputs[num_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
337 inputs[num_inputs].signal = data[i].humidity;
338 inputs[num_inputs].time_stamp = trigger_time_ns;
339 num_inputs++;
340 }
341 if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_PRESSURE)) {
342 inputs[num_inputs].sensor_id = BSEC_INPUT_PRESSURE;
343 inputs[num_inputs].signal = data[i].pressure;
344 inputs[num_inputs].time_stamp = trigger_time_ns;
345 num_inputs++;
346 }
347 if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_GASRESISTOR)) {
348 if (data[i].status & BME68X_GASM_VALID_MSK) {
349 inputs[num_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
350 inputs[num_inputs].signal = data[i].gas_resistance;
351 inputs[num_inputs].time_stamp = trigger_time_ns;
352 num_inputs++;
353 } else {
354 ESP_LOGD(TAG, "BME68X did not report gas data");
355 }
356 }
357 if (BSEC_CHECK_INPUT(this->bsec_settings_.process_data, BSEC_INPUT_PROFILE_PART) &&
358 (data[i].status & BME68X_GASM_VALID_MSK)) {
359 inputs[num_inputs].sensor_id = BSEC_INPUT_PROFILE_PART;
360 inputs[num_inputs].signal = (this->op_mode_ == BME68X_FORCED_MODE) ? 0 : data[i].gas_index;
361 inputs[num_inputs].time_stamp = trigger_time_ns;
362 num_inputs++;
363 }
364
365 if (num_inputs < 1) {
366 ESP_LOGD(TAG, "No signal inputs available for BSEC2");
367 return;
368 }
369
370 bsec_output_t outputs[BSEC_NUMBER_OUTPUTS];
371 uint8_t num_outputs = BSEC_NUMBER_OUTPUTS;
372 this->bsec_status_ = bsec_do_steps_m(&this->bsec_instance_, inputs, num_inputs, outputs, &num_outputs);
373 if (this->bsec_status_ != BSEC_OK) {
374 ESP_LOGW(TAG, "BSEC2 failed to process signals (BSEC2 error code %d)", this->bsec_status_);
375 return;
376 }
377 if (num_outputs < 1) {
378 ESP_LOGD(TAG, "No signal outputs provided by BSEC2");
379 return;
380 }
381
382 this->publish_(outputs, num_outputs);
383 }
384}
385
386void BME68xBSEC2Component::publish_(const bsec_output_t *outputs, uint8_t num_outputs) {
387 ESP_LOGV(TAG, "Publishing sensor states");
388 bool update_accuracy = false;
389 uint8_t max_accuracy = 0;
390 for (uint8_t i = 0; i < num_outputs; i++) {
391 float signal = outputs[i].signal;
392 switch (outputs[i].sensor_id) {
393 case BSEC_OUTPUT_IAQ:
394 max_accuracy = std::max(outputs[i].accuracy, max_accuracy);
395 update_accuracy = true;
396#ifdef USE_SENSOR
397 this->queue_push_([this, signal]() { this->publish_sensor_(this->iaq_sensor_, signal); });
398#endif
399 break;
400 case BSEC_OUTPUT_STATIC_IAQ:
401 max_accuracy = std::max(outputs[i].accuracy, max_accuracy);
402 update_accuracy = true;
403#ifdef USE_SENSOR
404 this->queue_push_([this, signal]() { this->publish_sensor_(this->iaq_static_sensor_, signal); });
405#endif
406 break;
407 case BSEC_OUTPUT_CO2_EQUIVALENT:
408#ifdef USE_SENSOR
409 this->queue_push_([this, signal]() { this->publish_sensor_(this->co2_equivalent_sensor_, signal); });
410#endif
411 break;
412 case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
413#ifdef USE_SENSOR
414 this->queue_push_([this, signal]() { this->publish_sensor_(this->breath_voc_equivalent_sensor_, signal); });
415#endif
416 break;
417 case BSEC_OUTPUT_RAW_PRESSURE:
418#ifdef USE_SENSOR
419 this->queue_push_([this, signal]() { this->publish_sensor_(this->pressure_sensor_, signal / 100.0f); });
420#endif
421 break;
422 case BSEC_OUTPUT_RAW_GAS:
423#ifdef USE_SENSOR
424 this->queue_push_([this, signal]() { this->publish_sensor_(this->gas_resistance_sensor_, signal); });
425#endif
426 break;
427 case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
428#ifdef USE_SENSOR
429 this->queue_push_([this, signal]() { this->publish_sensor_(this->temperature_sensor_, signal); });
430#endif
431 break;
432 case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
433#ifdef USE_SENSOR
434 this->queue_push_([this, signal]() { this->publish_sensor_(this->humidity_sensor_, signal); });
435#endif
436 break;
437 }
438 }
439 if (update_accuracy) {
440#ifdef USE_SENSOR
441 this->queue_push_(
442 [this, max_accuracy]() { this->publish_sensor_(this->iaq_accuracy_sensor_, max_accuracy, true); });
443#endif
444#ifdef USE_TEXT_SENSOR
445 this->queue_push_([this, max_accuracy]() {
446 this->publish_sensor_(this->iaq_accuracy_text_sensor_, IAQ_ACCURACY_STATES[max_accuracy]);
447 });
448#endif
449 // Queue up an opportunity to save state
450 this->queue_push_([this, max_accuracy]() { this->save_state_(max_accuracy); });
451 }
452}
453
455 int64_t time_ms = millis();
456 if (this->last_time_ms_ > time_ms) {
458 }
459 this->last_time_ms_ = time_ms;
460
461 return (time_ms + ((int64_t) this->millis_overflow_counter_ << 32)) * INT64_C(1000000);
462}
463
464#ifdef USE_SENSOR
465void BME68xBSEC2Component::publish_sensor_(sensor::Sensor *sensor, float value, bool change_only) {
466 if (!sensor || (change_only && sensor->has_state() && sensor->state == value)) {
467 return;
468 }
469 sensor->publish_state(value);
470}
471#endif
472
473#ifdef USE_TEXT_SENSOR
474void BME68xBSEC2Component::publish_sensor_(text_sensor::TextSensor *sensor, const std::string &value) {
475 if (!sensor || (sensor->has_state() && sensor->state == value)) {
476 return;
477 }
478 sensor->publish_state(value);
479}
480#endif
481
483 uint32_t hash = this->get_hash();
484 this->bsec_state_ = global_preferences->make_preference<uint8_t[BSEC_MAX_STATE_BLOB_SIZE]>(hash, true);
485
486 uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
487 if (this->bsec_state_.load(&state)) {
488 ESP_LOGV(TAG, "Loading state");
489 uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
490 this->bsec_status_ =
491 bsec_set_state_m(&this->bsec_instance_, state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, sizeof(work_buffer));
492 if (this->bsec_status_ != BSEC_OK) {
493 ESP_LOGW(TAG, "Failed to load state (BSEC2 error code %d)", this->bsec_status_);
494 }
495 ESP_LOGI(TAG, "Loaded state");
496 }
497}
498
499void BME68xBSEC2Component::save_state_(uint8_t accuracy) {
500 if (accuracy < 3 || (millis() - this->last_state_save_ms_ < this->state_save_interval_ms_)) {
501 return;
502 }
503
504 ESP_LOGV(TAG, "Saving state");
505
506 uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
507 uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
508 uint32_t num_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
509
510 this->bsec_status_ = bsec_get_state_m(&this->bsec_instance_, 0, state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer,
511 BSEC_MAX_STATE_BLOB_SIZE, &num_serialized_state);
512 if (this->bsec_status_ != BSEC_OK) {
513 ESP_LOGW(TAG, "Failed fetch state for save (BSEC2 error code %d)", this->bsec_status_);
514 return;
515 }
516
517 if (!this->bsec_state_.save(&state)) {
518 ESP_LOGW(TAG, "Failed to save state");
519 return;
520 }
521 this->last_state_save_ms_ = millis();
522
523 ESP_LOGI(TAG, "Saved state");
524}
525
526} // namespace bme68x_bsec2
527} // namespace esphome
528#endif
uint8_t status
Definition bl0942.h:8
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
void status_set_warning(const char *message=nullptr)
void status_clear_warning()
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void status_set_error(const char *message=nullptr)
bool save(const T *src)
Definition preferences.h:21
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
bool has_state() const
Definition entity_base.h:78
void publish_(const bsec_output_t *outputs, uint8_t num_outputs)
void publish_sensor_(sensor::Sensor *sensor, float value, bool change_only=false)
text_sensor::TextSensor * iaq_accuracy_text_sensor_
struct bme68x_heatr_conf bme68x_heatr_conf_
uint8_t bsec_instance_[BSEC_INSTANCE_SIZE]
void set_config_(const uint8_t *config, u_int32_t len)
float calc_sensor_sample_rate_(SampleRate sample_rate)
std::queue< std::function< void()> > queue_
void queue_push_(std::function< void()> &&f)
Base-class for all sensors.
Definition sensor.h:59
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:45
float state
This member variable stores the last state that has passed through all filters.
Definition sensor.h:133
void publish_state(const std::string &state)
bool state
Definition fan.h:0
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:50
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:279
ESPPreferences * global_preferences
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28