ESP8266: Uploading Weather Data to openweathermap.org

A couple of months ago I designed a small weather station to measure weather data such as temperature,  humidity and barometric pressure using an ESP8266 module and a couple of sensors. How this outdoor weather sensor is constructed is described in an older blog post.

openweathermap.org allows to connect a home made weather station to its network of weather stations around the world (currently >40.000). This may help to improve the data which is provided by openweathermap.org.

Uploading measured weather data is easily accomplished by performing an HTTP POST to http://openweathermap.org/data/post using basic authentication.

This manual describes how to upload weather data. Which weather details may be submitted in the post is illustrated in the table of the manual.

Prerequisites

An account for openweathermap.org is required. The username and password must be translatedinto BASE64 encoding. This online tool helps to transfer username:password for openweathermap.org into the required format.

The location of the weather station is required as GPS coordinates. The latitude and the longitude of the location of the weather station can be determined with google maps for example. All it needs is to click on the location on the map. The coordinates will be displayed in a small window below the adress.

Components used

Outdoor weather sensor

Source Code

The Arduino sketch for the outdoor weather sensor may be enhanced. For brevity I concentrate in this example on the additional functionality required to upload the weather data, not on their measurement.

#include <ESP8266WiFi.h>  // http://esp8266.github.io/Arduino/versions/2.0.0/doc/libraries.html
#include <WiFiClient.h>   // https://www.arduino.cc/en/Reference/WiFiClient

boolean debug=true;
// WiFi connection data
const char* ssid = "SSID";
const char* password = "PASSWORD";

const char* server = "openweathermap.org";
const int serverPort = 80;

const unsigned long BAUD_RATE = 115200; // serial connection speed
const unsigned long HTTP_TIMEOUT = 10000;   // max respone time from server

void initSerial();
void connectWiFi();
bool connect(const char* hostName, const int port);
bool sendPost(const char* hostName, float temperature, float humidity, float pressure);
void displayResponse();
void disconnect();
WiFiClient client;

unsigned long previousMillis = 0;
#define INTERVAL_MS 60000

#define CredentialsBase64 "sOmECRYPticStRiNggg" // enter here the BASE64 encoded credentials in the form &amp;amp;amp;lt;username&amp;amp;amp;gt;:&amp;amp;amp;lt;password&amp;amp;amp;gt;
// https://www.base64encode.org/enc/credential/
const String stationName = "MyOwnWeatherStation"; // enter the station name (it will be displayed on openweathermap.org)
// use coordinates from google maps
const String lat = "xx.xxxxx"; // latitude
const String lng = "yy.yyyyy"; // longitude
const String alt = "5"; // altitude of the location in meters without decimals

void setup() {
  initSerial();
  connectWiFi();
}

void loop() {
  unsigned long currentMillis = millis();
  // run every minute
  if (currentMillis - previousMillis >= INTERVAL_MS) {
    previousMillis = currentMillis;
    if( debug ) Serial.println("loop: measure weather data");
    float temperature=14.6;
    float humidity=89.1;
    float pressure=1004.6;
    // TODO use measured data from sensors!

    if( connect(server, serverPort) ) {
      if( sendPost(server, temperature, humidity, pressure) ) {
        displayResponse();
      }
    }
    disconnect();
  }
}

