Weather station middleware

In this post we are describing a  middleware communicating with a USB weather station and transferring the information to the cloud. Applications of the specific project can be found in many fields, such as remote weather monitoring, surveillance systems, smart home or any Internet of Thing integration. Due to the protocols simplicity any sensor or system capable to access the web server can post weather data into our server.

wsThe middleware communicates with WH3081 or WH3080 like Weather Station, through the USB port, and acquires the stored weather data. After processing the received measurements the information passed to a simple bash script that posts the data to a webserver. Data are posted using a REST API and on the other side, a PHP code running on the server is responsible to validate and store the information in the database.  Finally, information can be accessed from anywhere, either using a plot library or acquired the raw measurements.

The driver application is written in C and is responsible to communicate with the USB interface and decode the weather data according to WH308x protocol:

[sourcecode language=”c”]
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include "hidapi.h"
#include <time.h>
#include <unistd.h>

using namespace std;

float intTemp = 0;
float extTemp = 0;
float intHum = 0;
float extHum = 0;
float windSpeed = 0;
float windDir = 0;
float windGust = 0;
float pressure = 0;
float rain = 0;
float light = 0;
float uv = 0;

void parseWeatherData(unsigned char* buffer){

if (buffer[15] & 0x40){
printf("Error communicating with weather station\n");
return;
}

intHum = buffer[1];
intTemp = (short int)(buffer[2] + buffer[3] * 256) / 10.0;
extHum = buffer[4];
extTemp = (short int)(buffer[5] + buffer[6] * 256) / 10.0;
pressure = (buffer[7] + buffer[8] * 256) / 10.0;
windSpeed = 3.6 * buffer[9] / 10.0;
windGust = 3.6 * buffer[10] / 10.0;
windDir = buffer[12] * 22.5;
rain = buffer[13]* 0.33;
if (buffer[16] != 0xFF && buffer[17] != 0xFF && buffer[18] != 0xFF)
light = (buffer[16] + buffer[17] * 256 + buffer[18] * 65536) / 10.0;
else
light = 0;
uv = buffer[19];

// printf("Inside Temperature %3.2f C\n"
// "Outside Temperature %3.2f C\n"
// "Inside Humidity %3.2f %\n"
// "Ouside Humidity %3.2f %\n"
// "Wind Speed %3.2f Km/h\n"
// "Wind Direction %3.2f\n"
// "Wind Gust %3.2f Km/h\n"
// "Atm. Pressure %3.2f kPa\n"
// "Cum. Rain %3.2f mm\n"
// "Light intesity %3.2f Lux\n",
// intTemp,extTemp,intHum,extHum,windSpeed,windDir,windGust,pressure,rain,light);
printf("ws1=%3.2f&"
"ws2=%3.2f&"
"ws3=%3.2f&"
"ws4=%3.2f&"
"ws5=%3.2f&"
"ws6=%3.2f&"
"ws7=%3.2f&"
"ws8=%3.2f&"
"ws9=%3.2f&"
"ws0=%3.2f",
intTemp,extTemp,intHum,extHum,windSpeed,windDir,windGust,pressure,rain,light);

}

int readAddress(hid_device *handle, unsigned short int address, unsigned char* buffer){
int cnt = 0;

buffer[0] = 0xA1;
buffer[1] = address / 256;
buffer[2] = (address % 256 );
buffer[3] = 0x20;
buffer[4] = 0xA1;
buffer[5] = address / 256;
buffer[6] = (address % 256 );
buffer[7] = 0x20;
buffer[8] = 0x00;

if (hid_write(handle, buffer, 8) < 0){
printf("Error writting hid\n");
return -1;
}

cnt =+ hid_read_timeout(handle, &buffer[0], 8, 200);
cnt =+ hid_read_timeout(handle, &buffer[8], 8, 200);
cnt =+ hid_read_timeout(handle, &buffer[16], 8, 200);
cnt =+ hid_read_timeout(handle, &buffer[24], 8, 200);
#ifdef DEBUG
printf("%4.0d: %2.2X %2.2X %2.2X %2.2X – %2.2X %2.2X %2.2X %2.2X \n",
address, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);
printf("%4.0d: %2.2X %2.2X %2.2X %2.2X – %2.2X %2.2X %2.2X %2.2X \n",
address, buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15]);
printf("%4.0d: %2.2X %2.2X %2.2X %2.2X – %2.2X %2.2X %2.2X %2.2X \n",
address, buffer[16], buffer[17], buffer[18], buffer[19], buffer[20], buffer[21], buffer[22], buffer[23]);
printf("%4.0d: %2.2X %2.2X %2.2X %2.2X – %2.2X %2.2X %2.2X %2.2X \n",
address, buffer[24], buffer[25], buffer[26], buffer[27], buffer[28], buffer[29], buffer[30], buffer[31]);
#endif
return cnt;
}

