mysensors / NodeManager

Plugin for a rapid development of battery-powered sensors
130 stars 82 forks source link

BME280/BMP280 high power comsumption when sleeping #522

Open bpbastos opened 4 years ago

bpbastos commented 4 years ago

Hi,

I'm getting about 0.50mA when deep sleeping using BME280/BMP280, just arduino and radio gives me 5uA. I've tried to power the sensor from digital pins 5,6 - PowerManager power(5,6) - but still gets 0.50mA when sleeping.

user2684 commented 4 years ago

Weird, would you mind ensuring with a multimeter that while sleeping ping 5 and 6 and both 0v? thanks

bpbastos commented 4 years ago

Weird, would you mind ensuring with a multimeter that while sleeping ping 5 and 6 and both 0v? thanks

Here it's: WhatsApp Image 2020-06-19 at 15 52 36

Sorry for the bad picture. I'm still geting 3.48v through ping 5,6 even when sleeping. My Sketch:

/**********************************
 * MySensors node configuration
 */

// General settings
#define SKETCH_NAME "escritorio"
#define SKETCH_VERSION "1.0"
#define MY_NODE_ID 10

// NRF24 radio settings
#define MY_RADIO_NRF24

// Advanced settings
#define MY_BAUD_RATE 9600
#define MY_SPLASH_SCREEN_DISABLED
#define MY_SIGNAL_REPORT_ENABLED

/***********************************
 * NodeManager configuration
 */

#define NODEMANAGER_DEBUG ON
#define NODEMANAGER_INTERRUPTS ON
#define NODEMANAGER_SLEEP ON
#define NODEMANAGER_RECEIVE ON
#define NODEMANAGER_DEBUG_VERBOSE OFF
#define NODEMANAGER_POWER_MANAGER ON
#define NODEMANAGER_CONDITIONAL_REPORT OFF
#define NODEMANAGER_EEPROM OFF
#define NODEMANAGER_TIME OFF
#define NODEMANAGER_RTC OFF
#define NODEMANAGER_SD OFF
#define NODEMANAGER_HOOKING OFF
#define NODEMANAGER_OTA_CONFIGURATION OFF
#define NODEMANAGER_SERIAL_INPUT OFF

// import NodeManager library (a nodeManager object will be then made available)
#include <MySensors_NodeManager.h>

/***********************************
 * Add your sensors
 */
PowerManager power(5,6);

#include <sensors/SensorBattery.h>
SensorBattery battery;

#include <sensors/SensorSignal.h>
SensorSignal signal;

//#include <sensors/SensorDoor.h>
//SensorDoor door(3);

#define NODEMANAGER_SENSOR_BOSCH_LITE
#include <sensors/SensorBME280.h>
SensorBME280 bme280;

/***********************************
 * Main Sketch
 */

// before
void before() {

  /***********************************
   * Configure your sensors
   */

 // send unit prefixes to controller (i.e. V, A, hPa, %, etc.)
  nodeManager.setSendUnitPrefix(true);
  nodeManager.setSleepMinutes(15);

  // let controller know ambient pressure sensor reports in hPa
  bme280.children.get(3)->setUnitPrefix("hPa");
  bme280.children.get(1)->setFloatPrecision(1);  
  bme280.children.get(2)->setFloatPrecision(1);  
  bme280.setReportIntervalMinutes(15);

  // report battery level every 60 minutes
  battery.setReportIntervalMinutes(60);
  battery.setMinVoltage(1.8);
  battery.setMaxVoltage(3.2);

  // report radio signal level every 10 minutes
  signal.setReportIntervalMinutes(10);

  // only a pseudo SR_TX_RSSI and SR_UPLINK_QUALITY are available for NRF24
  // radio. All other methods return as INVALID.
  signal.setSignalCommand(SR_UPLINK_QUALITY);

  //power all the nodes through dedicated pins
  nodeManager.setPowerManager(power);  

  nodeManager.before();
}

// presentation
void presentation() {
  // call NodeManager presentation routine
  nodeManager.presentation();
}

// setup
void setup() {
  // call NodeManager setup routine
  nodeManager.setup();
}

// loop
void loop() {
  // call NodeManager loop routine
  nodeManager.loop();
}

#if NODEMANAGER_RECEIVE == ON
// receive
void receive(const MyMessage &message) {
  // call NodeManager receive routine
  nodeManager.receive(message);
}
#endif

#if NODEMANAGER_TIME == ON
// receiveTime
void receiveTime(unsigned long ts) {
  // call NodeManager receiveTime routine
  nodeManager.receiveTime(ts);
}
#endif
bpbastos commented 4 years ago

Using mysensors library directly with the sketch below, I was able to get 7uA during sleep.

// Enable debug prints to serial monitor
#define MY_DEBUG
//#define MY_REPEATER_FEATURE

// Enable and select radio type attached
#define MY_RADIO_NRF24

#define MY_NODE_ID 100

//#define MY_PARENT_NODE_ID

#include <SPI.h>
#include <MySensors.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h> // I had to change I2C address in library for 0x76 (line 32)
#include <Wire.h>

Adafruit_BME280 bme; // I2C

#define CHILD_ID_HUM 0
#define CHILD_ID_TEMP 1
#define CHILD_ID_PRESS 2

