Weather Station 2

Start 

Starting here.

Modules 

Gather the following parts to complete this project.

Parts

All Parts
All Parts
WiFi
Cable
Finished WS1 project
PartQuantity
WiFi 1
Cable 1
Finished WS1 project 1

WiFi Module 

Remove the LCD Display module and button module. Take a cable and unwrap it. Plug one side into the WiFi socket and the other into any Digital socket.

Parts Needed
Parts Needed
Remove button from base board
Remove button module
Remove LCD from base board
Remove LCD module
Take a cable
Unwrap it
Plug one side into the WiFi socket
The other into any Digital socket

Upload

Upload the following code. The example below uses the D8 digital pin.

Download file Copy to clipboard
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include "WiFiEsp.h"
#include <Wire.h>
#include "Seeed_BME280.h"
#include <math.h>
#include "Arduino.h"
#include "SI114X.h"
#include "SoftwareSerial.h"

//Create Serial communication Object
SoftwareSerial Serial1(8, 9); // RX, TX

//Create sensor objects
SI114X sunlightSensor;
BME280 bme280;

//title to use for your webpage
String title = "Your Weather Station";

//Weather variables
float temperature;
float humidity;
float pressure;
float uv;

//Wifi settings
char ssid[] = "Weather Node";    // your network SSID (name)
char pass[] = "password";        // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
int reqCount = 0;                // number of requests received

//Wifi server object
WiFiEspServer server(80);

// use a ring buffer to increase speed and reduce memory allocation
RingBuffer buf(8);

void setup()
{
  //Start Serial Communication with computer and WiFi module
  Serial.begin(9600);   // initialize serial for debugging
  Serial1.begin(9600);    // initialize serial for ESP module
  WiFi.init(&Serial1);    // initialize ESP module

  //Start sunlight sensor commmunications
  while (!sunlightSensor.Begin()) {
    Serial.println("Sunlight Error");
    delay(1000);
  }
  //Start BME280 communications
  if (!bme280.init()) {
    Serial.println("BME Error");
  }

  //Print out debugging messages
  Serial.print("Attempting to start AP ");
  Serial.println(ssid);

  // start access point
  status = WiFi.beginAP(ssid);

  //Print out more debugging info
  Serial.println("Access point started");
  printWifiStatus();

  // start the web server on port 80
  server.begin();
  Serial.println("Server started");
}


void loop()
{
  //Get temperature
  temperature = bme280.getTemperature();
  //convert to F from C
  temperature = temperature * 1.8 + 32;

  //Get humidity
  humidity = bme280.getHumidity();

  //Get pressure
  pressure = bme280.getPressure();

  //Get uv value and convert to UV Index values
  uv = (float)sunlightSensor.ReadUV() / 100;

  //Wait for a device to connect to the WiFi
  WiFiEspClient client = server.available();  // listen for incoming clients

    // if you get a client,
  if (client) {
    // print a message out the serial port
    Serial.println("New client");
// initialize the circular buffer
    buf.init();
      // loop while the client's connected
    while (client.connected()) {
      // if there's bytes to read from the client,
      if (client.available()) {
        // read a byte, then
        char c = client.read();
        // push it to the ring buffer
        buf.push(c);

        // you got two newline characters in a row
        // that's the end of the HTTP request, so send a response
        if (buf.endsWith("\r\n\r\n")) {
          sendHttpResponse(client);
          break;
        }
      }
    }

    // give the web browser time to receive the data
    delay(10);

    // close the connection
    client.stop();
    Serial.println("Client disconnected");
  }
}

void sendHttpResponse(WiFiEspClient client)
{
  client.print(
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n"
    // the connection will be closed after completion of the response
    "Connection: close\r\n"
     // refresh the page automatically every 20 sec
    "Refresh: 20\r\n"
    "\r\n");

  client.print(
    "<!DOCTYPE HTML>\r\n"
    "<html>\r\n"
    "<head>\r\n"
    "<style>\r\n"
    "</style>\r\n"
    "</head>\r\n"
    "<body>\r\n"
    "<h1>" + title + "</h1>\r\n"
    "<br>\r\n");

  // Print # of requests received
  client.print("Requests received: ");
  client.print(++reqCount);

  client.print("<p id=\"date\"></p>"
    "<script>"
    "document.getElementById(\"date\").innerHTML = 'Date: ' + Date();"
    "</script>"
    "<p><br>\r\n");

  // Print temperature
  client.print("Temperature: ");
  client.print(temperature);
  client.print("F"
    "<br>\r\n"
    "Humidity: ");

  client.print(humidity);
  client.print("%"
    "<br>\r\n"
    "Air Pressure: ");
  client.print(pressure);

  client.print("Pa"
    "<br>\r\n"
    "UV Index: ");
  client.print(uv);
  client.print("<br>\r\n"
    "</body>\r\n"
    "</html>\r\n");
}

