Need help finding example code for sending mesh data from xenon to argon

Sorry, I misunderstood the question.

As ScruffR advises, the first thing is to prepare a meaningful string to transport your message and data. To achieve this, a JSON message is the way to go. It gives you a structured ability to send multiple data fields in a single message. In essense it is nothing more than a text string, but its brilliance is in its structure.

So the JSON message to send your two data points would look like this:

{“humidity”:“75.5”,“temperature”:“24.0”}

The words “humidity” and “temperature” are the key, and the values represent your data.

Here is a simple program for the Xenon to prepare the message and send it via mesh to the Argon.

int boardLed = D7; // This is the LED that is already on your device.

float temperature = 23.6;
float humidity = 75.1;

char msg [100];

void setup() {

  pinMode(boardLed,OUTPUT); // Our on-board LED is output as well
  
  Serial.begin();
  
}


// Now for the loop.

void loop() {
    
        temperature += 0.1;
        humidity += 0.1;

        snprintf(msg, sizeof(msg), "{\"humidity\":\"%.1f\",\"temperature\":\"%.1f\"}", humidity, temperature);        
        
        Serial.println (msg);
        
        Mesh.publish ("beam", msg);
        Mesh.publish ("beam", "broken");
        digitalWrite(boardLed,HIGH);
        delay(500);
        digitalWrite(boardLed,LOW);
        Mesh.publish ("beam", "fixed");
        
        delay (5000);
}

The Argon program shown in an earlier post above will now println the message on a terminal. This JSON can now be deserialised and converted to new variables in your Argon program.

Let me know if you would like an example of this.

2 Likes

If you have the Grove Kit try this:

SYSTEM_MODE(MANUAL); // Will controll manually for mesh connections

#include <Seeed_DHT11.h>

#define DHTPIN D2
#define SENDLED D7

DHT dht(DHTPIN);

unsigned long previousTime;
int LEDSTATE = LOW;

const long interval = 60 * 1000 * 30; // Delay Amount: 30 Minutes
const char* device = "XPX-Xenon-01";

void setup() {
    pinMode(SENDLED, OUTPUT);
    dht.begin();
}

void loop() {
    
    unsigned long currentTime = millis();
    
    if ( currentTime - previousTime >= interval)
    {
        previousTime = currentTime;
        
        Mesh.on();
        Mesh.connect();
        
        while ( Mesh.connecting() )
        {
            // pause for connection
        }
        
        if ( Mesh.ready() )
        {
            char data[128];
            sprintf(data, "{\"Temperature\":\%.2f\, \"Humidity\":\%.2f\, \"Battery Voltage\":\%.2f\, \"Device\":\"%s\"}", checkTemp(), checkHumidity(), checkBattery(), device);
            Mesh.publish("Environment Read", data);
            digitalWrite(SENDLED, HIGH);
            delay(2000);
            digitalWrite(SENDLED, LOW);
            Mesh.off();
        }

    }
    
}

float checkHumidity()
{
    return dht.getHumidity();
}

float checkTemp()
{
    return dht.getTempFarenheit();
}

float checkBattery()
{
    return analogRead(BATT) * 0.0011224;
}

Thanks, @Grenello and @callen. I spent quite a bit of time last night trying to understand how JSONs work but I'm still not there yet. Your examples will help. I'll give them a try soon.

Just to make this post complete so others like me (hobbyist) might benefit, what I'm trying to do is take my code that works great on a standalone Argon and essentially split it into two (2) codes, one for a Xenon (data collection) and one for an Argon (which will take the data and output the data to the Particle Console and to a 4-digit display.) The temp/humidity sensor and 4-digit display were included in the Grove Starter Kit for Particle Mesh. My standalone code is:

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

#include "TM1637.h"

#define CLK D2//pins definitions for TM1637
#define DIO D3

TM1637 tm1637(CLK,DIO);

#define DHTPIN D4//set pin for DHT

DHT dht(DHTPIN);

int tempF = 0;
int humidity = 0;

