Remote Control of Temperature and Humidity with Blynk

Today I would like to write a very easy tutorial on how to read remotely temperature and humidity using Blynk.

I am using a HTU21D temperature / humidity sensor by Adafruit and an (amazing :grinning:) Particle Photon.

Lets start from the wiring layout:

Connect the HTU21D’s pins to the Photon as follows:
VIN, GND ----------> 3V3, GND (in my case they are located in the + and - tracks)
SDA -----------------> D0
SCL -----------------> D1
(nothing on 3V3 pin!)

Make sure to import the HTU21D and the Blynk libraries in your app.

Here is the code:

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

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

HTU21D htu = HTU21D();

double tempVal, tempFVal, humidVal;
char auth[] = "01234567890123456789";

void setup() {
    //Serial.begin(9600);
    Blynk.begin(auth);
    
    if (!htu.begin()){
        Serial.println("Couldn't find sensor!");
        while(1);
    }
	
}

BLYNK_READ(V0){
    Blynk.virtualWrite(V0, round(tempVal*100)/100);
}
BLYNK_READ(V1){
    Blynk.virtualWrite(V1, round(tempFVal*100)/100);
}
 BLYNK_READ(V2){       
    Blynk.virtualWrite(V2, humidVal);
 }  

void loop() {
    Blynk.run();
    //Serial.print("Temp: "); Serial.print(htu.readTemperature()); Serial.print(" C"); Serial.print("\t"); Serial.print(tempFVal); Serial.print(" F");        
    //Serial.print("\t\tHUM: "); Serial.print(htu.readHumidity()); Serial.println(" %");      
    //Serial.println("");                                                                     
    //delay(10000);
    tempVal = htu.readTemperature();
    tempFVal = ((9.0/5.0)*tempVal + 32);
    humidVal = htu.readHumidity();
}

Make sure in the char auth[] line to use the token Blynk generates for your project. You can find the token in the Project Settings of the Blynk app you installed in your Android or IOS device. Within the Blynk app it is very easy and intuitive to create widgets. In my case I have two gauge widgets to measure the temperature (Celsius and Fahrenheit) and a label value for the humidity. Here are the three widgets and relative settings:

I am refreshing the reading of temperature and humidity every 10 seconds. Make sure to look at the Blynk’s doc about the code you must include in your app.

Also be sure to create the Blink.virtualWrite() function outside of the void loop and avoid to use the delay() function inside the void loop. If you do not follow this step your app is going to send hundreds of readings per second to the Blynk server and your Photon will start disconnecting from the cloud for a short period of time every couple of minutes (thank you @ScruffR for the heads-up…). Originally I thought the delay() function was enough to avoid communication issues with the Blynk server. Please refer to the Blynk doc.

We are almost there… Flash the firmware to your Photon.

Open the Blynk app:

Congratulations you have made your first weather station (or at least a small part of it… :wave: )! Enjoy monitoring the temperature and humidity of your room from anywhere in the world!! :wink:

1 Like

i have followed the steps however after 5 or 6 seconds my photon then blinks green has the code you talk about (Also be sure to create the Blink.virtualWrite() function outside of the void loop and avoid to use the delay()) been added or do i need to add it

Thanks for your help…Ben

If you are using the same code as above, I’d think your code gets stuck here

void setup() {
    //Serial.begin(9600);
    Blynk.begin(auth);
    
    if (!htu.begin()){
        Serial.println("Couldn't find sensor!");
        while(1);  // <--- stuck here IMHO
    }
}

If you change this line to

  while(1) Particle.process();

your code will still block, but you won’t get blinking green and keep breathing cyan.


That’s already present in the code above and does work as is - provided your HTU21D is wired and working correctly :wink:

thanks for the help, im still getting on my blynk app photon is not even online even though it is. is it only char auth code which needs changing.

cheers Ben

Hello @benjiiiiuk,

Did you import the HTU21D and Bynk libraries in your app? Did you check the connections of the HTU21D?

Also make sure to use the token Blynk generates for your project. The string I have in the char auth[] line of the above code will not work!

Let me know if you still have issues.

If my hint above cured the green blinking that other part of my post will still hold true

You need to get that sorted before you can expect Blynk to see your device. Only when you regularly call Blynk.run() (which you don’t if you’re still blocking) Blink will see your device.

2 Likes

