From 9afac219cf8ed2002b88b39af53aeb56764706cd Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Mon, 29 Dec 2025 10:17:26 +0700 Subject: [PATCH 1/2] Added i2c_probe for sensors and fixed BME680 to support Wire1 - Fixed BME680 to support Wire1 - Added i2c_probe to check I2C addresses before triggering begin() for sensors. This is to speed up startup process, to avoid unnecessary initiation of unused sensors and to avoid bugs due to sensor codes of unused sensors --- src/helpers/SensorManager.h | 2 + .../sensors/EnvironmentSensorManager.cpp | 56 +++++++++++-------- .../sensors/EnvironmentSensorManager.h | 1 + 3 files changed, 35 insertions(+), 24 deletions(-) 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 From f08b93a14e1855749937461766250823af8c6f20 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Mon, 29 Dec 2025 10:41:41 +0700 Subject: [PATCH 2/2] Added LPS22HB as local library as public Arduino_LPS22HB breaks Wire connection if Wire1 connection is initiated. --- lib/Arduino_LPS22HB/Arduino_LPS22HB.h | 25 ++++++ lib/Arduino_LPS22HB/BARO.cpp | 122 ++++++++++++++++++++++++++ lib/Arduino_LPS22HB/BARO.h | 53 +++++++++++ platformio.ini | 2 +- 4 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 lib/Arduino_LPS22HB/Arduino_LPS22HB.h create mode 100644 lib/Arduino_LPS22HB/BARO.cpp create mode 100644 lib/Arduino_LPS22HB/BARO.h 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