Weather Display

by phidgeteer in Circuits > Electronics

2161 Views, 16 Favorites, 0 Comments

Weather Display

Weather Display

In this project, we will be using an online weather service to display local weather and time on a Graphic LCD Phidget (LCD1100). Code is available for this project in C# and Python.

Supplies

lcdweather_parts.jpg

The following hardware is used:

  • VINT Hub Phidget (HUB0000_0)
  • Graphic LCD Phidget (LCD1100_0)

Setup

lcdweather_setup.jpg

Connect your Graphic LCD Phidget to your VINT Hub on any port.

Overview

lcdweather_Flow.jpg

As shown above, there are two main parts of this project:

  1. Accessing weather data
  2. Displaying weather data

Let's start by taking a look at accessing the data.

Accessing Weather Data

openweather.PNG

We will be using OpenWeather to access our local weather forecast. They provide free access to weather forecasts in over 200,000 cities. The following formats are supported:

  • JSON
  • XML
  • HTML

For this project, we will be using XML format.


In order to access weather data, you must create a free account and get an API key.

Create Your Account

weather_xml.PNG

Follow this link to create a free account and get an API key. After getting your API key, you will can access data through this URL:

api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}

Replace {city name} with your city, and {API key} with your API key. For example, this is what ours looks like:

http://api.openweathermap.org/data/2.5/weather?q=Calgary&APPID=fakeid111111111111111111111111111&units=metric&mode=xml

Try entering your URL into any web browser. You will see XML formatted weather data as shown above. The next step is creating a program that can parse the data so it can be displayed.

Read/Parse Weather Data - C#

For C#, you can use the XMLTextReader class to quickly parse the XML data:

static string readXML(string arg1, string arg2)
{
    String URLString = "http://api.openweathermap.org/data/2.5/weather?q=Calgary&APPID=fakeid111111111111111111111111111&units=metric&mode=xml";
    XmlTextReader reader = new XmlTextReader(URLString);
    reader.ReadToFollowing(arg1);
    reader.MoveToAttribute(arg2);
    return reader.Value;
}

You can use the function above like this:

static void updateWeather(LCD lcd) {
	string city = readXML("city", "name");
	string temperature = readXML("temperature", "value");
	string humidity = readXML("humidity", "value");
	string windspeed = readXML("speed", "value");
	string descript = readXML("weather", "value");
	string iconID = readXML("weather", "icon");
}

There are other values available (sunrise time, sunset time, pressure, etc.) but for this project, we will only be displaying a subset of the values.

Read/Parse Weather Data - Python

For Python, you can use the ElementTree XML API to quickly parse the data:

import xml.etree.ElementTree as ET
from urllib.request import urlopen

url = urlopen('http://api.openweathermap.org/data/2.5/weather?q=Calgary&APPID=fakeid111111111111111111111111111&units=metric&mode=xml')
tree = ET.parse(url)
root = tree.getroot()

def readXML(arg1, arg2):
    for item in root.iter(arg1):
        return item.get(arg2)

print(readXML('city','name'))
print(readXML('temperature','value'))
print(readXML('humidity','value'))
print(readXML('speed','value'))
print(readXML('weather','value'))
print(readXML('weather','icon'))

There are other values available (sunrise time, sunset time, pressure, etc.) but for this project, we will only be displaying a subset of the values.

OpenWeather Icons

piskel.PNG

You may have noticed that we stored the iconID above. This value represents an image describing the current weather. You can view the icons here. The Graphic LCD Phidget is capable of displaying bitmaps, we can easily implement these icons in our program. If you haven't explored bitmaps on the Graphic LCD Phidget, check out this project.

There are many pixel art programs available online, we used Piskel. It was easy to recreate the OpenWeatherMap icons because of the simple Export to C File option. The results of the bitmaps are provided in the github repo below.

Displaying Data - C#

lcdweather_working.jpg

Now that we have collected the weather data, the last step is to display it on the Graphic LCD Phidget:

