2017-01-28 13:41:01 +00:00
|
|
|
/*
|
2017-05-13 12:02:10 +01:00
|
|
|
xsns_bmp.ino - BMP pressure, temperature and humidity sensor support for Sonoff-Tasmota
|
|
|
|
|
|
|
|
Copyright (C) 2017 Heiko Krupp and Theo Arends
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2017-01-28 13:41:01 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef USE_I2C
|
|
|
|
#ifdef USE_BMP
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* BMP085, BMP180, BMP280, BME280 - Pressure and Temperature and Humidy (BME280 only)
|
|
|
|
*
|
|
|
|
* Source: Heiko Krupp and Adafruit Industries
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
#define BMP_ADDR 0x77
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
#define BMP180_CHIPID 0x55
|
|
|
|
#define BMP280_CHIPID 0x58
|
|
|
|
#define BME280_CHIPID 0x60
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
#define BMP_REGISTER_CHIPID 0xD0
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
double bmp_sealevel = 0.0;
|
2017-04-25 17:24:42 +01:00
|
|
|
uint8_t bmpaddr;
|
|
|
|
uint8_t bmptype = 0;
|
2017-01-28 13:41:01 +00:00
|
|
|
char bmpstype[7];
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* BMP085 and BME180
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
#define BMP180_REG_CONTROL 0xF4
|
|
|
|
#define BMP180_REG_RESULT 0xF6
|
|
|
|
#define BMP180_TEMPERATURE 0x2E
|
|
|
|
#define BMP180_PRESSURE3 0xF4 // Max. oversampling -> OSS = 3
|
|
|
|
|
|
|
|
#define BMP180_AC1 0xAA
|
|
|
|
#define BMP180_AC2 0xAC
|
|
|
|
#define BMP180_AC3 0xAE
|
|
|
|
#define BMP180_AC4 0xB0
|
|
|
|
#define BMP180_AC5 0xB2
|
|
|
|
#define BMP180_AC6 0xB4
|
|
|
|
#define BMP180_VB1 0xB6
|
|
|
|
#define BMP180_VB2 0xB8
|
|
|
|
#define BMP180_MB 0xBA
|
|
|
|
#define BMP180_MC 0xBC
|
|
|
|
#define BMP180_MD 0xBE
|
|
|
|
|
|
|
|
#define BMP180_OSS 3
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
int16_t cal_ac1;
|
|
|
|
int16_t cal_ac2;
|
|
|
|
int16_t cal_ac3;
|
|
|
|
int16_t cal_b1;
|
|
|
|
int16_t cal_b2;
|
|
|
|
int16_t cal_mc;
|
|
|
|
int16_t cal_md;
|
|
|
|
uint16_t cal_ac4;
|
|
|
|
uint16_t cal_ac5;
|
|
|
|
uint16_t cal_ac6;
|
2017-01-28 13:41:01 +00:00
|
|
|
int32_t bmp180_b5 = 0;
|
|
|
|
|
|
|
|
boolean bmp180_calibration()
|
|
|
|
{
|
|
|
|
cal_ac1 = i2c_read16(bmpaddr, BMP180_AC1);
|
|
|
|
cal_ac2 = i2c_read16(bmpaddr, BMP180_AC2);
|
|
|
|
cal_ac3 = i2c_read16(bmpaddr, BMP180_AC3);
|
|
|
|
cal_ac4 = i2c_read16(bmpaddr, BMP180_AC4);
|
|
|
|
cal_ac5 = i2c_read16(bmpaddr, BMP180_AC5);
|
|
|
|
cal_ac6 = i2c_read16(bmpaddr, BMP180_AC6);
|
2017-10-08 15:51:05 +01:00
|
|
|
cal_b1 = i2c_read16(bmpaddr, BMP180_VB1);
|
|
|
|
cal_b2 = i2c_read16(bmpaddr, BMP180_VB2);
|
|
|
|
cal_mc = i2c_read16(bmpaddr, BMP180_MC);
|
|
|
|
cal_md = i2c_read16(bmpaddr, BMP180_MD);
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
// Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!cal_ac1 | !cal_ac2 | !cal_ac3 | !cal_ac4 | !cal_ac5 | !cal_ac6 | !cal_b1 | !cal_b2 | !cal_mc | !cal_md) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
if ((cal_ac1 == 0xFFFF) |
|
|
|
|
(cal_ac2 == 0xFFFF) |
|
|
|
|
(cal_ac3 == 0xFFFF) |
|
|
|
|
(cal_ac4 == 0xFFFF) |
|
|
|
|
(cal_ac5 == 0xFFFF) |
|
|
|
|
(cal_ac6 == 0xFFFF) |
|
|
|
|
(cal_b1 == 0xFFFF) |
|
|
|
|
(cal_b2 == 0xFFFF) |
|
|
|
|
(cal_mc == 0xFFFF) |
|
2017-04-25 17:24:42 +01:00
|
|
|
(cal_md == 0xFFFF)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
double bmp180_readTemperature()
|
|
|
|
{
|
|
|
|
i2c_write8(bmpaddr, BMP180_REG_CONTROL, BMP180_TEMPERATURE);
|
|
|
|
delay(5); // 5ms conversion time
|
|
|
|
int ut = i2c_read16(bmpaddr, BMP180_REG_RESULT);
|
|
|
|
int32_t x1 = (ut - (int32_t)cal_ac6) * ((int32_t)cal_ac5) >> 15;
|
2017-10-08 15:51:05 +01:00
|
|
|
int32_t x2 = ((int32_t)cal_mc << 11) / (x1 + (int32_t)cal_md);
|
|
|
|
bmp180_b5 = x1 + x2;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
return ((bmp180_b5 + 8) >> 4) / 10.0;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double bmp180_readPressure()
|
|
|
|
{
|
|
|
|
int32_t p;
|
2017-04-25 17:24:42 +01:00
|
|
|
uint8_t msb;
|
|
|
|
uint8_t lsb;
|
|
|
|
uint8_t xlsb;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
i2c_write8(bmpaddr, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution
|
2017-10-08 15:51:05 +01:00
|
|
|
delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution
|
2017-01-28 13:41:01 +00:00
|
|
|
uint32_t up = i2c_read24(bmpaddr, BMP180_REG_RESULT);
|
|
|
|
up >>= (8 - BMP180_OSS);
|
|
|
|
|
|
|
|
int32_t b6 = bmp180_b5 - 4000;
|
2017-10-08 15:51:05 +01:00
|
|
|
int32_t x1 = ((int32_t)cal_b2 * ((b6 * b6) >> 12)) >> 11;
|
2017-01-28 13:41:01 +00:00
|
|
|
int32_t x2 = ((int32_t)cal_ac2 * b6) >> 11;
|
|
|
|
int32_t x3 = x1 + x2;
|
2017-10-08 15:51:05 +01:00
|
|
|
int32_t b3 = ((((int32_t)cal_ac1 * 4 + x3) << BMP180_OSS) + 2) >> 2;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
x1 = ((int32_t)cal_ac3 * b6) >> 13;
|
|
|
|
x2 = ((int32_t)cal_b1 * ((b6 * b6) >> 12)) >> 16;
|
|
|
|
x3 = ((x1 + x2) + 2) >> 2;
|
|
|
|
uint32_t b4 = ((uint32_t)cal_ac4 * (uint32_t)(x3 + 32768)) >> 15;
|
2017-10-08 15:51:05 +01:00
|
|
|
uint32_t b7 = ((uint32_t)up - b3) * (uint32_t)(50000UL >> BMP180_OSS);
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
if (b7 < 0x80000000) {
|
|
|
|
p = (b7 * 2) / b4;
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-01-28 13:41:01 +00:00
|
|
|
p = (b7 / b4) * 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
x1 = (p >> 8) * (p >> 8);
|
|
|
|
x1 = (x1 * 3038) >> 16;
|
|
|
|
x2 = (-7357 * p) >> 16;
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
p += ((x1 + x2 + (int32_t)3791) >> 4);
|
|
|
|
return p / 100.0; // convert to mbar
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double bmp180_calcSealevelPressure(float pAbs, float altitude_meters)
|
|
|
|
{
|
2017-10-08 15:51:05 +01:00
|
|
|
double pressure = pAbs * 100.0;
|
|
|
|
return (double)(pressure / pow(1.0 - altitude_meters / 44330, 5.255)) / 100.0;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* BMP280 and BME280
|
|
|
|
*
|
|
|
|
* Programmer : BMP280/BME280 Datasheet and Adafruit with changes by Theo Arends
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
#define BME280_REGISTER_CONTROLHUMID 0xF2
|
|
|
|
#define BME280_REGISTER_CONTROL 0xF4
|
|
|
|
#define BME280_REGISTER_PRESSUREDATA 0xF7
|
|
|
|
#define BME280_REGISTER_TEMPDATA 0xFA
|
|
|
|
#define BME280_REGISTER_HUMIDDATA 0xFD
|
|
|
|
|
|
|
|
#define BME280_REGISTER_DIG_T1 0x88
|
|
|
|
#define BME280_REGISTER_DIG_T2 0x8A
|
|
|
|
#define BME280_REGISTER_DIG_T3 0x8C
|
|
|
|
#define BME280_REGISTER_DIG_P1 0x8E
|
|
|
|
#define BME280_REGISTER_DIG_P2 0x90
|
|
|
|
#define BME280_REGISTER_DIG_P3 0x92
|
|
|
|
#define BME280_REGISTER_DIG_P4 0x94
|
|
|
|
#define BME280_REGISTER_DIG_P5 0x96
|
|
|
|
#define BME280_REGISTER_DIG_P6 0x98
|
|
|
|
#define BME280_REGISTER_DIG_P7 0x9A
|
|
|
|
#define BME280_REGISTER_DIG_P8 0x9C
|
|
|
|
#define BME280_REGISTER_DIG_P9 0x9E
|
|
|
|
#define BME280_REGISTER_DIG_H1 0xA1
|
|
|
|
#define BME280_REGISTER_DIG_H2 0xE1
|
|
|
|
#define BME280_REGISTER_DIG_H3 0xE3
|
|
|
|
#define BME280_REGISTER_DIG_H4 0xE4
|
|
|
|
#define BME280_REGISTER_DIG_H5 0xE5
|
|
|
|
#define BME280_REGISTER_DIG_H6 0xE7
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
struct bme280_calib_data
|
|
|
|
{
|
|
|
|
uint16_t dig_T1;
|
2017-10-08 15:51:05 +01:00
|
|
|
int16_t dig_T2;
|
|
|
|
int16_t dig_T3;
|
2017-01-28 13:41:01 +00:00
|
|
|
uint16_t dig_P1;
|
2017-10-08 15:51:05 +01:00
|
|
|
int16_t dig_P2;
|
|
|
|
int16_t dig_P3;
|
|
|
|
int16_t dig_P4;
|
|
|
|
int16_t dig_P5;
|
|
|
|
int16_t dig_P6;
|
|
|
|
int16_t dig_P7;
|
|
|
|
int16_t dig_P8;
|
|
|
|
int16_t dig_P9;
|
|
|
|
uint8_t dig_H1;
|
|
|
|
int16_t dig_H2;
|
|
|
|
uint8_t dig_H3;
|
|
|
|
int16_t dig_H4;
|
|
|
|
int16_t dig_H5;
|
|
|
|
int8_t dig_H6;
|
2017-01-28 13:41:01 +00:00
|
|
|
} _bme280_calib;
|
|
|
|
|
|
|
|
int32_t t_fine;
|
|
|
|
|
|
|
|
boolean bmp280_calibrate()
|
|
|
|
{
|
2017-10-08 15:51:05 +01:00
|
|
|
// if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BMP280_CHIPID) return false;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
_bme280_calib.dig_T1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_T1);
|
|
|
|
_bme280_calib.dig_T2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T2);
|
|
|
|
_bme280_calib.dig_T3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T3);
|
|
|
|
_bme280_calib.dig_P1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_P1);
|
|
|
|
_bme280_calib.dig_P2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P2);
|
|
|
|
_bme280_calib.dig_P3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P3);
|
|
|
|
_bme280_calib.dig_P4 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P4);
|
|
|
|
_bme280_calib.dig_P5 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P5);
|
|
|
|
_bme280_calib.dig_P6 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P6);
|
|
|
|
_bme280_calib.dig_P7 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P7);
|
|
|
|
_bme280_calib.dig_P8 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P8);
|
|
|
|
_bme280_calib.dig_P9 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P9);
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
// i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0x3F); // Temp 1x oversampling, Press 16x oversampling, normal mode (Adafruit)
|
|
|
|
i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean bme280_calibrate()
|
|
|
|
{
|
2017-10-08 15:51:05 +01:00
|
|
|
// if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
_bme280_calib.dig_T1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_T1);
|
|
|
|
_bme280_calib.dig_T2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T2);
|
|
|
|
_bme280_calib.dig_T3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T3);
|
|
|
|
_bme280_calib.dig_P1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_P1);
|
|
|
|
_bme280_calib.dig_P2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P2);
|
|
|
|
_bme280_calib.dig_P3 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P3);
|
|
|
|
_bme280_calib.dig_P4 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P4);
|
|
|
|
_bme280_calib.dig_P5 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P5);
|
|
|
|
_bme280_calib.dig_P6 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P6);
|
|
|
|
_bme280_calib.dig_P7 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P7);
|
|
|
|
_bme280_calib.dig_P8 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P8);
|
|
|
|
_bme280_calib.dig_P9 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P9);
|
|
|
|
_bme280_calib.dig_H1 = i2c_read8(bmpaddr, BME280_REGISTER_DIG_H1);
|
|
|
|
_bme280_calib.dig_H2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_H2);
|
|
|
|
_bme280_calib.dig_H3 = i2c_read8(bmpaddr, BME280_REGISTER_DIG_H3);
|
|
|
|
_bme280_calib.dig_H4 = (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H4) << 4) | (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H4 + 1) & 0xF);
|
|
|
|
_bme280_calib.dig_H5 = (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H5 + 1) << 4) | (i2c_read8(bmpaddr, BME280_REGISTER_DIG_H5) >> 4);
|
|
|
|
_bme280_calib.dig_H6 = (int8_t)i2c_read8(bmpaddr, BME280_REGISTER_DIG_H6);
|
|
|
|
|
|
|
|
// Set before CONTROL_meas (DS 5.4.3)
|
2017-10-08 15:51:05 +01:00
|
|
|
i2c_write8(bmpaddr, BME280_REGISTER_CONTROLHUMID, 0x05); // 16x oversampling (Adafruit)
|
|
|
|
i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
double bmp280_readTemperature(void)
|
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
int32_t var1;
|
|
|
|
int32_t var2;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
int32_t adc_T = i2c_read24(bmpaddr, BME280_REGISTER_TEMPDATA);
|
|
|
|
adc_T >>= 4;
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
var1 = ((((adc_T >> 3) - ((int32_t)_bme280_calib.dig_T1 << 1))) * ((int32_t)_bme280_calib.dig_T2)) >> 11;
|
|
|
|
var2 = (((((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1)) * ((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) *
|
|
|
|
((int32_t)_bme280_calib.dig_T3)) >>
|
|
|
|
14;
|
2017-01-28 13:41:01 +00:00
|
|
|
t_fine = var1 + var2;
|
2017-10-08 15:51:05 +01:00
|
|
|
double T = (t_fine * 5 + 128) >> 8;
|
2017-01-28 13:41:01 +00:00
|
|
|
return T / 100.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double bmp280_readPressure(void)
|
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
int64_t var1;
|
|
|
|
int64_t var2;
|
|
|
|
int64_t p;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
// Must be done first to get the t_fine variable set up
|
|
|
|
// bmp280_readTemperature();
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
int32_t adc_P = i2c_read24(bmpaddr, BME280_REGISTER_PRESSUREDATA);
|
|
|
|
adc_P >>= 4;
|
|
|
|
|
|
|
|
var1 = ((int64_t)t_fine) - 128000;
|
|
|
|
var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6;
|
|
|
|
var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) << 17);
|
|
|
|
var2 = var2 + (((int64_t)_bme280_calib.dig_P4) << 35);
|
|
|
|
var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) >> 8) + ((var1 * (int64_t)_bme280_calib.dig_P2) << 12);
|
|
|
|
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)_bme280_calib.dig_P1) >> 33;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (0 == var1) {
|
2017-10-08 15:51:05 +01:00
|
|
|
return 0; // avoid exception caused by division by zero
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
p = 1048576 - adc_P;
|
|
|
|
p = (((p << 31) - var2) * 3125) / var1;
|
|
|
|
var1 = (((int64_t)_bme280_calib.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
|
|
|
|
var2 = (((int64_t)_bme280_calib.dig_P8) * p) >> 19;
|
|
|
|
p = ((p + var1 + var2) >> 8) + (((int64_t)_bme280_calib.dig_P7) << 4);
|
|
|
|
return (double)p / 25600.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double bme280_readHumidity(void)
|
|
|
|
{
|
|
|
|
int32_t v_x1_u32r;
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
// Must be done first to get the t_fine variable set up
|
|
|
|
// bmp280_readTemperature();
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
int32_t adc_H = i2c_read16(bmpaddr, BME280_REGISTER_HUMIDDATA);
|
|
|
|
|
|
|
|
v_x1_u32r = (t_fine - ((int32_t)76800));
|
|
|
|
|
|
|
|
v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) -
|
2017-10-08 15:51:05 +01:00
|
|
|
(((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) +
|
|
|
|
((int32_t)16384)) >>
|
|
|
|
15) *
|
|
|
|
(((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) *
|
|
|
|
(((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >>
|
|
|
|
10) +
|
|
|
|
((int32_t)2097152)) *
|
|
|
|
((int32_t)_bme280_calib.dig_H2) +
|
|
|
|
8192) >>
|
|
|
|
14));
|
2017-01-28 13:41:01 +00:00
|
|
|
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
|
2017-10-08 15:51:05 +01:00
|
|
|
((int32_t)_bme280_calib.dig_H1)) >>
|
|
|
|
4));
|
2017-01-28 13:41:01 +00:00
|
|
|
v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
|
|
|
|
v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
|
|
|
|
double h = (v_x1_u32r >> 12);
|
2017-10-08 15:51:05 +01:00
|
|
|
return h / 1024.0;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* BMP
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
double fastPrecisePow(double a, double b)
|
|
|
|
{
|
|
|
|
// https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
|
|
|
|
// calculate approximation with fraction of the exponent
|
|
|
|
int e = (int)b;
|
|
|
|
union {
|
|
|
|
double d;
|
|
|
|
int x[2];
|
|
|
|
} u = { a };
|
|
|
|
u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
|
|
|
|
u.x[0] = 0;
|
|
|
|
// exponentiation by squaring with the exponent's integer part
|
|
|
|
// double r = u.d makes everything much slower, not sure why
|
|
|
|
double r = 1.0;
|
|
|
|
while (e) {
|
|
|
|
if (e & 1) {
|
|
|
|
r *= a;
|
|
|
|
}
|
|
|
|
a *= a;
|
|
|
|
e >>= 1;
|
|
|
|
}
|
|
|
|
return r * u.d;
|
|
|
|
}
|
|
|
|
|
2017-05-03 17:19:13 +01:00
|
|
|
double bmp_readTemperature(void)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
|
|
|
double t = NAN;
|
2017-09-02 13:37:02 +01:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
switch (bmptype)
|
|
|
|
{
|
2017-01-28 13:41:01 +00:00
|
|
|
case BMP180_CHIPID:
|
|
|
|
t = bmp180_readTemperature();
|
|
|
|
break;
|
|
|
|
case BMP280_CHIPID:
|
|
|
|
case BME280_CHIPID:
|
|
|
|
t = bmp280_readTemperature();
|
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
if (!isnan(t))
|
|
|
|
{
|
2017-05-03 17:19:13 +01:00
|
|
|
t = convertTemp(t);
|
2017-01-28 13:41:01 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double bmp_readPressure(void)
|
|
|
|
{
|
2017-10-08 15:51:05 +01:00
|
|
|
double pressure = 0.0;
|
|
|
|
|
2017-01-28 13:41:01 +00:00
|
|
|
switch (bmptype) {
|
|
|
|
case BMP180_CHIPID:
|
2017-10-08 15:51:05 +01:00
|
|
|
pressure = bmp180_readPressure();
|
2017-01-28 13:41:01 +00:00
|
|
|
case BMP280_CHIPID:
|
|
|
|
case BME280_CHIPID:
|
2017-10-08 15:51:05 +01:00
|
|
|
pressure = bmp280_readPressure();
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
if (pressure != 0.0) {
|
|
|
|
// bmp_sealevel = pressure / pow(1.0 - ((float)sysCfg.altitude / 44330.0), 5.255); // Adds 8k to the code
|
|
|
|
bmp_sealevel = (pressure / fastPrecisePow(1.0 - ((float)sysCfg.altitude / 44330.0), 5.255)) - 21.6;
|
|
|
|
}
|
|
|
|
return pressure;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double bmp_readHumidity(void)
|
|
|
|
{
|
|
|
|
switch (bmptype) {
|
|
|
|
case BMP180_CHIPID:
|
|
|
|
case BMP280_CHIPID:
|
|
|
|
break;
|
|
|
|
case BME280_CHIPID:
|
|
|
|
return bme280_readHumidity();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean bmp_detect()
|
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
if (bmptype) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
boolean success = false;
|
|
|
|
|
|
|
|
bmpaddr = BMP_ADDR;
|
|
|
|
bmptype = i2c_read8(bmpaddr, BMP_REGISTER_CHIPID);
|
|
|
|
if (!bmptype) {
|
|
|
|
bmpaddr--;
|
|
|
|
bmptype = i2c_read8(bmpaddr, BMP_REGISTER_CHIPID);
|
|
|
|
}
|
2017-02-28 15:01:48 +00:00
|
|
|
strcpy_P(bmpstype, PSTR("BMP"));
|
2017-01-28 13:41:01 +00:00
|
|
|
switch (bmptype) {
|
|
|
|
case BMP180_CHIPID:
|
|
|
|
success = bmp180_calibration();
|
2017-02-28 15:01:48 +00:00
|
|
|
strcpy_P(bmpstype, PSTR("BMP180"));
|
2017-01-28 13:41:01 +00:00
|
|
|
break;
|
|
|
|
case BMP280_CHIPID:
|
|
|
|
success = bmp280_calibrate();
|
2017-02-28 15:01:48 +00:00
|
|
|
strcpy_P(bmpstype, PSTR("BMP280"));
|
2017-01-28 13:41:01 +00:00
|
|
|
break;
|
|
|
|
case BME280_CHIPID:
|
|
|
|
success = bme280_calibrate();
|
2017-02-28 15:01:48 +00:00
|
|
|
strcpy_P(bmpstype, PSTR("BME280"));
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
if (success) {
|
2017-09-13 13:19:34 +01:00
|
|
|
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "%s " D_FOUND_AT " 0x%x"), bmpstype, bmpaddr);
|
|
|
|
addLog(LOG_LEVEL_DEBUG);
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-01-28 13:41:01 +00:00
|
|
|
bmptype = 0;
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Presentation
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
void bmp_mqttPresent(uint8_t *djson)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!bmptype) {
|
|
|
|
return;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
char stemp1[10];
|
|
|
|
char stemp2[10];
|
|
|
|
char stemp3[10];
|
2017-10-08 15:51:05 +01:00
|
|
|
char stemp4[10];
|
|
|
|
char sealevel[40];
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-05-03 17:19:13 +01:00
|
|
|
double t = bmp_readTemperature();
|
2017-01-28 13:41:01 +00:00
|
|
|
double p = bmp_readPressure();
|
|
|
|
double h = bmp_readHumidity();
|
2017-09-02 13:37:02 +01:00
|
|
|
dtostrfd(t, sysCfg.flag.temperature_resolution, stemp1);
|
|
|
|
dtostrfd(p, sysCfg.flag.pressure_resolution, stemp2);
|
|
|
|
dtostrfd(h, sysCfg.flag.humidity_resolution, stemp3);
|
2017-10-08 15:51:05 +01:00
|
|
|
|
|
|
|
dtostrfd(bmp_sealevel, sysCfg.flag.pressure_resolution, stemp4);
|
|
|
|
snprintf_P(sealevel, sizeof(sealevel), PSTR(", \"" D_PRESSUREATSEALEVEL "\":%s"), stemp4);
|
|
|
|
if (!strcmp(bmpstype, "BME280")) {
|
|
|
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_HUMIDITY "\":%s, \"" D_PRESSURE "\":%s%s}"),
|
|
|
|
mqtt_data, bmpstype, stemp1, stemp3, stemp2, (sysCfg.altitude != 0) ? sealevel : "");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_PRESSURE "\":%s%s}"),
|
|
|
|
mqtt_data, bmpstype, stemp1, stemp2, (sysCfg.altitude != 0) ? sealevel : "");
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
*djson = 1;
|
|
|
|
#ifdef USE_DOMOTICZ
|
2017-09-02 13:37:02 +01:00
|
|
|
domoticz_sensor3(stemp1, stemp3, stemp2);
|
2017-10-08 15:51:05 +01:00
|
|
|
#endif // USE_DOMOTICZ
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_WEBSERVER
|
|
|
|
String bmp_webPresent()
|
|
|
|
{
|
|
|
|
String page = "";
|
|
|
|
if (bmptype) {
|
2017-04-25 17:24:42 +01:00
|
|
|
char stemp[10];
|
|
|
|
char sensor[80];
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-05-03 17:19:13 +01:00
|
|
|
double t_bmp = bmp_readTemperature();
|
2017-01-28 13:41:01 +00:00
|
|
|
double p_bmp = bmp_readPressure();
|
|
|
|
double h_bmp = bmp_readHumidity();
|
2017-09-02 13:37:02 +01:00
|
|
|
dtostrfi(t_bmp, sysCfg.flag.temperature_resolution, stemp);
|
2017-05-03 17:19:13 +01:00
|
|
|
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, bmpstype, stemp, tempUnit());
|
2017-02-28 15:01:48 +00:00
|
|
|
page += sensor;
|
2017-10-08 15:51:05 +01:00
|
|
|
if (!strcmp(bmpstype, "BME280")) {
|
2017-09-02 13:37:02 +01:00
|
|
|
dtostrfi(h_bmp, sysCfg.flag.humidity_resolution, stemp);
|
2017-02-28 15:01:48 +00:00
|
|
|
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_HUM, bmpstype, stemp);
|
|
|
|
page += sensor;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
2017-09-02 13:37:02 +01:00
|
|
|
dtostrfi(p_bmp, sysCfg.flag.pressure_resolution, stemp);
|
2017-02-28 15:01:48 +00:00
|
|
|
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_PRESSURE, bmpstype, stemp);
|
|
|
|
page += sensor;
|
2017-10-08 15:51:05 +01:00
|
|
|
if (sysCfg.altitude != 0) {
|
|
|
|
dtostrfi(bmp_sealevel, sysCfg.flag.pressure_resolution, stemp);
|
|
|
|
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_PRESSUREATSEALEVEL, bmpstype, stemp);
|
|
|
|
page += sensor;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
return page;
|
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
#endif // USE_WEBSERVER
|
|
|
|
#endif // USE_BMP
|
|
|
|
#endif // USE_I2C
|