int lasttempF = 0;//I'll use these to get rid of spikes in the data
int tempFdelta;
int lasthumidity = 0;
int humiditydelta;

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

//Global variables to store messages.
char *message = "Room Environment";
char msg[128];

void setup()

{
  tm1637.init();
  tm1637.set(BRIGHT_TYPICAL);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
  tm1637.point(POINT_ON);
  
  dht.begin(); //initialize the sensor
  // variable name max length is 12 characters long
  Particle.variable("tempF", tempF);
  Particle.variable("humidity", humidity);
  
  delay(1500);

}
void loop()
{
        //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
    {
        humidity = dht.getHumidity();
        tempF = dht.getTempFarenheit();
        tempFdelta = tempF-lasttempF;
        tempFdelta = abs(tempFdelta);
        humiditydelta = humidity-lasthumidity;
        humiditydelta = abs(humiditydelta);
        
            if(tempFdelta <2 && humiditydelta <2)
            {
                    //Create your message to publish and load into the message buffer.
                    snprintf(msg,arraySize(msg)-1,"T = %d;H = %d",tempF,humidity);
            
                    //Send your data.
                    Particle.publish("Room Environment",msg);
                
                    int digit1 = tempF/10;
                    int digit2 = tempF % 10;
                    int digit3 = humidity/10;
                    int digit4 = humidity % 10;
                    tm1637.display(0,digit1);
                    tm1637.display(1,digit2);
                    tm1637.display(2,digit3);
                    tm1637.display(3,digit4);
            }

        //Update your pub millis timer.
        lastPubMillis = millis();
                            
        lasttempF = tempF;
        lasthumidity = humidity;
    }
}

Here’s where I’m at right now. While both codes compile, I only get a single temp/humidity reading of 0/0 so obviously I’m doing something wrong, probably something basic. I’ll have to look at it more tomorrow.

Xenon code:

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

#include "Particle.h"

#define DHTPIN D4//set pin for DHT

DHT dht(DHTPIN);

int tempF = 0;
int humidity = 0;

int lasttempF = 0;//I'll use these to get rid of spikes in the data
int tempFdelta;
int lasthumidity = 0;
int humiditydelta;

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

//Global variables to store messages.
char *message = "Xenon1";
char msg[128];

void setup()

{
    Particle.variable("tempF", tempF);
    Particle.variable("humidity", humidity);
    
    dht.begin(); //initialize the sensor
}
void loop()
{
        //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
    {
        humidity = dht.getHumidity();
        tempF = dht.getTempFarenheit();
        tempFdelta = tempF-lasttempF;
        tempFdelta = abs(tempFdelta);
        humiditydelta = humidity-lasthumidity;
        humiditydelta = abs(humiditydelta);
        
            if(tempFdelta <2 && humiditydelta <2)
            {
                    //Create your message to publish and load into the message buffer.
                    char data[128];
                    sprintf(data, "{\"Temperature\":\%d\, \"Humidity\":\%d\}", tempF, humidity);
                    
                    //Send your data.
                    Particle.publish("Xenon1",msg);
             }

        //Update your pub millis timer.
        lastPubMillis = millis();
                            
        lasttempF = tempF;
        lasthumidity = humidity;
    }
}

Argon Code:


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

#define CLK D2//pins definitions for TM1637
#define DIO D3

TM1637 tm1637(CLK,DIO);

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

int tempF;
int humidity;

//Global variables to store messages.
char *message = "Room Environment";
char msg[128];

void myHandler(const char *event, const char *data){
}

void setup()

{
  tm1637.init();
  tm1637.set(BRIGHT_TYPICAL);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
  tm1637.point(POINT_ON);

  delay(1500);
  
  Mesh.subscribe("Xenon1",myHandler);
}
void loop()
{
        //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
            {
                     //Create your message to publish and load into the message buffer.
                    snprintf(msg,arraySize(msg)-1,"T = %d;H = %d",tempF,humidity);
            
                    //Send your data.
                    Particle.publish("Room Environment",msg);
                
                    int digit1 = tempF/10;
                    int digit2 = tempF % 10;
                    int digit3 = humidity/10;
                    int digit4 = humidity % 10;
                    tm1637.display(0,digit1);
                    tm1637.display(1,digit2);
                    tm1637.display(2,digit3);
                    tm1637.display(3,digit4);
            }

        //Update your pub millis timer.
        lastPubMillis = millis();
}

