One good reading through phant then no more but lots of "nulls" on Particle Console [Solved]

This project is probably more than a newbie should tackle but I feel like I’m getting close. Using a Photon, I’m reading an RHT and a TMP sensor and posting the readings to data.sparkfun. All is good there. I then tried to add some language to compare the temp from the RHT to the temp from the TMP and publish to Spark.publish depending on the readings. That is where I’m hitting a wall.

The sketch compiles okay but when I flash I get one - and only one - good reading to to data.sparkfun, followed by a bunch of “null” outputs on my console. The event name next to each null reading is “pipetempbig”. The temp difference isn’t enough to trigger the pipetempbig to be published. I feel like I’m missing something fairly simple but after spending many hours playing around I can no longer focus on the screen due to my tears. Thanks in advance.

// This #include statement was automatically added by the Particle IDE.
#include "SparkFunPhant/SparkFunPhant.h"

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

/////////////////////
// Pin Definitions //
/////////////////////
const int RHT03_DATA_PIN = D3; // RHT03 data pin
const int PIPE_PIN = A0; // Photocell analog output
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

int pipef = 0;//I need this variable to run a temp comparison

boolean pipedelta = false;
///////////////////////////////////////////////
// Phant (data.sparkfun.com) Keys and Server //
///////////////////////////////////////////////
// These keys are given to you when you create a new stream:
const char server[] = "data.sparkfun.com"; // Phant destination server
const char publicKey[] = "publicblahblah"; // Phant public key
const char privateKey[] = "privateblahblah"; // Phant private key
Phant phant(server, publicKey, privateKey); // Create a Phant object

///////////////////////
// Post Rate Control //
///////////////////////
// data.sparkfun.com limits how often you can post to the service. You are allowed up
// to 100 posts every 15 minutes.
unsigned long lastPost = 0; // lastPost keeps track of the last UNIX time we posted
const unsigned int POST_RATE_S = 60; // This sets the post rate to 60 seconds. Avoid setting it below 10s.

//////////////////////////
// Station Name Globals //
//////////////////////////
String stationName = ""; // String object to keep track of our Photon's name

void setup() 
{
    Serial.begin(9600); // Start the serial interface at 9600 bps
    
    rht.begin(RHT03_DATA_PIN); // Initialize the RHT03 sensor
    
    pinMode(PIPE_PIN, INPUT); // Set the photocell pin as an INPUT.
    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.
    
    // getDeviceName() -- defined at the bottom of this code -- polls Particle's
    // server to get the name of the Photon running this application.
    getDeviceName(); // Update the stationName String
}

void loop() 

{
  
STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));//I'm using an external antenna on the Photon

analogRead(PIPE_PIN);//get a reading from the TMP
pipef = (((((((analogRead(PIPE_PIN) * (3.3/4095)) *1000) - 500)/10)*(9.0/5.0)) + 32), 1);//convert it to F

int update = rht.update();
if (update == 1)
{
float tempF = rht.tempF();

if (((tempF-pipef) > 4.0) && pipedelta == false){
    Spark.publish("pipetempbig");
    pipedelta == true;
}
if  (((tempF-pipef) < 2.0) && pipedelta == true){
    Spark.publish("pipetempnormal");
    pipedelta = false;
}
else
{
    delay(RHT_READ_INTERVAL_MS);
}
}

    // This conditional should only run when the last successful post to Phant
    // was POST_RATE_S (60 seconds) or longer ago.
    // Time.now() returns the current UNIX timestamp (number of seconds since January 1, 1970).
    // It should increase by 1 every second. On a successful POST, we set lastPost equal to Time.now().
    if (lastPost + POST_RATE_S <= Time.now())
    {
        digitalWrite(LED_PIN, HIGH); // Turn the LED on to indicate we're posting
        int update = rht.update(); // Get new values from the RHT03.
        
        if (update == 1) // If the RHT03 update was successful
        {
            int postResult = 0; // This variable will keep track of whether or not
            
            //while (postResult <= 0)
            // Phant posts aren't always successful. Our postToPhant() function,
            // defined below, will return 1 if it was successful. Or a negative
            // number if it failed.
            while (postToPhant() <= 0)
            {
                Serial.println("Phant post failed. Trying again."); // Debug statement
                // Delay 1s, so we don't flood the server. Little delay's allow the Photon time
                // to communicate with the Cloud.
                for (int i=0; i<1000; i++)
                    delay(1);
            }
            // After a successful Phant POST:
            Serial.println("Phant post success!"); // Debug print
            // Set lastPost to current time, so we don't post for another POST_RATE_S seconds:
            lastPost = Time.now(); 
        }
        else // If the RHT03 update failed:
        {
            delay(RHT_READ_INTERVAL_MS); // Delay to give the sensor time to reset
        }
        digitalWrite(LED_PIN, LOW); // Turn the LED off to indicate we're done posting (/trying to post)
    }
}