void printWifiStatus()
{
  // print your WiFi IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print where to go in the browser
  Serial.println();
  Serial.print("To see this page in action, connect to ");
  Serial.print(ssid);
  Serial.print(" and open a browser to http://");
  Serial.println(ip);
  Serial.println();
}

Observe

To make sure we have everything set up correctly, open up the Serial Monitor. The WiFi module needs to initialize. After that, an IP will show up and we'll need that for the next step. In my case the IP address is 192.168.4.1 . Go over to your WiFi settings on any device with a web browser, and connect to "Weather Node". The password is "password". Once connected, head over to a web browser and type in that IP address. You'll be taken to a page that displays the current weather data from your weather station.

Modify

You can change the ssid[] to change the name of the WiFi network and the pass[] to any password you'd like. You can change the title variable to what you'd like your weather station to be called on the webpage.

Experiment

Check out the HTML and CSS page to learn more about customizing your Weather Station webpage.

Connecting to WiFi 

If you'd like to upload your weather data to the internet and be able to monitor it remotely then start here to connect your WiFi module to a WiFi network.

Upload

Upload the following code.

Download file Copy to clipboard
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include "WiFiEsp.h"
#include "SoftwareSerial.h"

//Creates serial communication object
SoftwareSerial Serial1(8, 9); // RX, TX

void setup() {
  // initialize serial for debugging
  Serial.begin(9600);
  // initialize serial for ESP module
  Serial1.begin(9600);
  // initialize ESP module
  WiFi.init(&Serial1);

  // Print WiFi MAC address
  printMacAddress();
}

void loop()
{
  // scan for existing networks
  Serial.println();
  Serial.println("Scanning available networks...");
  //function to scan for wifi networks
  listNetworks();
  //Wait 10 seconds before scanning agian
  delay(10000);
}


void printMacAddress()
{
  // get your MAC address
  byte mac[6];
  //This is a unique hardware address for the wifi module
  WiFi.macAddress(mac);

  // print MAC address
  char buf[20];
  //replaces %02X with a MAC address byte
  sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
  Serial.print("MAC address: ");
  Serial.println(buf);
}

void listNetworks()
{
  // scan for nearby networks
  int numSsid = WiFi.scanNetworks();
  //This runs when there isn't a wifi connection
  if (numSsid == -1) {
    Serial.println("Couldn't get a WiFi connection");
    //The Arduino will stay in this loop forever if it can't get a connection
    while (true);
  }

  // print the list of networks seen
  Serial.print("Number of available networks:");
  Serial.println(numSsid);

  // print the network number and name for each network found
  for (int thisNet = 0; thisNet < numSsid; thisNet++) {
    //Print the network number
    Serial.print(thisNet);
    Serial.print(") ");
    //Print network name
    Serial.print(WiFi.SSID(thisNet));
    //Print out the signal strength
    Serial.print("\tSignal: ");
    Serial.print(WiFi.RSSI(thisNet));
    Serial.print(" dBm");
    //Print password type
    Serial.print("\tEncryption: ");
    printEncryptionType(WiFi.encryptionType(thisNet));
  }
}

void printEncryptionType(int thisType) {
  // read the encryption type and print out the name
  switch (thisType) {
    case ENC_TYPE_WEP:
      Serial.print("WEP");
      break;
    case ENC_TYPE_WPA_PSK:
      Serial.print("WPA_PSK");
      break;
    case ENC_TYPE_WPA2_PSK:
      Serial.print("WPA2_PSK");
      break;
    case ENC_TYPE_WPA_WPA2_PSK:
      Serial.print("WPA_WPA2_PSK");
      break;
    case ENC_TYPE_NONE:
      Serial.print("None");
      break;
  }
  Serial.println();
}

Observe

Open up the Serial Monitor and wait for the WiFi module to scan. It will print out a list of all the possible WiFi networks it can connect to. You should see the name of your normal WiFi network.

