How to create a Raspberry PI frost alert using a weather api

In this tutorial we will create a simple frost alert using a Raspberry PI and the Visual Crossing Timeline Weather API. The aim of the simple circuit is to use colored LED lights to inform the user if frost or low temperatures are expected. A red light indicates below freezing temperatures are expected, yellow light means low temperatures are expected and a green light means there are no cold temperatures expected.

If you would like to download the complete source code, you can find it on our GitHub: at https://github.com/visualcrossing/WeatherApi/blob/master/RaspberryPi/frostwarning.py

Steps to build the frost alert

We will be focusing on the technologies involved to create our frost alert and therefore we want to keep things simple. We will be using a network enabled, Raspberry PI that runs a Python script to download the 15 day weather forecast. When there is a temperature below freezing (32F or 0C) forecast, we will shine a red LED light. When the temperature is predicted to be below 40F (around 4.5C), we will show an orange light. Finally we’ll shine a green LED if the temperature is above 40F.

If you would prefer to work in metric units, then you can easily tweak some of the set up variables to indicate metric temperature (Celcius) and a freezing threshold of 0C and a cold threshold of 4C.

Step one – create a simple circuit to drive three LED lights

We will assume you are familiar with the basics of operating a Raspberry PI device and wiring simple circuits. If not, head over the one of the great Raspberry PI tutorials. You can use any Raspberry PI providing that it is network enabled (so we can download the weather data) and can run Python 3 scripts (Python 2 should work too but you’ll have to modify the script a little to make it run).

We will be using three GPIO pins to drive our LEDS – 23, 24 and 25 for red, yellow and green colors respectively.

For each port, we connect a LED and a resistor (don’t forget the resistor otherwise you’ll risk damaging the LED or board). Then each are connected to the common ground (pin 6 in our case).

Step two – create a Python script to download the weather forecast data

Now we have our simple circuit, we are ready to create a Python script to download the weather forecast and check for freezing temperatures.

Before we write our script, let’s take a look at a sample Timeline API call to retrieve the weather forecast for ‘Chicago, IL’ in the USA. The call is very simple – include the encoded location in the path and then add your API key to the key parameter.

https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/Chicago%2CIL?unitGroup=us&key=YOUR_API_KEY

If you don’t have an API key yet, head over to Visual Crossing Weather Data Services to sign up for you free account – you will be able to make up to 1000 requests for free every day. You can also create Timeline API requests interactively directly within the tool and explore the JSON output.

We can now write the script we’ll need. At the top, we’ll had the libraries we’ll use:

import RPi.GPIO as GPIO
import urllib.parse
import urllib.request
import json
import time

For simplicity, we’ll set the parameters we need as variables:

UPDATEINTERVAL=5
API_KEY=”YOUR_API_KEY”
LOCATION=”New York City,NY”
FREEZING_TEMP=32
COLD_TEMP=40
UNIT_GROUP=”us”

If you prefer to work in metric, change the UNIT_GROUP to metric and the freezing and cold temperature thresholds to 0 and 4 respectively.

Our first function is the call to retrieve the data from the Weather API:

def getWeatherForecast():
         requestUrl = "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/" + urllib.parse.quote_plus(LOCATION) + "?key="+API_KEY+"&unitGroup="+UNIT_GROUP;
         try:
                 req = urllib.request.urlopen(requestUrl)
         except:
                 print("Could not read from:"+requestUrl);
                 return []
         rawForecastData = req.read()
         req.close()
         return json.loads(rawForecastData)

This method constructs the Weather API request using the location, API Key and unit group selected in the parameters. Then we submit the Weather API request and, assuming no errors, we parse the result as JSON so we can read the minimum temperatures predicted.

We now set up a loop to continuously retrieve the weather data, wait and then try again.

def main():
  while True:
    print("Fetching forecast...")
    
//retrieve the forecast
    weatherForecast = getWeatherForecast()
    if ('days' not in weatherForecast):
      print("Problem retrieving forecast")
    else:
//retrieve the days array 
      days=weatherForecast['days'];
      nextColdDayIndex=-1;
      nextFreezingDayIndex=-1;
      totalFreezingDays=0;
//loop through the days, checking the tempmin property
      for dayIndex in range(len(days)):
        tempmin=days[dayIndex]['tempmin'];
        if tempmin<FREEZING_TEMP:
          totalFreezingDays=totalFreezingDays+1;
          if nextFreezingDayIndex==-1:
            nextFreezingDayIndex=dayIndex;

        if tempmin<COLD_TEMP and nextColdDayIndex==-1:
          nextColdDayIndex=dayIndex;

