Introduction
Tiny Weather uses the services of Weather Underground and Freegeoip.net, this application only grabs the current weather conditions, but with Weather Underground, you can get a lot more.
We get the weather data in JSON format so we need to use the NewtonSoft.json.dll to parse the data (link below). Getting your location can be as easy as typing it in manually or we can geolocate our location by the freegeoip.net service using your IP address, this data is also in the JSON format.
Also, there will be an additional class added to this project, a wind pointer. This class is a Windows Forms control to display the wind direction, because the wind direction data gives a compass direction. It generally means the wind is coming from that direction, not going to. So to address that, we invert the image in the custom control.
In order to get any weather data at all, you need to grab yourself an API key from weather underground, it's free, but has limits. You may not call the weather more than 500 times in 24 hours and there is a limit to how much weather data you can get using the Stratus Plan (the first free plan for a developer's license).
Download the Newtonsoft.json.dll and place the file inside your application folder.
Screenshots
Main form
Settings form
Using the Code
First, let's add a reference to NewtonSoft.json.dll, in the solution explorer, right mouse click on the application name and select "Add Reference".
Browse to your application folder and select the Newtonsoft.json.dll.
Form 1 has the following items from the toolbox:
- 6 labels
- a picturebox
- 2 buttons
- wind pointer (the added class below)
Let's Code Form 1 First
Now let's import some things:
Imports System
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Public Class Form1
Dim deg As String = Chr(176)
Dim iconKey As String = ""
Dim minuteCounter As Integer = 30
Dim i As Integer = 60
Dim str As String = ""
Dim tmp_locationstr As String
Dim _ApiKey As String
#Region "Conditions"
Public LocationFullName, City, State, StateName, Country, CountryISO, _
Zip, Magic, WMO, Latitude, Longitude, ElevationMeters, ElevationFeet As String
Public StationID, ObservationTime, ObservationTime_RFC822, ObservationEpoch As String
Public LocalTime_RFC822, LocalEpoch, LocalTimeZone_Short, _
LocalTimeZone_Long, LocalTimeZone_Offset As String
Public WeatherDescription, TempreatureString, Temp_F, Temp_C, RelativeHumidity As String
Public WindString, WindDir, WindDegrees, _
WindMPH, WindGustMPH, WindKPH, WindGustKPH As String
Public PressureMB, PressureIN, PressureTrend As String
Public DewpointString, Dewpoint_F, Dewpoint_C As String
Public HeatIndexString, HeatIndex_F, HeatIndex_C As String
Public WindChillString, WindChill_F, WindChill_C As String
Public FeelsLikeString, FeelsLike_F, FeelsLike_C As String
Public Visibiltiy_M, Visibility_K As String
Public SolarRadiation, UVIndex As String
Public PrecipitationString_1HR, Precipitation_1HR_In, _
Precipitation_1HR_Metric, PrecipitationString_Today, _
Precipitation_Today_In, Precipitation_Today_Metric As String
Public IconName, IconURL As String
#End Region
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Timer1.Start()
lclTempUnit.Text = deg & "c"
_ApiKey = My.Settings.apikey
tmp_locationstr = My.Settings.locationstring
GetWeather(_ApiKey)
UpdateLabels()
End Sub
Public Sub GetWeather(ByVal key As String)
Dim req As HttpWebRequest = DirectCast(WebRequest.Create_
("http://api.wunderground.com/api/" & key & _
"/conditions/q/" & tmp_locationstr & ".json"), HttpWebRequest)
Dim res As HttpWebResponse = DirectCast(req.GetResponse(), HttpWebResponse)
Dim reader As New StreamReader(res.GetResponseStream())
Dim serverResponse As String = reader.ReadToEnd
Dim json As String = serverResponse
Dim obj As JObject = JObject.Parse(json)
Try
LocationFullName = obj.SelectToken("current_observation").SelectToken_
("display_location").SelectToken("full")
City = obj.SelectToken("current_observation").SelectToken_
("display_location").SelectToken("city")
State = obj.SelectToken("current_observation").SelectToken_
("display_location").SelectToken("state")
WeatherDescription = obj.SelectToken("current_observation").SelectToken("weather")
TempreatureString = obj.SelectToken("current_observation").SelectToken("temperature_string")
Temp_F = obj.SelectToken("current_observation").SelectToken("temp_f")
Temp_C = obj.SelectToken("current_observation").SelectToken("temp_c")
RelativeHumidity = obj.SelectToken("current_observation").SelectToken("relative_humidity")
WindString = obj.SelectToken("current_observation").SelectToken("wind_string")
WindDir = obj.SelectToken("current_observation").SelectToken("wind_dir")
WindDegrees = obj.SelectToken("current_observation").SelectToken("wind_degrees")
WindMPH = obj.SelectToken("current_observation").SelectToken("wind_mph")
WindGustMPH = obj.SelectToken("current_observation").SelectToken("wind_gust_mph")
WindKPH = obj.SelectToken("current_observation").SelectToken("wind_kph")
WindGustKPH = obj.SelectToken("current_observation").SelectToken("wind_gust_kph")
PressureMB = obj.SelectToken("current_observation").SelectToken("pressure_mb")
PressureIN = obj.SelectToken("current_observation").SelectToken("pressure_in")
PressureTrend = obj.SelectToken("current_observation").SelectToken("pressure_trend")
DewpointString = obj.SelectToken("current_observation").SelectToken("dewpoint_string")
Dewpoint_F = obj.SelectToken("current_observation").SelectToken("dewpoint_f")
Dewpoint_C = obj.SelectToken("current_observation").SelectToken("dewpoint_c")
HeatIndexString = obj.SelectToken("current_observation").SelectToken("heat_index_string")
HeatIndex_F = obj.SelectToken("current_observation").SelectToken("heat_index_f")
HeatIndex_C = obj.SelectToken("current_observation").SelectToken("heat_index_c")
WindChillString = obj.SelectToken("current_observation").SelectToken("windchill_string")
WindChill_F = obj.SelectToken("current_observation").SelectToken("windchill_f")
WindChill_C = obj.SelectToken("current_observation").SelectToken("windchill_c")
FeelsLikeString = obj.SelectToken("current_observation").SelectToken("feelslike_string")
FeelsLike_F = obj.SelectToken("current_observation").SelectToken("feelslike_f")
FeelsLike_C = obj.SelectToken("current_observation").SelectToken("feelslike_c")
Visibiltiy_M = obj.SelectToken("current_observation").SelectToken("visibility_mi")
Visibility_K = obj.SelectToken("current_observation").SelectToken("visibility_km")
SolarRadiation = obj.SelectToken("current_observation").SelectToken("solarradiation")
UVIndex = obj.SelectToken("current_observation").SelectToken("UV")
PrecipitationString_1HR = _
obj.SelectToken("current_observation").SelectToken("precip_1hr_string")
Precipitation_1HR_In = obj.SelectToken("current_observation").SelectToken("precip_1hr_in")
Precipitation_1HR_Metric = _
obj.SelectToken("current_observation").SelectToken("precip_1hr_metric")
PrecipitationString_Today = _
obj.SelectToken("current_observation").SelectToken("precip_today_string")
Precipitation_Today_In = _
obj.SelectToken("current_observation").SelectToken("precip_today_in")
Precipitation_Today_Metric = _
obj.SelectToken("current_observation").SelectToken("precip_today_metric")
IconName = obj.SelectToken("current_observation").SelectToken("icon")
IconURL = obj.SelectToken("current_observation").SelectToken("icon_url")
Catch ex As Exception
End Try
End Sub
Public Sub UpdateLabels()
lblTempMain.Text = Temp_C.ToString
WindSock_A1.Angle = WindDegrees
lblWindSpeed.Text = "Spd: " & WindMPH & ".mph"
lblWindDir.Text = "Dir: " & WindDir.ToString
lblHumidity.Text = "Hm: " & RelativeHumidity.ToString
lblPressure.Text = "Pr: " & PressureIN.ToString & ".in"
Dim icnURL As String = "http://icons.wxug.com/i/c/" & "g" & "/" & IconName & ".gif"
Dim cli As New WebClient
Dim tmpBitmap As Bitmap
tmpBitmap = Bitmap.FromStream(New MemoryStream(cli.DownloadData(icnURL)))
pbIcon.Image = tmpBitmap
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Form2.Show()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
MsgBox("The Weather will update every 30 minutes." & vbCr & _
"Time till next update is: " & minuteCounter & " minutes , " & i & "seconds.", _
MsgBoxStyle.Information, "Help:")
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
i -= 1
Me.Text = "Tiny Weather: " & " " & WeatherDescription & " - " _
& City & " " & i & " " & minuteCounter
If i = 0 AndAlso minuteCounter <= 30 Then
i = 60
minuteCounter -= 1
If minuteCounter <= 0 Then
minuteCounter = 30
GetWeather(_ApiKey)
UpdateLabels()
End If
End If
End Sub
End Class
Form 1 is Done - Let's Move On to form2
As with form 1, we need to import newtonsoft.json to parse the location data from the geolocation service
freegeoip.net.
This form has the following items from the toolbox:
- 2 textboxes
- 3 buttons
- groupbox (optional)
Time to add some settings, go to the project tab and select 'your application name' properties on the left hand panel, select on 'Settings' and add 2 new settings, apikey
as type string and locationstring
as type string leave scope as it is.
Imports System.Net
Imports System.IO
Imports Newtonsoft.Json.Linq
Public Class Form2
Dim _city, _country, _key As String
Private Sub Form2_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
lbl_apikey.ForeColor = Color.Black
txt_apikey.Text = My.Settings.apikey
txt_location.Text = My.Settings.locationstring
End Sub
Private Sub btn_geolocate_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btn_geolocate.Click
Dim _request As HttpWebRequest = DirectCast_
(WebRequest.Create("http://freegeoip.net/json/"), HttpWebRequest)
Dim _response As HttpWebResponse = DirectCast(_request.GetResponse, HttpWebResponse)
Dim _reader As New StreamReader(_response.GetResponseStream())
Dim _ServerResponse As String = _reader.ReadToEnd
Dim _json As String = _ServerResponse
Dim _Jobject As JObject = JObject.Parse(_json)
Try
_city = _Jobject.SelectToken("city")
_country = _Jobject.SelectToken("country_code")
txt_location.Text = _country & "/" & _city
Catch ex As Exception
End Try
End Sub
Private Sub btn_save_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btn_save.Click
If txt_apikey.Text = Nothing Then
lbl_apikey.ForeColor = Color.Red
MsgBox("You need an api key to get the weather.")
Else
lbl_apikey.ForeColor = Color.Black
End If
My.Settings.apikey = txt_apikey.Text
My.Settings.locationstring = txt_location.Text
My.Settings.Save()
End Sub
Private Sub btn_close_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btn_close.Click
Me.Close()
End Sub
End Class
That's form2
done.
Wind Pointer Control Class
It is better to make a new class project for this control.
I make my controls with .NET Framework 2.0.
You need to add the arrow image supplied to the projects resources by going to "project name" properties in the project tab and selecting resources and simply dragging and dropping the arrow image here.
When receiving the wind direction, the wind meteorologically is coming from that direction.
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.IO
Public Class WindSock_A : Inherits Control
Dim myimg As Bitmap
Dim _angle As Single
Dim _p As Pen
Dim _arcColor As Color = Color.DimGray
Dim _pWidth As Single = 1.0F
Dim _spacing As Single = 20.0F
Dim _labelPoints As Boolean = True
Sub New()
MyBase.New()
Me.Width = 100
Me.Height = 100
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
End Sub
Public Property ArcColor() As Color
Get
Return _arcColor
End Get
Set(ByVal value As Color)
_arcColor = value
Me.Invalidate()
End Set
End Property
Public Property Angle() As Single
Get
Return _angle
End Get
Set(ByVal value As Single)
_angle = value
Me.Invalidate()
End Set
End Property
Public Property ArcWidth() As Single
Get
Return _pWidth
End Get
Set(ByVal value As Single)
_pWidth = value
Me.Invalidate()
End Set
End Property
Public Property DrawLabelPoints() As Boolean
Get
Return _labelPoints
End Get
Set(ByVal value As Boolean)
_labelPoints = value
Me.Invalidate()
End Set
End Property
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
e.Graphics.CompositingQuality = CompositingQuality.HighQuality
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
myimg = My.Resources.arrow_100
_p = New Pen(New SolidBrush(_arcColor), _pWidth)
Dim nSize = e.Graphics.MeasureString("N", MyBase.Font)
Dim eSize = e.Graphics.MeasureString("E", MyBase.Font)
Dim sSize = e.Graphics.MeasureString("S", MyBase.Font)
Dim wSize = e.Graphics.MeasureString("W", MyBase.Font)
Dim nPoint As Point = New Point(Me.Width / 2 - _
(CType(nSize.Width, Single) / 2), _spacing - (CType(nSize.Height, Single)))
Dim ePoint As Point = New Point(Me.Width - _spacing, _
Me.Height / 2 - (CType(eSize.Height, Single) / 2))
Dim sPoint As Point = New Point(Me.Width / 2 - _
(CType(sSize.Width, Single) / 2), Me.Height - _spacing)
Dim wPoint As Point = New Point(1 + _spacing - _
(CType(wSize.Width, Single)), Me.Height / 2 - (CType(wSize.Height, Single) / 2))
e.Graphics.DrawArc(_p, _pWidth / 2, _pWidth / 2, _
Me.Width - _pWidth - 1, Me.Height - _pWidth - 1, -90, 360)
myimg.RotateFlip(RotateFlipType.RotateNoneFlipX)
e.Graphics.TranslateTransform(Me.Width / 2, Me.Height / 2)
e.Graphics.RotateTransform(-90 + _angle)
e.Graphics.DrawImage(myimg, -25, -25, 50, 50)
e.Graphics.ResetTransform()
If _labelPoints = True Then
e.Graphics.DrawString_
("N", MyBase.Font, New SolidBrush(MyBase.ForeColor), nPoint)
e.Graphics.DrawString_
("E", MyBase.Font, New SolidBrush(MyBase.ForeColor), ePoint)
e.Graphics.DrawString_
("S", MyBase.Font, New SolidBrush(MyBase.ForeColor), sPoint)
e.Graphics.DrawString_
("W", MyBase.Font, New SolidBrush(MyBase.ForeColor), wPoint)
End If
e.Graphics.Dispose()
_p.Dispose()
End Sub
End Class
After completing the control, build the control, go to the build folder and click and drag the .ddl file into the weather application toolbox.
You can now add the control to your weather application.
Notes
The wind control is named WindSock_A
because I was trying different things.
If you run into any errors running the downloaded project, continue when prompted and go to the settings
button. The error is because the application has started before the API key and location are entered,
once entered, the weather will update after 30 minutes, you won't get that same error when you start the application again but you can tweak the code to prevent this.
History
- 2nd March, 2017: Initial version