diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2c2753edd..7bf6d8aba 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,7 +1,8 @@ /* 6.2.1.20 20181028 * Add command SetOption35 0..255 (seconds) to delay mDNS initialization to control possible Wifi connect problems - * Add command SetOption53 0/1 to toggle gui display of Hostname and IP address + * Add command SetOption53 0/1 to toggle gui display of Hostname and IP address (#1006, #2091) * Add token %hostname% to command FullTopic (#3018) + * Add support for two BMP/BME sensors (#4195) * * 6.2.1.19 20181023 * Fix header file execution order by renaming user_config.h to my_user_config.h diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 187f8cb5e..5b721af2a 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -281,8 +281,7 @@ #ifdef USE_I2C #define USE_SHT // Enable SHT1X sensor (+1k4 code) #define USE_HTU // Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code) - #define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address either 0x76 or 0x77) (+4k code) -//#define USE_BMP2X // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address both 0x76 or 0x77) (+???k code) + #define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensors (I2C addresses 0x76 and 0x77) (+4k4 code) // #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code) #define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code) // #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+1k5 code) diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino index 8a50b8ae6..781b85f20 100755 --- a/sonoff/xsns_09_bmp.ino +++ b/sonoff/xsns_09_bmp.ino @@ -27,8 +27,8 @@ * I2C Address: 0x76 or 0x77 \*********************************************************************************************/ -#define BMP_ADDR1 0x77 -#define BMP_ADDR2 0x76 +#define BMP_ADDR1 0x76 +#define BMP_ADDR2 0x77 #define BMP180_CHIPID 0x55 #define BMP280_CHIPID 0x58 @@ -37,18 +37,27 @@ #define BMP_REGISTER_CHIPID 0xD0 +#define BMP_MAX_SENSORS 2 + const char kBmpTypes[] PROGMEM = "BMP180|BMP280|BME280|BME680"; - -uint8_t bmp_address; uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 }; -uint8_t bmp_type = 0; -uint8_t bmp_model = 0; -char bmp_name[7]; +uint8_t bmp_count = 0; -uint8_t bmp_valid = 0; -float bmp_temperature = 0.0; -float bmp_pressure = 0.0; -float bmp_humidity = 0.0; +struct BMPSTRUCT { + uint8_t bmp_address; // I2C bus address + char bmp_name[7]; // Sensor name - "BMPXXX" + uint8_t bmp_type = 0; + uint8_t bmp_model = 0; + + uint8_t bmp_valid = 0; +#ifdef USE_BME680 + uint8_t bme680_state = 0; + float bmp_gas_resistance = 0.0; +#endif // USE_BME680 + float bmp_temperature = 0.0; + float bmp_pressure = 0.0; + float bmp_humidity = 0.0; +} bmp_sensors[BMP_MAX_SENSORS]; /*********************************************************************************************\ * BMP085 and BME180 @@ -84,18 +93,18 @@ uint16_t cal_ac4; uint16_t cal_ac5; uint16_t cal_ac6; -boolean Bmp180Calibration() +boolean Bmp1802xCalibration(uint8_t bmp_idx) { - cal_ac1 = I2cRead16(bmp_address, BMP180_AC1); - cal_ac2 = I2cRead16(bmp_address, BMP180_AC2); - cal_ac3 = I2cRead16(bmp_address, BMP180_AC3); - cal_ac4 = I2cRead16(bmp_address, BMP180_AC4); - cal_ac5 = I2cRead16(bmp_address, BMP180_AC5); - cal_ac6 = I2cRead16(bmp_address, BMP180_AC6); - cal_b1 = I2cRead16(bmp_address, BMP180_VB1); - cal_b2 = I2cRead16(bmp_address, BMP180_VB2); - cal_mc = I2cRead16(bmp_address, BMP180_MC); - cal_md = I2cRead16(bmp_address, BMP180_MD); + cal_ac1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC1); + cal_ac2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC2); + cal_ac3 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC3); + cal_ac4 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC4); + cal_ac5 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC5); + cal_ac6 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC6); + cal_b1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB1); + cal_b2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB2); + cal_mc = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MC); + cal_md = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MD); // Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF if (!cal_ac1 | !cal_ac2 | !cal_ac3 | !cal_ac4 | !cal_ac5 | !cal_ac6 | !cal_b1 | !cal_b2 | !cal_mc | !cal_md) { @@ -117,19 +126,20 @@ boolean Bmp180Calibration() return true; } -void Bmp180Read() +void Bmp1802xRead(uint8_t bmp_idx) { - I2cWrite8(bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE); + + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE); delay(5); // 5ms conversion time - int ut = I2cRead16(bmp_address, BMP180_REG_RESULT); + int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); int32_t xt1 = (ut - (int32_t)cal_ac6) * ((int32_t)cal_ac5) >> 15; int32_t xt2 = ((int32_t)cal_mc << 11) / (xt1 + (int32_t)cal_md); int32_t bmp180_b5 = xt1 + xt2; - bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0; + bmp_sensors[bmp_idx].bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0; - I2cWrite8(bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution - uint32_t up = I2cRead24(bmp_address, BMP180_REG_RESULT); + uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); up >>= (8 - BMP180_OSS); int32_t b6 = bmp180_b5 - 4000; @@ -155,7 +165,7 @@ void Bmp180Read() x1 = (x1 * 3038) >> 16; x2 = (-7357 * p) >> 16; p += ((x1 + x2 + (int32_t)3791) >> 4); - bmp_pressure = (float)p / 100.0; // convert to mbar + bmp_sensors[bmp_idx].bmp_pressure = (float)p / 100.0; // convert to mbar } /*********************************************************************************************\ @@ -212,45 +222,45 @@ struct BME280CALIBDATA int8_t dig_H6; } Bme280CalibrationData; -boolean Bmx280Calibrate() +boolean Bmx2802xCalibrate(uint8_t bmp_idx) { // if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false; - Bme280CalibrationData.dig_T1 = I2cRead16LE(bmp_address, BME280_REGISTER_DIG_T1); - Bme280CalibrationData.dig_T2 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_T2); - Bme280CalibrationData.dig_T3 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_T3); - Bme280CalibrationData.dig_P1 = I2cRead16LE(bmp_address, BME280_REGISTER_DIG_P1); - Bme280CalibrationData.dig_P2 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P2); - Bme280CalibrationData.dig_P3 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P3); - Bme280CalibrationData.dig_P4 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P4); - Bme280CalibrationData.dig_P5 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P5); - Bme280CalibrationData.dig_P6 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P6); - Bme280CalibrationData.dig_P7 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P7); - Bme280CalibrationData.dig_P8 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P8); - Bme280CalibrationData.dig_P9 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P9); - if (BME280_CHIPID == bmp_type) { // #1051 - Bme280CalibrationData.dig_H1 = I2cRead8(bmp_address, BME280_REGISTER_DIG_H1); - Bme280CalibrationData.dig_H2 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_H2); - Bme280CalibrationData.dig_H3 = I2cRead8(bmp_address, BME280_REGISTER_DIG_H3); - Bme280CalibrationData.dig_H4 = (I2cRead8(bmp_address, BME280_REGISTER_DIG_H4) << 4) | (I2cRead8(bmp_address, BME280_REGISTER_DIG_H4 + 1) & 0xF); - Bme280CalibrationData.dig_H5 = (I2cRead8(bmp_address, BME280_REGISTER_DIG_H5 + 1) << 4) | (I2cRead8(bmp_address, BME280_REGISTER_DIG_H5) >> 4); - Bme280CalibrationData.dig_H6 = (int8_t)I2cRead8(bmp_address, BME280_REGISTER_DIG_H6); + Bme280CalibrationData.dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1); + Bme280CalibrationData.dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2); + Bme280CalibrationData.dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3); + Bme280CalibrationData.dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1); + Bme280CalibrationData.dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2); + Bme280CalibrationData.dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3); + Bme280CalibrationData.dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4); + Bme280CalibrationData.dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5); + Bme280CalibrationData.dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6); + Bme280CalibrationData.dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7); + Bme280CalibrationData.dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8); + Bme280CalibrationData.dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9); + if (BME280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { // #1051 + Bme280CalibrationData.dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1); + Bme280CalibrationData.dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2); + Bme280CalibrationData.dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3); + Bme280CalibrationData.dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1) & 0xF); + Bme280CalibrationData.dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5) >> 4); + Bme280CalibrationData.dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6); - I2cWrite8(bmp_address, BME280_REGISTER_CONTROL, 0x00); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) // Set before CONTROL_meas (DS 5.4.3) - I2cWrite8(bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01); // 1x oversampling - I2cWrite8(bmp_address, BME280_REGISTER_CONFIG, 0xA0); // 1sec standby between measurements (to limit self heating), IIR filter off - I2cWrite8(bmp_address, BME280_REGISTER_CONTROL, 0x27); // 1x oversampling, normal mode + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01); // 1x oversampling + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0); // 1sec standby between measurements (to limit self heating), IIR filter off + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27); // 1x oversampling, normal mode } else { - I2cWrite8(bmp_address, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit) + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit) } return true; } -void Bme280Read(void) +void Bme2802xRead(uint8_t bmp_idx) { - int32_t adc_T = I2cRead24(bmp_address, BME280_REGISTER_TEMPDATA); + int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA); adc_T >>= 4; int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData.dig_T1 << 1))) * ((int32_t)Bme280CalibrationData.dig_T2)) >> 11; @@ -258,9 +268,9 @@ void Bme280Read(void) ((int32_t)Bme280CalibrationData.dig_T3)) >> 14; int32_t t_fine = vart1 + vart2; float T = (t_fine * 5 + 128) >> 8; - bmp_temperature = T / 100.0; + bmp_sensors[bmp_idx].bmp_temperature = T / 100.0; - int32_t adc_P = I2cRead24(bmp_address, BME280_REGISTER_PRESSUREDATA); + int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA); adc_P >>= 4; int64_t var1 = ((int64_t)t_fine) - 128000; @@ -277,11 +287,11 @@ void Bme280Read(void) var1 = (((int64_t)Bme280CalibrationData.dig_P9) * (p >> 13) * (p >> 13)) >> 25; var2 = (((int64_t)Bme280CalibrationData.dig_P8) * p) >> 19; p = ((p + var1 + var2) >> 8) + (((int64_t)Bme280CalibrationData.dig_P7) << 4); - bmp_pressure = (float)p / 25600.0; + bmp_sensors[bmp_idx].bmp_pressure = (float)p / 25600.0; - if (BMP280_CHIPID == bmp_type) { return; } + if (BMP280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { return; } - int32_t adc_H = I2cRead16(bmp_address, BME280_REGISTER_HUMIDDATA); + int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA); int32_t v_x1_u32r = (t_fine - ((int32_t)76800)); v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData.dig_H4) << 20) - @@ -294,7 +304,7 @@ void Bme280Read(void) v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; float h = (v_x1_u32r >> 12); - bmp_humidity = h / 1024.0; + bmp_sensors[bmp_idx].bmp_humidity = h / 1024.0; } #ifdef USE_BME680 @@ -306,17 +316,14 @@ void Bme280Read(void) struct bme680_dev gas_sensor; -float bmp_gas_resistance = 0.0; -uint8_t bme680_state = 0; - static void BmeDelayMs(uint32_t ms) { delay(ms); } -boolean Bme680Init() +boolean Bme6802xInit(uint8_t bmp_idx) { - gas_sensor.dev_id = bmp_address; + gas_sensor.dev_id = bmp_sensors[bmp_idx].bmp_address; gas_sensor.intf = BME680_I2C_INTF; gas_sensor.read = &I2cReadBuffer; gas_sensor.write = &I2cWriteBuffer; @@ -353,17 +360,17 @@ boolean Bme680Init() rslt = bme680_set_sensor_settings(set_required_settings,&gas_sensor); if (rslt != BME680_OK) { return false; } - bme680_state = 0; + bmp_sensors[bmp_idx].bme680_state = 0; return true; } -void Bme680Read() +void Bme6802xRead(uint8_t bmp_idx) { int8_t rslt = BME680_OK; - if (BME680_CHIPID == bmp_type) { - if (0 == bme680_state) { + if (BME680_CHIPID == bmp_sensors[bmp_idx].bmp_type) { + if (0 == bmp_sensors[bmp_idx].bme680_state) { /* Trigger the next measurement if you would like to read data out continuously */ rslt = bme680_set_sensor_mode(&gas_sensor); if (rslt != BME680_OK) { return; } @@ -374,22 +381,22 @@ void Bme680Read() // bme680_get_profile_dur(&meas_period, &gas_sensor); // delay(meas_period); /* Delay till the measurement is ready */ // 183 mSec - we'll wait a second - bme680_state = 1; + bmp_sensors[bmp_idx].bme680_state = 1; } else { - bme680_state = 0; + bmp_sensors[bmp_idx].bme680_state = 0; struct bme680_field_data data; rslt = bme680_get_sensor_data(&data, &gas_sensor); if (rslt != BME680_OK) { return; } - bmp_temperature = data.temperature / 100.0; - bmp_humidity = data.humidity / 1000.0; - bmp_pressure = data.pressure / 100.0; + bmp_sensors[bmp_idx].bmp_temperature = data.temperature / 100.0; + bmp_sensors[bmp_idx].bmp_humidity = data.humidity / 1000.0; + bmp_sensors[bmp_idx].bmp_pressure = data.pressure / 100.0; /* Avoid using measurements from an unstable heating setup */ if (data.status & BME680_GASM_VALID_MSK) { - bmp_gas_resistance = data.gas_resistance / 1000.0; + bmp_sensors[bmp_idx].bmp_gas_resistance = data.gas_resistance / 1000.0; } else { - bmp_gas_resistance = 0; + bmp_sensors[bmp_idx].bmp_gas_resistance = 0; } } } @@ -402,65 +409,66 @@ void Bme680Read() void BmpDetect() { - if (bmp_type) { return; } + if (bmp_count) return; - for (byte i = 0; i < sizeof(bmp_addresses); i++) { - bmp_address = bmp_addresses[i]; - bmp_type = I2cRead8(bmp_address, BMP_REGISTER_CHIPID); + for (byte i = 0; i < BMP_MAX_SENSORS; i++) { + uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID); if (bmp_type) { - break; - } - } - if (bmp_type) { - bmp_model = 0; - boolean success = false; - switch (bmp_type) { - case BMP180_CHIPID: - success = Bmp180Calibration(); - break; - case BME280_CHIPID: - bmp_model++; // 2 - case BMP280_CHIPID: - bmp_model++; // 1 - success = Bmx280Calibrate(); - break; -#ifdef USE_BME680 - case BME680_CHIPID: - bmp_model = 3; // 3 - success = Bme680Init(); - break; -#endif // USE_BME680 - } - if (success) { - GetTextIndexed(bmp_name, sizeof(bmp_name), bmp_model, kBmpTypes); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp_name, bmp_address); - AddLog(LOG_LEVEL_DEBUG); - } - else { - bmp_type = 0; + bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; + bmp_sensors[bmp_count].bmp_type = bmp_type; + bmp_sensors[bmp_count].bmp_model = 0; + + boolean success = false; + switch (bmp_type) { + case BMP180_CHIPID: + success = Bmp1802xCalibration(bmp_count); + break; + case BME280_CHIPID: + bmp_sensors[bmp_count].bmp_model++; // 2 + case BMP280_CHIPID: + bmp_sensors[bmp_count].bmp_model++; // 1 + success = Bmx2802xCalibrate(bmp_count); + break; + #ifdef USE_BME680 + case BME680_CHIPID: + bmp_sensors[bmp_count].bmp_model = 3; // 3 + success = Bme6802xInit(bmp_count); + break; + #endif // USE_BME680 + } + if (success) { + GetTextIndexed(bmp_sensors[bmp_count].bmp_name, sizeof(bmp_sensors[bmp_count].bmp_name), bmp_sensors[bmp_count].bmp_model, kBmpTypes); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp_sensors[bmp_count].bmp_name, bmp_sensors[bmp_count].bmp_address); + AddLog(LOG_LEVEL_DEBUG); + bmp_count++; + } } } } void BmpRead() { - switch (bmp_type) { - case BMP180_CHIPID: - Bmp180Read(); - break; - case BMP280_CHIPID: - case BME280_CHIPID: - Bme280Read(); - break; -#ifdef USE_BME680 - case BME680_CHIPID: - Bme680Read(); - break; -#endif // USE_BME680 + for (byte bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { + switch (bmp_sensors[bmp_idx].bmp_type) { + case BMP180_CHIPID: + Bmp1802xRead(bmp_idx); + break; + case BMP280_CHIPID: + case BME280_CHIPID: + Bme2802xRead(bmp_idx); + break; + #ifdef USE_BME680 + case BME680_CHIPID: + Bme6802xRead(bmp_idx); + break; + #endif // USE_BME680 + } + if (bmp_sensors[bmp_idx].bmp_temperature != 0.0) { + bmp_sensors[bmp_idx].bmp_temperature = ConvertTemp(bmp_sensors[bmp_idx].bmp_temperature); + } } - if (bmp_temperature != 0.0) { bmp_temperature = ConvertTemp(bmp_temperature); } - SetGlobalValues(bmp_temperature, bmp_humidity); + SetGlobalValues(bmp_sensors[0].bmp_temperature, bmp_sensors[0].bmp_humidity); } void BmpEverySecond() @@ -477,72 +485,91 @@ void BmpEverySecond() void BmpShow(boolean json) { - if (bmp_type) { - float bmp_sealevel = 0.0; - char temperature[10]; - char pressure[10]; - char sea_pressure[10]; - char humidity[10]; + for (byte bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { + if (bmp_sensors[bmp_idx].bmp_type) { + float bmp_sealevel = 0.0; + char temperature[10]; + char pressure[10]; + char sea_pressure[10]; + char humidity[10]; + char name[10]; - if (bmp_pressure != 0.0) { - bmp_sealevel = (bmp_pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6; - } - - dtostrfd(bmp_temperature, Settings.flag2.temperature_resolution, temperature); - dtostrfd(bmp_pressure, Settings.flag2.pressure_resolution, pressure); - dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure); - dtostrfd(bmp_humidity, Settings.flag2.humidity_resolution, humidity); -#ifdef USE_BME680 - char gas_resistance[10]; - dtostrfd(bmp_gas_resistance, 2, gas_resistance); -#endif // USE_BME680 - - if (json) { - char json_humidity[40]; - snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); - char json_sealevel[40]; - snprintf_P(json_sealevel, sizeof(json_sealevel), PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure); -#ifdef USE_BME680 - char json_gas[40]; - snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"), - mqtt_data, bmp_name, temperature, (bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "", (bmp_model >= 3) ? json_gas : ""); -#else - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"), - mqtt_data, bmp_name, temperature, (bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : ""); -#endif // USE_BME680 -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzTempHumPressureSensor(temperature, humidity, pressure); -#ifdef USE_BME680 - if (bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)bmp_gas_resistance); } -#endif // USE_BME680 + if (bmp_sensors[bmp_idx].bmp_pressure != 0.0) { + bmp_sealevel = (bmp_sensors[bmp_idx].bmp_pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6; } + + snprintf(name, sizeof(name), bmp_sensors[bmp_idx].bmp_name); + if (bmp_count > 1) { + snprintf_P(name, sizeof(name), PSTR("%s-%02X"), name, bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX + } + + dtostrfd(bmp_sensors[bmp_idx].bmp_temperature, Settings.flag2.temperature_resolution, temperature); + dtostrfd(bmp_sensors[bmp_idx].bmp_pressure, Settings.flag2.pressure_resolution, pressure); + dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure); + dtostrfd(bmp_sensors[bmp_idx].bmp_humidity, Settings.flag2.humidity_resolution, humidity); +#ifdef USE_BME680 + char gas_resistance[10]; + dtostrfd(bmp_sensors[bmp_idx].bmp_gas_resistance, 2, gas_resistance); +#endif // USE_BME680 + + if (json) { + char json_humidity[40]; + snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); + char json_sealevel[40]; + snprintf_P(json_sealevel, sizeof(json_sealevel), PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure); +#ifdef USE_BME680 + char json_gas[40]; + snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance); + + snprintf_P(mqtt_data, + sizeof(mqtt_data), + PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"), + mqtt_data, + name, + temperature, + (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", + pressure, + (Settings.altitude != 0) ? json_sealevel : "", + (bmp_sensors[bmp_idx].bmp_model >= 3) ? json_gas : "" + ); +#else + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"), + mqtt_data, name, temperature, (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : ""); +#endif // USE_BME680 + +#ifdef USE_DOMOTICZ + if ((0 == tele_period) && (0 == bmp_idx)) { // We want the same first sensor to report to Domoticz in case a read is missed + DomoticzTempHumPressureSensor(temperature, humidity, pressure); +#ifdef USE_BME680 + if (bmp_sensors[bmp_idx].bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)bmp_sensors[bmp_idx].bmp_gas_resistance); } +#endif // USE_BME680 + } #endif // USE_DOMOTICZ #ifdef USE_KNX - if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, bmp_temperature); - KnxSensor(KNX_HUMIDITY, bmp_humidity); - } + if (0 == tele_period) { + KnxSensor(KNX_TEMPERATURE, bmp_sensors[bmp_idx].bmp_temperature); + KnxSensor(KNX_HUMIDITY, bmp_sensors[bmp_idx].bmp_humidity); + } #endif // USE_KNX #ifdef USE_WEBSERVER - } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, bmp_name, temperature, TempUnit()); - if (bmp_model >= 2) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, bmp_name, humidity); - } - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_PRESSURE, mqtt_data, bmp_name, pressure); - if (Settings.altitude != 0) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_SEAPRESSURE, mqtt_data, bmp_name, sea_pressure); - } + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, name, temperature, TempUnit()); + if (bmp_sensors[bmp_idx].bmp_model >= 2) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, name, humidity); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_PRESSURE, mqtt_data, name, pressure); + if (Settings.altitude != 0) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_SEAPRESSURE, mqtt_data, name, sea_pressure); + } #ifdef USE_BME680 - if (bmp_model >= 3) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{s}%s " D_GAS "{m}%s " D_UNIT_KILOOHM "{e}"), mqtt_data, bmp_name, gas_resistance); - } + if (bmp_sensors[bmp_idx].bmp_model >= 3) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{s}%s " D_GAS "{m}%s " D_UNIT_KILOOHM "{e}"), mqtt_data, name, gas_resistance); + } #endif // USE_BME680 #endif // USE_WEBSERVER + } } } } diff --git a/sonoff/xsns_09_bmp2x.ino b/sonoff/xsns_09_bmp2x.ino deleted file mode 100644 index 52561de3d..000000000 --- a/sonoff/xsns_09_bmp2x.ino +++ /dev/null @@ -1,622 +0,0 @@ -/* - xsns_09_bmp2x.ino - BMP pressure, temperature, humidity and gas sensor support for Sonoff-Tasmota - - Copyright (C) 2018 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 . -*/ - -#ifdef USE_I2C -#ifdef USE_BMP2X -/*********************************************************************************************\ - * BMP085, BMP180, BMP280, BME280, BME680 - Pressure, Temperature, Humidity (BME280/BME680) and gas (BME680) - * - * Source: Heiko Krupp and Adafruit Industries - * - * I2C Address: 0x76 or 0x77 -\*********************************************************************************************/ - -#define BMP_ADDR1 0x77 -#define BMP_ADDR2 0x76 - -#define BMP180_CHIPID 0x55 -#define BMP280_CHIPID 0x58 -#define BME280_CHIPID 0x60 -#define BME680_CHIPID 0x61 - -#define BMP_REGISTER_CHIPID 0xD0 - -#define BMP2X_MAX_SENSORS 2 - -const char kBmpTypes[] PROGMEM = "BMP1802X|BMP2802X|BME2802X|BME6802X"; -uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 }; - -uint8_t bmp2x_count = 0; -struct BMP2XSTRUCT { - uint8_t bmp_address; // I2C bus address - char bmp_name[9]; // Sensor name - "BMPXXX2x" - uint8_t bmp_type = 0; - uint8_t bmp_model = 0; - - uint8_t bmp_valid = 0; - float bmp_temperature = 0.0; - float bmp_pressure = 0.0; - float bmp_humidity = 0.0; - #ifdef USE_BME680 - float bmp_gas_resistance = 0.0; - uint8_t bme680_state = 0; - #endif // USE_BME680 - - -} bmp2x_sensors[BMP2X_MAX_SENSORS]; - - -uint8_t bmp_type = 0; - -/*********************************************************************************************\ - * BMP085 and BME180 -\*********************************************************************************************/ - -#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 - -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; - -boolean Bmp1802xCalibration(uint8_t bmp2x_idx) -{ - cal_ac1 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_AC1); - cal_ac2 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_AC2); - cal_ac3 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_AC3); - cal_ac4 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_AC4); - cal_ac5 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_AC5); - cal_ac6 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_AC6); - cal_b1 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_VB1); - cal_b2 = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_VB2); - cal_mc = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_MC); - cal_md = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_MD); - - // Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF - if (!cal_ac1 | !cal_ac2 | !cal_ac3 | !cal_ac4 | !cal_ac5 | !cal_ac6 | !cal_b1 | !cal_b2 | !cal_mc | !cal_md) { - return false; - } - - if ((cal_ac1 == (int16_t)0xFFFF) | - (cal_ac2 == (int16_t)0xFFFF) | - (cal_ac3 == (int16_t)0xFFFF) | - (cal_ac4 == 0xFFFF) | - (cal_ac5 == 0xFFFF) | - (cal_ac6 == 0xFFFF) | - (cal_b1 == (int16_t)0xFFFF) | - (cal_b2 == (int16_t)0xFFFF) | - (cal_mc == (int16_t)0xFFFF) | - (cal_md == (int16_t)0xFFFF)) { - return false; - } - return true; -} - -void Bmp1802xRead(uint8_t bmp2x_idx) -{ - - I2cWrite8(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE); - delay(5); // 5ms conversion time - int ut = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_REG_RESULT); - int32_t xt1 = (ut - (int32_t)cal_ac6) * ((int32_t)cal_ac5) >> 15; - int32_t xt2 = ((int32_t)cal_mc << 11) / (xt1 + (int32_t)cal_md); - int32_t bmp180_b5 = xt1 + xt2; - bmp2x_sensors[bmp2x_idx].bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0; - - I2cWrite8(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution - delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution - uint32_t up = I2cRead24(bmp2x_sensors[bmp2x_idx].bmp_address, BMP180_REG_RESULT); - up >>= (8 - BMP180_OSS); - - int32_t b6 = bmp180_b5 - 4000; - int32_t x1 = ((int32_t)cal_b2 * ((b6 * b6) >> 12)) >> 11; - int32_t x2 = ((int32_t)cal_ac2 * b6) >> 11; - int32_t x3 = x1 + x2; - int32_t b3 = ((((int32_t)cal_ac1 * 4 + x3) << BMP180_OSS) + 2) >> 2; - - 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; - uint32_t b7 = ((uint32_t)up - b3) * (uint32_t)(50000UL >> BMP180_OSS); - - int32_t p; - if (b7 < 0x80000000) { - p = (b7 * 2) / b4; - } - else { - p = (b7 / b4) * 2; - } - x1 = (p >> 8) * (p >> 8); - x1 = (x1 * 3038) >> 16; - x2 = (-7357 * p) >> 16; - p += ((x1 + x2 + (int32_t)3791) >> 4); - bmp2x_sensors[bmp2x_idx].bmp_pressure = (float)p / 100.0; // convert to mbar -} - -/*********************************************************************************************\ - * BMP280 and BME280 - * - * Programmer : BMP280/BME280 Datasheet and Adafruit with changes by Theo Arends -\*********************************************************************************************/ - -#define BME280_REGISTER_CONTROLHUMID 0xF2 -#define BME280_REGISTER_CONTROL 0xF4 -#define BME280_REGISTER_CONFIG 0xF5 -#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 - -struct BME280CALIBDATA -{ - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; - uint16_t dig_P1; - 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; -} Bme280CalibrationData; - -boolean Bmx2802xCalibrate(uint8_t bmp2x_idx) -{ - // if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false; - - Bme280CalibrationData.dig_T1 = I2cRead16LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_T1); - Bme280CalibrationData.dig_T2 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_T2); - Bme280CalibrationData.dig_T3 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_T3); - Bme280CalibrationData.dig_P1 = I2cRead16LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P1); - Bme280CalibrationData.dig_P2 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P2); - Bme280CalibrationData.dig_P3 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P3); - Bme280CalibrationData.dig_P4 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P4); - Bme280CalibrationData.dig_P5 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P5); - Bme280CalibrationData.dig_P6 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P6); - Bme280CalibrationData.dig_P7 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P7); - Bme280CalibrationData.dig_P8 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P8); - Bme280CalibrationData.dig_P9 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_P9); - if (BME280_CHIPID == bmp_type) { // #1051 - Bme280CalibrationData.dig_H1 = I2cRead8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H1); - Bme280CalibrationData.dig_H2 = I2cReadS16_LE(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H2); - Bme280CalibrationData.dig_H3 = I2cRead8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H3); - Bme280CalibrationData.dig_H4 = (I2cRead8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H4) << 4) | (I2cRead8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1) & 0xF); - Bme280CalibrationData.dig_H5 = (I2cRead8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1) << 4) | (I2cRead8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H5) >> 4); - Bme280CalibrationData.dig_H6 = (int8_t)I2cRead8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_DIG_H6); - - I2cWrite8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) - // Set before CONTROL_meas (DS 5.4.3) - I2cWrite8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01); // 1x oversampling - I2cWrite8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0); // 1sec standby between measurements (to limit self heating), IIR filter off - I2cWrite8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27); // 1x oversampling, normal mode - } else { - I2cWrite8(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit) - } - - return true; -} - -void Bme2802xRead(uint8_t bmp2x_idx) -{ - int32_t adc_T = I2cRead24(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_TEMPDATA); - adc_T >>= 4; - - int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData.dig_T1 << 1))) * ((int32_t)Bme280CalibrationData.dig_T2)) >> 11; - int32_t vart2 = (((((adc_T >> 4) - ((int32_t)Bme280CalibrationData.dig_T1)) * ((adc_T >> 4) - ((int32_t)Bme280CalibrationData.dig_T1))) >> 12) * - ((int32_t)Bme280CalibrationData.dig_T3)) >> 14; - int32_t t_fine = vart1 + vart2; - float T = (t_fine * 5 + 128) >> 8; - bmp2x_sensors[bmp2x_idx].bmp_temperature = T / 100.0; - - int32_t adc_P = I2cRead24(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_PRESSUREDATA); - adc_P >>= 4; - - int64_t var1 = ((int64_t)t_fine) - 128000; - int64_t var2 = var1 * var1 * (int64_t)Bme280CalibrationData.dig_P6; - var2 = var2 + ((var1 * (int64_t)Bme280CalibrationData.dig_P5) << 17); - var2 = var2 + (((int64_t)Bme280CalibrationData.dig_P4) << 35); - var1 = ((var1 * var1 * (int64_t)Bme280CalibrationData.dig_P3) >> 8) + ((var1 * (int64_t)Bme280CalibrationData.dig_P2) << 12); - var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)Bme280CalibrationData.dig_P1) >> 33; - if (0 == var1) { - return; // avoid exception caused by division by zero - } - int64_t p = 1048576 - adc_P; - p = (((p << 31) - var2) * 3125) / var1; - var1 = (((int64_t)Bme280CalibrationData.dig_P9) * (p >> 13) * (p >> 13)) >> 25; - var2 = (((int64_t)Bme280CalibrationData.dig_P8) * p) >> 19; - p = ((p + var1 + var2) >> 8) + (((int64_t)Bme280CalibrationData.dig_P7) << 4); - bmp2x_sensors[bmp2x_idx].bmp_pressure = (float)p / 25600.0; - - if (BMP280_CHIPID == bmp2x_sensors[bmp2x_idx].bmp_type) { return; } - - int32_t adc_H = I2cRead16(bmp2x_sensors[bmp2x_idx].bmp_address, BME280_REGISTER_HUMIDDATA); - - int32_t v_x1_u32r = (t_fine - ((int32_t)76800)); - v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData.dig_H4) << 20) - - (((int32_t)Bme280CalibrationData.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * - (((((((v_x1_u32r * ((int32_t)Bme280CalibrationData.dig_H6)) >> 10) * - (((v_x1_u32r * ((int32_t)Bme280CalibrationData.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + - ((int32_t)2097152)) * ((int32_t)Bme280CalibrationData.dig_H2) + 8192) >> 14)); - v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * - ((int32_t)Bme280CalibrationData.dig_H1)) >> 4)); - v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; - v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; - float h = (v_x1_u32r >> 12); - bmp2x_sensors[bmp2x_idx].bmp_humidity = h / 1024.0; -} - -#ifdef USE_BME680 -/*********************************************************************************************\ - * BME680 support by Bosch https://github.com/BoschSensortec/BME680_driver -\*********************************************************************************************/ - -#include - -struct bme680_dev gas_sensor; - - - -static void BmeDelayMs(uint32_t ms) -{ - delay(ms); -} - -boolean Bme6802xInit(uint8_t bmp2x_idx) -{ - gas_sensor.dev_id = bmp2x_sensors[bmp2x_idx].bmp_address; - gas_sensor.intf = BME680_I2C_INTF; - gas_sensor.read = &I2cReadBuffer; - gas_sensor.write = &I2cWriteBuffer; - gas_sensor.delay_ms = BmeDelayMs; - /* amb_temp can be set to 25 prior to configuring the gas sensor - * or by performing a few temperature readings without operating the gas sensor. - */ - gas_sensor.amb_temp = 25; - - int8_t rslt = BME680_OK; - rslt = bme680_init(&gas_sensor); - if (rslt != BME680_OK) { return false; } - - /* Set the temperature, pressure and humidity settings */ - gas_sensor.tph_sett.os_hum = BME680_OS_2X; - gas_sensor.tph_sett.os_pres = BME680_OS_4X; - gas_sensor.tph_sett.os_temp = BME680_OS_8X; - gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_3; - - /* Set the remaining gas sensor settings and link the heating profile */ - gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS; - /* Create a ramp heat waveform in 3 steps */ - gas_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */ - gas_sensor.gas_sett.heatr_dur = 150; /* milliseconds */ - - /* Select the power mode */ - /* Must be set before writing the sensor configuration */ - gas_sensor.power_mode = BME680_FORCED_MODE; - - /* Set the required sensor settings needed */ - uint8_t set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL; - - /* Set the desired sensor configuration */ - rslt = bme680_set_sensor_settings(set_required_settings,&gas_sensor); - if (rslt != BME680_OK) { return false; } - - bmp2x_sensors[bmp2x_idx].bme680_state = 0; - - return true; -} - -void Bme6802xRead(uint8_t bmp2x_idx) -{ - int8_t rslt = BME680_OK; - - if (BME680_CHIPID == bmp2x_sensors[bmp2x_idx].bmp_type) { - if (0 == bmp2x_sensors[bmp2x_idx].bme680_state) { - /* Trigger the next measurement if you would like to read data out continuously */ - rslt = bme680_set_sensor_mode(&gas_sensor); - if (rslt != BME680_OK) { return; } - - /* Get the total measurement duration so as to sleep or wait till the - * measurement is complete */ -// uint16_t meas_period; -// bme680_get_profile_dur(&meas_period, &gas_sensor); -// delay(meas_period); /* Delay till the measurement is ready */ // 183 mSec - we'll wait a second - - bmp2x_sensors[bmp2x_idx].bme680_state = 1; - } else { - bmp2x_sensors[bmp2x_idx].bme680_state = 0; - - struct bme680_field_data data; - rslt = bme680_get_sensor_data(&data, &gas_sensor); - if (rslt != BME680_OK) { return; } - - bmp2x_sensors[bmp2x_idx].bmp_temperature = data.temperature / 100.0; - bmp2x_sensors[bmp2x_idx].bmp_humidity = data.humidity / 1000.0; - bmp2x_sensors[bmp2x_idx].bmp_pressure = data.pressure / 100.0; - /* Avoid using measurements from an unstable heating setup */ - if (data.status & BME680_GASM_VALID_MSK) { - bmp2x_sensors[bmp2x_idx].bmp_gas_resistance = data.gas_resistance / 1000.0; - } else { - bmp2x_sensors[bmp2x_idx].bmp_gas_resistance = 0; - } - } - } - return; -} - -#endif // USE_BME680 - -/********************************************************************************************/ - -void Bmp2xDetect() -{ - //if (bmp_type) { return; } - if (bmp2x_count) return; - - //for (byte i = 0; i < sizeof(bmp_addresses); i++) { - for (byte i = 0; i < BMP2X_MAX_SENSORS; i++) { - - bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID); - if (bmp_type) { - bmp2x_sensors[bmp2x_count].bmp_address = bmp_addresses[i]; - bmp2x_sensors[bmp2x_count].bmp_type = bmp_type; - bmp2x_sensors[bmp2x_count].bmp_model = 0; - - boolean success = false; - - switch (bmp_type) { - case BMP180_CHIPID: - success = Bmp1802xCalibration(bmp2x_count); - break; - case BME280_CHIPID: - bmp2x_sensors[bmp2x_count].bmp_model++; // 2 - case BMP280_CHIPID: - bmp2x_sensors[bmp2x_count].bmp_model++; // 1 - success = Bmx2802xCalibrate(bmp2x_count); - break; - #ifdef USE_BME680 - case BME680_CHIPID: - bmp2x_sensors[bmp2x_count].bmp_model = 3; // 3 - success = Bme6802xInit(bmp2x_count); - break; - #endif // USE_BME680 - } - - if (success) { - GetTextIndexed(bmp2x_sensors[bmp2x_count].bmp_name, sizeof(bmp2x_sensors[bmp2x_count].bmp_name), bmp2x_sensors[bmp2x_count].bmp_model, kBmpTypes); - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp2x_sensors[bmp2x_count].bmp_name, bmp2x_sensors[bmp2x_count].bmp_address); - AddLog(LOG_LEVEL_DEBUG); - bmp2x_count++; - } - else { - bmp_type = 0; - } - } - } - -} - -void Bmp2xRead(uint8_t bmp2x_idx) -{ - switch (bmp2x_sensors[bmp2x_idx].bmp_type) { - case BMP180_CHIPID: - Bmp1802xRead(bmp2x_idx); - break; - case BMP280_CHIPID: - case BME280_CHIPID: - Bme2802xRead(bmp2x_idx); - break; - #ifdef USE_BME680 - case BME680_CHIPID: - Bme6802xRead(bmp2x_idx); - break; - #endif // USE_BME680 - } - if (bmp2x_sensors[bmp2x_idx].bmp_temperature != 0.0) { - bmp2x_sensors[bmp2x_idx].bmp_temperature = ConvertTemp(bmp2x_sensors[bmp2x_idx].bmp_temperature); } - - //SetGlobalValues(bmp_temperature, bmp_humidity); -} - -void Bmp2xEverySecond() -{ - if (91 == (uptime %100)) { - // 1mS - Bmp2xDetect(); - } - else { - // 2mS - for (byte bmp2x_idx = 0; bmp2x_idx < bmp2x_count; bmp2x_idx++) { - Bmp2xRead(bmp2x_idx); - } - } -} - -void Bmp2xShow(boolean json) -{ - for (byte bmp2x_idx = 0; bmp2x_idx < bmp2x_count; bmp2x_idx++) { - - if (bmp2x_sensors[bmp2x_idx].bmp_type) { - float bmp_sealevel = 0.0; - char temperature[10]; - char pressure[10]; - char sea_pressure[10]; - char humidity[10]; - char name[14]; // "BMXXXX2X-XX" - - if (bmp2x_sensors[bmp2x_idx].bmp_pressure != 0.0) { - bmp_sealevel = (bmp2x_sensors[bmp2x_idx].bmp_pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6; - } - - snprintf_P(name, sizeof(name), PSTR("%s-%02X"), bmp2x_sensors[bmp2x_idx].bmp_name, bmp2x_sensors[bmp2x_idx].bmp_address); // "BMXXXX2X-0xXX" - - dtostrfd(bmp2x_sensors[bmp2x_idx].bmp_temperature, Settings.flag2.temperature_resolution, temperature); - dtostrfd(bmp2x_sensors[bmp2x_idx].bmp_pressure, Settings.flag2.pressure_resolution, pressure); - dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure); - dtostrfd(bmp2x_sensors[bmp2x_idx].bmp_humidity, Settings.flag2.humidity_resolution, humidity); -#ifdef USE_BME680 - char gas_resistance[10]; - dtostrfd(bmp2x_sensors[bmp2x_idx].bmp_gas_resistance, 2, gas_resistance); -#endif // USE_BME680 - - if (json) { - char json_humidity[40]; - snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); - char json_sealevel[40]; - snprintf_P(json_sealevel, sizeof(json_sealevel), PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure); -#ifdef USE_BME680 - char json_gas[40]; - snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance); - - snprintf_P(mqtt_data, - sizeof(mqtt_data), - PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"), - mqtt_data, - name, - temperature, - (bmp2x_sensors[bmp2x_idx].bmp_model >= 2) ? json_humidity : "", - pressure, - (Settings.altitude != 0) ? json_sealevel : "", - (bmp2x_sensors[bmp2x_idx].bmp_model >= 3) ? json_gas : "" - ); -#else - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"), - mqtt_data, name, temperature, (bmp2x_sensors[bmp2x_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : ""); -#endif // USE_BME680 - -#ifdef USE_DOMOTICZ - if ((0 == tele_period) && (0 == bmp2x_idx)) { // We want the same first sensor to report to Domoticz in case a read is missed - DomoticzTempHumPressureSensor(temperature, humidity, pressure); -#ifdef USE_BME680 - if (bmp2x_sensors[bmp2x_idx].bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)bmp2x_sensors[bmp2x_idx].bmp_gas_resistance); } -#endif // USE_BME680 - } -#endif // USE_DOMOTICZ - -#ifdef USE_KNX - if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, bmp2x_sensors[bmp2x_idx].bmp_temperature); - KnxSensor(KNX_HUMIDITY, bmp2x_sensors[bmp2x_idx].bmp_humidity); - } -#endif // USE_KNX - -#ifdef USE_WEBSERVER - } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, name, temperature, TempUnit()); - if (bmp2x_sensors[bmp2x_idx].bmp_model >= 2) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, name, humidity); - } - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_PRESSURE, mqtt_data, name, pressure); - if (Settings.altitude != 0) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_SEAPRESSURE, mqtt_data, name, sea_pressure); - } -#ifdef USE_BME680 - if (bmp2x_sensors[bmp2x_idx].bmp_model >= 3) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{s}%s " D_GAS "{m}%s " D_UNIT_KILOOHM "{e}"), mqtt_data, name, gas_resistance); - } -#endif // USE_BME680 -#endif // USE_WEBSERVER - } - } - } -} - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -#define XSNS_09 - -boolean Xsns09(byte function) -{ - boolean result = false; - - if (i2c_flg) { - switch (function) { - case FUNC_INIT: - Bmp2xDetect(); - break; - case FUNC_EVERY_SECOND: - Bmp2xEverySecond(); - break; - case FUNC_JSON_APPEND: - Bmp2xShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_APPEND: - Bmp2xShow(0); - break; -#endif // USE_WEBSERVER - } - } - return result; -} - -#endif // USE_BMP2X -#endif // USE_I2C