@ScruffR why the code should stuck in the if statement at the void setup? Why this does not happen in my case? I am using the code I posted in the tutorial with no issues. Silly question, @benjiiiiuk are you using the HTU21D-F sensor? I am curious to understand what is the cause of your problems.

Not stuck in the if() statement but in the while(1) (code flow only breaks out of a while() when the condition evaluates to false which is the same as 0).
When will 1 ever become 0 to get out of the while()?
The answer to your question, why this doesn’t happen with your code is probably because !htu.begin() does not evaluate to true since your HTU does respond, but @benjiiiiuk’s most likely does not.

That was your code, so I thought you knew what it does :sunglasses:

Thank you for the clarification :smile: , the question is if @benjiiiiuk is using the HTU21D-F properly connected and imported the HTU21D library in his app what do you think the reason would be to have !htu.begin() evaluated to true?

That’s why I said this in my first post :wink:

If he hadn’t done that his code would not have built, but since he was even able to flash the code the lib was definetly present.

Exactly what I implicitly suggested by the above “condition” - I think the sensor is not wired or working correctly :wink:

Yep, it must be some hardware issue. Sorry for asking so many questions, but I’m totally new to programming and I am trying to learn as much as I can. I appreciate your replys and feedback!

1 Like

Thanks for all your replies. I have just had a look and realised that I am infact using the bmp180 sensor so no wonder it won’t work “what a clown” I have oredered the correct sensor and will give it a go when it arrives.

1 Like

Or you just use the correct library and adjust the respective code.
See https://build.particle.io/libs/5393009b7b167fbbb60008ab/tab/bmp085test.ino

1 Like

Hello, I used the code above and everything works fine for a little bit. Then the boron still breaths cyan blue but no data is being sent. The error message is This device is currently unreachable by the Device Cloud. Displaying last recorded device vitals. Im confused about your conversation dealing with the

while(1);
and the delay() not being in the loop

Should i be adding something to this. Will this fix my issue?

here is my code

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

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

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


#ifndef TOKEN
#define TOKEN "My token"  // Put here your Ubidots TOKEN
#endif

Ubidots ubidots(TOKEN, UBI_TCP); // Comment this line to use another protocol.

HTU21D htu = HTU21D();

double tempVal, tempFVal, humidVal;
char auth[] = "My token";

void setup() {
    Serial.begin(115200);
  ubidots.setDebug(true);  // Uncomment this line for printing debug messages
//Serial.begin(9600);
    Blynk.begin(auth);
    
    if (!htu.begin()){
        Serial.println("Couldn't find sensor!");
        while(1);
    }
	
}

BLYNK_READ(V0){
    Blynk.virtualWrite(V0, round(tempVal*100)/100);
}
BLYNK_READ(V1){
    Blynk.virtualWrite(V1, round(tempFVal*100)/100);
}
 BLYNK_READ(V2){       
    Blynk.virtualWrite(V2, humidVal);
 }  

void loop() {
    Blynk.run();
    //Serial.print("Temp: "); Serial.print(htu.readTemperature()); Serial.print(" C"); Serial.print("\t"); Serial.print(tempFVal); Serial.print(" F");        
    //Serial.print("\t\tHUM: "); Serial.print(htu.readHumidity()); Serial.println(" %");      
    //Serial.println("");                                                                     
    //delay(10000);
    tempVal = htu.readTemperature();
    tempFVal = ((9.0/5.0)*tempVal + 32);
    humidVal = htu.readHumidity();
    
     Particle.publish("Temperature C", String(tempVal), PRIVATE);
     Particle.publish("Temperature F", String(tempFVal), PRIVATE);
     Particle.publish("Humidity", String(humidVal), PRIVATE);
     
  float value1 = tempVal;
  float value2 = tempFVal;
  float value3 = humidVal;
  ubidots.add("Temperature C", value1);  // Change for your variable name
  ubidots.add("Temperature F", value2);
  ubidots.add("Humidity", value3);

  bool bufferSent = false;
  bufferSent = ubidots.send();  

  if(bufferSent){
    // Do something if values were sent properly
    Serial.println("Values sent by the device");
  }
  delay(5000);

}

Thank you

Also sometimes my humidity values is 998. Has anyone seen this before and know what I should go to fix it?
Thanks again

First, you make multiple Particle.publish() calls very quickly. You should combine your multiple publishes into one single publish. If you don’t know, there is a limit on how fast you call publish (1/second or 4/within 4 seconds with a 4 second cool down period). You come close to violating the limit which may cause disconnects or bad publishes.