int main(int argc, char *argv[]){

hid_device *handle;
unsigned char buffer[64];
unsigned int offset, updCount, lastAddress;
int i;

updCount = 0;

handle = hid_open(0x1941, 0x8021, NULL);
if (handle <= 0){
printf("Error opening HID device\n");
hid_close(handle);
return 1;
}

hid_set_nonblocking(handle, 0);

if (readAddress(handle, 0, buffer) < 0){
hid_close(handle);
printf("Error reading HID device\n");
return 1;
}

if (buffer[0] != 0x55 || buffer[1] != 0xAA || buffer[2] != 0xFF || buffer[3] != 0xFF){
printf("Error reading data header %X %X %X %X\n",
buffer[0], buffer[1], buffer[2], buffer[3]);
return 1;
}

lastAddress = buffer[31] * 256 + buffer[30];
// printf ("Weather address: %X\n", lastAddress);

readAddress(handle, lastAddress, buffer);

parseWeatherData(buffer);

hid_close(handle);

return 0;

}

[/sourcecode]

Then a simple bash script can used to POST the data to web sever:

[sourcecode language=”bash”]
#!/bin/bash
# Update Weather data on server

MY_SERVER="www.test.gr"

###########################################################

#Weather address: 7248
#Inside Temperature 31.70 C
#Outside Temperature 29.30 C
#Inside Humidity 32.00 %
#Ouside Humidity 41.00 %
#Wind Speed 5.80 Km/h
#Wind Direction 270.00
#Wind Gust 7.80 Km/h
#Atm. Pressure 1009.00 kPa
#Cum. Rain 0.00 mm
#Light intesity 105082.50 Lux

res=$(/home/user/./ws-weather)

# Update DB
wsr=`curl -X POST -H "User-Agent: Mozilla/5.0" -H "Accept: text/html" -H "Content-Type: text/html" –connect-timeout 3 ${MY_SERVER}/UpdateWeather.php?${res}`

echo $wsr
[/sourcecode]

On the server side, the appropriate page should exist in order to receive the REST request:

[sourcecode language=”php”]
&lt;?php
$url = $_SERVER[‘QUERY_STRING’];
$servername = "localhost";
$username = "my_username";
$password = "my_password";
$dbname = "my_db";

function updWeather() {

parse_str($GLOBALS[‘url’]);

if ($ws1 != ” &amp;&amp; $ws2 != ” &amp;&amp; $ws3 != ” &amp;&amp; $ws4 != ” &amp;&amp; $ws5 != ” &amp;&amp;
$ws6 != ” &amp;&amp; $ws7 != ” &amp;&amp; $ws8 != ” &amp;&amp; $ws9 != ” &amp;&amp; $ws0 != ”) {

mysqli_query( $GLOBALS[‘conn’], "INSERT INTO `weather` (`in_temp`, `out_temp`, `in_hum`, `out_hum`, `wind_speed`, `wind_dir`, `wind_gust`, `pressure`, `rain`, `light`) VALUES (‘$ws1’, ‘$ws2’, ‘$ws3’, ‘$ws4’, ‘$ws5’, ‘$ws6’, ‘$ws7’, ‘$ws8’, ‘$ws9’, ‘$ws0’)");

}
}

// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);

// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}

updWeather();

$conn-&gt;close();
?&gt;
[/sourcecode]

The complete source code can be found under the following GitHub repository: https://github.com/johnkok/weather_station

Leave a Reply