Davis WeatherlinkIP API / custom script

A few days ago a friend of mine asked me to help him to program a weather page with weather station details. He purchased Davis Vantage Pro 2 weather station and did not like what the manufacturer provided in the form of the widget for his website. It lacked some basic information. Even though I am not a developer, I’m not afraid to get my hands dirty so I did not mid to look at the API provided by the vendor. Davis Instruments is the maker of one of the best rated home professional weather stations.

Upon reviewing the vendors software I felt like I was teleported 20 years to the past. Their fat client software looks like from the late 90’s. Even the hardware looks and feels old, WeatherlinkIP interface looks like it was programmed by a young 15 year old child. I’m not here not bush their software, but they should really look deeply at their offering and should feel disappointed and even outraged as they have not kept up with the latest technologies.

Fortunately, they now provide fairly solid api via XML and JSON, which on a contrary works very well. Just one simple url call and you will receive all the details in XML or JSON. As they are in the US, the data is provided with the imperial measurements, not metric, even though the rest of the world actually uses metric! Ah… I’m ranting again.

I still poses basic html and php knowledge with a lot of common sense so I started to learn about how to extract data from XML or JSON. XML looked complicated to me, JSON output was for me more understandable and easier to read. Initially, I though using javascript as it was the preferred method of extracting the data, but after few hours digging around I spotted easier and more straightforward data extraction using pure php.

So let me guide you with what I had to go through and what I have came up with

In php, you can grab the content of the JSON file by using the URL very simply:

$json = file_get_contents('https://your url here');

In the case of the Davis Instruments API, it will look similar to:

$json = file_get_contents('https://api.weatherlink.com/v1/NoaaExt.json?user=xxx&pass=xxx&apiToken=7343431a-3434-4279-34344-34344');

You will actually receive the above link directly from the vendor, so you don’t need to recreate it on your own.

The next step is to save the JSON data in a variable:

$obj = json_decode($json);

Viola! Now we have all of the JSON file stored within the $obj!

This part was easy. But what do we do with this data now? Well, it depends. In my case, my friend requested a simple page which can be integrated with his current one and which will show few basic data from the WeatherlinkIP / Davis Instruments Vantage Pro 2 weather station like: wind, temperature, barometer, etc ..

Luckily for me, I have found out that all I just need to do is to store the data in objects within the php and then to display them. So I grabbed the first 3 bits from $obj array:

$stationname = $obj->davis_current_observation->station_name;
$location = $obj->location;
$observationtime = $obj->observation_time;

Let me explain what is happening here. As I am dealing with the JSON data, stored in the $obj, all I have to do is to look at the line which contains the bits I’m after, for example, this is part of the JSON file given via API to me:

observation_time	"Last Updated on Nov 3 2018, 1:58 pm AEDT"
observation_time_rfc822 "Sat, 3 Nov 2018 13:58:58 +1100"
pressure_in "29.956"
pressure_mb "1014.4"
pressure_string "1014.4 mb"

In order to use for example “observation_time” from the JSON array all we need to do is to assing it to a php object:

$observationtime = $obj->observation_time;

I did have an issue initially as the JSON output provided by Davis Instruments had “nested data” and I did not know how to assign data from there to a php object. Here is an example:

davis_current_observation
observation_age 79
dewpoint_day_high_f "57"
dewpoint_day_high_time "2:54pm"
dewpoint_day_low_f "39"

But as you can see above, it was much more easier than I have anticipated. All I had to do is to add another arrow to point to the right data:

$stationname = $obj->davis_current_observation->station_name;

From that point it was very easy to dig all the relevant data from the JSON array ($obj) and assign them to php’s objects:

$temphightime = $obj->davis_current_observation->temp_day_high_time;
$templowtime = $obj->davis_current_observation->temp_day_low_time;

$winddir = $obj->wind_dir;
$winddegrees = $obj->wind_degrees;

That was all good until I got around the data which were provided to me in the imperial format as we wanted to show them in metric only. I have solved it easily:

$tempc = $obj->temp_c;
$tempdayhighf = $obj->davis_current_observation->temp_day_high_f;
$tempdayhighc = ($tempdayhighf - 32) / 1.8;
$tempdaylowf = $obj->davis_current_observation->temp_day_low_f;
$tempdaylowc = ($tempdaylowf - 32) / 1.8;

$kmhtenmin = $obj->davis_current_observation->wind_ten_min_avg_mph * 1.609;
$kmhguststenmin = $obj->davis_current_observation->wind_ten_min_gust_mph * 1.609;

I was even able to calculate addition things like cloudbase:

$dewpoint = $obj->dewpoint_c;
$cloudbase = ((($tempc - $dewpoint) / 2.5) * 304.8) + 900;

The formula is from the internet, but I have confirm that it’s very acurrate. The last number - 900, is the station heigh in meters, so you have to adjust it depending how high is your Davis Instruments weather station.

Once I have created all the objects, I started to write simple HTML to show all the relevant data. We only needed basic table, nothing fancy, but I did wanted to spruce it up with some icons and as I use font awesome on this page, I knew it could be very useful so I have included code to show some font awesome icons (free only).

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">

Awesome! I have even added meta tag to refresh the page automatically every 60 seconds. The whole process took me most of the day with one evening “studying” and learning how to approach data extraction from XML or JSON. No fancy javascript involved, not special skills needed. Let me say it again - I’m not a developer, I prefer IT management and System Administration. But I do love to tinker with the code occasionally. Here is the full code I came up with (substitute $json = file_get_contents URL with yours):

<?php

$json = file_get_contents('https://api.weatherlink.com/xxxxxxx');
$obj = json_decode($json);

$stationname = $obj->davis_current_observation->station_name;
$location = $obj->location;
$observationtime = $obj->observation_time;