// postToPhant() gathers all of our sensor data, bundles it into a Phant post,
// and sends it out to data.sparkfun.com.
// It'll return either 1 on success, or a negative number if the post fails
int postToPhant(void)
{
    Serial.println("Posting to Phant!");// Debug statement
    
    // Use phant.add(, ) to add data to each field.
    // Phant requires you to update each and every field before posting,
    // make sure all fields defined in the stream are added here.
    phant.add("humidity", rht.humidity(), 1); // These first three phant adds set a field value to float variable
   // phant.add("tempc", rht.tempC(), 1); // The third parameter -- valid for float variables -- sets the number
    phant.add("tempf", rht.tempF(), 1); // of decimal points after the number.
    phant.add("pipef", ((((((analogRead(PIPE_PIN) * (3.3/4095)) *1000) - 500))/10)*(9.0/5.0) + 32), 1);
    
      //phant.add("pipeF", ((((analogRead(LIGHT_PIN) - 500)/10)*1.8)+32),1); 
    
    phant.add("station", stationName); // phant.add(, ) is perfectly valid too!
    
    // phant.particlePost() performs all of the Phant server connection and HTTP POSTING for you.
    // It'll either return a 1 on success or negative number on fail.
    // It uses the field/value combinations added previously to send Phant its data.
    // MAKE SURE YOU COMMIT A phant.add() FOR EVERY FIELD IN YOUR STREAM BEFORE POSTING!
    return phant.particlePost();
}

///////////////////////////////
// Get Device Name Functions //
///////////////////////////////
// These sets of functions poll Particle's server for the name of our Photon.
// This method is described in Particle's documentation here:
// https://docs.particle.io/reference/firmware/photon/#get-device-name
// Function handlers are used here -- when the Spark.subscribe function
// returns, it will call the nameHandler([topic], [data]) function with our 
// Photon's name.
bool validName = false; // Boolean to track if we have a valid name or not

// nameHandler() is a function handler. It's passed to Spark.subscribe() and
// called when that function returns.
// The [data] variable should have the name of our Photon when it's done.
void nameHandler(const char *topic, const char *data)
{
    stationName = String(data);  // Store the name in the stationName global variable
    validName = true; // Set validName to true, so getDeviceName can stop blocking.
}

// getDeviceName manages the spark subscribing and publishing required to get our
// Photon's name. It'll block for up to 30 seconds. On success it'll return a
// positive number. On fail, it'll return 0.
int getDeviceName(void)
{
    Spark.subscribe("spark/", nameHandler);
    Spark.publish("spark/device/name");
    
    int timeout = 30;
    while ((!validName) && (timeout > 0))
    {
        Serial.println("Waiting for name..." + String(timeout--));
        delay(1000); // Spark.process() is called during delay()
    }
    
    Serial.println("Station name = " + stationName);
    
    return timeout;
}
STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));//I'm using an external antenna on the Photon

This line should not be inside loop() but at the top of your .ino file.

You should only need this called once (e.g. in setup())

   Spark.subscribe("spark/", nameHandler);

(unless you are using Particle.unsubscribe() for some reason - BTW use Particle.xxx instead of Spark.xxx)

1 Like

Thanks for the look, ScruffR. I moved the antenna to the .ino file, moved Spark.subscribe to setup, and renamed everything Particle. Unfortunately I now get one or two nulls, no posts to data.sparkfun, and then the device kicks itself offline. Weird stuff.

IGNORE MY LAST POST. (I f’d up my sketch last night and had to copy the one posted here but forgot to change my keys. Sorry.)

I made all the changes and am receiving viable data to sparkfun but still getting repeated nulls with pipetempbig as the event name. Aaargh.

Is that the name of one of your devices?

Sorry, is what the name of one of my devices? pipetempbig? That is an event. I might be missing your question.

That one

When you publish an event with the name of spark/device/name the cloud publishes back an event containing the name of your device, hence the question.

But after having another look at your code I see what you meant :blush:

Gotcha. I think for now I’ll comment out that part of the code and stick with what I have. Thanks for the look!

I think I solved it. I’m not sure exactly what fixed the problem as I made several changes and corrections, trying different things along the way. One issue MAY have been I was using “boolean” (which I grabbed from a Simon Monk book) rather than “bool.” I think the bigger issue was I had “==” after my first pipedelta statement rather than a single “=” I also relocated my if statements and some other stuff. At any rate, I’ll be glad to post my final code if anyone is interested. Otherwise, I think this is SOLVED. Man, this coding stuff is tough!

2 Likes

Glad you were able to get it to work @Silverminer! Thanks for the help @ScruffR!

Thanks, KyleG. I’m very happy with the whole project and I think I have it dialed in. For about $50, I now have a device that monitors my incoming water line and furnace room and can warn me via my cell phone if I have a major water line break or the furnace quits working. No monthly fees! If my parents and my neighbor had this device a few winters back it would have saved them a whole lot of problems and money. I couldn’t be happier about the Photon; the possibilities are endless.

2 Likes

That’s great to here!