diff --git a/lib/Arduino_LPS22HB/Arduino_LPS22HB.h b/lib/Arduino_LPS22HB/Arduino_LPS22HB.h new file mode 100644 index 000000000..5d32d537a --- /dev/null +++ b/lib/Arduino_LPS22HB/Arduino_LPS22HB.h @@ -0,0 +1,25 @@ +/* + This file is part of the Arduino_LPS22HB library. + Copyright (c) 2019 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _ARUDINO_LPS22HB_H_ +#define _ARUDINO_LPS22HB_H_ + +#include "BARO.h" + +#endif diff --git a/lib/Arduino_LPS22HB/BARO.cpp b/lib/Arduino_LPS22HB/BARO.cpp new file mode 100644 index 000000000..10046d6b1 --- /dev/null +++ b/lib/Arduino_LPS22HB/BARO.cpp @@ -0,0 +1,122 @@ +/* + This file is part of the Arduino_LPS22HB library. + Copyright (c) 2019 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "BARO.h" + +#define LPS22HB_ADDRESS 0x5C + +#define LPS22HB_WHO_AM_I_REG 0x0f +#define LPS22HB_CTRL2_REG 0x11 +#define LPS22HB_STATUS_REG 0x27 +#define LPS22HB_PRESS_OUT_XL_REG 0x28 +#define LPS22HB_PRESS_OUT_L_REG 0x29 +#define LPS22HB_PRESS_OUT_H_REG 0x2a +#define LPS22HB_TEMP_OUT_L_REG 0x2b +#define LPS22HB_TEMP_OUT_H_REG 0x2c + +LPS22HBClass::LPS22HBClass(TwoWire& wire) : + _wire(&wire), + _initialized(false) +{ +} + +int LPS22HBClass::begin() +{ + if (i2cRead(LPS22HB_WHO_AM_I_REG) != 0xb1) { + _initialized = false; + return 0; + } + + _initialized = true; + return 1; +} + +void LPS22HBClass::end() +{ + _initialized = false; +} + +float LPS22HBClass::readPressure(int units) +{ + if (_initialized == true) { + // trigger one shot + i2cWrite(LPS22HB_CTRL2_REG, 0x01); + + // wait for ONE_SHOT bit to be cleared by the hardware + while ((i2cRead(LPS22HB_CTRL2_REG) & 0x01) != 0) { + yield(); + } + + float reading = (i2cRead(LPS22HB_PRESS_OUT_XL_REG) | + (i2cRead(LPS22HB_PRESS_OUT_L_REG) << 8) | + (i2cRead(LPS22HB_PRESS_OUT_H_REG) << 16)) / 40960.0; + + if (units == MILLIBAR) { // 1 kPa = 10 millibar + return reading * 10; + } else if (units == PSI) { // 1 kPa = 0.145038 PSI + return reading * 0.145038; + } else { + return reading; + } + } + return 0; +} + +float LPS22HBClass::readTemperature(void) +{ + float reading = (i2cRead(LPS22HB_TEMP_OUT_L_REG) << 0) | + (i2cRead(LPS22HB_TEMP_OUT_H_REG) << 8); + + return reading/100; +} + +int LPS22HBClass::i2cRead(uint8_t reg) +{ + _wire->beginTransmission(LPS22HB_ADDRESS); + _wire->write(reg); + if (_wire->endTransmission(false) != 0) { + return -1; + } + + if (_wire->requestFrom(LPS22HB_ADDRESS, 1) != 1) { + return -1; + } + + return _wire->read(); +} + +int LPS22HBClass::i2cWrite(uint8_t reg, uint8_t val) +{ + _wire->beginTransmission(LPS22HB_ADDRESS); + _wire->write(reg); + _wire->write(val); + if (_wire->endTransmission() != 0) { + return 0; + } + + return 1; +} + +#ifdef ARDUINO_ARDUINO_NANO33BLE +LPS22HBClass BARO(Wire1); +#else +LPS22HBClass BARO(Wire); +#endif diff --git a/lib/Arduino_LPS22HB/BARO.h b/lib/Arduino_LPS22HB/BARO.h new file mode 100644 index 000000000..6a66004a2 --- /dev/null +++ b/lib/Arduino_LPS22HB/BARO.h @@ -0,0 +1,53 @@ +/* + This file is part of the Arduino_LPS22HB library. + Copyright (c) 2019 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BARO_H_ +#define _BARO_H_ + +#include +#include + +enum { + PSI, + MILLIBAR, + KILOPASCAL +}; + +class LPS22HBClass { +public: + LPS22HBClass(TwoWire& wire); + + int begin(); + void end(); + + float readPressure(int units = KILOPASCAL); + float readTemperature(void); + +private: + int i2cRead(uint8_t reg); + int i2cWrite(uint8_t reg, uint8_t val); + +private: + TwoWire* _wire; + bool _initialized; +}; + +extern LPS22HBClass BARO; + +#endif diff --git a/platformio.ini b/platformio.ini index 75d37e869..0ec31163a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -142,7 +142,7 @@ lib_deps = adafruit/Adafruit BMP280 Library @ ^2.6.8 adafruit/Adafruit SHTC3 Library @ ^1.0.1 sensirion/Sensirion I2C SHT4x @ ^1.1.2 - arduino-libraries/Arduino_LPS22HB @ ^1.0.2 + ;arduino-libraries/Arduino_LPS22HB @ ^1.0.2 adafruit/Adafruit MLX90614 Library @ ^2.1.5 adafruit/Adafruit_VL53L0X @ ^1.2.4 stevemarple/MicroNMEA @ ^2.0.6 diff --git a/src/helpers/SensorManager.h b/src/helpers/SensorManager.h index 89a174c22..d4aa63b70 100644 --- a/src/helpers/SensorManager.h +++ b/src/helpers/SensorManager.h @@ -2,6 +2,7 @@ #include #include "sensors/LocationProvider.h" +#include #define TELEM_PERM_BASE 0x01 // 'base' permission includes battery #define TELEM_PERM_LOCATION 0x02 @@ -15,6 +16,7 @@ class SensorManager { double node_altitude; // altitude in meters SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; } + virtual bool i2c_probe(TwoWire& wire, uint8_t addr) { return false; } virtual bool begin() { return false; } virtual bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { return false; } virtual void loop() { } diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 77a791bde..32099dad4 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -12,7 +12,7 @@ #endif #define TELEM_BME680_SEALEVELPRESSURE_HPA (1013.25) #include -static Adafruit_BME680 BME680; +static Adafruit_BME680 BME680(TELEM_WIRE); #endif #ifdef ENV_INCLUDE_BMP085 @@ -148,6 +148,12 @@ class RAK12500LocationProvider : public LocationProvider { static RAK12500LocationProvider RAK12500_provider; #endif +bool EnvironmentSensorManager::i2c_probe(TwoWire &wire, uint8_t addr) { + wire.beginTransmission(addr); + uint8_t error = wire.endTransmission(); + return (error == 0); // If found i2c device, the error is 0 +} + bool EnvironmentSensorManager::begin() { #if ENV_INCLUDE_GPS #ifdef RAK_WISBLOCK_GPS @@ -169,7 +175,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_AHTX0 - if (AHTX0.begin(TELEM_WIRE, 0, TELEM_AHTX_ADDRESS)) { + if (i2c_probe(*TELEM_WIRE, TELEM_AHTX_ADDRESS) && AHTX0.begin(TELEM_WIRE, 0, TELEM_AHTX_ADDRESS)) { MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); AHTX0_initialized = true; } else { @@ -179,7 +185,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_BME680 - if (BME680.begin(TELEM_BME680_ADDRESS, TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, TELEM_BME680_ADDRESS) && BME680.begin(TELEM_BME680_ADDRESS, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found BME680 at address: %02X", TELEM_BME680_ADDRESS); BME680_initialized = true; } else { @@ -189,7 +195,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_BME280 - if (BME280.begin(TELEM_BME280_ADDRESS, TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, TELEM_BME280_ADDRESS) && BME280.begin(TELEM_BME280_ADDRESS, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS); MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID()); // Reduce self-heating: single-shot conversions, light oversampling, long standby. @@ -207,7 +213,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_BMP280 - if (BMP280.begin(TELEM_BMP280_ADDRESS)) { + if (i2c_probe(*TELEM_WIRE, TELEM_BMP280_ADDRESS) && BMP280.begin(TELEM_BMP280_ADDRESS)) { MESH_DEBUG_PRINTLN("Found BMP280 at address: %02X", TELEM_BMP280_ADDRESS); MESH_DEBUG_PRINTLN("BMP sensor ID: %02X", BMP280.sensorID()); BMP280_initialized = true; @@ -218,7 +224,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_SHTC3 - if (SHTC3.begin()) { + if (i2c_probe(*TELEM_WIRE, 0x70) && SHTC3.begin()) { MESH_DEBUG_PRINTLN("Found sensor: SHTC3"); SHTC3_initialized = true; } else { @@ -229,21 +235,23 @@ bool EnvironmentSensorManager::begin() { #if ENV_INCLUDE_SHT4X - SHT4X.begin(*TELEM_WIRE, TELEM_SHT4X_ADDRESS); - uint32_t serialNumber = 0; - int16_t sht4x_error; - sht4x_error = SHT4X.serialNumber(serialNumber); - if (sht4x_error == 0) { - MESH_DEBUG_PRINTLN("Found SHT4X at address: %02X", TELEM_SHT4X_ADDRESS); - SHT4X_initialized = true; - } else { - SHT4X_initialized = false; - MESH_DEBUG_PRINTLN("SHT4X was not found at I2C address %02X", TELEM_SHT4X_ADDRESS); + if (i2c_probe(*TELEM_WIRE, TELEM_SHT4X_ADDRESS)) { + SHT4X.begin(*TELEM_WIRE, TELEM_SHT4X_ADDRESS); + uint32_t serialNumber = 0; + int16_t sht4x_error; + sht4x_error = SHT4X.serialNumber(serialNumber); + if (sht4x_error == 0) { + MESH_DEBUG_PRINTLN("Found SHT4X at address: %02X", TELEM_SHT4X_ADDRESS); + SHT4X_initialized = true; + } else { + SHT4X_initialized = false; + MESH_DEBUG_PRINTLN("SHT4X was not found at I2C address %02X", TELEM_SHT4X_ADDRESS); + } } #endif #if ENV_INCLUDE_LPS22HB - if (BARO.begin()) { + if (i2c_probe(*TELEM_WIRE, 0x5C) && BARO.begin()) { MESH_DEBUG_PRINTLN("Found sensor: LPS22HB"); LPS22HB_initialized = true; } else { @@ -253,7 +261,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_INA3221 - if (INA3221.begin(TELEM_INA3221_ADDRESS, TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, TELEM_INA3221_ADDRESS) && INA3221.begin(TELEM_INA3221_ADDRESS, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); @@ -268,7 +276,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_INA219 - if (INA219.begin(TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, TELEM_INA219_ADDRESS) && INA219.begin(TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); INA219_initialized = true; } else { @@ -278,7 +286,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_INA260 - if (INA260.begin(TELEM_INA260_ADDRESS, TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, TELEM_INA260_ADDRESS) && INA260.begin(TELEM_INA260_ADDRESS, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found INA260 at address: %02X", TELEM_INA260_ADDRESS); INA260_initialized = true; } else { @@ -288,7 +296,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_INA226 - if (INA226.begin()) { + if (i2c_probe(*TELEM_WIRE, TELEM_INA226_ADDRESS) && INA226.begin()) { MESH_DEBUG_PRINTLN("Found INA226 at address: %02X", TELEM_INA226_ADDRESS); INA226.setMaxCurrentShunt(TELEM_INA226_MAX_AMP, TELEM_INA226_SHUNT_VALUE); INA226_initialized = true; @@ -299,7 +307,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_MLX90614 - if (MLX90614.begin(TELEM_MLX90614_ADDRESS, TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, TELEM_MLX90614_ADDRESS) && MLX90614.begin(TELEM_MLX90614_ADDRESS, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found MLX90614 at address: %02X", TELEM_MLX90614_ADDRESS); MLX90614_initialized = true; } else { @@ -309,7 +317,7 @@ bool EnvironmentSensorManager::begin() { #endif #if ENV_INCLUDE_VL53L0X - if (VL53L0X.begin(TELEM_VL53L0X_ADDRESS, false, TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, TELEM_VL53L0X_ADDRESS) && VL53L0X.begin(TELEM_VL53L0X_ADDRESS, false, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found VL53L0X at address: %02X", TELEM_VL53L0X_ADDRESS); VL53L0X_initialized = true; } else { @@ -321,7 +329,7 @@ bool EnvironmentSensorManager::begin() { #if ENV_INCLUDE_BMP085 // First argument is MODE (aka oversampling) // choose ULTRALOWPOWER - if (BMP085.begin(0, TELEM_WIRE)) { + if (i2c_probe(*TELEM_WIRE, 0x77) && BMP085.begin(0, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found sensor BMP085"); BMP085_initialized = true; } else { diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index f176a33f5..5a0643a67 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -46,6 +46,7 @@ class EnvironmentSensorManager : public SensorManager { #else EnvironmentSensorManager(){}; #endif + bool i2c_probe(TwoWire& wire, uint8_t addr) override; bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; #if ENV_INCLUDE_GPS