$tempc = $obj->temp_c;
$tempdayhighf = $obj->davis_current_observation->temp_day_high_f;
$tempdayhighc = ($tempdayhighf - 32) / 1.8;
$tempdaylowf = $obj->davis_current_observation->temp_day_low_f;
$tempdaylowc = ($tempdaylowf - 32) / 1.8;

$temphightime = $obj->davis_current_observation->temp_day_high_time;
$templowtime = $obj->davis_current_observation->temp_day_low_time;

$winddir = $obj->wind_dir;
$winddegrees = $obj->wind_degrees;

$windspeedkmh = $obj->wind_mph * 1.609;

$kmhtenmin = $obj->davis_current_observation->wind_ten_min_avg_mph * 1.609;
$kmhguststenmin = $obj->davis_current_observation->wind_ten_min_gust_mph * 1.609;

$humidity = $obj->relative_humidity;
$feelslike = $obj->windchill_c;

$raindailyin = $obj->davis_current_observation->rain_day_in;
$raindaily = $raindailyin * 25.4;
$rainseasonin = $obj->davis_current_observation->rain_year_in;
$rainseason = $rainseasonin * 25.4;

$barometer = $obj->pressure_string;
$barometertendency = $obj->davis_current_observation->pressure_tendency_string;

$dewpoint = $obj->dewpoint_c;
$cloudbase = ((($tempc - $dewpoint) / 2.5) * 304.8) + 900;

$sunrise = $obj->davis_current_observation->sunrise;
$sunset = $obj->davis_current_observation->sunset;
?>

<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="60" >
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
</head>

<body>

<center>

<table width="600px">
<tbody align="left">
<tr>
<td colspan="3"><h3>Station Name: <?php echo $stationname ?></h3></td>
</tr>
<tr>
<td colspan="3"><b>Location: <?php echo $location; ?></b></td>
</tr>
<tr>
<td colspan="3"><b><?php echo $observationtime; ?></b></td>
</tr>
<tr>
<td>&nbsp;</td>
</tr>
</tbody>

<tbody>
<tr>
<td width="25"><i class="fa fa-compass" style="font-size:25px;"></i></td>
<td width="45%"><b>Wind Direction:</b></td>
<td width="45%"> <?php echo $winddir; ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-compass" style="font-size:25px;"></i></td>
<td width="45%"><b>Wind Degrees:</b></td>
<td width="45%"><?php echo $winddegrees ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-wind" style="font-size:25px;"></i></td>
<td width="45%"><b>Wind Speed (kmh):</b></td>
<td width="45%"><?php echo round($windspeedkmh,1) ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-arrows-alt-h" style="font-size:25px;"></i></td>
<td width="45%"><b>Wind 10 min AVG (kmh):</b></td>
<td width="45%"><?php echo round($kmhtenmin,1); ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-arrow-up" style="font-size:25px;"></i></td>
<td width="45%"><b>Wind 10 min gust (kmh):</b></td>
<td width="45%"><?php echo round($kmhguststenmin,1); ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-cloud" style="font-size:25px;"></i></td>
<td width="45%"><b>Estimated Cloudbase:</b></td>
<td width="45%"><?php echo round($cloudbase,0); ?> meters</td>
</tr>
<tr>
<td width="10%"><i class="fa fa-thermometer-half" style="font-size:25px;"></td>
<td width="45%"></i><b>Temperature (C):</b></td>
<td width="45%"><?php echo $tempc; ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-temperature-high" style="font-size:25px;"></i></td>
<td width="45%"><b>Temperature HIGH (day):</b></td>
<td width="45%"><?php echo round($tempdayhighc,1); ?> at <?php echo $temphightime; ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-temperature-low" style="font-size:25px;"></i></td>
<td width="45%"><b>Temperature LOW (day):</b></td>
<td width="45%"><?php echo round($tempdaylowc,1); ?> at <?php echo $templowtime; ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-grin-beam-sweat" style="font-size:25px;"></i></td>
<td width="45%"><b>Humidity:</b> <?php echo $humidity; ?>%</td>
<td width="45%"><b>Feels like:</b> <?php echo $feelslike; ?></td>
</tr>
<tr>
<td width="25"><i class="fa fa-cloud-rain" style="font-size:25px;"></i></td>
<td width="45%"><b>Rain past 24hrs:</b></td>
<td width="45%"><?php echo round($raindaily,1); ?>&nbsp;mm</td>
</tr>
<tr>
<td width="25"><i class="fa fa-tint" style="font-size:25px;"></i></td>
<td width="45%"><b>Seaonal total:</b></td>
<td width="45%"><?php echo round($rainseason,1); ?>&nbsp;mm</td>
</tr>
<tr>
<td width="25"><i class="fa fa-chart-bar" style="font-size:25px;"></i></td>
<td width="45%"><b>Barometer:</b> <?php echo $barometer; ?></td>
<td width="45%"> <?php echo $barometertendency; ?></td>
</tr>
<tr>
<td colspan="3">&nbsp;</td>
</tr>
<tr>
<td width="2%">&nbsp;</td>
<td width="49%"><i class="fa fa-sun" style="font-size:25px;"></i>&nbsp; <b>Sunrise:</b> <?php echo $sunrise; ?></td>
<td width="49%"><i class="fa fa-sun" style="font-size:25px;"></i>&nbsp; <b>Sunset:</b> <?php echo $sunset; ?></td>
</tr>
</tbody>
</table>

<i><br/>Script &copy Oliver Bross MBA -> <a href="https://www.oliverbross.com" target="_blank">www.oliverbross.com</a></i>
</center>

</body>

</html>

Let me know if you would do a different / better aproach. I had to learn how to round numbers in PHP as well, lol. The above code works very well for me and can be used for any weather station purchased from Davis Instruments.