SHT15 Humidity and Temperature Sensor - SHT15 Breakout

james211, the sht15 will do just fine taking the readings. The Spark can make data “available” to external apps using Spark.variable() and can “push” the data using Spark.publish(). You can also use Spark.function() to send commands to your Core. The development of an iOS app is out of my realm but there are great tutorials on how to read a core using a web page and script. These include:

1 Like

Hello,
anyone have an example with spark publish?

thanks

Hello @peekay123,
could you make an example with spark.publish()?
thanks

@hmmatos, if you use the library and demo code from my repo, here is a modified loop() for the demo that will publish a string containing the readings. Don’t forget the data pin is D0 and the clock pin is D1.

void loop()
{
  float temp_c;
  float temp_f;
  float humidity;
  char msg[60];

  if (millis() > wait) {
    wait = millis() + waittime;

    // Read values from the sensor
    temp_c = sht1x.readTemperatureC();
    temp_f = sht1x.readTemperatureF();
    humidity = sht1x.readHumidity();

    //Create the string for publishing
    sprintf(msg,"%2.1fC  %2.1fF  %3.1f%%", temp_c, temp_f, humidity);

    //Publish with event name "SHTreadings", TTL of 60 seconds and set to PRIVATE publishing (can only be read by your account)
    Spark.publish("SHTreadings", msg, 60, PRIVATE);	//Remove private to publish publicly
	
    // Print the values to the serial port
    Serial.println(msg);
    }
 }

I test compiled the code on the web IDE without any problems. :smile:

Thanks @peekay123 it work perfectly with the SHT71

1 Like

I have the SHT15 Temp + Humidity sensor hooked up to the Spark Core and uploading data to Ubidots.com now.

I also have a event setup so when the temp is 87F or higher it will send me a email to alert me of this which actually works and works fast.

@peekay123 @BDub @bko @wgbartley @zachary @Dave @zach Guys this Ubidots makes getting started with the Spark Core and getting email and SMS responses easier than anything else out there that I have come across. I would highly recommend it to people getting started out since its going to provide the least frustration than most other options based on my experience. Just my 2 cents.

@aguspg is with Ubidots and he posted a how to guide showing how you integrate Ubitods with the Spark Core and that is what I used to get this up and running. Its pretty simple.

4 Likes

Looks neat, I’ll have to check it out! :slight_smile:

@RWB (Or anyone?) Would you mind sharing how you got the Spark to send two, unique variables to ubidots? I’m almost there… and feel like I need to define two variable ID’s: one for temp and one for humidity… below is what I have thus far - which obviously is not working properly. It’s sending humidity info to my temp VariableID in ubidots, and the humidity in ubidots is empty.
thanks for all the great info already provided - I was was going to ask for the a github share of the final, but wanted to put this together / learn along the way, and it has been quite fun! I’ll be locating the unit up in the attic space to monitor humidity levels over the winter and comparing to house and outdoor levels. Might even add a small fan to move air?

#define VARIABLE_ID "__ubidots_variableID_temp__"
#define VARIABLE_IDH "__ubidots_variableID_humidity__"
...
request.path = "/api/v1.6/variables/"VARIABLE_ID"/values";
requesth.path = "/api/v1.6/variables/"VARIABLE_IDH"/values";

  sprintf(resultstr, "{\"value\":%.1f}", temp_f);
request.body = resultstr;
http.post(request, response, headers); 

   sprintf(resultstr, "{\"value\":%.1f}", humidity);
requesth.body = resultstr;
http.post(requesth, responseh, headers);

@h2ogood Here is the code I’m using to send temp and humidity data to Ubidots.

Your going to need to replace the Variable ID and API key with your own unique numbers from your Ubidots account:

Here is the main code:

// This #include statement was automatically added by the Spark IDE.
#include "SHT1x.h"

// This #include statement was automatically added by the Spark IDE.
#include "HttpClient/HttpClient.h"

/**
 * ReadSHT1xValues
 *
 * Read temperature and humidity values from an SHT1x-series (SHT10,
 * SHT11, SHT15) sensor.
 *
 * Copyright 2009 Jonathan Oxer <jon@oxer.com.au>
 * www.practicalarduino.com
 */
 


// Specify data and clock connections and instantiate SHT1x object
#define dataPin  D0
#define clockPin D1
SHT1x sht1x(dataPin, clockPin);