Modify

Before uploading this next bit of code, swap out ssid with your WiFi network's name and pass with its password.

Download file Copy to clipboard
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 WiFiEsp example: UdpNTPClient
 Get the time from a Network Time Protocol (NTP) time server.
 Demonstrates use of UDP to send and receive data packets
 For more on NTP time servers and the messages needed to communicate with them,
 see http://en.wikipedia.org/wiki/Network_Time_Protocol
*/

#include "WiFiEsp.h"
#include "WiFiEspUdp.h"
#include "SoftwareSerial.h"

//Create channel for communication to wifi module
SoftwareSerial Serial1(8, 9); // RX, TX

//Wifi settings
char ssid[] = "YOURWIFINETOWRK";       // your network SSID (name)
char pass[] = "YOURPASSWORD";      // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status

//Location of the time server
char timeServer[] = "time.nist.gov";  // NTP server
unsigned int localPort = 2390;        // local port to listen for UDP packets

//Communication settings
const int NTP_PACKET_SIZE = 48;  // NTP timestamp is in the first 48 bytes of the message
const int UDP_TIMEOUT = 2000;    // timeout in miliseconds to wait for an UDP packet to arrive
byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiEspUDP Udp;

void setup()
{
  // initialize serial for debugging
  Serial.begin(9600);
  // initialize serial for ESP module
  Serial1.begin(9600);
  // initialize ESP module
  WiFi.init(&Serial1);

  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }

  // you're connected now, so print out the data
  Serial.println("You're connected to the network");

  //Open the communication port
  Udp.begin(localPort);
}

void loop()
{
  // send an NTP packet to a time server
  sendNTPpacket(timeServer);

  // wait for a reply for UDP_TIMEOUT miliseconds
  unsigned long startMs = millis();
  while (!Udp.available() && (millis() - startMs) < UDP_TIMEOUT) {

  }
  //Print out the information received
  Serial.println(Udp.parsePacket());
  //If packet is sent from the time server
  if (Udp.parsePacket()) {
    Serial.println("packet received");
    // We've received a packet, read the data from it into the buffer
    Udp.read(packetBuffer, NTP_PACKET_SIZE);

    // the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = ");
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970, which is 70 years after NTP time starts.
    // Seventy years is 2208988800 seconds after we add in the extra days for the leap years.
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    Serial.println(epoch);


    // print the hour, minute and second:
    Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
    Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)
    Serial.print(':');
    if (((epoch % 3600) / 60) < 10) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':');
    if ((epoch % 60) < 10) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch % 60); // print the second
  }
  // wait ten seconds before asking for the time again
  delay(10000);
}

// send an NTP request to the time server at the given address
void sendNTPpacket(char *ntpSrv)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)

  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(ntpSrv, 123); //NTP requests are to port 123

  Udp.write(packetBuffer, NTP_PACKET_SIZE);

  Udp.endPacket();
}

Observe Again

Open up the Serial Monitor and check it out. You should connect to your WiFi network then you'll see reports with the time in the UNIX standard. If it doesn't connect make sure your ssid and pass are correct.

Wunderground 

Wunderground is a weather reporting service that supports the use of personal weather stations or PWS. We'll be using that PWS service as the endpoint for our weather data. We'll need to register an account, create our PWS, then push data to it.

Register

Head over to this link to sign up for a Wunderground account. Once joined, head over to this link to create your personal weather station name and details. You'll need to type in your location so the service know where you are reporting the weather. Hit Verify Location on the bottom to go to the next page. There are two required fields on this page. Neighborhood is the name of your weather station so name it something descriptive to your area. The other field is Station Hardware. Since we build our weather stations, scroll down that list and select other. Once finished with the settings, press Submit to get your ID and KEY that we need for the next section. The information on the next page is what we'll put into the Arduino sketch so keep it open. If you ever need to find your ID and KEY again just navigate here.

Upload

Copy the code below but before uploading your code, replace the WID and WKEY with your ID and KEY from Wunderground. Also change ssid[] and pass[] to your WiFi network name and password so we can send data. After doing both of those changes, upload the code.

Download file Copy to clipboard
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include "WiFiEsp.h"
#include <Wire.h>
#include "Seeed_BME280.h"
#include <math.h>
#include "Arduino.h"
#include "SI114X.h"
#include "SoftwareSerial.h"

