Event driven Temp help

Hello,

I have some simple code that reads a temp and publishes its value every 10 seconds. I’d like it to only send the data when theres a change in temp greater than 3 degrees. Im unsure of the code and also wondering if that saved value is retained when the device loses power. Any suggestions?

// Variables
int temperature;
int humidity;

// DHT sensor
DHT dht(DHTPIN, DHTTYPE);

void setup() {
    
    // Start DHT sensor
    dht.begin();
    
}

void loop() {
    
    // Humidity measurement
    temperature = dht.getTempFarenheit();
    
    // Humidity measurement
    humidity = dht.getHumidity();
    
    Particle.publish("temperature", String(temperature) + " °F", PRIVATE);
    delay(10000);
    Particle.publish("humidity", String(humidity) + "%", PRIVATE);
    delay(10000);
}

To answer this one first

If your device really loses power and you haven't got a backup power connected (e.g. coin cell on VBAT for Photons) then the last values won't be retained, unless you store them in EEPROM (or any other non-volatile medium).

And for the other part, you'd need two variables (should be float or double instead of int) - one to hold the new reading and one to keep the old one - and then compare the absolute value of both like this

  float newTemp = dht.getTempFarenheit(); // although there is a spelling error in the library 
                                          // as it should be Fahrenheit
  if (fabs(newTemp - temperature) > 3) {
    temperature = newTemp;
    ...
  }

BTW, I'd rather only publish one event that features both values like this

  char data[32];
  snprintf(data, sizeof(data), "%.1f °F, %.1f %%", temperature, humidity);
  Particle.publish("envData", data, PRIVATE);

And finally instead of using delay() I'd go non-blocking like this

void loop() {
  static uint32_t ms = 0;
  if (millis() - ms < 10000) return; // if the last visit was less than 10 sec ago bail out
  ms = millis(); 
  ...
}
3 Likes

Thank you!

Hello,

I tried your suggestion. Then publishes are now combined (good idea!) but the events are publishing regardless of changes. What did I do wrong here?

// Variables
float temperature;
float humidity;
 
// DHT sensor
DHT dht(DHTPIN, DHTTYPE);

void setup() {
    
    // Start DHT sensor
    dht.begin();

}

void loop() {
    
    float newTemp = dht.getTempFarenheit(); 
    float newHumidity = dht.getHumidity();

      if (abs(newTemp - temperature) > 3) {
    temperature = newTemp;
      
      if (abs(newHumidity - humidity) >3) 
    humidity = newHumidity;
      }
    
char data[32];
  snprintf(data, sizeof(data), "%.1f °F, %.1f %%", temperature, humidity);
  Particle.publish("Temp, Humidity", data, PRIVATE);
    
     static uint32_t ms = 0;
  if (millis() - ms < 10000) return; // if the last visit was less than 10 sec ago bail out
  ms = millis(); 
}

What I meant was this tho’

void loop() {
  static uint32_t ms = 0;

  if (millis() - ms < 10000) return; // if the last visit was less than 10 sec ago bail out
  ms = millis(); 

  char data[32];
  float newTemp = dht.getTempFarenheit(); 

  if (fabs(newTemp - temperature) > 3.0) {
    temperature = newTemp;
    humidity = dht.getHumidity();
    snprintf(data, sizeof(data), "%.1f °F, %.1f %%", temperature, humidity);
    Particle.publish("Temp, Humidity", data, PRIVATE);
  }
}

I'm sure you know this, but lest anyone be confused, when you use battery backup you need to declare a variable as 'retained'. Variables are not automatically saved when you have VBAT.

1 Like

Ok, got it! That all works. How would that work with something like GPS coordinates (ie - 12.345678) If I only want to publish changes in position? I can’t convert a char to float, correct?

TinyGPS gps;
char szInfo[64];
// Every 15 minutes 
int sleep = 1 * 60 * 1000;

void setup(){
        Serial1.begin(9600);
}
void loop(){
    bool isValidGPS = false;
    
    for (unsigned long start = millis(); millis() - start < 1000;){
        // Check GPS data is available
        while (Serial1.available()){
            char c = Serial1.read();
            
            // parse GPS data
            if (gps.encode(c))
                isValidGPS = true;
         }
    }
     // If we have a valid GPS location then publish it
    if (isValidGPS){
        float lat, lon;
        unsigned long age;
    
        gps.f_get_position(&lat, &lon, &age);
        
        sprintf(szInfo, "%.6f,%.6f", (lat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : lat), (lon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : lon));
    }
    else{
        // Not a vlid GPS location, jsut pass 0.0,0.0
        // This is not correct because 0.0,0.0 is a valid GPS location, we have to pass a invalid GPS location
        // and check it at the client side
        sprintf(szInfo, "0.0,0.0");
    }
    
     Particle.publish("gpsloc", szInfo);
}

You can convert char to float, but you don’t need to since the GPS library should provide you with the latitude and longitude values as floats and if you are using TinyGPS++ library you should also get a distanceBetween() function that you can use to calculate the distance between your last and current position and compare that against a threshold.

Thats a much better library. Thank you!