About

About the Site

Some stuff about the site - as with my main site, the details are the same:

Site

This is a static HTML site created using Alexis M├ętaireau's Pelican static blog generator with all items starting their life written in reStructuredText.

Theme

Using Daan Debie's pelican-Bootstrap3. I would recommend this as it is very extensible and full of useful configurations options - in short, it is awesome!

In addition because this theme supports bootswatch I am using Thomas Park's simplex bootstrap theme extension.

Graphs

This site makes extensive use of HighCharts, written in JavaScript.

Weather Observation Hardware and Software

Hardware

All the Weather Report data is sampled and provided by a Maplin WH1080 weather station. The Soil Temperature data is collected by my own soil temperature monitoring system, which became operational in late 2014. Data from the various systems is stored and processed by a Raspberry Pi - the credit card sized ARM based single board computer.

Software

The Raspberry Pi runs Raspbian OS as its core operating system. The weather station data is retrieved and collated with the help of pywws software, written and maintained by Jim Easterbrook. All other software functionalities for the data gathering, both on a Pi and a Linux box are provided by a couple of Python based personal projects hosted at Bitbucket.

Code Samples

Below are a few code samples. Have fun.

Dew Point Calculation

Below is a sample of the Python code I use to derive the dew point temperature. It uses two separate samples from the weather station: air temperature and external relative humidity. I am indebted to Rob Tillaart, whose C code I originally borrowed the formula from.

def dewpoint(temperature, humidity):
    """
    Dew point function NOAA - returns dew point, as calculated from
    temperature and relative humidity.

    Reference (1): http://playground.arduino.cc/main/DHT11Lib
    Reference (2): http://wahiduddin.net/calc/density_algorithms.htm
    Reference (3): http://www.colorado.edu/geography/weather_station/Geog_site/about.htm
    """
    try:
        # Cast them, just in case
        tempf = float(temperature)
        humf = float(humidity)
    except ValueError as error:
        return ''
    else:
        # (2) Saturation Vapour Pressure = ESGG(T)
        ratio = 373.15 / (273.15 + tempf)
        rhs = -7.90298 * (ratio - 1)
        rhs += 5.02808 * math.log10(ratio)
        rhs += -1.3816e-07 * (pow(10, (11.344 * (1 - 1/ratio))) - 1)
        rhs += 8.1328e-3 * (pow(10, (-3.49149 * (ratio - 1))) - 1)
        rhs += math.log10(1013.246)

        # factor -3 is to adjust units - Vapour Pressure SVP * humidity
        vapourpressure = pow(10, rhs - 3) * humf;

        # (3) DEWPOINT = F(Vapour Pressure)
        dwpt = math.log(vapourpressure/0.61078)

        # Done
        return (241.88 * dwpt) / (17.558 - dwpt)

Pressure at Station Calibration

In order to keep my weather station relative pressure reading accurate, I get the system to periodically recalibrate against a known and trusted source. In this case, EGNJ, my local airport gives out a METAR information feed, which looks something like this:

EGNJ 301920Z 01009KT 9999 FEW012 SCT016 BKN032 11/09 Q1016

The Qnnnn code at the end of the METAR data above is the current altimeter setting - the mean sea level pressure in millibars (or hPA if you prefer). There are web sites out there which will pick up the METAR feeds and publish them on the net, such as aviatorjoe, the one I use.

import feedparser
import metar.Metar
import math

def pressure_reference(local_alt, airport_code, air_temp=15.0):
    """
    Returns a reference MSLP pressure from a local METAR feed - usually provided
    by a nearby airport.
    local_alt is your weather station altitude from sea level in metres.
    airport_code is the ICAO 4 letter code (in my case, EGNJ).
    air_temp is the local air temperature and defaults to 15C if not supplied
    """
    # Get the MSLP from the METAR feed
    airport = 'http://rss.aviatorjoe.net/3/{0}.rss'.format(airport_code)
    feed = feedparser.parse(airport)
    try:
        summ = feed.entries[0]['summary']
        data = metar.Metar.Metar(summ)
        airport_mslp = data.press.value()
        abs_press = (1-(local_alt*0.0065)/(air_temp+(0.0065*local_alt)+273.15))
        abs_press = abs_press**-5.275
    except Exception:
        return -1
    else:
        return math.ceil(airport_mslp/abs_press*10)/10

The above, is buried in calling code in a file called run.py - this in turn is called by the exceedingly simple script below:

#!/bin/bash

OUTPUT=$(python /home/pi/wsdatproc/run.py press_ref)
if [ $OUTPUT -ne -1 ]
then
  /usr/local/bin/pywws-setweatherstation --pressure $OUTPUT
fi

Environmental Lapse Rate Calculation

As mentioned on the weather report page, this is really just a little bit of fun - there is no intention of presenting the freeze altitude in a scientifically accurate manner implied here. In order to underline the inaccuracy of the whole enterprise, some heavy rounding takes place to keep the numbers looking sensible. There is no point in estimating the freezing level at three thousand metres to the nearest millimetre! Please excuse the code; it is rather mundane and makes a huge number of assumptions.

import math

def calc_elr(air_temp):
    """
    Returns environmental lapse rate dependent on temperature
    See: http://en.wikipedia.org/wiki/Lapse_rate#Environmental_lapse_rate
    Treat this with the caveats within the documentation above.
    elr = 1000/6.49
    """
    if air_temp <= 0.0:
        return 0
    res = round(float(air_temp) * 1000/6.49, 2)
    # Round to nearest 10 if greater than 1000m
    if res > 1000:
        return math.ceil(res / 10.0) * 10
    # Round to nearest 1 if greater than 100m
    if res > 100:
        return math.ceil(res / 1.0) * 1
    # Round to nearest 0.1 if greater than 10m
    if res > 10:
        return round(res, 1)
    return res