BME280 only retrieves higher temperature values if I reboot the device

I am using the following library because it calculates dew point and heat index, whereas other libraries don't: GitHub - finitespace/BME280: Provides an Arduino library for reading and interpreting Bosch BME280 data over I2C, SPI or Sw SPI.

My project notifies me through Telegram when motion is detected, sends me weather values upon command and periodically uploads them to Thingspeak so I can keep a graphical record.

During this testing phase, I've been keeping a small digital thermometer next to the project so I can confirm if they are showing similar values or not.

I noticed that if the temperature doesn't vary much during the day, I get similar readings between them. However, there's been a few days with temperatures rising from 10ºC to 25ºC around lunch time, but the BME280 still shows lows temperatures. When I reboot the device, it sends me around 25ºC.

I have read the library files and the datasheet but still can't figure this how.

Should I set global variables and keep polling the BME280 every second in the loop() section, then do something with the values? Or should I read the BME280 only when I want a reading or when it's timeto send a reading to Thingspeak?

/*******************************************************************
  ESP8266
  HC-SR501 PIR output to GPIO13: send message to Telegram channel upon interrupt
  BME280 to D1 D2: sends weather data to Telegram chat upon request with "/status"
  Send periodically to Thingspeak

  Using library ESP8266WiFi at version 1.0 in folder: E:\arduino-1.8.13\portable\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi
  Using library UniversalTelegramBot at version 1.3.0 in folder: E:\arduino-1.8.13\portable\sketchbook\libraries\UniversalTelegramBot
  Using library ArduinoJson at version 6.19.4 in folder: E:\arduino-1.8.13\portable\sketchbook\libraries\ArduinoJson
  Using library BME280 at version 3.0.0 in folder: E:\arduino-1.8.13\portable\sketchbook\libraries\BME280
  Using library Wire at version 1.0 in folder: E:\arduino-1.8.13\portable\packages\esp8266\hardware\esp8266\3.0.2\libraries\Wire
  Using library SPI at version 1.0 in folder: E:\arduino-1.8.13\portable\packages\esp8266\hardware\esp8266\3.0.2\libraries\SPI

  https://en.allmetsat.com/index.html
  https://pt.allmetsat.com/metar-taf/portugal-espanha.php?icao=LPPT
  https://moja-elka.blogspot.com/2018/01/bme280-czujnik-wilgotnosci-cisnienia-i.html
 *******************************************************************/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

String apiKey = "blablabla";     //  Enter your Write API key from ThingSpeak
const char* server = "api.thingspeak.com";
unsigned long thingspeak_lasttime = 0;
WiFiClient client;

// Wifi network station credentials
#define WIFI_SSID "blablabla"
#define WIFI_PASSWORD "blablabla"
#define BOT_TOKEN "blablabla" // Telegram BOT Token (Get from Botfather)

const unsigned long BOT_MTBS = 5000; // mean time between scan messages

X509List cert(TELEGRAM_CERTIFICATE_ROOT);
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);
unsigned long bot_lasttime; // last time messages' scan has been done
String chat_id;

#define CHANNEL_ID "blablabla"
#define INT_PIN 13 //D7
volatile bool interruptFlag;
boolean pir_active = false;
int counter = 0;

bool reboot_request = false;
bool reset_request = false;

#include <EnvironmentCalculations.h>
#include <BME280I2C.h>
#include <Wire.h>

// https://pt.allmetsat.com/metar-taf/portugal-espanha.php?icao=LPPT
// Assumed environmental values:
float referencePressure = 1020.1;  // hPa local QFF (official meteor-station reading)
float outdoorTemp = 16.1;           // °C  measured local outdoor temp.
float barometerAltitude = 108.1;  // meters ... map readings + barometer position

float temp(NAN), hum(NAN), pres(NAN);
float altitude, dewPoint, seaLevel, absHum, heatIndex;

EnvironmentCalculations::AltitudeUnit envAltUnit  =  EnvironmentCalculations::AltitudeUnit_Meters;
EnvironmentCalculations::TempUnit     envTempUnit =  EnvironmentCalculations::TempUnit_Celsius;
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
BME280::PresUnit presUnit(BME280::PresUnit_hPa);