// MyMessage to controler
MyMessage msgT1(CHILD_ID_TEMP, V_TEMP);
MyMessage msgP1(CHILD_ID_PRESS, V_PRESSURE);
MyMessage msgF1(CHILD_ID_PRESS, V_FORECAST);
MyMessage msgH1(CHILD_ID_HUM, V_HUM);

void presentation() {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("BME280 Test", "1.0");
  present(CHILD_ID_TEMP, S_TEMP);
  present(CHILD_ID_PRESS, S_BARO);
  present(CHILD_ID_HUM, S_HUM);  
}

void setup() {
  //GND
  pinMode(5,OUTPUT);
  digitalWrite(5, LOW);
  //VCC
  pinMode(6,OUTPUT);
  digitalWrite(6, HIGH);
  //Baudrate
  Serial.begin(9600);
  //BME280 init  
  initBme280();
  //Initial reading
  serverUpdate(); 
}

void loop() { 
  digitalWrite(6, HIGH);
  initBme280();
  serverUpdate();
  //delay(200);
  digitalWrite(6, LOW);
  digitalWrite(SDA, LOW); // disable internal pullup
  digitalWrite(SCL, LOW);  // disable internal pullup  
  sleep(60000); //sleep 1 minute
}

void initBme280() {
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

// used to read sensor data and send it to controller
void serverUpdate() {
  double T, P, H;
  T=bme.readTemperature();
  P=bme.readPressure()/100.0;
  H=bme.readHumidity();
  delay(10);
  send(msgT1.set(T, 1));
  send(msgP1.set(P, 1));
  send(msgH1.set(H,1));

   // unmark for debuging
  Serial.print("T = \t"); Serial.print(T, 1); Serial.print(" C\t");
  Serial.print("P = \t"); Serial.print(P, 1); Serial.print(" mBar\t");
  Serial.print("H = \t"); Serial.print(H, 1); Serial.print(" %\t");
}

The code below seems to be the key for the power consumpition drop:

digitalWrite(SDA, LOW); // disable internal pullup
digitalWrite(SCL, LOW);  // disable internal pullup  
user2684 commented 4 years ago

Ok thanks so seems to be two different issues: first of all when the node is sleeping, PowerManager should bring both the pins to 0V but doesn't look the case for you. Weird cause I have a similar configuration and would have noticed a battery drain. Which NodeManager version are you using? Second issue is with SDA/SCL, actually your recommendation makes sense since the internal pullup is always on so potentially some current would flow. I'll add this into the code. Thanks!

bpbastos commented 4 years ago

Thank you! I'm using the latest developement branch - 1.9-dev. I don't now if it's related, but I was trying to do an multi-sensor node, bme/p280 + door sensor.

bpbastos commented 4 years ago

I did some further improvements in power consumption. By default, the Adfruit library uses normal mode that's not indicated for battery-powered nodes. I had changed SensorBME280's onLoop method to use forced mode:

    // define what to do during loop
    void onLoop(Child* child) {
#if defined(NODEMANAGER_SLEEP)  
        setSampling(Adafruit_BME280::MODE_FORCED,
                Adafruit_BME280::SAMPLING_X8,  // temperature
                Adafruit_BME280::SAMPLING_X16, // pressure
                Adafruit_BME280::SAMPLING_X8,  // humidity
                Adafruit_BME280::FILTER_X16, //filter
                Adafruit_BME280::STANDBY_MS_0_5);           
        _bm->takeForcedMeasurement();                           
#endif  
        // temperature sensor
        if (child->getType() == V_TEMP) {
            // read the temperature
            float temperature = _bm->readTemperature();
            // convert it
            temperature = nodeManager.celsiusToFahrenheit(temperature);
            // store the value
            child->setValue(temperature);
        }
        // Humidity Sensor
        else if (child->getType() == V_HUM) {
            // read humidity
            float humidity = _bm->readHumidity();
            // store the value
            child->setValue(humidity);
        }
        // Pressure Sensor
        else if (child->getType() == V_PRESSURE) {
            // read pressure
            float pressure = _bm->readPressure() / 100.0F;
            // store the value
            child->setValue(pressure);
        }
#if !defined(NODEMANAGER_SENSOR_BOSCH_LITE)
        // Forecast Sensor
        else if (child->getType() == V_FORECAST) {
            float pressure = _bm->readPressure() / 100.0F;
            child->setValue(_forecast(pressure));
        }
#endif
    };

Now it's using 15uA when sleeping. Probably the code above can be much better coded and placed taking into account my poor c++ skills. Unfortunately, I wasn't able to use PowerManager and the code above, which I believe, would bring more power savings.

user2684 commented 4 years ago

OK thanks, what I need to do for my own reference is:

  1. Check if PowerManager is working as expected
  2. Check if disabling internal pullup for I2C is ok for all the sensors and if so, add it to powerManager
  3. Apply your change in the BME280 code

thanks!

bpbastos commented 4 years ago

Thank you @user2684! Just to let you known, I had made some testing disabling SDA an SCL internal pullup, but this brought the need to re-initiate the sensor every loop. This added some seconds to the sketch making it more power-hungry.

user2684 commented 4 years ago

Thanks for the feedback, yes this is what I was afraid of, that the attached sensors needed to be re-initialized. Ok so I will keep the SDA/SCL on during sleeping as per the original code base. Thanks!