7typedef TinyWire TwoWire;
13#include "helper/mup_i2c_registers.h"
114 String BME280_VERSION =
"0.1.0";
120 double temperatureValue, pressureValue, pressureNNValue, humidityValue;
121 unsigned long stateMachineClock;
122 int32_t rawTemperature;
125 double calibratedTemperature;
126 double calibratedPressure;
127 double calibratedHumidity;
128 double baseRelativeNNPressure;
129 bool relativeAltitudeStarted;
130 bool captureRelative =
false;
133 int16_t dig_T2, dig_T3, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9, dig_H2, dig_H4, dig_H5;
134 uint16_t dig_T1, dig_P1;
135 unsigned char dig_H1, dig_H3;
139 enum BMESensorState { UNAVAILABLE,
142 WAIT_NEXT_MEASUREMENT };
152 BMESensorState sensorState;
153 unsigned long errs = 0;
154 unsigned long oks = 0;
155 unsigned long basePollRateUs = 500000L;
156 uint32_t pollRateMs = 2000;
157 uint32_t lastPollMs = 0;
159 uint16_t oversampleMode = 3;
160 uint16_t oversampleModePressure = 3;
161 uint16_t oversampleModeTemperature = 1;
162 uint16_t oversampleModeHumidity = 1;
163 enum FilterMode { FAST,
166#define MUP_BME_INVALID_ALTITUDE -1000000.0
167 double referenceAltitudeMeters;
168 FilterMode filterMode;
170 ustd::sensorprocessor temperatureSensor = ustd::sensorprocessor(4, 600, 0.005);
171 ustd::sensorprocessor pressureSensor = ustd::sensorprocessor(4, 600, 0.005);
172 ustd::sensorprocessor humiditySensor = ustd::sensorprocessor(4, 600, 0.005);
173 bool bActive =
false;
175 PressTempHumBME280(String name, FilterMode filterMode = FilterMode::MEDIUM, uint8_t i2cAddress = 0x76)
176 : name(name), filterMode(filterMode), i2cAddress(i2cAddress) {
182 sensorState = BMESensorState::UNAVAILABLE;
183 referenceAltitudeMeters = MUP_BME_INVALID_ALTITUDE;
184 relativeAltitudeStarted =
false;
185 captureRelative =
false;
187 setFilterMode(filterMode,
true);
191 if (pI2C !=
nullptr) {
200 referenceAltitudeMeters = _referenceAltitudeMeters;
209 if (referenceAltitudeMeters != MUP_BME_INVALID_ALTITUDE) {
210 captureRelative =
true;
218 return temperatureValue;
225 return pressureValue;
232 return humidityValue;
243 if (referenceAltitudeMeters != MUP_BME_INVALID_ALTITUDE) {
244 double prNN = _pressure / pow((1.0 - (referenceAltitudeMeters / 44330.0)), 5.255);
251 oversampleMode = (uint16_t)_sampleMode;
252 oversampleModePressure = oversampleMode;
253 oversampleModeHumidity = 1;
255 oversampleModeTemperature = 2;
257 oversampleModeTemperature = 1;
261 bool initBmeSensorConstants() {
262 if (!pI2C->readRegisterWordLE(0x88, (uint16_t *)&dig_T1))
return false;
263 if (!pI2C->readRegisterWordLE(0x8A, (uint16_t *)&dig_T2))
return false;
264 if (!pI2C->readRegisterWordLE(0x8C, (uint16_t *)&dig_T3))
return false;
265 if (!pI2C->readRegisterWordLE(0x8E, (uint16_t *)&dig_P1))
return false;
266 if (!pI2C->readRegisterWordLE(0x90, (uint16_t *)&dig_P2))
return false;
267 if (!pI2C->readRegisterWordLE(0x92, (uint16_t *)&dig_P3))
return false;
268 if (!pI2C->readRegisterWordLE(0x94, (uint16_t *)&dig_P4))
return false;
269 if (!pI2C->readRegisterWordLE(0x96, (uint16_t *)&dig_P5))
return false;
270 if (!pI2C->readRegisterWordLE(0x98, (uint16_t *)&dig_P6))
return false;
271 if (!pI2C->readRegisterWordLE(0x9A, (uint16_t *)&dig_P7))
return false;
272 if (!pI2C->readRegisterWordLE(0x9C, (uint16_t *)&dig_P8))
return false;
273 if (!pI2C->readRegisterWordLE(0x9E, (uint16_t *)&dig_P9))
return false;
275 if (!pI2C->readRegisterByte(0xA1, (uint8_t *)&dig_H1))
return false;
276 if (!pI2C->readRegisterWordLE(0xE1, (uint16_t *)&dig_H2))
return false;
277 if (!pI2C->readRegisterByte(0xE3, (uint8_t *)&dig_H3))
return false;
278 unsigned char fb1, fb2, fb3;
279 if (!pI2C->readRegisterByte(0xE4, (uint8_t *)&fb1))
return false;
280 if (!pI2C->readRegisterByte(0xE5, (uint8_t *)&fb2))
return false;
281 if (!pI2C->readRegisterByte(0xE6, (uint8_t *)&fb3))
return false;
282 dig_H4 = ((int16_t)fb1 << 4) + (int16_t)(fb2 & 0x0f);
283 dig_H5 = (((int16_t)fb2 & 0xf0) >> 4) + ((int16_t)fb3 << 4);
284 if (!pI2C->readRegisterByte(0xE7, (uint8_t *)&dig_H6))
return false;
293 setSampleMode(_sampleMode);
294 pollRateMs = _pollRateMs;
296 pI2C =
new I2CRegisters(pWire, i2cAddress);
298 auto ft = [=]() { this->loop(); };
299 tID = pSched->add(ft, name, basePollRateUs);
301 auto fnall = [=](String topic, String msg, String originator) {
302 this->subsMsg(topic, msg, originator);
304 pSched->subscribe(tID, name +
"/sensor/#", fnall);
306 pI2C->lastError = pI2C->checkAddress(i2cAddress);
307 if (pI2C->lastError == I2CRegisters::I2CError::OK) {
308 if (!pI2C->readRegisterByte(0xd0, &data)) {
310 Serial.print(
"Failed to inquire BME280 chip-id at address 0x");
311 Serial.println(i2cAddress, HEX);
316 if (!initBmeSensorConstants()) {
318 Serial.print(
"Failed to read calibration data for sensor BME280 at address 0x");
319 Serial.println(i2cAddress, HEX);
321 pI2C->lastError = I2CRegisters::I2CError::I2C_HW_ERROR;
325 Serial.print(
"BME280 sensor active at address 0x");
326 Serial.println(i2cAddress, HEX);
328 sensorState = BMESensorState::IDLE;
333 Serial.print(
"Wrong hardware (not BME280) found at address 0x");
334 Serial.print(i2cAddress, HEX);
335 Serial.print(
" chip-id is ");
336 Serial.print(data, HEX);
337 Serial.println(
" expected: 0x60 for BME280.");
338 if (data == 0x58) Serial.println(
"This is not a BME280 but a BME280 sensor (no humidity). This might be a fake chip/source.");
340 pI2C->lastError = I2CRegisters::I2CError::I2C_WRONG_HARDWARE_AT_ADDRESS;
346 Serial.print(
"No BME280 sensor found at address 0x");
347 Serial.println(i2cAddress, HEX);
353 void setFilterMode(FilterMode mode,
bool silent =
false) {
357 temperatureSensor.update(1, 2, 0.05);
358 pressureSensor.update(1, 2, 0.001);
359 humiditySensor.update(1, 2, 0.01);
363 temperatureSensor.update(4, 30, 0.1);
364 pressureSensor.update(4, 30, 0.1);
365 humiditySensor.update(4, 30, 0.1);
369 filterMode = LONGTERM;
370 temperatureSensor.update(10, 600, 0.1);
371 pressureSensor.update(30, 600, 0.3);
372 humiditySensor.update(30, 600, 0.2);
379 void setPollRateMs(uint32_t _pollRateMs) {
380 pollRateMs = _pollRateMs;
384 void publishTemperature() {
386 sprintf(buf,
"%6.2f", temperatureValue);
387 pSched->publish(name +
"/sensor/temperature", buf);
390 void publishPressure() {
392 sprintf(buf,
"%7.2f", pressureValue);
393 pSched->publish(name +
"/sensor/pressure", buf);
394 if (referenceAltitudeMeters != MUP_BME_INVALID_ALTITUDE) {
395 sprintf(buf,
"%7.2f", pressureNNValue);
396 pSched->publish(name +
"/sensor/pressureNN", buf);
400 void publishHumidity() {
402 sprintf(buf,
"%6.2f", humidityValue);
403 pSched->publish(name +
"/sensor/humidity", buf);
406 void publishPollRateMs() {
408 sprintf(buf,
"%d", pollRateMs);
409 pSched->publish(name +
"/sensor/pollratems", buf);
412 void publishError(String errMsg) {
413 pSched->publish(name +
"/sensor/error", errMsg);
416 void publishFilterMode() {
417 switch (filterMode) {
418 case FilterMode::FAST:
419 pSched->publish(name +
"/sensor/mode",
"FAST");
421 case FilterMode::MEDIUM:
422 pSched->publish(name +
"/sensor/mode",
"MEDIUM");
424 case FilterMode::LONGTERM:
425 pSched->publish(name +
"/sensor/mode",
"LONGTERM");
430 void publishOversampling() {
433 pSched->publish(name +
"/sensor/oversampling",
"ULTRA_LOW_POWER");
436 pSched->publish(name +
"/sensor/oversampling",
"LOW_POWER");
439 pSched->publish(name +
"/sensor/oversampling",
"STANDARD");
442 pSched->publish(name +
"/sensor/oversampling",
"HIGH_RESOLUTION");
445 pSched->publish(name +
"/sensor/oversampling",
"ULTRA_HIGH_RESOLUTION");
448 pSched->publish(name +
"/sensor/oversampling",
"INVALID");
453 void publishCalibrationData() {
455 sprintf(msg,
"dig_T1=%u, dig_T2=%d, dig_T3=%d, dig_P1=%u, dig_P2=%d, dig_P3=%d, dig_P4=%d, dig_P5=%d, dig_P6=%d, dig_P7=%d, dig_P8=%d, dig_P9=%d, dig_H1=%u dig_H2=%d dig_H3=%u dig_H4=%d dig_H5=%d dig_H6=%d",
456 dig_T1, dig_T2, dig_T3, dig_P1, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9, (uint16_t)dig_H1, dig_H2, (uint16_t)dig_H3, dig_H4, dig_H5, (int16_t)dig_H6);
457 pSched->publish(
"sensor/calibrationdata", msg);
460 void publishReferenceAltitude() {
461 if (referenceAltitudeMeters != MUP_BME_INVALID_ALTITUDE) {
463 sprintf(buf,
"%7.2f", referenceAltitudeMeters);
464 pSched->publish(name +
"/sensor/referencealtitude", buf);
466 pSched->publish(name +
"/sensor/referencealtitude",
"unknown");
470 void publishRelativeAltitude() {
472 if (relativeAltitudeStarted) {
473 double ralt = 44330.0 * (1.0 - pow(pressureValue / baseRelativeNNPressure, 1. / 5.255));
474 sprintf(buf,
"%7.2f", ralt);
475 pSched->publish(name +
"/sensor/relativealtitude", buf);
476 double dalt = ralt - referenceAltitudeMeters;
477 sprintf(buf,
"%7.2f", dalt);
478 pSched->publish(name +
"/sensor/deltaaltitude", buf);
482 bool sensorStateMachine() {
483 bool newData =
false;
488 const uint8_t status_register = 0xf3;
489 const uint8_t measure_mode_register = 0xf4;
490 const uint8_t config_register = 0xf5;
491 const uint8_t ctrl_hum_register = 0xf2;
492 const uint8_t temperature_registers = 0xfa;
493 const uint8_t pressure_registers = 0xf7;
494 const uint8_t humidity_registers = 0xfd;
496 uint8_t normalmodeInactivity = 0, IIRfilter = 0;
497 switch (sensorState) {
498 case BMESensorState::UNAVAILABLE:
500 case BMESensorState::IDLE:
501 reg_data = (normalmodeInactivity << 5) + (IIRfilter << 2) + 0;
502 if (!pI2C->writeRegisterByte(config_register, reg_data)) {
504 sensorState = BMESensorState::WAIT_NEXT_MEASUREMENT;
505 stateMachineClock = micros();
508 reg_data = oversampleModeHumidity & 0x7;
509 if (!pI2C->writeRegisterByte(ctrl_hum_register, reg_data)) {
511 sensorState = BMESensorState::WAIT_NEXT_MEASUREMENT;
512 stateMachineClock = micros();
515 reg_data = (oversampleModeTemperature << 5) + (oversampleModePressure << 2) + 0x1;
516 if (!pI2C->writeRegisterByte(measure_mode_register, reg_data)) {
518 sensorState = BMESensorState::WAIT_NEXT_MEASUREMENT;
519 stateMachineClock = micros();
522 sensorState = BMESensorState::MEASUREMENT_WAIT;
523 stateMachineClock = micros();
526 case BMESensorState::MEASUREMENT_WAIT:
527 if (!pI2C->readRegisterByte(status_register, &status)) {
530 sensorState = BMESensorState::WAIT_NEXT_MEASUREMENT;
531 stateMachineClock = micros();
534 status = status & 0x09;
535 if (timeDiff(stateMachineClock, micros()) > 1 && status == 0) {
538 if (pI2C->readRegisterTripple(temperature_registers, &rt) && pI2C->readRegisterTripple(pressure_registers, &rp) &&
539 pI2C->readRegisterWord(humidity_registers, &rh)) {
540 rawTemperature = rt >> 4;
541 rawPressure = rp >> 4;
542 rawHumidity = (int32_t)rh;
543 sensorState = BMESensorState::WAIT_NEXT_MEASUREMENT;
544 stateMachineClock = micros();
546 Serial.print(
"BME raw T=");
547 Serial.print(rawTemperature);
549 Serial.print(rawPressure);
551 Serial.println(rawHumidity);
557 sensorState = BMESensorState::WAIT_NEXT_MEASUREMENT;
558 stateMachineClock = micros();
562 case BMESensorState::WAIT_NEXT_MEASUREMENT:
563 if (timeDiff(lastPollMs, millis()) > pollRateMs) {
564 sensorState = BMESensorState::IDLE;
565 lastPollMs = millis();
576 double bme280_compensate_T_double(int32_t adc_T, int32_t *pt_fine) {
577 double var1, var2, T;
578 var1 = (((double)adc_T) / 16384.0 - ((double)dig_T1) / 1024.0) * ((
double)dig_T2);
579 var2 = ((((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0) *
580 (((
double)adc_T) / 131072.0 - ((
double)dig_T1) / 8192.0)) *
582 *pt_fine = (int32_t)(var1 + var2);
583 T = (var1 + var2) / 5120.0;
589 double bme280_compensate_P_double(int32_t adc_P, int32_t t_fine) {
590 double var1, var2, p;
591 var1 = ((double)t_fine / 2.0) - 64000.0;
592 var2 = var1 * var1 * ((double)dig_P6) / 32768.0;
593 var2 = var2 + var1 * ((double)dig_P5) * 2.0;
594 var2 = (var2 / 4.0) + (((
double)dig_P4) * 65536.0);
595 var1 = (((double)dig_P3) * var1 * var1 / 524288.0 + ((double)dig_P2) * var1) / 524288.0;
596 var1 = (1.0 + var1 / 32768.0) * ((
double)dig_P1);
600 p = 1048576.0 - (double)adc_P;
601 p = (p - (var2 / 4096.0)) * 6250.0 / var1;
602 var1 = ((double)dig_P9) * p * p / 2147483648.0;
603 var2 = p * ((double)dig_P8) / 32768.0;
604 p = p + (var1 + var2 + ((double)dig_P7)) / 16.0;
610 double bme280_compensate_H_double(int32_t adc_H, int32_t t_fine) {
612 var_H = (((double)t_fine) - 76800.0);
613 var_H = (adc_H - (((double)dig_H4) * 64.0 + ((double)dig_H5) / 16384.0 * var_H)) *
614 (((double)dig_H2) / 65536.0 * (1.0 + ((double)dig_H6) / 67108864.0 * var_H * (1.0 + ((double)dig_H3) / 67108864.0 * var_H)));
615 var_H = var_H * (1.0 - ((double)dig_H1) * var_H / 524288.0);
619 if (var_H < 0.0) var_H = 0.0;
624 bool calibrateRawData() {
627 calibratedTemperature = bme280_compensate_T_double(rawTemperature, &t_fine);
629 calibratedPressure = bme280_compensate_P_double(rawPressure, t_fine) / 100.0;
631 calibratedHumidity = bme280_compensate_H_double(rawHumidity, t_fine);
636 double tempVal, pressVal, humVal;
638 if (!sensorStateMachine())
return;
640 tempVal = (double)calibratedTemperature;
641 pressVal = (double)calibratedPressure;
642 humVal = (double)calibratedHumidity;
643 if (temperatureSensor.filter(&tempVal)) {
644 temperatureValue = tempVal;
645 publishTemperature();
647 if (pressureSensor.filter(&pressVal)) {
648 pressureValue = pressVal;
649 if (referenceAltitudeMeters != MUP_BME_INVALID_ALTITUDE) {
651 if (captureRelative) {
652 baseRelativeNNPressure = pressureNNValue;
653 relativeAltitudeStarted =
true;
654 captureRelative =
false;
658 if (relativeAltitudeStarted) publishRelativeAltitude();
660 if (humiditySensor.filter(&humVal)) {
661 humidityValue = humVal;
667 void subsMsg(String topic, String msg, String originator) {
668 if (topic == name +
"/sensor/temperature/get") {
669 publishTemperature();
670 }
else if (topic == name +
"/sensor/pressure/get") {
672 }
else if (topic == name +
"/sensor/humidity/get") {
674 }
else if (topic == name +
"/sensor/mode/get") {
676 }
else if (topic == name +
"/sensor/calibrationdata/get") {
677 publishCalibrationData();
678 }
else if (topic == name +
"/sensor/referencealtitude/get") {
679 publishReferenceAltitude();
680 }
else if (topic == name +
"/sensor/relativealtitude/get") {
681 publishRelativeAltitude();
682 }
else if (topic == name +
"/sensor/relativealtitude/set") {
684 }
else if (topic == name +
"/sensor/oversampling/get") {
685 publishOversampling();
686 }
else if (topic == name +
"/sensor/pollratems/set") {
687 setPollRateMs(msg.toInt());
688 }
else if (topic == name +
"/sensor/pollratems/get") {
690 }
else if (topic == name +
"/sensor/referencealtitude/set") {
691 double alt = atof(msg.c_str());
693 }
else if (topic == name +
"/sensor/mode/set") {
694 if (msg ==
"fast" || msg ==
"FAST") {
695 setFilterMode(FilterMode::FAST);
697 if (msg ==
"medium" || msg ==
"MEDIUM") {
698 setFilterMode(FilterMode::MEDIUM);
700 setFilterMode(FilterMode::LONGTERM);
703 }
else if (topic == name +
"/sensor/oversampling/set") {
704 if (msg ==
"ULTRA_LOW_POWER") {
707 if (msg ==
"LOW_POWER") {
710 if (msg ==
"STANDARD") {
713 if (msg ==
"HIGH_RESOLUTION") {
mupplet-sensor temperature and pressure with Bosch BME280
Definition: mup_presstemphum_bme280.h:112
double getTemperature()
Definition: mup_presstemphum_bme280.h:214
void startRelativeAltitude()
Definition: mup_presstemphum_bme280.h:203
double getHumidity()
Definition: mup_presstemphum_bme280.h:228
BMESampleMode
Definition: mup_presstemphum_bme280.h:145
@ LOW_POWER
2 samples, pressure resolution 17bit / 1.31 Pa, rec temperature oversampling: x1
Definition: mup_presstemphum_bme280.h:147
@ ULTRA_LOW_POWER
1 samples, pressure resolution 16bit / 2.62 Pa, rec temperature oversampling: x1
Definition: mup_presstemphum_bme280.h:146
@ ULTRA_HIGH_RESOLUTION
16 samples, pressure resolution 20bit / 0.16 Pa, rec temperature oversampling: x2
Definition: mup_presstemphum_bme280.h:150
@ HIGH_RESOLUTION
8 samples, pressure resolution 19bit / 0.33 Pa, rec temperature oversampling: x1
Definition: mup_presstemphum_bme280.h:149
@ STANDARD
4 samples, pressure resolution 18bit / 0.66 Pa, rec temperature oversampling: x1
Definition: mup_presstemphum_bme280.h:148
double getPressure()
Definition: mup_presstemphum_bme280.h:221
PressTempHumBME280(String name, FilterMode filterMode=FilterMode::MEDIUM, uint8_t i2cAddress=0x76)
Definition: mup_presstemphum_bme280.h:175
void setReferenceAltitude(double _referenceAltitudeMeters)
Definition: mup_presstemphum_bme280.h:196
double getPressureNN(double _pressure)
Definition: mup_presstemphum_bme280.h:235