/**
* Declaring the variables.
*/
HttpClient http;
#define VARIABLE_ID "Put Variable ID here"
#define VARIABLE_ID2 "Put Variable ID here"
#define TOKEN "put your Ubidots Token here"


// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
      { "Content-Type", "application/json" },
      { "X-Auth-Token" , TOKEN },
    { NULL, NULL } // NOTE: Always terminate headers will NULL
};

http_request_t request;
http_response_t response;

void setup() {
   
    request.hostname = "things.ubidots.com";
    request.port = 80;
    //Serial.begin(9600);
}

void loop() {


float temp_f = 0;
float humidity = 0;

 
    // Read values from the sensor
    temp_f = sht1x.readTemperatureF();
    humidity = sht1x.readHumidity();
    
    delay(10001);

    // Send to Ubidots

    request.path = "/api/v1.6/variables/"VARIABLE_ID"/values";
    request.body = "{\"value\":" + String(temp_f) + "}";
    
    http.post(request, response, headers);
    
    request.path = "/api/v1.6/variables/"VARIABLE_ID2"/values";
    request.body = "{\"value\":" + String(humidity) + "}";

    http.post(request, response, headers);
    //Serial.println(response.status);

    //Serial.println(response.body);

   
}  

Here is the SHT1x.cpp file:

/**
 * SHT1x Library
 *
 * Copyright 2009 Jonathan Oxer <jon@oxer.com.au> / <www.practicalarduino.com>
 * Based on previous work by:
 *    Maurice Ribble: <www.glacialwanderer.com/hobbyrobotics/?p=5>
 *    Wayne ?: <ragingreality.blogspot.com/2008/01/ardunio-and-sht15.html>
 *
 * Manages communication with SHT1x series (SHT10, SHT11, SHT15)
 * temperature / humidity sensors from Sensirion (www.sensirion.com).
 */

