Introduction
This is a set of tools that was developed to make it easier to keep track of the Real Time Price of ComEd electricity. As part of this project, a single DLL for pulling the data from an AJAX source was used for both .NET and .NET CF so that multiple separate sources aren't needed.
Background
This project came about because there was a need for me to be able to monitor the real time price of electricity. ComEd didn't provide any such tools to do this. When I started the project, I wanted to have an application for my phone as well as my desktop. I only wanted to have to write the code once for both platforms. Thus, I wrote a module that pools the ComEd server, which is used for their AJAX web page, for the pricing information. The module is written in such a way that it can be compiled for either .NET or .NET CF.
Using the Code
Using the code is quite easy. A simple call to GetRTP
will return the price in a structure called RTPData
. The structure contains the time of the last price update, the current price, the predicted time, and the predicted price.
In addition to the GetRTP
function, there is a function that will parse the response stream. That function is quite basic, and the GetRTP
function simply uses a WebRequest
to get the pricing data from the ComEd server.
Public Function GetRTP() As RTPData
Dim myRTPData As RTPData
Dim randomNumber As New Random
Dim myWebRequest As HttpWebRequest
Dim myResponseStream As System.IO.Stream = Nothing
Dim strRequest As String = "http://il.thewattspot.com/dwr/exec/rtp.getRTP?" & _
"callCount=1&c0-scriptName=rtp&c0-methodName=getRTP&c0-id=" & _
randomNumber.Next.ToString.Substring(0, 4) & _
"_" & DateTime.Now.Ticks.ToString.Substring(0, 13) & _
"&xml=true"
Dim objReader As System.IO.StreamReader = Nothing
Try
myWebRequest = WebRequest.Create(strRequest)
myResponseStream = myWebRequest.GetResponse.GetResponseStream
Dim strLine As String = ""
objReader = New System.IO.StreamReader(myResponseStream)
If objReader.Peek >= 0 Then
ParseResponse(objReader.ReadLine, myRTPData)
End If
myResponseStream.Close()
Catch ex As Exception
End Try
If myResponseStream IsNot Nothing Then myResponseStream.Close()
If objReader IsNot Nothing Then objReader.Close()
Return myRTPData
End Function
Displaying the Results
Both the .NET and the .NET CF version of the program display the data color coded. I've never tried to create graphics on the fly before, this was my first attempt. I must admit, there is a very small memory leak somewhere in the code, and I think it is here, but I can't find it. It doesn't seem to matter much because I've run the code for days without having memory problems.
The routine to create the tray icon used by the .NET version of the program will draw a pair of colored boxes and write text over them.
Private Sub CreateTextIcon(ByVal strPrice As String, _
ByVal sglPredictedPrice As Single)
tmrExtremePrice.Stop()
Dim fontPrice As Font = New Font("Microsoft Sans Serif", _
9, FontStyle.Regular, GraphicsUnit.Pixel)
Dim brushPrice As Brush = New SolidBrush(Color.Black)
Dim brushBackground As SolidBrush
Dim gIcon As Graphics = Drawing.Graphics.FromImage(bmpIcon)
Dim gAltIcon As Graphics = Drawing.Graphics.FromImage(bmpAltIcon)
Dim hIcon As IntPtr
Dim intTemp As Integer
Dim drawRectange As New Rectangle(0, 0, 16, 16)
Dim stringFormat As New StringFormat()
stringFormat.Alignment = StringAlignment.Center
stringFormat.LineAlignment = StringAlignment.Center
intTemp = strPrice * 32
If strPrice > 8 Then
If intTemp > 255 Then
brushBackground = New SolidBrush(Color.FromArgb(255, 255, 0, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb(0, 255, 0, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
tmrExtremePrice.Start()
Else
brushBackground = New SolidBrush(Color.FromArgb _
(255, 255, 255 - intTemp, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb _
(255, 255, 255 - intTemp, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
End If
ElseIf strPrice < 8 Then
brushBackground = New SolidBrush(Color.FromArgb(255, intTemp, 255, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb(255, intTemp, 255, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
Else
brushBackground = New SolidBrush(Color.FromArgb(255, 255, 255, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb(255, 255, 255, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 0, 16, 8))
brushBackground.Dispose()
End If
intTemp = sglPredictedPrice * 32
If sglPredictedPrice > 8 Then
If intTemp > 255 Then
brushBackground = New SolidBrush(Color.FromArgb(255, 255, 0, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb(0, 255, 0, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
tmrExtremePrice.Start()
Else
brushBackground = New SolidBrush(Color.FromArgb _
(255, 255, 255 - intTemp, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb _
(255, 255, 255 - intTemp, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
End If
ElseIf sglPredictedPrice < 8 Then
brushBackground = New SolidBrush(Color.FromArgb(255, intTemp, 255, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb(255, intTemp, 255, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
Else
brushBackground = New SolidBrush(Color.FromArgb(255, 255, 255, 0))
gIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
brushBackground = New SolidBrush(Color.FromArgb(255, 255, 255, 0))
gAltIcon.FillRectangle(brushBackground, New Rectangle(0, 8, 16, 8))
brushBackground.Dispose()
End If
gIcon.DrawString(strPrice, fontPrice, brushPrice, drawRectange, stringFormat)
gAltIcon.DrawString(strPrice, fontPrice, brushPrice, drawRectange, stringFormat)
hIcon = bmpIcon.GetHicon
notifyPrice.Icon = Drawing.Icon.FromHandle(hIcon)
DestroyIcon(hIcon)
fontPrice.Dispose()
brushPrice.Dispose()
gIcon.Dispose()
gAltIcon.Dispose()
stringFormat.Dispose()
End Sub
The above code actually creates two icons: one for displaying, and if the price is extremely high, one for blinking. Both icons have two rectangles of color on them depending on the price. Over the colors is a bit of text. This way, the icon can change as the price does, providing an easy way to keep track of the price of electricity.
Points of Interest
The biggest hurdle that I had to deal with in this program is finding the memory leaks. Working with GDI is quite a challenge in .NET. One would think that managed code would do better at tracking allocated resources and cleaning up after itself, or at least that Visual Studio would alert you when it can't clean up after itself.
History
- 22-Dec-2009 - Initial release (contains a few small bugs).