Particle double variables from photon are all (almost) the same value

I am trying to modify https://learn.sparkfun.com/tutorials/sparkfun-inventors-kit-for-photon-experiment-guide/experiment-6-environment-monitor to put it on the cloud so I can access the temperature and humidity from my phone. However I think my photon has other ideas…

I’ve read up a lot about the problems I’m having and I know that one of them is that the RHT03 returns float values, but the Particle variable api only accepts double values. I currently connected 3 values to Particle. I’ve went through a few iterations of how to store the values, and settled on what you see below. This minimizes the number of times any variable is equal to ########e-270, but now all three variables are always equal to the same value, which is whatever the Celsius value is (current 26.6). Sometimes one of them will deviate by 0.1, and sometimes they will still hit that weird e-270 number, something like this: temperatureF (double) = 5.245949012094471e-270. The serial output is perfect.

Are there any reasons you guys can see why this happens?

// This #include statement was automatically added by the Particle IDE.
#include <SparkFunRHT03.h>


/////////////////////
// Pin Definitions //
/////////////////////
const int RHT03_DATA_PIN = D3; // RHT03 data pin
const int LED_PIN = D7; // LED to show when the sensor's are being read

///////////////////////////
// RHT03 Object Creation //
///////////////////////////
RHT03 rht; // This creates a RTH03 object, which we'll use to interact with the sensor

float minimumTempC = 5505;
float maximumTempC = 0;
float minimumTempF = 9941;
float maximumTempF = 0;
float minimumHumidity = 100;
float maximumHumidity = 0;
char deg = 248;

double humidity;
double tempF;
double tempC;
#define PRINT_RATE 1500 // Time in ms to delay between prints.
#define ROUNDF(f, c) (((double)((int)((f) * (c))) / (c)))

void setup() 
{
    humidity = 0;
    tempF = 0;
    tempC = 0;
    // Serial.begin() is used to open up a serial interface between the Photon
    // and your computer.
    // The '9600' parameter configures the speed of the interface. This value is
    // called the "baud rate", which is equivalent to bits per second (bps).
    Serial.begin(9600); // Start the serial interface at 9600 bps
    
    // Using the 'rht' object created in the global section, we'll begin by calling
    // its member function `begin`.
    // The parameter in this function is the DIGITAL PIN we're using to communicate
    // with the sensor.
    rht.begin(RHT03_DATA_PIN);  // Initialize the RHT03 sensor
    
    // Don't forget to set the pin modes of our analog sensor (INPUT) and the LED (OUTPUT):
    pinMode(LED_PIN, OUTPUT); // Set the LED pin as an OUTPUT
    digitalWrite(LED_PIN, LOW); // Initially set the LED pin low -- turn the LED off.
}