#include "SHT1x.h"

    SHT1x::SHT1x(int dataPin, int clockPin)
    {
      _dataPin = dataPin;
      _clockPin = clockPin;
    }
    
    
    /* ================  Public methods ================ */
    
    /**
     * Reads the current temperature in degrees Celsius
    */
    float SHT1x::readTemperatureC()
    {
      int _val;                // Raw value returned from sensor
      float _temperature;      // Temperature derived from raw value
    
      // Conversion coefficients from SHT15 datasheet
      const float CC1 = -40.0;  // for 14 Bit @ 5V
      const float CC2 =   0.01; // for 14 Bit DEGC
    
      // Fetch raw value
      _val = readTemperatureRaw();
    
      // Convert raw value to degrees Celsius
      _temperature = (_val * CC2) + CC1;
    
      return (_temperature);
    }
    
    /**
     * Reads the current temperature in degrees Fahrenheit
     */
    float SHT1x::readTemperatureF()
    {
      int _val;                 // Raw value returned from sensor
      float _temperature;       // Temperature derived from raw value
    
      // Conversion coefficients from SHT15 datasheet
      const float CC1 = -40.0;   // for 14 Bit @ 5V
      const float CC2 =   0.018; // for 14 Bit DEGF
    
      // Fetch raw value
      _val = readTemperatureRaw();
    
      // Convert raw value to degrees Fahrenheit
      _temperature = (_val * CC2) + CC1;
    
      return (_temperature);
    }
    
    /**
     * Reads current temperature-corrected relative humidity
     */
    float SHT1x::readHumidity()
    {
      int _val;                    // Raw humidity value returned from sensor
      float _linearHumidity;       // Humidity with linear correction applied
      float _correctedHumidity;    // Temperature-corrected humidity
      float _temperature;          // Raw temperature value
    
      // Conversion coefficients from SHT15 datasheet
      const float CC1 = -4.0;       // for 12 Bit
      const float CC2 =  0.0405;    // for 12 Bit
      const float CC3 = -0.0000028; // for 12 Bit
      const float CT1 =  0.01;      // for 14 Bit @ 5V
      const float CT2 =  0.00008;   // for 14 Bit @ 5V
    
      // Command to send to the SHT1x to request humidity
      int _gHumidCmd = 0b00000101;
    
      // Fetch the value from the sensor
      sendCommandSHT(_gHumidCmd, _dataPin, _clockPin);
      waitForResultSHT(_dataPin);
      _val = getData16SHT(_dataPin, _clockPin);
      skipCrcSHT(_dataPin, _clockPin);
    
      // Apply linear conversion to raw value
      _linearHumidity = CC1 + CC2 * _val + CC3 * _val * _val;
    
      // Get current temperature for humidity correction
      _temperature = readTemperatureC();
    
      // Correct humidity value for current temperature
      _correctedHumidity = (_temperature - 25.0 ) * (CT1 + CT2 * _val) + _linearHumidity;
    
      return (_correctedHumidity);
    }
    
    
    /* ================  Private methods ================ */
    
    /**
     * Reads the current raw temperature value
     */
    float SHT1x::readTemperatureRaw()
    {
      int _val;
    
      // Command to send to the SHT1x to request Temperature
      int _gTempCmd  = 0b00000011;
    
      sendCommandSHT(_gTempCmd, _dataPin, _clockPin);
      waitForResultSHT(_dataPin);
      _val = getData16SHT(_dataPin, _clockPin);
      skipCrcSHT(_dataPin, _clockPin);
    
      return (_val);
    }
    
    /**
     */
    int SHT1x::shiftIn(int _dataPin, int _clockPin, int _numBits)
    {
      int ret = 0;
      int i;
    
      for (i=0; i<_numBits; ++i)
      {
         digitalWrite(_clockPin, HIGH);
         delay(10);  // I don't know why I need this, but without it I don't get my 8 lsb of temp
         ret = ret*2 + digitalRead(_dataPin);
         digitalWrite(_clockPin, LOW);
      }
    
      return(ret);
    }
    
    /**
     */
    void SHT1x::sendCommandSHT(int _command, int _dataPin, int _clockPin)
    {
      int ack;
    
      // Transmission Start
      pinMode(_dataPin, OUTPUT);
      pinMode(_clockPin, OUTPUT);
      digitalWrite(_dataPin, HIGH);
      digitalWrite(_clockPin, HIGH);
      digitalWrite(_dataPin, LOW);
      digitalWrite(_clockPin, LOW);
      digitalWrite(_clockPin, HIGH);
      digitalWrite(_dataPin, HIGH);
      digitalWrite(_clockPin, LOW);
    
      // The command (3 msb are address and must be 000, and last 5 bits are command)
      shiftOut(_dataPin, _clockPin, MSBFIRST, _command);
    
      // Verify we get the correct ack
      digitalWrite(_clockPin, HIGH);
      pinMode(_dataPin, INPUT);
      ack = digitalRead(_dataPin);
      if (ack != LOW) {
        //Serial.println("Ack Error 0");
      }
      digitalWrite(_clockPin, LOW);
      ack = digitalRead(_dataPin);
      if (ack != HIGH) {
        //Serial.println("Ack Error 1");
      }
    }
    
    /**
     */
    void SHT1x::waitForResultSHT(int _dataPin)
    {
      int i;
      int ack;
    
      pinMode(_dataPin, INPUT);
    
      for(i= 0; i < 100; ++i)
      {
        delay(10);
        ack = digitalRead(_dataPin);
    
        if (ack == LOW) {
          break;
        }
      }
    
      if (ack == HIGH) {
        //Serial.println("Ack Error 2"); // Can't do serial stuff here, need another way of reporting errors
      }
    }
    
    /**
     */
    int SHT1x::getData16SHT(int _dataPin, int _clockPin)
    {
      int val;
    
      // Get the most significant bits
      pinMode(_dataPin, INPUT);
      pinMode(_clockPin, OUTPUT);
      val = shiftIn(_dataPin, _clockPin, 8);
      val *= 256;
    
      // Send the required ack
      pinMode(_dataPin, OUTPUT);
      digitalWrite(_dataPin, HIGH);
      digitalWrite(_dataPin, LOW);
      digitalWrite(_clockPin, HIGH);
      digitalWrite(_clockPin, LOW);
    
      // Get the least significant bits
      pinMode(_dataPin, INPUT);
      val |= shiftIn(_dataPin, _clockPin, 8);
    
      return val;
    }
    
    /**
     */
    void SHT1x::skipCrcSHT(int _dataPin, int _clockPin)
    {
      // Skip acknowledge to end trans (no CRC)
      pinMode(_dataPin, OUTPUT);
      pinMode(_clockPin, OUTPUT);
    
      digitalWrite(_dataPin, HIGH);
      digitalWrite(_clockPin, HIGH);
      digitalWrite(_clockPin, LOW);
    }

