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