void loop() 
{
    digitalWrite(LED_PIN, HIGH); // Turn the LED on -- it'll blink whenever the sensor is being read.
    
    // Use the RHT03 member function `update()` to read new humidity and temperature values from the sensor.
    // There's a chance the reading might fail, so `update()` returns a success indicator. It'll return 1
    // if the update is successful, or a negative number if it fails.
    int update = rht.update();
    
    if (update == 1) // If the update succeeded, print out the new readings:
    {
        // The `humidity()` RHT03 member function returns the last successfully read relative
        // humidity value from the RHT03.
        // It'll return a float value -- a percentage of RH between 0-100.
        // ONLY CALL THIS FUNCTION AFTER SUCCESSFULLY RUNNING rht.update()!.
        humidity = (double)rht.humidity();
        // Do some math to calculate the max/min humidity
        if (humidity > maximumHumidity) maximumHumidity = humidity;
        if (humidity < minimumHumidity) minimumHumidity = humidity;
        Particle.variable("humidity", ROUNDF(humidity, 100));
        
        // The `tempF()` RHT03 member function returns the last succesfully read 
        // farenheit temperature value from the RHT03.
        // It returns a float variable equal to the temperature in Farenheit.
        // ONLY CALL THIS FUNCTION AFTER SUCCESSFULLY RUNNING rht.update()!.
        tempF = (double)rht.tempF();
        // Do some math to calculate the max/min tempF
        if (tempF > maximumTempF) maximumTempF = tempF;
        if (tempF < minimumTempF) minimumTempF = tempF;
        Particle.variable("temperatureF", ROUNDF(tempF, 100));
        
        // `tempC()` works just like `tempF()`, but it returns the temperature value in
        // Celsius.
        // ONLY CALL THIS FUNCTION AFTER SUCCESSFULLY RUNNING rht.update()!.
        tempC = (double)rht.tempC();
        // Do some math to calculate the max/min tempC
        if (tempC > maximumTempC) maximumTempC = tempC;
        if (tempC < minimumTempC) minimumTempC = tempC;
        Particle.variable("temperatureC", ROUNDF(tempC, 100));
        
        // Print the temperature in °C:
        // Example printout: "Temp: 24.9 °C (23.5/24.5) (min/max)"
        Serial.print("Temp: ");
        Serial.print(tempC, 1); // Printing a float, we can set the precision (number of decimal points) with the second parameter 
        Serial.print(" ");
        // `write()` can be used to write a SINGLE BYTE value over the serial line:
        Serial.write(248); // 248 is the ASCII value for the ° symbol. We're fancy.
        Serial.print("C (");
        Serial.print(minimumTempC, 1);
        Serial.print('/'); // Print a '/'
        Serial.print(maximumTempC, 1);
        Serial.println(") (min/max)");
        
        // Print the temperature in °F:
        // Example printout: "Temp: 76.1 °F (74.3/76.1) (min/max)"
        Serial.print("Temp: "); // Print "Temp: "
        Serial.print(tempF, 1); // Print the tempF variable -- 1 decimal point
        Serial.print(' ');      // Print a space
        Serial.write(248);      // Print ASCII value 248 (the ° symbol)
        Serial.print("F (");    // Print "F ("
        Serial.print(minimumTempF, 1); // Print minimum temperature -- 1 decimal point
        Serial.print('/');      // Print a '/'
        Serial.print(maximumTempF, 1); // Print maximum temp -- 1 decimal point
        Serial.println(") (min/max)"); // Finsh the line by printing ") (min/max)"
        
        // Print the relative humidity:
        // Example printout: Humidity: 29.7 % (29.10/41.80) (min/max)
        Serial.print("Humidity: ");
        Serial.print(humidity, 1);
        Serial.print(" %");
        Serial.print(" (");
        Serial.print(minimumHumidity, 1);
        Serial.print("/");
        Serial.print(maximumHumidity, 1);
        Serial.println(") (min/max)");
        
        Serial.println(); // Print a blank line:
    }
    else // If the update failed, give the sensor time to reset:
    {
        Serial.println("Error reading from the RHT03."); // Print an error message
        Serial.println(); // Print a blank line
        
        delay(RHT_READ_INTERVAL_MS); // The RHT03 needs about 1s between read attempts
    }
    digitalWrite(LED_PIN, LOW); // Turn the LED off
    
    delay(PRINT_RATE); // delay for 1s, printing too much will make the output very hard to read.
}

Hi @bitasy,

You have to call Particle.variable() once per variable in setup() not in loop(). This registers the variable with the cloud and makes it accessible. It won’t work correctly until you fix that.

3 Likes

As a side note, you can use printlnf() to simplify your printing,

char degreeSymbol[2] = {0xC2, 0xB0}; // this works on Mac Terminal, I don't know if it works in Windows


Serial.printlnf("Temp: %.1f %sC (%.1f/%.1f) (min/max)", tempC, degreeSymbol, minimumTempC, maximumTempC);

prints, for example,

Temp: 76.1 °C (74.3/76.1) (min/max)

4 Likes

You cannot provide a function return value to Particle.variable() (like here Particle.variable("temperatureC", ROUNDF(tempC, 100));)
As @bko said, Particle.variable() registers a global variable used in your code with the cloud to be “read” from there.
So any change you make on the “exposed” variable will be accessible to the cloud without and extra call to Particle.variable(). But for that to happen it needs to be a global (permanently existing) variable and not a temporary return value of a function call.

BTW, if you want your readings to only have a limited number of decimal places, you need to use strings since floating point variables can’t represent all kinds of values without breaking the “decimal-places-limit”.
Even if you had temperatureC = ROUND(temperatureC, 100) you may see values with more than two decimal places in the cloud when using doubles.

3 Likes

Thanks everyone! Now everything is perfect!

1 Like