static void updateWeather(LCD lcd)
{
    string city = readXML("city", "name");
    string temperature = readXML("temperature", "value");
    string humidity = readXML("humidity", "value");
    string windspeed = readXML("speed", "value");
    string descript = readXML("weather", "value");
    string iconID = readXML("weather", "icon");
    if (temperature.Length > 5)
    {
        temperature = temperature.Remove(5);
    }   
    //Temperature box
    int x = (44 - ((temperature.Length * 6) + 12)) / 2;
    lcd.WriteText(LCDFont.Dimensions_6x12, x, 15, temperature);
    lcd.WriteText(LCDFont.User1, x + temperature.Length * 6, 15, "0");
    lcd.WriteText(LCDFont.Dimensions_6x12, x + temperature.Length * 6 + 6, 15, "C");
    //Weather image + descript box
    byte[] temp;
    if (iconID == "01d")
        temp = _01d;
    else if (iconID == "02d")
        temp = _02d;
    else if (iconID == "03d")
        temp = _03d;
    else if (iconID == "04d")
        temp = _04d;
    else if (iconID == "09d")
        temp = _09d;
    else if (iconID == "10d")
        temp = _10d;
    else if (iconID == "11d")
        temp = _11d;
    else if (iconID == "13d")
        temp = _13d;
    else if (iconID == "50d")
        temp = _50d;
    else if (iconID == "01n")
        temp = _01n;
    else if (iconID == "02n")
        temp = _02n;
    else if (iconID == "10n")
        temp = _10n;
    else
        temp = unknown;

    lcd.WriteBitmap(2, 31, 32, 32, temp);
    lcd.WriteText(LCDFont.Dimensions_5x8, 40, 42, descript);

    //Extra info box
    lcd.WriteText(LCDFont.Dimensions_5x8, 50, 11, "Humidity: " + humidity + "%");
    lcd.WriteText(LCDFont.Dimensions_5x8, 50, 20, "Wind: " + windspeed + "km/h");
}
static void redraw(LCD lcd)
{
    lcd.Clear();
    //draw borders around outside
    lcd.DrawLine(0, 0, 127, 0);
    lcd.DrawLine(0, 0, 0, 63);
    lcd.DrawLine(127, 0, 127, 63);
    lcd.DrawLine(0, 63, 127, 63);

    //draw borders inside
    lcd.DrawLine(0, 10, 128, 10);
    lcd.DrawLine(43, 10, 43, 30);
    lcd.DrawLine(1, 30, 127, 30);
    lcd.WriteText(LCDFont.Dimensions_5x8, 1, 1, DateTime.Now.ToString(" ddd, MMM d hh:mm:ss tt"));
    updateWeather(lcd);
    lcd.Flush();
}<br>

Here is a quick review of the code above:

redraw

This function draws the main borders on the Graphic LCD. It also prints the current time and calls the updateWeather program.

updateWeather

This function arranges the data from the OpenWeather service onto the Graphic LCD.

Displaying Data - Python

Now that we have collected the weather data, the last step is to display it on the Graphic LCD Phidget:

def updateWeather():
    city = readXML('city', 'name')
    temperature = readXML('temperature', 'value')
    humidity = readXML('humidity', 'value')
    windspeed = readXML('speed', 'value')
    descript = readXML('weather', 'value')
    iconID = readXML('weather', 'icon')
    if(len(temperature) > 5):
        temperature = temperature[:-1:] #remove last char so it fits
    #temperature box
    x = (44 - ((len(temperature) * 6) + 12)) / 2
    x = int(x) #force to int
    lcd.writeText(LCDFont.FONT_6x12, x, 15, temperature)
    lcd.writeText(LCDFont.FONT_User1, x + len(temperature) * 6, 15, "0")
    lcd.writeText(LCDFont.FONT_6x12, x + len(temperature) * 6 + 6, 15, "C")

    #Weather icon + descript box
    temp = []
    if(iconID == "01d"):
        temp = _01d
    elif(iconID == "02d"):
        temp = _02d
    elif (iconID == "03d"):
        temp = _03d
    elif (iconID == "04d"):
        temp = _04d
    elif (iconID == "09d"):
        temp = _09d
    elif (iconID == "10d"):
        temp = _10d
    elif (iconID == "11d"):
        temp = _11d
    elif (iconID == "13d"):
        temp = _13d
    elif (iconID == "50d"):
        temp = _50d
    elif (iconID == "01n"):
        temp = _01n
    elif (iconID == "02n"):
        temp = _02n
    elif (iconID == "10n"):
        temp = _10n
    else:
        temp = unknown

    lcd.writeBitmap(2, 31, 32, 32, temp)
    lcd.writeText(LCDFont.FONT_5x8, 40, 42, descript)

    #Extra info box
    lcd.writeText(LCDFont.FONT_5x8, 50, 11, "Humidity: " + humidity + "%")
    lcd.writeText(LCDFont.FONT_5x8, 50, 20, "Wind: " + windspeed + "km/h")

def redraw():
    lcd.clear()
    #Draw borders around outside
    lcd.drawLine(0, 0, 127, 0)
    lcd.drawLine(0, 0, 0, 63)
    lcd.drawLine(127, 0, 127, 63)
    lcd.drawLine(0, 63, 127, 63)

    #draw borders inside
    lcd.drawLine(0, 10, 128, 10)
    lcd.drawLine(43, 10, 43, 30)
    lcd.drawLine(1, 30, 127, 30)

    timeStr = datetime.now().strftime("%a, %b %d %I:%M:%S %p")
    lcd.writeText(LCDFont.FONT_5x8, 1, 1, timeStr)
    updateWeather()
    lcd.flush()<br>

Here is a quick review of the code above:
redraw

This function draws the main borders on the Graphic LCD. It also prints the current time and calls the updateWeather program.

updateWeather

This function arranges the data from the OpenWeather service onto the Graphic LCD.

Main Loop

The last thing to do is to create a main loop that updates the LCD on a set schedule. Here is what we recommend:

  1. Every second: update the time on the LCD
  2. Every 15 minutes: update the weather status on the LCD

Create an infinite loop that loops every second. Create a counter to track the loops, when the counter hits 900 (900 seconds is 15 minutes) update the weather.

Going Forward

The full code for this project is available here: https://github.com/phidgeteer/LCDWeather.git

If you have any questions, drop a comment below!