Second, get ride of String and instead us snprintf.

Third, you asked about this, don’t use delay() within your loop. You should use another method to space out your updates such as a millis timer or a timer library.

Fourth, the HTU library returns float values. Why do you declare doubles, then convert back to float before updating Blynk?

Here are some of those comments implemented on your own code… I did not compile so you will have to test:

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

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

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


#ifndef TOKEN
#define TOKEN "My token"  // Put here your Ubidots TOKEN
#endif

Ubidots ubidots(TOKEN, UBI_TCP); // Comment this line to use another protocol.

HTU21D htu = HTU21D();

float tempVal, tempFVal, humidVal;
char auth[] = "My token";

unsigned long lastUpdateMillis = 0;  //Used to hold the last time, in millis, that we updated.
unsigned long updateInterval = 5000;  //This is the interval, in millis, between updates.

char msg[200];

void setup() {
    Serial.begin(115200);
    ubidots.setDebug(true);  // Uncomment this line for printing debug messages
    //Serial.begin(9600);
    Blynk.begin(auth);
    
    if (!htu.begin()){
        Serial.println("Couldn't find sensor!");
        while(1) Particle.process();  //Stay here forever... never exit. Must reconnect sensor and reset device.
    }
	
}

BLYNK_READ(V0){
    Blynk.virtualWrite(V0, round(tempVal*100)/100);
}
BLYNK_READ(V1){
    Blynk.virtualWrite(V1, round(tempFVal*100)/100);
}
 BLYNK_READ(V2){       
    Blynk.virtualWrite(V2, humidVal);
 }  

void loop() {
  Blynk.run();  //Moved outside of the millis timer to run as often as possible. See scruffR's comments.

  if (millis() - lastUpdateMillis > updateInterval) {
    //Serial.print("Temp: "); Serial.print(htu.readTemperature()); Serial.print(" C"); Serial.print("\t"); Serial.print(tempFVal); Serial.print(" F");        
    //Serial.print("\t\tHUM: "); Serial.print(htu.readHumidity()); Serial.println(" %");      
    //Serial.println("");                                                                     
    //delay(10000);
    tempVal = htu.readTemperature();
    tempFVal = ((9.0/5.0)*tempVal + 32);
    humidVal = htu.readHumidity();
    
    snprintf(msg, sizeof(msg) - 1, "TempC:%u,TempF:%u,Humidity:%u", tempVal, tempFval, humidVal);
    Particle.publish("EnvironmentData", msg, PRIVATE);

    ubidots.add("Temperature C", tempVal);  // Change for your variable name
    ubidots.add("Temperature F", tempFVal);
    ubidots.add("Humidity", humidVal);

    bool bufferSent = false;
    bufferSent = ubidots.send();  

    if(bufferSent){
      // Do something if values were sent properly
      Serial.println("Values sent by the device");
    }

    lastUpdateMillis = millis();
  }
}
1 Like

This will definetly break the cloud connection.
You should change that to while(1) Particle.process();

Blynk.run() should be called as often as possible, so it should be outside of the if() block.

2 Likes

Thank you so much for your help. As you can see Im new to this.

1 Like

Ninjatill thank you for posting the code. I had a question about it,

Can I play with the number (5000) in the code below to take measurements every hours?

unsigned long lastUpdateMillis = 0; //Used to hold the last time, in millis, that we updated.
unsigned long updateInterval = 5000; //This is the interval, in millis, between updates.

Im assuming it wont be very accurate (example: sampling every 20 min), so there is a better way

I have used

if(Time.minute() % 20== 0 && Time.minute() != Time_old){ //sample every 20 min

During testing I used sample every minute. The issue was that ubidots was updating at weird times (not every min) and the values was wrong — 998 C and 1830F, humidity was steady

Yes. Change to 3600000 for one hour. Or 1200000 for 20 minutes.

How accurate do you need it? No matter what the update internal, the millis timer method will be accurate to a few milliseconds. There may be some drift over time since I wasn't resetting the timer until after the sensor readings. Move the timer reset closer to the top of the if statement to reduce the drift.

I don't know how you update Time_old so it's hard to say. I have seen others trip over using Time because they forget that when Time.minute() % 20== 0 becomes true, you will be updating as fast as possible for one whole minute (possibly 10s of thousands of iterations in a minute.) There needs to be some other safety mechanism to only run once when that condition becomes true. You can use this method, or numerous others, as long as you use it correctly.

1 Like