// send the HTTP POST request to the server
bool sendPost(const char* hostName, float temperature, float humidity, float pressure) {
  if( debug ) {
    Serial.print("POST weather data to");
    Serial.println(hostName);
    Serial.print("t = ");
    Serial.println(temperature);
    Serial.print("h = ");
    Serial.println(humidity);
    Serial.print("p = ");
    Serial.println(pressure);
  }

  // construct packet
  String packet = "";
  packet += "temp=";
  packet += (int)temperature;
  packet += "&humidity=";
  packet += (int)humidity;
  packet += "&pressure=";
  packet += (int)pressure;
  packet += "&lat=";
  packet += lat;
  packet += "&long=";
  packet += lng;
  packet += "&alt=";
  packet += alt;
  packet += "&name=";
  packet += stationName;

  // construct POST request
  String cmd = "POST /data/post HTTP/1.1\n";
  cmd += "Host: ";
  cmd += hostName;
  cmd += "\n";
  cmd += "Content-Type: application/x-www-form-urlencoded\n";
  cmd += "Authorization: Basic ";
  cmd += CredentialsBase64;
  cmd += "\n";
  cmd += "Content-Length: ";
  cmd += packet.length();
  cmd += "\n";
  cmd += "Connection: close\n\n";
  cmd += packet;
  cmd += "\r\n\r\n";

  if( debug ) {
    Serial.print("packet: ");
    Serial.println(packet);
    Serial.print("cmd: ");
    Serial.println(cmd);
  }
  client.println(cmd);
  return true;
}

void displayResponse() {
  client.setTimeout(HTTP_TIMEOUT);
  char reply[400];
  size_t length = client.readBytes(reply, 400);
  reply[length] = 0;
  String replyString = String(reply);

  if( debug ) {
    Serial.print("HTTP response ");
    Serial.println(replyString.c_str());
  }
}

// initialize serial port
void initSerial() {
  Serial.begin(BAUD_RATE);
  while (!Serial) {
    ;  // wait for serial port to initialize
  }
  if( debug ) Serial.println("Serial ready");
}

// attempt to connect to WiFi
void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    if( debug ) Serial.print(".");
  }
  if( debug ) {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }
}

// open connection to the HTTP server
bool connect(const char* hostName, const int port) {
  if( debug ) {
    Serial.print("Connect to ");
    Serial.println(hostName);
  }
  bool ok = client.connect(hostName, port);
  if( debug ) Serial.println(ok ? "Connected" : "Connection Failed!");
  return ok;
}

// close the connection with the HTTP server
void disconnect() {
  if( debug ) Serial.println("Disconnect from HTTP server");
  client.stop();
}

Notes

The HTTP POST to upload weather data boils down to

POST /data/post HTTP/1.1
Host: openweathermap.org
Content-Type: application/x-www-form-urlencoded
Authorization: Basic sOmECRYPticStRiNggg
Content-Length: 80
Connection: close

temp=20&humidity=71&pressure=1011&lat=49.11&long=24.11&alt=200&name=StationName

The content length is the length of the string containing the measured weather data, the coordinates etc. . More weather parameters may be added – everything that is measurable can be interesting for the upload.

How to find the own Weather Station

Finding the data from the own weather station after the upload was a bit tricky. It looks like openweathermap.org is working on improvements for uploading weather data as I conclude from this support answer. At least the documentation for upploading data needs improvements.

The station ID is returned in the HTTP response to the post. This is easy to miss. If the upload of weather data was successful the response should look similar to this:

HTTP response header HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sat, 20 Aug 2016 11:37:00 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: close
X-Powered-By: Fat-Free Framework (http://fatfree.sourceforge.net)
Pragma: no-cache
Cache-Control: no-cache, must-revalidate

{"message":"","cod":"200","id":987654321}

The ID can be used to observe the station using the URL http://openweathermap.org/station/987654321 .

To retrieve the weather data from this station in JSON format an HTTP GET request can be performed using this URL in a browser:

http://api.openweathermap.org/data/2.5/station?id=987654321&APPID=<YOURAPPID&gt; .

With some delay the uploaded data becomes visible in JSON format:

{
"station":
{"name":"MyOwnWeatherStation",
"type":5,"status":20,"user_id":0,"id":987654321,
"coord":{"lon":y.yyyy,"lat":xx.xxxx}},
"last":{"main":{"temp":290.15,"humidity":69,"pressure":1030},
"dt":1471791637},
"params":["temp","pressure","humidity"]
}

Inspirational Links

https://github.com/Benjamin3992/OpenWeatherDuino

http://openweathermap.org/stations

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s