haarislabs
Published © GPL3+

Weather Station Using Single Board - SLabs-32

A weather station which measures temperature, air humidity, and soil moisture and sends this data to the cloud using the SLabs-32 board.

IntermediateFull instructions provided1,395
Weather Station Using Single Board - SLabs-32

Things used in this project

Hardware components

DHT11 Temperature & Humidity Sensor (4 pins)
DHT11 Temperature & Humidity Sensor (4 pins)
×1
SparkFun Soil Moisture Sensor (with Screw Terminals)
SparkFun Soil Moisture Sensor (with Screw Terminals)
×1
Jumper wires (generic)
Jumper wires (generic)
×1
SLabs-32
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Connections

Code

Atmega

C/C++
#define cs   6  // CS & DC can use pins 2, 6, 9, 10, 15, 20, 21, 22, 23
#define dc   17   //  but certain pairs must NOT be used: 2+10, 6+9, 20+23, 21+22
#define rst  16 // RST can use any pin

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <stdio.h>
#include<Wire.h>
#include <dht.h> //DHT library


#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif


Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);

//Sensor Connections
// PID sensor on pin 2 or D2
// DHT sensor on pin 3
// Soil moisture sensor on A0

#define DHT11_PIN 3

int PIR_value, soilmoisture_sensor;
byte temperature_sensor;
byte humidity_sensor;
dht DHT;


//Black theme
//#define COLOR1 ST7735_WHITE
//#define COLOR2 ST7735_BLACK

//White theme
#define COLOR1 ST7735_BLACK
#define COLOR2 ST7735_WHITE

int text_color_humidex;
float humidity, temperature;
String message;
String stemp, shumid, city;
void setup(void) {

  Wire.begin(8); //address pin 8
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  Serial.begin(115200);
  tft.initR(INITR_GREENTAB);   // initialize a ST7735S chip, greentab for v0.1 and blacktab for v0.0
  tft.fillScreen(COLOR2);

  pinMode(2, INPUT); //PID sensor

}

void loop() {

  int chk = DHT.read11(DHT11_PIN);
  temperature_sensor = DHT.temperature;
  humidity_sensor = DHT.humidity;
  PIR_value = digitalRead(2); //PIR sensor conntected at D2
  soilmoisture_sensor = analogRead(A0); //Soil moisture sensor connect to A0 pin
  soilmoisture_sensor = 1020 - soilmoisture_sensor;

  Serial.print("Local Temperature : ");
  Serial.println(temperature_sensor);
  Serial.print("Local Humidity : ");
  Serial.println(humidity_sensor);
  Serial.print("PIR : ");
  Serial.println(PIR_value);
  Serial.print("Soil moisture : ");
  Serial.println(soilmoisture_sensor);

  // Table
  tft.drawRect(0, 0, 128, 160, COLOR1);
  tft.drawLine(0, 50, 128, 50, COLOR1);
  tft.drawLine(0, 100, 128, 100, COLOR1);

  // data is outputed

  temperature_to_lcd (temperature, 4);
  humidity_to_lcd (humidity, 55);
  location_to_lcd ();

}

// outputs temperature to LCD
void temperature_to_lcd (float temperature, unsigned char text_position )
{
  int text_color;

  tft.setCursor(4, text_position);
  tft.setTextColor(COLOR1, COLOR2);
  tft.setTextSize(1);
  tft.print("Temperature:");

  tft.setTextSize(3);
  tft.setCursor(1, text_position + 20);
  fix_number_position(temperature);
  tft.print(temperature, 1);

  tft.setCursor(108, text_position + 20);
  tft.print("C");
  tft.drawChar(90, text_position + 20, 247, text_color, COLOR2, 2); //degree symbol

}

//outputs humidity to LCD

void humidity_to_lcd (float humidity, unsigned char text_position )
{


  tft.setTextColor(COLOR1, COLOR2);
  tft.setCursor(4, text_position);
  tft.setTextSize(1);
  tft.println("Humidity:");
  tft.setTextSize(3);
  tft.setCursor(1, text_position + 20);

  fix_number_position(humidity);

  tft.print(humidity, 1);
  tft.print(" %");

}


void location_to_lcd ()

{
  int  text_position = 105;
  tft.setCursor(4, text_position);

  tft.setTextSize(1);
  tft.println("Location:");
  tft.setTextSize(2);

  tft.setCursor(1, text_position + 17);


  tft.print(city);
  tft.setCursor(108, text_position + 17);
  //  tft.print("A");
  //  tft.drawChar(90,text_position+17, 247, COLOR1, COLOR2, 2); //degree symbol
  tft.setCursor(1, text_position + 43);
  tft.setTextSize(1);
  // tft.println("Hyd/India");


}