BME280I2C::Settings settings(
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::Mode_Forced,
  BME280::StandbyTime_1000ms,
  BME280::Filter_16,
  BME280::SpiEnable_False,
  BME280I2C::I2CAddr_0x76
);

BME280I2C bme(settings);

ICACHE_RAM_ATTR void handleInterrupt() {
  Serial.println("movement detected");
  interruptFlag = true;
}

void handleNewMessages(int numNewMessages) {
  Serial.print("handleNewMessages ");
  Serial.println(numNewMessages);

  for (int i = 0; i < numNewMessages; i++)
  {
    chat_id = bot.messages[i].chat_id;
    String text = bot.messages[i].text;

    String from_name = bot.messages[i].from_name;
    if (from_name == "")
      from_name = "Guest";

    if (text == "/enpir")
    {
      pir_active = 1;
      bot.sendMessage(chat_id, "PIR activated", "");
    }

    if (text == "/dispir")
    {
      pir_active = 0;
      bot.sendMessage(chat_id, "PIR deactivated", "");
    }

    if (text == "/status")
    {
      readBME280(); // get values from weather sensor

      String stat = "Rssi: " + String(WiFi.RSSI());

      stat += "\n\nPIR Status: " + String(pir_active);

      stat += "\n\nTemperature: " + String(temp) + " ºC";
      stat += "\nHumidity: " + String(hum) + " %";
      stat += "\nPressure: " + String(pres) + " hPa";

      stat += "\n\nAltitude: " + String(altitude) + " m";

      stat += "\nHeat Index: " + String(heatIndex) + " ºC";
      stat += "\nDew Point: " + String(dewPoint) + " ºC";

      stat += "\n\nAbsolute Humidity: " + String(absHum) + " ";
      stat += "\nEquivalent Sea Level Pressure: " + String(seaLevel) + " hPa";
      bot.sendMessage(chat_id, stat, "Markdown");
    }

    if (text == "/reboot") {
      //      String stat = "Rebooting on request\nRssi: " + String(WiFi.RSSI()) + "\nip: " +  WiFi.localIP().toString() ;
      //      bot.sendMessage(chat_id, stat, "");
      reboot_request = true;
    }

    if (text == "/reset") {
      reset_request = true;
    }

    if (text == "/start")
    {
      String welcome = "Motion Detection & Weather Station Bot\n\n";
      welcome += "/enpir: enable PIR alert\n";
      welcome += "/dispir: disable PIR alert\n\n";
      welcome += "/status: PIR state & weather readings\n\n";
      welcome += "/reset: reset wifi params\n";
      welcome += "/reboot: reboot\n";
      bot.sendMessage(chat_id, welcome, "Markdown");
    }
  }
}

void setup() {
  delay(500);
//  Serial.begin(115200);
  Serial.println();

  Wire.begin();

  while (!bme.begin())
  {
    Serial.println("Could not find BME280 sensor!");
    delay(500);
    counter++;
    if (counter >= 30) {
      counter = 0;
      break;
    }
  }

  // Interrupt on HIGH output from PIR
  pinMode(INT_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(INT_PIN), handleInterrupt, RISING);

  // attempt to connect to Wifi network:
  configTime(0, 0, "pool.ntp.org");      // get UTC time via NTP
  secured_client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org

  Serial.print("Connecting to Wifi SSID ");
  Serial.print(WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    counter++;
    if (counter >= 60) {
      counter = 0;
      ESP.restart(); //restart board if wifi not connected within 30sec
    }
  }
  Serial.print("\nWiFi connected. IP address: ");
  Serial.println(WiFi.localIP());

  // Check NTP/Time, usually it is instantaneous and you can delete the code below.
  int counter = 0;
  Serial.print("Retrieving time: ");
  time_t now = time(nullptr);
  while (now < 24 * 3600)
  {
    Serial.print(".");
    delay(500);
    now = time(nullptr);
    counter++;
    if (counter >= 120) {
      counter = 0;
      ESP.restart(); //restart board if wifi not connected within 30sec
    }
  }
  Serial.println(now);

}