//print the results
      if nextFreezingDayIndex!=-1:
        print("Freezing day:"+str(nextFreezingDayIndex)+", temp="+str(days[nextFreezingDayIndex]['tempmin']))

      if nextColdDayIndex!=-1:
        print("Cold day:"+str(nextColdDayIndex)+", temp="+str(days[nextColdDayIndex]['tempmin']))

//wait and then try again
    try:
      time.sleep(UPDATEINTERVAL)
    except KeyboardInterrupt:
      break
 
 

//call main to start the script
main();

In this simple case, we look at the ‘days’ property of the Weather Forecast JSON and, from there, examine the ‘tempmin’ property. This is the minimum temperature predicted for each day. We record the first day where the temperature will be below our FREEZING_TEMP threshold and the first day when it will be below the COLD_TEMP threshold. For more information on the output JSON structure, take a look at the Timeline API documentation.

After printing the status to the console, we wait for the ‘UPDATEINTERVAL’ number of seconds and then repeat the process

Step three – based on the weather forecast, enable the appropriate LED warning and status lights.

The above script retrieves the weather forecast but only prints out the results to the console. To finish our simple frost alert project, we need to drive some LEDs.

To do this, we simply add the appropriate logic to the GPIO pins. At the start of our script, we initialize the pins:

GPIO.setmode(GPIO.BCM)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
GPIO.setup(25,GPIO.OUT)

We set the pins to high and low, depending on our frost detection. Setting the pin high, will drive a signal through the LED to light them up:

GPIO.output(23,GPIO.HIGH)

Here is the full script:

def main():
  while True:
    print("Fetching forecast...")
//turn on all the LEDs when retrieving the data
    GPIO.output(23,GPIO.HIGH)
    GPIO.output(24,GPIO.HIGH)
    GPIO.output(25,GPIO.HIGH)

    weatherForecast = getWeatherForecast()
    if ('days' not in weatherForecast):
      print("Problem retrieving forecast")
    else:
      days=weatherForecast['days'];
      nextColdDayIndex=-1;
      nextFreezingDayIndex=-1;
      totalFreezingDays=0;
      for dayIndex in range(len(days)):
        tempmin=days[dayIndex]['tempmin'];
        if tempmin<FREEZING_TEMP:
          totalFreezingDays=totalFreezingDays+1;
          if nextFreezingDayIndex==-1:
            nextFreezingDayIndex=dayIndex;
        if tempmin<COLD_TEMP and nextColdDayIndex==-1:
          nextColdDayIndex=dayIndex;


      if nextFreezingDayIndex!=-1:
        print("Freezing day:"+str(nextFreezingDayIndex)+", temp="+str(days[nextFreezingDayIndex]['tempmin']))
        GPIO.output(23,GPIO.HIGH)
      else:
        GPIO.output(23,GPIO.LOW)

      if nextColdDayIndex!=-1:
        print("Cold day:"+str(nextColdDayIndex)+", temp="+str(days[nextColdDayIndex]['tempmin']))
        GPIO.output(24,GPIO.HIGH)
      else:
        GPIO.output(24,GPIO.LOW)

      if nextColdDayIndex==-1 and nextFreezingDayIndex==-1:
        GPIO.output(25,GPIO.HIGH)
      else:
        GPIO.output(25,GPIO.LOW)
      print("Total freezing days:{0}".format(totalFreezingDays));
    try:
      time.sleep(UPDATEINTERVAL)
    except KeyboardInterrupt:
      break
 
 //turn off all the LEDs before exiting
  GPIO.output(23,GPIO.LOW)
  GPIO.output(24,GPIO.LOW)
  GPIO.output(25,GPIO.LOW)

main();

Final thoughts

We’ve created a very simple Raspberry PI based frost alarm by simply connecting to the Visual Crossing Weather API, downloading the 15 day weather forecast and if any of those days will be below freezing (or cold), we display the results in LEDs to indicate the risk.

Using Weather APIs in Python and Raspberry PI in this manner is very straightforward. It would be straightforward to extend this to look at other information in weather forecast such as high temperature, wind, rain or snow fall and many other weather variables. You could also look back to historical observations and beyond the 15 day weather forecast to consider statistical normals for any day in the future.

Questions or need help?

If you have a question or need help, please post on our actively monitored forum for the fastest replies. You can also contact us via our support site or drop us an email at support@visualcrossing.com.