// aligs number to constant position

void fix_number_position(float number)

{


  if ((number >= -40) && (number < -9.9))
  {
    ;
  }

  if ((number >= -9.9) && (number < 0.0))
  {
    tft.print(" ");
  }

  if ((number >= 0.0 ) && (number < 9.9))
  {
    tft.print("  ");
  }

  if ((number >= 9.9 ) && (number < 99.9))
  {
    tft.print(" ");
  }

  if ((number >= 99.9 ) && (number < 151))
  {
    tft.print("");
  }
}


void receiveEvent(int howMany) {

  int h, count;                           // used to convert string to char
  int len_h = 0;
  char humidity_string[15] = {'\0'};  // humidity string
  char str[15] = {'\0'};

  String city_temp;

  float t = Wire.read(); // taking the temperature value from ESP
  Serial.println(t);

  while (Wire.available()) {

    str[count] = Wire.read();
    count++;
    // For degugging
    // Serial.println(str[count]);

  }

  temperature = t;
  Serial.println("Temperature from esp :");
  Serial.print(t);

// extracting just the Humidity part and city information from the string

  for (h = 0; h < 2; h++) {
    humidity_string[len_h] = str[h];
    len_h++;
  }

  for (int c = 3; c < count ; c++) {
    city_temp += String(str[c]);
  }

  city = city_temp;
  shumid = humidity_string;
  Serial.println("Humidity from esp :");
  Serial.print(humidity_string);
  humidity = shumid.toInt();
}

void requestEvent() {

  Wire.write(temperature_sensor);//write temperature value
  Wire.write(humidity_sensor); //write humidity value
  Wire.write(PIR_value); //Write PIR sensor value
  Wire.write(soilmoisture_sensor); //write soil moisture sensorr value
}

Esp

C/C++
//Including libraries
#include<Wire.h>
#include<ESP8266WiFi.h>
#include <ArduinoJson.h>
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>

//Timer part

unsigned long timeNow = 0;
unsigned long timeLast = 0;
int seconds = 0;
int minutes = 0;
bool flag;


byte t; //Temperature
byte h; //Humidity
byte p; //PIR sensor
byte s; //Soil moisture sensor

const char SID[]     = "Enter_your_username"; //Network ssid
const char PASSWORD[] = "Enter_your_password";  //Network password
char username[] = "Enter_here"; //User name of cayenne account
char password[] = "Enter_here"; //Password of Cayenne account
char clientID[] = "Enter_here"; //Client id of Cayenne account

// Use your own API key by signing up for a free developer account.
// http://www.wunderground.com/weather/api/
#define WU_API_KEY "4a9fdc61f5681169" //API key of weather underground

#define WU_LOCATION "india/hyderabad"


#define DELAY_NORMAL    (5*1000) // 5 seconds
#define DELAY_ERROR     (30*1000)

#define WUNDERGROUND "api.wunderground.com"

// HTTP request
const char WUNDERGROUND_REQ[] =
  "GET /api/" WU_API_KEY "/conditions/q/" WU_LOCATION ".json HTTP/1.1\r\n" //Json file link
  "User-Agent: ESP8266/0.1\r\n"
  "Accept: */*\r\n"
  "Host: " WUNDERGROUND "\r\n"
  "Connection: close\r\n"
  "\r\n";

void setup()
{
  Wire.begin();
  Serial.begin(115200);

  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.print(F("Connecting to "));
  Serial.println(SID);
  Cayenne.begin(username, password, clientID, SID, PASSWORD);
  //WiFi.begin(SID, PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(F("."));
  }

}