//Defines for Wunderground variables
#define WID "WUNDERGROUND_ID"
#define WKEY "WUNDERGOUND_KEY"
#define getPayload "/weatherstation/updateweatherstation.php?ID="  WID  "&PASSWORD="  WKEY  "&dateutc=now&tempf=%s&humidity=%s&baromin=%s&UV=%s&action=updateraw"


//Create serial communication object
SoftwareSerial Serial1(8, 9); // RX, TX

//Wifi settings
char ssid[] = "YOURWIFINETOWRK";       // your network SSID (name)
char pass[] = "YOURPASSWORD";      // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status

//Server URL for later
char server[] = "weatherstation.wunderground.com";

//Storage for getPayload
char buf[200];


// Initialize the Ethernet client object
WiFiEspClient client;

// Construct sensor objects
SI114X sunlightSensor;
BME280 bme280;

// Variables for weather measurements
float temperature;
float humidity;
float pressure;
float uv;

// Letter version of the variables from above
char cTemp[8];
char cHum[8];
char cPress[8];
char cUv[8];

// Variable to hold time
unsigned long previousMillis = 0;

// Milliseconds to wait between updates.
const long interval = 2 * 60 * 1000L;

void setup() {
  // Initialize serial for debugging
  Serial.begin(9600);
  // Initialize serial for ESP module
  Serial1.begin(9600);
  // Initialize ESP module
  WiFi.init(&Serial1);

  // Initialize sunlight sensor
  while (!sunlightSensor.Begin()) {
    Serial.println("Sunlight Error");
    delay(1000);
  }

  // Initialize BME280 sensor
  if (!bme280.init()) {
    Serial.println("BME Error");
  }

  // Attempt to connect to WiFi network
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }

  // You're connected now, so print out the data
  Serial.println("You're connected to the network");

  // Print out all info about wifi connection
  printWifiStatus();

  // Run updateWeather function
  updateWeather();
  // Run sendData function
  sendData();
}

void loop() {
  // Store the current time
  unsigned long currentMillis = millis();

  // Check to see if enough time has passed
  if (currentMillis - previousMillis >= interval) {
    // Save the last time data was sent
    previousMillis = currentMillis;

    // Run updateWeather function
    updateWeather();
    // Run sendData function
    sendData();
  }

  // While there is a connection to the server
  while (client.available()) {
    // Store the response
    char c = client.read();
    // And print it to the serial console
    Serial.write(c);
  }

  // If the server's disconnected, stop the client:
  if (!client.connected()) {
    // Prints debugging messages
    //Serial.println();
    //Serial.println("disconnecting from server.");
    // Disconnect the server
    client.flush();
    client.stop();
  }
}

void updateWeather() {
  // Read temp and convert to F
  temperature = bme280.getTemperature();
  temperature = temperature * 1.8 + 32;

  // Read humidity
  humidity = bme280.getHumidity();

  // Read Pressure and convert to inches of water
  pressure = bme280.getPressure() * 0.00040146;

  // Read UV and convert to UV Index range
  uv = (float)sunlightSensor.ReadUV() / 100;
}

void sendData() {
  // Convert float numbers to char arrays
  dtostrf(temperature, 4, 2, cTemp);
  dtostrf(humidity, 4, 2, cHum);
  dtostrf(pressure, 4, 2, cPress);
  dtostrf(uv, 4, 2, cUv);

  // Try and send the data
  if (client.connect(server, 80)) {
    // Make a HTTP request:
    sprintf(buf, getPayload, cTemp, cHum, cPress, cUv);
    client.println(String("GET ") + buf + String(" HTTP/1.1"));
    //Serial.println(String("GET ") + buf + String(" HTTP/1.1"));
    client.println("Host: weatherstation.wunderground.com");
    client.println("Connection: close");
    client.println();
  }

}
void printWifiStatus()
{
  // Print the SSID of the network you're attached to
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Print your WiFi shield's IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // Print the received signal strength
  long rssi = WiFi.RSSI();
  Serial.print("Signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Observe

Open up the Serial Monitor and you'll see a couple of steps. The first is the initialization of the WiFi module. Then the connection to your local WiFi network. Once, you're online the weather station will attempt to send weather data to Wunderground. Assuming your ID and Key are correct you'll see a success message and within a few minutes you can visit your PWS page to see your weather data.