void loop() {

  // Check for Telegram messages
  if (millis() - bot_lasttime > BOT_MTBS)
  {

    if (WiFi.status() != WL_CONNECTED) {
      Serial.println("***** WiFi reconnect *****");
      WiFi.reconnect();
      delay(5000);
      if (WiFi.status() != WL_CONNECTED) {
        ESP.restart();
      }
    }

    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while (numNewMessages)
    {
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }

    bot_lasttime = millis();
  }

  // When interrupt is triggered by motion, don't send message if PIR is set as inactive
  if (interruptFlag && pir_active) {
    bot.sendMessage(CHANNEL_ID, "/clip", ""); // send message to Telegram channel
    interruptFlag  = false;
  } else {
    interruptFlag  = false;
  }

  // Update Thingspeak values every 30min 1800000
  if (millis() - thingspeak_lasttime >= 1800000) {
    thingspeak_lasttime = millis();
    readBME280();
    delay(100);
    SendToThingspeak();
  }

  if (reboot_request) {
    String stat = "Rebooting on request\nRssi: " + String(WiFi.RSSI()) + "\nip: " +  WiFi.localIP().toString() ;
    bot.sendMessage(chat_id, stat, "");
    delay(5000);
    ESP.restart();
  }

  if (reset_request) {
    //      wm.resetSettings();
    reset_request = false;
  }

}//end of loop()

void readBME280() {
  bme.read(pres, temp, hum, tempUnit, presUnit);

  altitude = EnvironmentCalculations::Altitude(pres, envAltUnit, referencePressure, outdoorTemp, envTempUnit);
  dewPoint = EnvironmentCalculations::DewPoint(temp, hum, envTempUnit);
  seaLevel = EnvironmentCalculations::EquivalentSeaLevelPressure(barometerAltitude, temp, pres, envAltUnit, envTempUnit);
  absHum = EnvironmentCalculations::AbsoluteHumidity(temp, hum, envTempUnit);
  heatIndex = EnvironmentCalculations::HeatIndex(temp, hum, envTempUnit);
}

void SendToThingspeak() {
  if (client.connect(server, 80))  //   "184.106.153.149" or api.thingspeak.com
  {
    String sendData = apiKey + "&field1=" + String(temp) + "&field2=" + String(heatIndex) + "&field3=" + String(pres) + "&field4=" + String(hum) + "&field5=" + String(dewPoint) + "\r\n\r\n";

    Serial.println(sendData);

    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(sendData.length());
    client.print("\n\n");
    client.print(sendData);

  }
  client.stop();
  Serial.println("Sending....");
}

What does that mean? Is it staying at 10°C or is it 2°C below the actual value? Does it keep exactly the same value over an extended time frame?

I also did not find any code in the library that would explain this.

When I checked the weather around lunch time, I noticed it was 25ºC outside but upon sending "/status" command the BME280 retrieved around 15ºC (it had raised from 11ºC during the morning). This value kept increasing as I re-sent "/status". Then I rebooted the device and it sent 25ºC back.

I wonder if I have to keep taking samples from the BME280 inside the loop() for example every second.

I've read the examples from different libraries on Github but they're always about printing to serial every second. I would like to keep using this one because it gives us a few more weather variables.

Here is my Thingspeak channel: pirBME280 - ThingSpeak IoT

You can see a big change in value when I rebooted...

Thank your for your reply!

How did you "reboot"? Power cycle? Reset?

I cannot find anything special in that library so I guess that this result from the hardware.

If you refreshed the status you wrote that the value increased. How much? Will it reach the actual value if you refresh often enough?

SOLVED

The sensor should be read every 60 seconds when in Forced mode, according to the datasheet and Adafruit library

https://www.esp8266.com/viewtopic.php?f=13&t=8030&start=28

// weather monitoring
Serial.println("-- Weather Station Scenario --");
Serial.println("forced mode, 1x temperature / 1x humidity / 1x pressure oversampling,");
Serial.println("filter off");
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF );

// suggested rate is 1/60Hz (1m)
delayTime = 60000; // in milliseconds