static char respBuf[4096];
void loop()
{

  // Timer for every 1 min for getting info from WUNDERGROUND
  timeNow = millis() / 1000;
  seconds = timeNow - timeLast;
  if (seconds == 60) {
    timeLast = timeNow;
    minutes = minutes + 1;
  }

  // Set the time here for getting update from WUNDERGROUND
  if (minutes == 1) {
    minutes = 0;
    flag = true;
  }

  Wire.requestFrom(8, 4); //requesting from slave

  while (Wire.available() > 0) {
    t = Wire.read();
    Serial.println(t);
    h = Wire.read();
    Serial.println(h);
    p = Wire.read();
    Serial.println(p);
    s = Wire.read();
    Serial.println(s);
  }

  Cayenne.loop();


  while (flag) {
    // Open socket to WU server port 80
    Serial.print(F("Connecting to "));
    Serial.println(WUNDERGROUND);

    // Use WiFiClient class to create TCP connections
    WiFiClient httpclient;
    const int httpPort = 80;
    if (!httpclient.connect(WUNDERGROUND, httpPort)) {
      Serial.println(F("connection failed"));
      delay(DELAY_ERROR);
      return;

    }


    // This will send the http request to the server
    Serial.print(WUNDERGROUND_REQ);
    httpclient.print(WUNDERGROUND_REQ);
    httpclient.flush();

    // Collect http response headers and content from Weather Underground
    // HTTP headers are discarded.
    // The content is formatted in JSON and is left in respBuf.
    int respLen = 0;
    bool skip_headers = true;
    while (httpclient.connected() || httpclient.available()) {
      if (skip_headers) {
        String aLine = httpclient.readStringUntil('\n');
        //Serial.println(aLine);
        // Blank line denotes end of headers
        if (aLine.length() <= 1) {
          skip_headers = false;
        }
      }
      else {
        int bytesIn;
        bytesIn = httpclient.read((uint8_t *)&respBuf[respLen], sizeof(respBuf) - respLen);
        Serial.print(F("bytesIn ")); Serial.println(bytesIn);
        if (bytesIn > 0) {
          respLen += bytesIn;
          if (respLen > sizeof(respBuf)) respLen = sizeof(respBuf);
        }
        else if (bytesIn < 0) {
          Serial.print(F("read error "));
          Serial.println(bytesIn);
        }
      }
      delay(1);
    }
    httpclient.stop();

    if (respLen >= sizeof(respBuf)) {
      Serial.print(F("respBuf overflow "));
      Serial.println(respLen);
      delay(DELAY_ERROR);
      return;
    }
    // Terminate the C string
    respBuf[respLen++] = '\0';
    Serial.print(F("respLen "));
    Serial.println(respLen);
    //Serial.println(respBuf);

    if (showWeather(respBuf)) {
      delay(DELAY_NORMAL);
    }
    else {
      delay(DELAY_ERROR);
    }
    flag = false;
  }
}

bool showWeather(char *json)
{
  StaticJsonBuffer<3 * 1024> jsonBuffer;

  // Skip characters until first '{' found
  // Ignore chunked length, if present
  char *jsonstart = strchr(json, '{');
  //Serial.print(F("jsonstart ")); Serial.println(jsonstart);
  if (jsonstart == NULL) {
    Serial.println(F("JSON data missing"));
    return false;
  }
  json = jsonstart;

  // Parse JSON
  JsonObject& root = jsonBuffer.parseObject(json);
  if (!root.success()) {
    Serial.println(F("jsonBuffer.parseObject() failed"));
    return false;
  }

  // Extract weather info from parsed JSON
  JsonObject& current = root["current_observation"];
  const float temp_f = current["temp_f"];
  Serial.print(temp_f, 1); Serial.print(F(" F, "));
  const float temp_c = current["temp_c"];
  Serial.print(temp_c, 1); Serial.print(F(" C, "));
  const char *humi = current[F("relative_humidity")];
  Serial.print(humi);   Serial.println(F(" RH"));
  const char *weather = current["weather"];
  Serial.println(weather);
  const char *pressure_mb = current["pressure_mb"];
  Serial.println(pressure_mb);
  const char *observation_time = current["observation_time_rfc822"];
  Serial.println(observation_time);

  // City

  const char *city = root["current_observation"]["display_location"]["city"];
  // Serial.println(city);


  //Sending the values to atmega

  Wire.beginTransmission(8);
  Wire.write(byte(temp_c));
  Wire.write(humi);
  Wire.write(city);
  Wire.endTransmission();
  Serial.println(temp_c);
  Serial.println(humi);
  Serial.println(city);


  // Extract local timezone fields
  const char *local_tz_short = current["local_tz_short"];
  Serial.println(local_tz_short);

  const char *local_tz_long = current["local_tz_long"];
  Serial.println(local_tz_long);
  const char *local_tz_offset = current["local_tz_offset"];
  Serial.println(local_tz_offset);

  return true;
}

CAYENNE_OUT_DEFAULT()
{
  Serial.println("cayenne call");
  //Writing on the cayenne platform (location, value)
  Cayenne.virtualWrite(1, t); // Sending temperature data on channel 1
  Cayenne.virtualWrite(2, h); // Sending humidity data on channel 2
  Cayenne.virtualWrite(3, p); // Sending pir data on channel 3
  Cayenne.virtualWrite(4, s); // Sending soil moisture data on channel 4
}

CAYENNE_IN_DEFAULT()
{
  CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());
  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

Credits

haarislabs
4 projects • 4 followers
Contact

Comments

Please log in or sign up to comment.