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
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;lt;username&amp;amp;gt;:&amp;amp;lt;password&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> .
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