Can you provide some more background of your intended setup.
Currently I guess your Argon is directly talking with the sensors and the display and you want to separate this into Xenon talking with the sensors, sending the collected data to the Argon and the Argon will receive that and for one display that on the 4-digit display and publish to the cloud, right?

If so, the first thing to change in your Argon code is this

An empty subscribe handler won't do any parsing of the received data, but without that received data you haven't got anything to display or publish.

To start with, you can just print out the received event data

void myHandler(const char *event, const char *data){
  Serial.println(data);
}

to see whether your device actually gets any data from the Xenon.

Once you have established that, I'd (again) recommend to look at the JsonParserGeneratorRK library - especially this example which illustrates how to subscribe to an event and then parse the received JSON string.

Correct!

I've looked at it (again and again and again.) I'm just not understanding it by way of the example. At this point my plan is to search around for some other examples in order to try and grasp the concept. Once I get a better understanding, I'll work it into my code and see what happens. If I get stuck again, I'll come back and ask for some more guidance.

Ultimately, I hope to have some working code to come back and post. From what I can see, there's not a lot to work from yet.

I'm sure there will be plenty of examples to work from before long. It seems to me that in order to use the Grove Starter Kit (or any sensors for that matter) the most basic task needed to work when using mesh is how to collect variables using one device and then send them to another device.

Thanks again, @ScruffR.

I agree, the examples in that library are showing a lot of stuff in one go.
But the main points for your needs shouldn’t be any more complicated than this

void myHandler(const char *event, const char *data){
  Serial.println(data);
  jsonParser.clear();
  jsonParser.addString(data);
  if (jsonParser.parse()) {
    if (!jsonParser.getOuterValueByKey("Temperature", tempF)) {
      Serial.println("failed to get Temperature");
    }
    if (!jsonParser.getOuterValueByKey("Humidity", humidity)) {
      Serial.println("failed to get Humidity");
    }
  }
}

I really appreciate all your help on this, @ScruffR. I don't know if you have a day job but you sure spend a lot of time helping people on this forum!

I've tried to make this work but now I'm resorting to cutting and pasting crap hoping something will start working, with no understanding of what I'm doing. I'm in over my head. Rather than waste people's time I'm going to wait on the sidelines until someone posts a similar project or tutorial. In the meantime I'll play around with all this some more and see if I start to grasp what's going on.

Thanks again!

Yes, I do have a day job too.

Does my suggested code work? I've just written it off the top of my head without acctually trying it out :blush:

But if it does, it's not that complicated (as long you don't want to care how the JSON parser works internally).

I'll add some comments to the code

// this will be called whenever an event arrives we subscribed to
void myHandler(const char *event, const char *data){
  Serial.println(data);       // print out the data as it comes in for debugging

  jsonParser.clear();         // make sure the parser buffer is fresh and empty
  jsonParser.addString(data); // copy the received data into the parser buffer for it to work with
  if (jsonParser.parse()) {   // let the parser do its job and split up the data internally
    // first ask the parser for the value connected with the key 'Temperature' 
    // if this is successful pop that value into the provided variable tempF
    // if not, the function will return false which - in turn - triggers the error output
    if (jsonParser.getOuterValueByKey("Temperature", tempF) == false) {
      Serial.println("failed to get Temperature");
    }
    // do the same for 'Humidity'
    // if(!someBoolean) is short hand for if(someBoolean == false) 
    if (!jsonParser.getOuterValueByKey("Humidity", humidity)) {
      Serial.println("failed to get Humidity");
    }
  }
}

Does this make things clearer?

2 Likes

