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