I’m trying to adapt a simple code I’ve used successfully for the past two (2) years on the Electron to my Argon. In the case of my Electron, the data posts to Ubidots. I’ve successfully used Particle.publish with this same Argon when I had a simple temperature sensor connected but now I’m trying to switch it to an RHT03 temp/humidity sensor. With the following code I’m getting humidity readings of 0 and temperature readings of 32 (just now when I checked it’s reporting 66 for temp and 825 for humidity!) I’ve double checked to make sure I have the wiring connected properly (there are only 3 wires.)
Since I’m a hobbyist without much coding experience it wouldn’t surprise me if my problem is with my program. But I’m also wondering if it could be that the library for the RHT03 is not compatible with the Argon.
Any suggestions?
// This #include statement was automatically added by the Particle IDE.
#include <SparkFunRHT03.h>
const int RHT03_DATA_PIN = D3;//RHT data pin
RHT03 rht;//creates the RHT03 object
int tempF = 0;
int humidity = 0;
char *message = "Room Environment";
String aString;
void setup()
{
rht.begin(RHT03_DATA_PIN);//initialize the RHT03 sensor
// variable name max length is 12 characters long
Particle.variable("tempF", tempF);
Particle.variable("humidity", humidity);
}
void loop()
{
int update = rht.update();//read the sensor
int tempF = rht.tempF();
int humidity = rht.humidity();
Particle.publish("tempF", String(tempF));
Particle.publish("humidity", String(humidity));
delay(5000);
}
I would re-think your variable declarations to start. First, you declare int tempF=0; and int humidity = 0; as global variables and set them as the source for the Particle.variable()'s in the Setup. But everytime you run through loop, you re-declare the same variables with a local scope. Then you publish the variables but which variable is published; the locally scoped or globally scoped variable?
Also, I would remove the use of String and combine your separate Particle.publish() into a single combined publish. You can change the event name in the below sample as you see fit.
Maybe something like this:
// This #include statement was automatically added by the Particle IDE.
#include <SparkFunRHT03.h>
const int RHT03_DATA_PIN = D3;//RHT data pin
RHT03 rht;//creates the RHT03 object
//Global variables to store environmental data.
float tempF = 0;
float humidity = 0;
//Global variable to store millis timer information.
unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;
//Global variables to store messages.
char *message = "Room Environment";
char msg[128];
void setup()
{
rht.begin(RHT03_DATA_PIN); //initialize the RHT03 sensor
// variable name max length is 12 characters long
Particle.variable("tempF", tempF);
Particle.variable("humidity", humidity);
}
void loop()
{
//Use a millis timer for non-blocking code design.
if (millis() - lastPubMillis > pubInterval) {
int update = rht.update(); //read the sensor
//Update your global environmental variables.
tempF = rht.tempF();
humidity = rht.humidity();
//Create your message to publish and load into the message buffer.
snprintf(msg,arraySize(msg)-1,"Temp:%4.2f;Humidity:%4.2f",tempF,humidity);
//Send your data.
Particle.publish("EnviromentData",msg);
//Update your pub millis timer.
lastPubMillis = millis();
}
}
@ninjatill, thanks for your help. I’m tied up at the present with a rambunctious 4-year old grandson but I stole a minute to load your code as-is (with the added library). I’ll make time tonight to learn from your suggestions. With the new program my initial readings were t = 32 and h = 0 followed after a few minutes with t = 71 (sounds right) and h = 112. But then it becomes t = 795 and h = 1238 and now t = 234 and h = 3699. I’ll dive into this more tonight.
I also just remembered I have a temp/humidity sensor from the Grove Starter Kit. That box has been sitting under my desk so long I forgot what was in it!
If you look at the RHT library, the tempF and humidity functions return a float, not an integer. So you would need to declare your variables as floats instead.
Yes, that issue is confusing to me. Somewhere along the line I cobbled together some code, using integers, for the same sensor in my campervan that is hooked to an Electron and it’s been working great for 2 years.
#include <Ubidots.h>
#define TOKEN ""
#include <SparkFunRHT03.h>//included from the library for the RHT
Ubidots ubidots(TOKEN);
const int RHT03_DATA_PIN = D1;//provdes temp & humidity inside van
RHT03 rht;//creates the RHT object
const int pinOut = A2;//provdes temp under van, near macerator (critical component)
const int pinFridge = A4;//you can guess this one
int tempF = 0;//temp inside van
int humidity = 0;//humidity inside van
int tempOut = 0;//outside temp reading
int tempFridge = 0;//yeah, that one
int SoC = 0;//fuel gauge
FuelGauge fuel;
int lasttempF = 0;//I'll use these to see if we really need to upload data each time
int lasthumidity = 0;
int lasttempOut = 0;
int lasttempFridge = 0;
int lastSoC = 0;
int tempFdelta;
int humiditydelta;
int tempOutdelta;
int tempFridgedelta;
int SoCdelta;
void setup() {
//pinMode(A2, OUTPUT);//RHT - I only want sensors energized when Electron is awake to save power
//pinMode(A3, OUTPUT);//TEMP OUT
//pinMode(A4, OUTPUT);//TEMP FRIDGE
rht.begin(RHT03_DATA_PIN);//initialize the RHT sensor
ubidots.setMethod(TYPE_UDP);
//Serial.begin(9600);//definitely worth checking if this works at my desk before going live
//while(!Serial.available()) Particle.process(); // start the serial monitor, then press any key
}
void loop() {
//digitalWrite(A2, HIGH);//power up the sensors
//digitalWrite(A3, HIGH);
//digitalWrite(A4, HIGH);
//delay(15000);//necessary delay for RHT to pass unstable status (1 sec), plus warm up (+14 sec)
int update = rht.update();//get temp and humidity readings from inside the van
int humidity = rht.humidity();
int tempF = rht.tempF();
tempF = (tempF-4);//calibration adjustment
tempOut = ((((((analogRead(pinOut) * (3.3/4095)) *1000.0) - 500)/10)*(9.0/5.0)) + 32.0);//calibrated
tempFridge = ((((((analogRead(pinFridge) * (3.3/4095)) *1000.0) - 500)/10)*(9.0/5.0)) + (32.0-6.0));
SoC = fuel.getSoC();
//Create logic so only significant readings get uploaded to cloud
tempFdelta = tempF-lasttempF;
tempFdelta = abs (tempFdelta);
if(tempFdelta>2){
//Serial.printlnf("vanTemp %d\n", tempF);
//Serial.printlnf("lasttempF %d\n", lasttempF);
//Serial.printlnf("tempFdelta %d\n", tempFdelta);
ubidots.add("t", tempF);
lasttempF = tempF;
}
humiditydelta = humidity-lasthumidity;
humiditydelta = abs (humiditydelta);
if(humiditydelta>2){
//Serial.printlnf("humidity %d\n", humidity);
ubidots.add("h", humidity);
lasthumidity = humidity;
}
tempOutdelta = tempOut-lasttempOut;
tempOutdelta = abs (tempOutdelta);
if(tempOutdelta>2){
//Serial.printlnf("tempOut %d\n", tempOut);
ubidots.add("o", tempOut);
lasttempOut = tempOut;
}
tempFridgedelta = tempFridge-lasttempFridge;
tempFridgedelta = abs (tempFridgedelta);
if(tempFridgedelta>2){
//Serial.printlnf("fridge %d\n", tempFridge);
ubidots.add("f", tempFridge);
lasttempFridge = tempFridge;
}
SoCdelta = SoC-lastSoC;
SoCdelta = abs (SoCdelta);
if(SoCdelta>2){
//Serial.printlnf("SoC %d\n", SoC);
ubidots.add("b", SoC);
lastSoC = SoC;
}
ubidots.sendAll();
//digitalWrite(3, LOW);//power down the sensors
//digitalWrite(4, LOW);
//digitalWrite(5, LOW);
//System.sleep(BTN,FALLING,SLEEP_NETWORK_STANDBY,30);
delay(1200000);//20 minute delay
}
That code also suffers from the same problematic variable re-declarations, data type and scoping problems. I’m not the C++ master so one of the elites might explain why this code would work in some situation and not in others. Looking at it, I don’t know how it was ever working properly. Perhaps since the data is sent to Ubidots, the Ubidots service can somehow interpret the floats even when sent as an integer.
You do not have to change the library, simply change the text at the top of the .ino file. For some reason, when you look at the Grove_temperature..._Sensor library, the filenames are "Seeed_DHT11.cpp" and Seeed_DHT11.h". But when you add the library to your project, it adds a totally different include statement. Looks like someone may have copied and pasted and forgot to edit some file names. @rickkas7 may be able to correct, maybe?!?
Probably unrelated, but, you keep moving your variable declarations for tempF and humidity inside of loop(). When you do that, the Particle.variable() functions declared in setup() don't have a valid variable to use. Either comment out the Particle.variables() or create global variables instead. I already demo'ed how to do that above. This is the variable scope problem I described above.
Sorry about that, @ninjatill. I hurried the new program while being distracted on the side. I shouldn’t have posted until later, after I had time to digest what you were telling me and check everything. I didn’t mean to waste your time.
I actually left out a whole bunch of stuff. I changed the code per your recommendations, added in the stuff I left out, and it now compiles! But I’ll have to leave it tonight to hook up and test. As a side note, when compiling with floats it tells me I have to use double instead. So that is how my code now reads. I’ll report back tonight.
// This #include statement was automatically added by the Particle IDE.
#include <Seeed_DHT11.h>
#define DHTPIN D3 //set pin
DHT dht(DHTPIN);
double tempF = 0;
double humidity = 0;
unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;
//Global variables to store messages.
char *message = "Room Environment";
char msg[128];
void setup()
{
dht.begin(); //initialize the sensor
// variable name max length is 12 characters long
Particle.variable("tempF", tempF);
Particle.variable("humidity", humidity);
}
void loop()
{
//Use a millis timer for non-blocking code design.
if (millis() - lastPubMillis > pubInterval) {
humidity = dht.getHumidity();
tempF = dht.getTempFarenheit();
//Create your message to publish and load into the message buffer.
snprintf(msg,arraySize(msg)-1,"Temp:%d;Humidity:%d",tempF,humidity);
//Send your data.
Particle.publish("Room Environment",msg);
//Update your pub millis timer.
lastPubMillis = millis();
}
}
No worries, I figured you couldn’t get past the include error so you didn’t see all the other errors. After getting a blank project to compile with that library included, I added the rest of your code and there were a bunch of things missing. Keep on plugging!
With your help I got it working, @ninjatill. Very much appreciated. I did end up switching to integers instead of floats or doubles. I still get an occasional wild reading but I’ll smooth those out later. I’m just happy to have my first functional project using a component from the Grove Starter Kit! Now that I have a base to work from I can start playing with the other components in the kit and then see if I can get the Xenons to play nicely. This is a great learning experience and couldn’t happen without people such as yourself.
So here’s my revised, functioning code using an Argon plus the Shield and Temp/Humidity Sensor from the Grove Starter Kit for Particle Mesh:
// This #include statement was automatically added by the Particle IDE.
#include <Seeed_DHT11.h>
#define DHTPIN D4 //set pin
DHT dht(DHTPIN);
int tempF = 0;
int humidity = 0;
unsigned long lastPubMillis = 0;
unsigned long pubInterval = 5000;
//Global variables to store messages.
char *message = "Room Environment";
char msg[128];
void setup()
{
dht.begin(); //initialize the sensor
// variable name max length is 12 characters long
Particle.variable("tempF", tempF);
Particle.variable("humidity", humidity);
}
void loop()
{
//Use a millis timer for non-blocking code design.
if (millis() - lastPubMillis > pubInterval) {
humidity = dht.getHumidity();
tempF = dht.getTempFarenheit();
//Create your message to publish and load into the message buffer.
snprintf(msg,arraySize(msg)-1,"Temp = %d;Humidity = %d",tempF,humidity);
//Send your data.
Particle.publish("Room Environment",msg);
//Update your pub millis timer.
lastPubMillis = millis();
}
}
The DHT11 continues to work perfectly with my Argon. But because I need additional temperature/humidity sensors, and before I go buy more DHT11 sensors, I’m back to my original question: The RHT03 works fine with the Electron but does not seem to work with the Argon/Xenon (I always get 32 for T, 0 for H.) Is it possible it’s not working because the SparkFunRHT03 library has to be updated for the Argon/Xenon?
My current code for the RHT03:
// This #include statement was automatically added by the Particle IDE.
#include <SparkFunRHT03.h>
const int RHT03_DATA_PIN = D4;
RHT03 rht;
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 Environment";
char msg[128];
void setup()
{
rht.begin(RHT03_DATA_PIN);//initialize the RHT sensor
// variable name max length is 12 characters long
Particle.variable("tempF", tempF);
Particle.variable("humidity", humidity);
}
void loop()
{
//Use a millis timer for non-blocking code design.
if (millis() - lastPubMillis > pubInterval)
{
int update = rht.update();
int humidity = rht.humidity();
int tempF = rht.tempF();
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("Xenon1 Environment",msg);
}
//Update your pub millis timer.
lastPubMillis = millis();
lasttempF = tempF;
lasthumidity = humidity;
}
}
Do you get the incorrect values via the Particle.variable() or the Particle.publish()? Check both and let us know.
Also, adding debugging output to the serial monitor is very helpful. Try running this slightly modified code which includes serial debugging info. (I did not change any of the variable declarations/re-declarations or anything so we can see where the issue lies… your code vs library.) You should attach the serial monitor after reboot and watch the serial output. You have 10 seconds to get the monitor up to catch the setup output… otherwise you might miss it and will just catch the loop output:
// This #include statement was automatically added by the Particle IDE.
#include <SparkFunRHT03.h>
const int RHT03_DATA_PIN = D4;
RHT03 rht;
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 Environment";
char msg[128];
SerialLogHandler logHandler(LOG_LEVEL_TRACE);
void setup()
{
//Start serial for console debugging.
Serial.begin(9600);
// variable name max length is 12 characters long
// Declare Particle.variables as soon as possible.
Particle.variable("tempF", tempF);
Particle.variable("humidity", humidity);
//Wait 10 seconds for the serial console to connect.
waitFor(Serial.isConnected, 10000);
//Initialize and update the sensor.
rht.begin(RHT03_DATA_PIN);
rht.update();
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Setup Readings:Ts = %d;Hs = %d",tempF,humidity);
Log.trace(msg);
Log.info("Setup complete.");
}
void loop()
{
//Use a millis timer for non-blocking code design.
if (millis() - lastPubMillis > pubInterval)
{
int update = rht.update();
int humidity = rht.humidity();
int tempF = rht.tempF();
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Pre-Filter Readings:Tp = %d;Hp = %d",tempF,humidity);
Log.trace(msg);
tempFdelta = tempF-lasttempF;
tempFdelta = abs(tempFdelta);
humiditydelta = humidity-lasthumidity;
humiditydelta = abs(humiditydelta);
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Delta Calcs:Td = %d;Hd = %d",tempFdelta,humiditydelta);
Log.trace(msg);
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("Xenon1 Environment",msg);
//Add debugging output.
strcat("Published Data:",msg);
Log.trace(msg);
} else {
Log.error("Delta calcs out of spec... cannot publish.");
}
//Update your pub millis timer.
lastPubMillis = millis();
lasttempF = tempF;
lasthumidity = humidity;
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Last Readings Updated:Tl = %d;Hl = %d",lasttempF,lasthumidity);
Log.trace(msg);
}
}
I was away for awhile but when I returned I looked at the data and it varied from (T/H) 32/0, 65/6, 3014/33, 227/3284, etc… So it’s all over the place.
The particle.variables both show 0.
I ran your modified code and this is what I get from the serial monitor. This is above my paygrade so I have no idea what any of this means:
Above your paygrade... give yourself more credit. On the left-most of the log file, there is a millis timestamp which tells you when the corresponding message was written to the log. The [app] message are generated by the code I gave you. It works just like Serial.print() but by using the logging feature, we get nice timestamps. Each one of those [app] messages posts the variable contents at various points in the loop(). What I tried to do was post the variables at all the different times they are updated.
I think the problem is still the global vs local variable declarations. I didn't say it before because I wanted to see this log file. I read up on double variable declarations and the locally-scoped variable will take precedence over the global variable. So with the "last" variables you added, it may have worked. Instead, try flashing this code with properly scoped variables:
// This #include statement was automatically added by the Particle IDE.
#include <SparkFunRHT03.h>
const int RHT03_DATA_PIN = D4;
RHT03 rht;
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.
const char pubEvent[] = "Xenon1 Environment";
char msg[128];
const char prePend[] = "Published Data:";
SerialLogHandler logHandler(LOG_LEVEL_TRACE);
void setup()
{
//Start serial for console debugging.
Serial.begin(9600);
// variable name max length is 12 characters long
// Declare Particle.variables as soon as possible.
Particle.variable("tempF", tempF);
Particle.variable("humidity", humidity);
//Wait 10 seconds for the serial console to connect.
waitFor(Serial.isConnected, 10000);
//Initialize and update the sensor.
rht.begin(RHT03_DATA_PIN);
rht.update();
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Setup Readings:Ts = %d;Hs = %d",tempF,humidity);
Log.trace(msg);
Log.info("Setup complete.");
}
void loop()
{
//Use a millis timer for non-blocking code design.
if (millis() - lastPubMillis > pubInterval)
{
int update = rht.update();
humidity = rht.humidity();
tempF = rht.tempF();
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Pre-Filter Readings:Tp = %d;Hp = %d",tempF,humidity);
Log.trace(msg);
tempFdelta = tempF-lasttempF;
tempFdelta = abs(tempFdelta);
humiditydelta = humidity-lasthumidity;
humiditydelta = abs(humiditydelta);
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Delta Calcs:Td = %d;Hd = %d",tempFdelta,humiditydelta);
Log.trace(msg);
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(pubEvent,msg);
//Add debugging output.
strcat(prePend,msg);
Log.trace(msg);
} else {
Log.error("Delta calcs out of spec... cannot publish.");
}
//Update your pub millis timer.
lastPubMillis = millis();
lasttempF = tempF;
lasthumidity = humidity;
//Add debugging output.
snprintf(msg,arraySize(msg)-1,"Last Readings Updated:Tl = %d;Hl = %d",lasttempF,lasthumidity);
Log.trace(msg);
}
}
I figured as much but wanted to confirm. Because you re-declare the variables inside loop, the global variable never gets updated... hence 0 and 0. However, the code I provided last post should have loaded the global variables so they would have most likely have been 32/0 as you see in the logs.
I would disagree. Software Timers and millis() counters have their place and are both good choices. Each has limitations. A well written non-blocking loop using an FSM approach (where it makes sense) will work just fine with millis() counters.