Yes, it does! But I'm still not understanding some of the basics for getting the data from the Xenon to the Argon.

After trying so many things, my code got a bit messy. I went back to each device, cleaned the code up, and then added code to print and make sure the Xenon was still collecting and outputting the correct data. It is.

Things are not so great on the Argon side. On the Particle Console I get "null" for Room Environment. If I comment out the print associated with the json parser and let it try to print to the monitor, I get nothing except carriage returns every 5 seconds. If I uncomment the json print and comment out the serial monitor print I only get the "failed to get..." comments. So it appears I'm not getting the data from the Xenon to the Argon.

At the risk of continued public embarrassment :roll_eyes:, my current code on the Xenon:

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

#include <Seeed_DHT11.h>

#define DHTPIN D4//set pin for DHT

DHT dht(DHTPIN);

int tempF = 0;
int humidity = 0;

int lasttempF = 0;//I'll use these to get rid of spikes in the data
int tempFdelta;
int lasthumidity = 0;
int humiditydelta;

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

//Global variables to store messages.
char *message = "Xenon1";
char msg[128];

// This creates a buffer to hold up to 256 bytes of JSON data (good for Particle.publish)
JsonWriterStatic<256> jw;

void setup()

{
    Particle.variable("tempF", tempF);
    Particle.variable("humidity", humidity);
    
    dht.begin(); //initialize the sensor
    
    Serial.begin(9600);
}
void loop()
{
    //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
    {
        humidity = dht.getHumidity();
        tempF = dht.getTempFarenheit();
        tempFdelta = tempF-lasttempF;
        tempFdelta = abs(tempFdelta);
        humiditydelta = humidity-lasthumidity;
        humiditydelta = abs(humiditydelta);

            if(tempFdelta <2 && humiditydelta <2)
            {

                //print to make sure data is actually there
                Serial.print("tempF:  ");
                Serial.println(tempF);
                Serial.print("humidity:  ");
                Serial.println(humidity);
                Serial.println();
                
                {
                JsonWriterAutoObject obj(&jw);

		        // Add various types of data
	        	jw.insertKeyValue("tempF", tempF);
		        jw.insertKeyValue("humidity", humidity);
                }

	        	//Send the data.
                Mesh.publish("Xenon1",msg);
                
             }

        //Update the pub millis timer.
        lastPubMillis = millis();
                            
        lasttempF = tempF;
        lasthumidity = humidity;
    }
}

My current code on the Argon:

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

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

#define CLK D2//pins definitions for TM1637
#define DIO D3

TM1637 tm1637(CLK,DIO);

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

int tempF;
int humidity;

//Global variables to store messages.
char *message = "Room Environment";
char msg[128];

void printJson(JsonParser &jp);

// Create a parser to handle 2K of data and 100 tokens
JsonParserStatic<2048, 100> jsonParser;

// this will be called whenever an event arrives we subscribed to
void myHandler(const char *event, const char *data){
  Serial.println(data);       // print out the data as it comes in for debugging

  jsonParser.clear();         // make sure the parser buffer is fresh and empty
  jsonParser.addString(data); // copy the received data into the parser buffer for it to work with
  if (jsonParser.parse()) {   // let the parser do its job and split up the data internally
    // first ask the parser for the value connected with the key 'Temperature' 
    // if this is successful pop that value into the provided variable tempF
    // if not, the function will return false which - in turn - triggers the error output
    if (jsonParser.getOuterValueByKey("tempF", tempF) == false) {
      Serial.println("failed to get Temperature");
    }
    // do the same for 'Humidity'
    // if(!someBoolean) is short hand for if(someBoolean == false) 
    if (!jsonParser.getOuterValueByKey("humidity", humidity)) {
      Serial.println("failed to get Humidity");
    }
  }
}

void setup()