And last here is the SHT1x.h file:

#include "application.h"
#ifndef SHT1x_h
#define SHT1x_h


class SHT1x
{
  public:
    SHT1x(int dataPin, int clockPin);
    float readHumidity();
    float readTemperatureC();
    float readTemperatureF();
  private:
    int _dataPin;
    int _clockPin;
    int _numBits;
    float readTemperatureRaw();
    int shiftIn(int _dataPin, int _clockPin, int _numBits);
    void sendCommandSHT(int _command, int _dataPin, int _clockPin);
    void waitForResultSHT(int _dataPin);
    int getData16SHT(int _dataPin, int _clockPin);
    void skipCrcSHT(int _dataPin, int _clockPin);
};

#endif
1 Like

sweet action - that did it, thanks @RWB ! Ah, you simply put your request.path within the loop, then did an http.post after defining the request.path. That works much better. I was trying to setup variables for the request.path and requesth.path (for humidity), then making unique calls. This is why I’m NOT a programmer. Thansk again - all is working great now.

1 Like

@h2ogood Sweet! It’s nice to help somebody else out. Usually its me asking for help :smile:

@aguspg Ubidots is the nicest and easiest to use online service I have ever used. They make it super simple to setup trigger events that send emails or text messages which is nice.

1 Like

I’m glad it worked guys! Btw we’re working on a more seamless integration with Spark that will make it simpler to setup this type of code (even if you’re not a programmer :slight_smile: )

2 Likes

@RWB - One more quick question, as I recall mention of adding some form of watchdog code to maintain a consistent web connection. Do you recommend, or have you found the Spark to maintain connectivity over time without that? I’m about to drop this bad boy in the attic, and I don’t really want to be crawling up there to reset it. Just curiuos on thoughts/findings.

My personal experience with the first Spark Cores has been mixed when it comes to needing to reset it by pushing the reset button on the actual board.

I think if your using your homes Wifi connection you may have minimal issues as far as resets will go but only time will tell.

My cellphone provides my WiFi hotspot and its always coming and going as I leave the house and come back. Normally it will reconnect without issues but sometimes it will flash green and will not automatically reconnect unless I do a physical reset. I think this would be less of a issue if I was connecting to a stable home Wifi router.

I say throw it up there and see how it goes over time. Also let me know what your experience is if you do have to actually push the reset button to get it going again.

@h2ogood, @RWB is right and with the (really soon to be released) firmware, the Core will be way better at reconnecting itself. :smiley:

@peekay123 @h2ogood

Good to know Peekay123, I’ve had my temp sensor up and running for what seems like a year now so I’ve had plenty of time with it. The auto reconnecting has become better as the new firmware’s has been released over time.

For me personally the Electron should solve the problems I have ever had since it eliminates the needs for a actual wifi connection which usually never has enough range for what I would like to do.

1 Like

Thanks - good to know (all around)! Honesty - it’s been rock solid on my home wifi… even flashing it many times over, it always seem to reconnect to WiFi without a problem. At this point, I’d have no reservations flashing without access to it. I also moved my WiFi to a non-broadcast, and it’s still hopping right on. Thanks again! Now to start piping in outdoor temp / humidity into my spreadsheet.

Good to hear.

How are you liking Ubidots?

Ubidots is rock solid. However, I’d like the ability to pipe external data sources into it (e.g. outdoor temp, humidity via yahoo weather/etc. API). From what I can tell Ubidots is setup for POST only, and does not have the ability to GET information from outside sources. I’ll also soon be moving to longer-term data review (as in weeks or months), and I feel like it views a day or two better. Still tinkering with all of it. I might give the Google spreadsheet a go (to compare), just so I can view a full years worth of data and pull outside sources into the data graphing. It’s all a work in progress.

1 Like

@h20good yea @aguspg may have some recommendations for you about Post and GET integration.

If you click on the gear icon at the top right of your line graph there are some more features I just found. One of the features is Culumative Graph which is supposed to show you the complete history of the data feed instead of just the last 1000 or 2000 readings. Give that a try.