{
  tm1637.init();
  tm1637.set(BRIGHT_TYPICAL);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
  tm1637.point(POINT_ON);
  
  Serial.begin(9600);

  delay(1500);
  
  Mesh.subscribe("Xenon1",myHandler);
}
void loop()
{
        //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
            {
                /*Serial.print("tempF:  ");
                Serial.println(tempF);
                Serial.print("humidity:  ");
                Serial.println(humidity);
                Serial.println();*/
            
                //Send your data.
                Particle.publish("Room Environment",msg);
                
                int digit1 = tempF/10;
                int digit2 = tempF % 10;
                int digit3 = humidity/10;
                int digit4 = humidity % 10;
                tm1637.display(0,digit1);
                tm1637.display(1,digit2);
                tm1637.display(2,digit3);
                tm1637.display(3,digit4);
            }

        //Update your pub millis timer.
        lastPubMillis = millis();
}

In your Xenon code you are not actually populating msg, so no surprise that you don't get any data on the Argon side :wink:

You only feed the data into your jw object, but never take the data from that object to insert it into msg. How should that magically get from one place to the other?

That sends the data that is in msg which is nowhere changed in your code, so it is still at its initial state of being an empty string.

Because it's magic and magicians never reveal their secrets? Or it could be because I needed to add this line to my Xenon:

 snprintf(msg, sizeof(msg), "{\"tempF\":\"%.d\",\"humidity\":\"%.d\"}",tempF,humidity);

Which (to me) is magical because I can now see the data on the monitor for both the Xenon and Argon!

{"tempF":"71","humidity":"22"}

So I'm getting closer! And now I know I've sent the data from the Xenon to the Argon. Yay! Unfortunately, I'm still getting "null" on the console and my 4-digit display only displays 00:00.

1 Like

The answer is the same: You don't set msg.

But the solution is slightly different

// this will be called whenever an event arrives we subscribed to
void myHandler(const char *event, const char *data){
  Serial.println(data);              // print out the data as it comes in for debugging
  strncpy(msg, data, sizeof(msg)-1); // copy the incoming data to the global variable msg (with boundary limit)
  ...
}

For that you should check whether your variables tempF and humidity actually get set in the subscription handler.

BTW, since you are creating the JSON string on the Xenon via snprintf() you won't need the jw JSON generator.
Or if you want to keep using it, don't us snprintf() but rather

  strncpy(msg, jw.getBuffer(), sizeof(msg)-1);  // copy the created JSON string to global variable msg
1 Like

Okay, I cleaned that up on the Xenon. I got rid of the JSON generator and the Xenon still works correctly.

#include <Seeed_DHT11.h>

#define DHTPIN D4//set pin for DHT

DHT dht(DHTPIN);

int tempF = 0;
int humidity = 0;

int lasttempF = 0;//I'll use these to get rid of spikes in the data
int tempFdelta;
int lasthumidity = 0;
int humiditydelta;

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

//Global variables to store messages.
char *message = "Xenon1";
char msg[128];

void setup()

{
    Particle.variable("tempF", tempF);
    Particle.variable("humidity", humidity);
    
    dht.begin(); //initialize the sensor
    
    Serial.begin(9600);
}
void loop()
{
    //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
    {
        humidity = dht.getHumidity();
        tempF = dht.getTempFarenheit();
        tempFdelta = tempF-lasttempF;
        tempFdelta = abs(tempFdelta);
        humiditydelta = humidity-lasthumidity;
        humiditydelta = abs(humiditydelta);

            if(tempFdelta <2 && humiditydelta <2)
            {

                snprintf(msg, sizeof(msg), "{\"tempF\":\"%.d\",\"humidity\":\"%.d\"}",tempF,humidity);
                Serial.println(msg);

	        	//Send the data.
                Mesh.publish("Xenon1",msg);
                
             }

        //Update the pub millis timer.
        lastPubMillis = millis();
                            
        lasttempF = tempF;
        lasthumidity = humidity;
    }
}

I'm sorry, @ScruffR, but I'm not following. I added the line (I'm including the entire myHandler to show where I put it):

 // this will be called whenever an event arrives we subscribed to
void myHandler(const char *event, const char *data){
  Serial.println(data);       // print out the data as it comes in for debugging
  strncpy(msg, data, sizeof(msg)-1); // copy the incoming data to the global variable msg (with boundary limit)

  jsonParser.clear();         // make sure the parser buffer is fresh and empty
  jsonParser.addString(data); // copy the received data into the parser buffer for it to work with
  if (jsonParser.parse()) {   // let the parser do its job and split up the data internally
    // first ask the parser for the value connected with the key 'tempF' 
    // if this is successful pop that value into the provided variable tempF
    // if not, the function will return false which - in turn - triggers the error output
    if (jsonParser.getOuterValueByKey("tempF", tempF) == false) {
      Serial.println("failed to get Temperature");
    }
    // do the same for 'humidity'
    // if(!someBoolean) is short hand for if(someBoolean == false) 
    if (!jsonParser.getOuterValueByKey("humidity", humidity)) {
      Serial.println("failed to get Humidity");
    }
  }
}

But my results are still the same. i guess I just assumed that since the data was printing correctly in the console then that meant that it was actually set in the subscription handler. I don't know how to check that.

Can you post the serial output of your Argon?
And also repost your Argon code?

You can also add this line before your Particle.publish() line (and reqirte that as shown too)

                //Send your data.
                Serial.printlnf("RoomEnv: '%s'", msg);
                Particle.publish("Room Environment", msg, PRIVATE);

And I think I found your issue

You only ever enter the if() block (which would do the updating) once on startup, since you keep "resetting" the delay timer every iteration of loop().
That lastPubMillis line needs to be inside that if() block.

For debugging you should have Serial.print() statements in each block you want to check whether they are actually doing anything and if they are also doing what you expect.

2 Likes

WAHOOOOOOOOO! Everything works! I must have moved the delay outside the loop when I was doing all the cutting and pasting.

My current (final?) Argon code:

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

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

#define CLK D2//pins definitions for TM1637
#define DIO D3

TM1637 tm1637(CLK,DIO);

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

int tempF;
int humidity;

//Global variables to store messages.
char *message = "Room Environment";
char msg[128];

void printJson(JsonParser &jp);

// Create a parser to handle 2K of data and 100 tokens
JsonParserStatic<2048, 100> jsonParser;

// this will be called whenever an event arrives we subscribed to
void myHandler(const char *event, const char *data){
  Serial.println(data);       // print out the data as it comes in for debugging
  strncpy(msg, data, sizeof(msg)-1); // copy the incoming data to the global variable msg (with boundary limit)

  jsonParser.clear();         // make sure the parser buffer is fresh and empty
  jsonParser.addString(data); // copy the received data into the parser buffer for it to work with
  if (jsonParser.parse()) {   // let the parser do its job and split up the data internally
    // first ask the parser for the value connected with the key 'tempF' 
    // if this is successful pop that value into the provided variable tempF
    // if not, the function will return false which - in turn - triggers the error output
    if (jsonParser.getOuterValueByKey("tempF", tempF) == false) {
      Serial.println("failed to get Temperature");
    }
    // do the same for 'humidity'
    // if(!someBoolean) is short hand for if(someBoolean == false) 
    if (!jsonParser.getOuterValueByKey("humidity", humidity)) {
      Serial.println("failed to get Humidity");
    }
  }
}

void setup()
{
  tm1637.init();
  tm1637.set(BRIGHT_TYPICAL);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
  tm1637.point(POINT_ON);
  
  Serial.begin(9600);

  delay(1500);
  
  Mesh.subscribe("Xenon1",myHandler);
}

void loop()
{
        //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
            {
                //Send your data.
                Serial.printlnf("RoomEnv: '%s'", msg);
                Particle.publish("Room Environment", msg, PRIVATE);
                
                int digit1 = tempF/10;
                int digit2 = tempF % 10;
                int digit3 = humidity/10;
                int digit4 = humidity % 10;
                tm1637.display(0,digit1);
                tm1637.display(1,digit2);
                tm1637.display(2,digit3);
                tm1637.display(3,digit4);
                
                //Update your pub millis timer.
                lastPubMillis = millis();
            }
}

My current (final) Xenon code:

#include <Seeed_DHT11.h>

#define DHTPIN D4//set pin for DHT

DHT dht(DHTPIN);

int tempF = 0;
int humidity = 0;

int lasttempF = 0;//I'll use these to get rid of spikes in the data
int tempFdelta;
int lasthumidity = 0;
int humiditydelta;

unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;

//Global variables to store messages.
char *message = "Xenon1";
char msg[128];

void setup()

{
    Particle.variable("tempF", tempF);
    Particle.variable("humidity", humidity);
    
    dht.begin(); //initialize the sensor
    
    Serial.begin(9600);
}
void loop()
{
    //Use a millis timer for non-blocking code design.
    if (millis() - lastPubMillis > pubInterval) 
    {
        humidity = dht.getHumidity();
        tempF = dht.getTempFarenheit();
        tempFdelta = tempF-lasttempF;
        tempFdelta = abs(tempFdelta);
        humiditydelta = humidity-lasthumidity;
        humiditydelta = abs(humiditydelta);

            if(tempFdelta <2 && humiditydelta <2)
            {

                snprintf(msg, sizeof(msg), "{\"tempF\":\"%.d\",\"humidity\":\"%.d\"}",tempF,humidity);
                Serial.println(msg);

	        	//Send the data.
                Mesh.publish("Xenon1",msg);
                
             }

        //Update the pub millis timer.
        lastPubMillis = millis();
                            
        lasttempF = tempF;
        lasthumidity = humidity;
    }
}

My serial output. I switched partway from the serial port for the Xenon to the serial port for the Argon:

{"tempF":"75","humidity":"17"}
{"tempF":"75","humidity":"17"}
{"tempF":"75","humidity":"18"}
{"tempF":"75","humidity":"18"}
RoomEnv: '{"tempF":"75","humidity":"18"}'
{"tempF":"75","humidity":"18"}
RoomEnv: '{"tempF":"75","humidity":"18"}'
{"tempF":"75","humidity":"18"}
RoomEnv: '{"tempF":"75","humidity":"18"}'
{"tempF":"75","humidity":"18"}

Both the console output and the 4-digit display are now working properly.

@ScruffR - First a big thanks for all your time! Second, it seems to me maybe I should post the final code in a separate, fresh post. While I don't want to cross-post, it just seems that putting this code in a standalone post would be nice for people that are just starting to play with their mesh networks and the Grove Starter Kits or similar. If you agree, it might makes sense to have you do one more runthrough on my code so I don't post a "dirty" code.

Regardless, thanks again.

3 Likes

I’d have some minor changes, like replacing #define PIN_X Dx with const int PIN_X = Dx; to reduce defines which may interfere with other (hidden) defines without throwing an error.
Remove superfluous comments like // This #include statement was automatically added by the Particle IDE.
And maybe clean up your indentations.

BTW, you may want to rename lastPubMillis in your Xenon code to lastSensorRead since you aren’t really timing for the publish - which only happens when your readings have changed enough - but limiting the frequency with what you read your sensors.
If you were timing for the publish, the line lastPubMillis = millis(); should live in the same block as the actual publish command.

4 Likes

Sorry to bother you again, @ScruffR, but I came to realize that if I disconnect the Xenon the Argon continues to publish the last T/H data to the Console. Same for the serial monitor. Any suggestions on where I might have gone wrong? Thanks!

You can keep track of the last update and only publish when that timestamp changes or you just set a global flag (e.g. needPublish = true;) in the event handler, change your condition to (needPublish && millis() - lastPubMillis > pubInterval) and once you have published the data reset that flag to false.

1 Like

It took me a bit to figure out where & how to do it but I figured it out and also modified my example code in the example on the forum:

[Example Code: Xenon collects temp/humidity data & sends to Argon which then outputs to 4-digit display and Particle Console]

I also made it so my display would show all 0s if the Xenon quit sending data.

Thanks again, @ScruffR