The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
I am going to be building a project which notifiers the user by raising a flag when a gmail message is found.
First I needed to create a php website that displays the number of unread messages for me. The site is located here: MY SITE The reason you need a site to host this is that the netduino plus doesn't handle ssl which the majority of email providers such as google require. The site is a middle man. This solution is nicer than running your own server / program on another computer because you do not depend on this additional computer.
The website give you a string like this which can be read by the netduino using a function while will be talked about in the next post.
Here is the c# code which holds 2 of my miscellaneous functions.
using System;
using Microsoft.SPOT;
using System.Net;
using System.IO;
using System.Text;
using Toolbox.NETMF;
namespace EmailStockChecker
{
public static class clMisc
{
public static string GetStringInBetween(string strBegin, string strEnd, string strSource)
{
string result = "";
int iIndexOfBegin = strSource.IndexOf(strBegin);
if (iIndexOfBegin != -1)
{
strSource = strSource.Substring(iIndexOfBegin
+ strBegin.Length);
int iEnd = strSource.IndexOf(strEnd);
if (iEnd != -1)
{
result = strSource.Substring(0, iEnd);
}
}
else
// stay where we are
result = strSource;
return result;
}
public static string GetOnlineWebPage(string url)
{
// used to build entire input
StringBuilder sb = new StringBuilder();
// used on each read operation
byte[] buf = new byte[8192];
// prepare the web page we will be asking for
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
// execute the request
HttpWebResponse response = (HttpWebResponse)
request.GetResponse();
// we will read data via the response stream
Stream resStream = response.GetResponseStream();
string tempString = null;
int count = 0;
do
{
// fill the buffer with data
count = resStream.Read(buf, 0, buf.Length);
// make sure we read some data
if (count != 0)
{
// translate from bytes to ASCII text
//tempString = Encoding.ASCII.GetString //(buf, 0, count);
tempString = new string(Tools.Bytes2Chars(buf));
// continue building the string
sb.Append(tempString);
}
}
while (count > 0); // any more data to read?
return sb.ToString();
}
}
}
The getStringInBetween function returns a string between 2 user inputted strings. This is useful in conjunction with the second function. getOnlineWebPage function returns a page as a string.
The second function allows netduino to pull data from an html page such as http://smarcus3.x10.mx/ and return it as a string. The first function allows you to basically parse up this data into useful chunks.
My project is almost completely together. There is a LCD which displays stock data on it and a servo which raises based on if there is an unread email message or not. Here are 3 pictures which show the arm raising, kinda. The pictures also show the stock data which is formatted like this.
TICKER Current Price
Change Percent Change
Daily Change
Total Value
Below is all of my code. If anyone would like an explanation on how something works just let me know and I can explain any part.
Program.cs
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using FusionWare.SPOT.Hardware;
using MicroLiquidCrystal;
using System.Diagnostics;
using Servo_API;
namespace EmailStockChecker
{
public class Program
{
public static void Main()
{
//LCD SECCTION
// initialize i2c bus (only one instance is allowed)
var bus = new I2CBus();
// initialize provider (multiple devices can be attached to same bus)
var lcdProvider = new MCP23008LcdTransferProvider(bus);
// create the LCD interface
var lcd = new Lcd(lcdProvider);
// set up the LCD's number of columns and rows:
lcd.Begin(20, 4);
lcd.BlinkCursor = false;
// Print a message to the LCD.
lcd.Clear();
lcd.Write("STARTING UP ... ");
lcd.SetCursorPosition(0, 2);
lcd.Write("PLEASE WAIT ... ");
//Stopwatch sw = Stopwatch.StartNew();
//END OF LCD SECTION
//Variable Decleration
//DECLARE ALL STOCKS
//int numberOfStocks = 6;
int currentStockOnLCD = 1;
clFinance stockEEM = new clFinance("EEM", 100);
clFinance stockEFA = new clFinance("EFA", 100);
clFinance stockIJJ = new clFinance("IJJ", 200);
clFinance stockIVV = new clFinance("IVV", 200);
clFinance stockIJK = new clFinance("IJK", 123);
clFinance stockVT = new clFinance("VT", 456);
int unreadEmailCount = 0;
Stopwatch StopWatchEmailChecker = Stopwatch.StartNew();
//Stopwatch StopWatchStockChecker = Stopwatch.StartNew();
Stopwatch StopWatchLCDChange = Stopwatch.StartNew();
Boolean BlinkLEDs = false;
int BlinkerCounter = 0;
//Declare Servo
Servo servo = new Servo(Pins.GPIO_PIN_D9);
//Brings the servo home.
servo.Degree = 0;
bool isServoDown = true;
//VARIABLE DECLERATION
//const int SDA = 10; //Analog Pin 4
//const int SCL = 11; //Analog Pin 5
//LED SECTION
//Already Hooked with On Board
OutputPort onBoardLED = new OutputPort(Pins.ONBOARD_LED, false);
OutputPort LED1 = new OutputPort(Pins.GPIO_PIN_D2, false);
OutputPort LED2 = new OutputPort(Pins.GPIO_PIN_D3, false);
OutputPort LED3 = new OutputPort(Pins.GPIO_PIN_D4, false);
OutputPort LED4 = new OutputPort(Pins.GPIO_PIN_D5, false);
//END OF LED SECTION
//Continuous Loop for the microcontroller
while (true)
{
//Email Checker
if (StopWatchEmailChecker.ElapsedMilliseconds > clConstants.EMAILUPDATETIME * 1000)
{
unreadEmailCount = clEmail.GetUnreadEmailCount("http://smarcus3.x10.mx");
if (unreadEmailCount > 0)
{
//You have a message
//Raise Flag
if (isServoDown == true)
{
for (int i = 0; i <= 180; i++)
{
servo.Degree = i;
Thread.Sleep(50);
}
Thread.Sleep(1000);
}
//Blink LEDS
BlinkLEDs = true;
}
else
{
//No messages
//Lower Flag
if (isServoDown == false)
{
for (int i = 180; i >= 0; i--)
{
servo.Degree = i;
Thread.Sleep(50);
}
Thread.Sleep(1000);
}
//Stop LEDS
BlinkLEDs = false;
}
StopWatchEmailChecker.Stop();
StopWatchEmailChecker.Reset();
StopWatchEmailChecker.Start();
}
//LCD SECTION
if (StopWatchLCDChange.ElapsedMilliseconds >= 1000 * clConstants.STOCKUPDATETIME) //every 60 seconds
{
switch (currentStockOnLCD)
{
case 1:
currentStockOnLCD += 1;
stockEEM.UpdateStock();
clMisc.updateLCDDisplay(stockEEM, lcd);
break;
case 2:
currentStockOnLCD += 1;
stockEFA.UpdateStock();
clMisc.updateLCDDisplay(stockEFA, lcd);
break;
case 3:
currentStockOnLCD += 1;
stockIJJ.UpdateStock();
clMisc.updateLCDDisplay(stockIJJ, lcd);
break;
case 4:
currentStockOnLCD += 1;
stockIJK.UpdateStock();
clMisc.updateLCDDisplay(stockIJK, lcd);
break;
case 5:
currentStockOnLCD += 1;
stockIVV.UpdateStock();
clMisc.updateLCDDisplay(stockIVV, lcd);
break;
case 6:
currentStockOnLCD = 1;
stockVT.UpdateStock();
clMisc.updateLCDDisplay(stockVT, lcd);
break;
}
StopWatchLCDChange.Stop();
StopWatchLCDChange.Reset();
StopWatchLCDChange.Start();
}
//END OF LCD SECTION
//LED SECTION
if (BlinkLEDs)
{
//Blinks half of the LEDs at a time.
if (BlinkerCounter == 0)
{
clMisc.ToggleDigitalPins(LED1);
clMisc.ToggleDigitalPins(LED2);
BlinkerCounter = 1;
}
else
{
clMisc.ToggleDigitalPins(LED3);
clMisc.ToggleDigitalPins(LED4);
BlinkerCounter = 0;
}
}
else
{
LED1.Write(false);
LED2.Write(false);
LED3.Write(false);
LED4.Write(false);
}
//LED SECTION
//Blinks the onboard LED
clMisc.ToggleDigitalPins(onBoardLED);
//adds a pause in the controllers thread
Thread.Sleep(100);
}
}
}
}
clMisc.cs
using System;
//using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.Net;
using System.IO;
using System.Text;
using Toolbox.NETMF;
using MicroLiquidCrystal;
using System.Threading;
namespace EmailStockChecker
{
public static class clMisc
{
public static string removeIllegalCharacters(string inputString)
{
int asciiValue;
for (int i = 0; i < inputString.Length - 1; i++)
{
asciiValue = (int) inputString[i];
if (asciiValue == 45 || asciiValue == 36 || asciiValue == 46 || asciiValue == 37 || (asciiValue >= 48 && asciiValue <= 57) ||
(asciiValue >= 97 && asciiValue <= 122) || (asciiValue >= 65 && asciiValue <= 90) || asciiValue == 32 || asciiValue == 44)
{
//This character is fine.
//Move on to the next
}
else
{
return "ILLEGAL CHAR FOUND";
}
}
return inputString;
}
public static string setDecimalPlaceOfString(double number, int decimalPlaces, bool placeCommas)
{
/* THIS FUNCTION TAKES IN A DOUBLE AND RETURNS IT IN A STRING WITH A SPECIFIED NUMBER OF DECIMAL
* PLACES WITH OR WITHOUT COMMAS.
*
* INPUT: NUMBER ---> DOUBLE WHICH CONTAINS THE UNFORMATTED NUMBER
* DECIMALPLACES ---> INTEGER WHICH CONTAINS THE NUMBER OF WANTED DECIMALPLACES
* PLACECOMMAS ---> BOOL WHEN TRUE COMMAS ARE INSERTED INTO THE OUTPUTTED STRING
*
* OUTPUT: A STRING WHICH HAS THE APPROPRIATE NUMBER OF DECIMAL PLACES WITH COMMAS IF REQUESTED.
*/
string tempstr = "";
//This path is for doubles which already have a decimal place. adds commas as needed to the string
if (number.ToString().IndexOf('.') >= 0)
{
if (number.ToString().Length - number.ToString().IndexOf('.') - 1 >= decimalPlaces)
tempstr = number.ToString().Substring(0, number.ToString().IndexOf('.') + decimalPlaces + 1);
else
{
tempstr = number.ToString();
for (int i = number.ToString().Length - 1; i < number.ToString().IndexOf('.') + decimalPlaces; i++)
{
tempstr += "0";
}
}
if (placeCommas == true)
{
for (int i = tempstr.Length - 6; i > 0; i = i - 3)
{
tempstr = tempstr.Substring(0, i) + "," + tempstr.Substring(i, tempstr.Length - i);
}
}
return tempstr; //return number.ToString().Substring(0, number.ToString().IndexOf('.') + decimalPlaces + 1);
}
//If there isn't a deciaml in the number
else
{
string tempString = "";
for (int i = 0; i < decimalPlaces; i++)
{
if (i == 0)
tempString = ".";
tempString += "0";
}
tempString = number.ToString() + tempString;
//adds commas as needed to the string
if (tempString.IndexOf('.') >= 0 && placeCommas == true)
{
for (int i = tempString.Length - 6; i > 0; i = i - 3)
{
tempString = tempString.Substring(0, i) + "," + tempString.Substring(i, tempString.Length - i);
}
}
return tempString;
}
}
public static string setDecimalPlaceOfString(int number, int decimalPlaces, bool placeCommas)
{
/* THIS FUNCTION TAKES IN A INTEGER AND RETURNS IT IN A STRING WITH A SPECIFIED NUMBER OF DECIMAL
* PLACES WITH OR WITHOUT COMMAS.
*
* INPUT: NUMBER ---> INTEGER WHICH CONTAINS THE UNFORMATTED NUMBER
* DECIMALPLACES ---> INTEGER WHICH CONTAINS THE NUMBER OF WANTED DECIMALPLACES
* PLACECOMMAS ---> BOOL WHEN TRUE COMMAS ARE INSERTED INTO THE OUTPUTTED STRING
*
* OUTPUT: A STRING WHICH HAS THE APPROPRIATE NUMBER OF DECIMAL PLACES WITH COMMAS IF REQUESTED.
*/
string tempstr = number.ToString().Substring(0, number.ToString().IndexOf('.') + decimalPlaces + 1);
//This path is for doubles which already have a decimal place. adds commas as needed to the string
if (number.ToString().IndexOf('.') >= 0 && placeCommas == true)
{
for (int i = tempstr.Length - 6; i > 0; i = i - 3)
{
tempstr = tempstr.Substring(0, i) + "," + tempstr.Substring(i, tempstr.Length - i);
}
return tempstr; //return number.ToString().Substring(0, number.ToString().IndexOf('.') + decimalPlaces + 1);
}
//If there isn't a deciaml in the number
else
{
string tempString = "";
for (int i = 0; i < decimalPlaces; i++)
{
if (i == 0)
tempString = ".";
tempString += "0";
}
tempString = number.ToString() + tempString;
//adds commas as needed to the string
if (tempString.IndexOf('.') >= 0 && placeCommas == true)
{
for (int i = tempString.Length - 6; i > 0; i = i - 3)
{
tempString = tempString.Substring(0, i) + "," + tempString.Substring(i, tempString.Length - i);
}
}
return tempString;
}
}
public static string centerString(string sourceString1, string sourceString2, int formattedStringLength)
{
/*THIS FUNCTION TAKES IN TWO STRINGS AND CENTERS IT IN THE OUTPUTTED STRING. THIS RETURNED STRING'S
* LENGTH IS DETERMINED BY THE INTEGER, FORMATTEDSTRINGLENGTH.
*
* INPUTS: SOURCESTRING1 ---> STRING CONTAINING A STRING NEEDED TO BE CENTERED
* SOURCESTRING2 ---> STRING CONTAINING A STRING NEEDED TO BE CENTERED
* FORMATTEDSTRINGLENGTH ---> INTEGER SPECIFING THE LENGTH OF THE RETURNED STRING
*
* OUTPUT: A STRING THE LENGTH OF FORMATTEDSTRINGLEGTH THAT CENTERS THE SOURCESTRINGS
*/
string formattedString = "";
if (sourceString1.Length + sourceString2.Length < formattedStringLength)
{
int diference = (int) (formattedStringLength - sourceString1.Length - sourceString2.Length)/3;
//only 2 spaces
if (diference == 0 && formattedStringLength - sourceString1.Length - sourceString2.Length >= 2)
{
diference = 1;
}
//only 1 space
if (diference == 0 && formattedStringLength - sourceString1.Length - sourceString2.Length == 1)
return sourceString1 + " " + sourceString2;
for (int i = 0; i < formattedStringLength; i++)
{
if (i < diference)
formattedString = formattedString + " ";
else if (i < sourceString1.Length + diference)
{
formattedString = formattedString + sourceString1;
i = diference + sourceString1.Length - 1;
}
else if (i < sourceString1.Length + 2 * diference)
{
formattedString = formattedString + " ";
}
else if (i < sourceString1.Length + sourceString2.Length + 2 * diference)
{
formattedString = formattedString + sourceString2;
i = sourceString1.Length + sourceString2.Length + 2 * diference - 1;
}
else
formattedString = formattedString + " ";
}
return formattedString;
}
else
return sourceString1 + sourceString2;
}
public static string centerString(string sourceString, int formattedStringLength)
{
/*THIS FUNCTION TAKES IN ONE STRINGS AND CENTERS IT IN THE OUTPUTTED STRING. THIS RETURNED STRING'S
* LENGTH IS DETERMINED BY THE INTEGER, FORMATTEDSTRINGLENGTH.
*
* INPUTS: SOURCESTRING1 ---> STRING CONTAINING A STRING NEEDED TO BE CENTERED
* FORMATTEDSTRINGLENGTH ---> INTEGER SPECIFING THE LENGTH OF THE RETURNED STRING
*
* OUTPUT: A STRING THE LENGTH OF FORMATTEDSTRINGLEGTH THAT CENTERS THE SOURCESTRING
*/
string formattedString = "";
if (sourceString.Length < formattedStringLength)
{
int diference = formattedStringLength - sourceString.Length;
for (int i = 0; i < formattedStringLength; i++)
{
if (i < (int) diference/2)
formattedString = formattedString + " ";
else if (i < sourceString.Length + (int) diference/2)
{
formattedString = formattedString + sourceString;
i = (int)diference / 2 + sourceString.Length - 1;
}
else
formattedString = formattedString + " ";
}
return formattedString = formattedString.Substring(0,formattedStringLength);
}
else
//forces it to be the right length
return sourceString.Substring(0, formattedStringLength);
}
public static void updateLCDDisplay(clFinance Stock, Lcd lcd) //needs LCD in it
{
/* THIS IS A HELPER FUNCTION WHICH IS CALLED TO UPDATE THE DISPLAY OF THE LCD DISPLAY WITH THE
* INPUTTED STOCK. THIS FUNCTION KEEPS THE MAIN FUNCTION CLEAN.
*
* // LCD Display //
*
* // LAYOUT //
* // STOCK NAME LAST //
* // CHANGE PERCENT //
* // DAILY - CHANGE //
* // MARKET VALUE //
*
*/
//20 x 4 size LCD
string formattedStockName = "";
string formattedMarketValue = "";
string formattedDailyChange = "";
string formattedChange = "";
string formattedPercChange = "";
string formattedLast = "";
//Stock Name
//if (Stock.GetStockName().Length > 20)
formattedStockName = Stock.GetTicker();
//else
// formattedStockName = Stock.GetStockName();
//Change
if (Stock.GetChange() > 0)
formattedChange = "$" + setDecimalPlaceOfString(Stock.GetChange(), 2, true);
else
formattedChange = "-$" + setDecimalPlaceOfString(Stock.GetChange() * -1,2, true);
//Percent
formattedPercChange = setDecimalPlaceOfString(Stock.GetPercentChange(), 2, true) +"%";
//Daily Change
if (Stock.GetDailyChange() > 0)
formattedDailyChange = "$" + setDecimalPlaceOfString(Stock.GetDailyChange(),2, true);
else
formattedDailyChange = "-$" + setDecimalPlaceOfString(Stock.GetDailyChange() * -1, 2, true);
//Market Value
if (Stock.GetMarketValue() > 0)
formattedMarketValue = "$" + setDecimalPlaceOfString(Stock.GetMarketValue(), 2,true);
else
formattedMarketValue = "-$" + setDecimalPlaceOfString(Stock.GetMarketValue() * -1, 2,true);
//Last
formattedLast = "$" + setDecimalPlaceOfString(Stock.GetLastPrice(), 2, true);
lcd.Clear();
//lcd.SetCursorPosition(0, 0);
Thread.Sleep(clConstants.DELAYBETWEENLCDWRITEMS);
//Row 1
clMisc.wrtieCharbyCharLCD(lcd, removeIllegalCharacters(centerString(formattedStockName, formattedLast, 20)), 0);
//Row 2
clMisc.wrtieCharbyCharLCD(lcd, removeIllegalCharacters(centerString(formattedChange, formattedPercChange, 20)), 1);
//Row 3
clMisc.wrtieCharbyCharLCD(lcd, removeIllegalCharacters(centerString(formattedDailyChange, 20)), 2);
//Row 4
clMisc.wrtieCharbyCharLCD(lcd, removeIllegalCharacters(centerString(formattedMarketValue, 20)), 3);
//TESTING CODE
//string temp2 = center2String(formattedStockName,formattedLast, 20);
//string temp3 = center2String(formattedChange, formattedPercChange, 20);
//string temp1 = center1String(formattedDailyChange, 20);
//string temp = center1String(formattedMarketValue, 20);
}
public static void wrtieCharbyCharLCD(Lcd lcd, string inputString, int cursorStartRow)
{
//Needs a string the width of the LCD.
lcd.SetCursorPosition(0, cursorStartRow); //COLUMN ROW
for (int i = 0; i < clConstants.LCDWIDTH; i++)
{
if (inputString[i].ToString() != " ")
{
Thread.Sleep(clConstants.DELAYBETWEENLCDWRITEMS);
lcd.SetCursorPosition(i, cursorStartRow);
lcd.Write(inputString[i].ToString());
}
}
}
public static void ToggleDigitalPins(OutputPort outPort)
{
/* THIS FUNCTION TAKES IN A PORT AND SWAPS THE STATE OF THE DIGITAL PIN. THIS MEANS THAT IF A PIN
* IS HIGH (5V) IT IS SWITCHED TO LOW (0V). THE OPPOSITE IS ALSO TRUE.
*
* INPUT: OUTPORT ---> TAKES IN AN OUTPORT PIN WHICH IS GOING TO BE TOGGED TO THE STATE IT IS NOT
* CURRENTLY IN.
*/
if (outPort.Read())
outPort.Write(false);
else
outPort.Write(true);
}
public static string GetStringInBetween(string strBegin, string strEnd, string strSource)
{
/* THIS FUNCTION RETURNS A STRING WHICH IS BETWEEN TWO SPECIFIED STRINGS. THESE TWO SEARCH STRINGS ENCAPSULATE
* THE TARGET STRING WHICH IS GOING TO BE FOUND. THIS FUNCTION IS VERY USEFUL TO PULL INFORMATION
* FROM A LONG STRING SUCH AS THE OUTPUT FROM AN ONLINE WEBSITE. THIS USE IS THE REASON WHY THIS FUNCTION WAS
* WRITTEN FOR THIS EXPLICIT REASON.
*
* INPUTS: STRBEGIN ---> THE FIRST STRING THAT MARKS THE BEGINNING OF THE STRING WHICH IS GOING TO BE FOUND
* STREND ---> THE SECOND STRING THAT MARKS THE END OF THE STRING WHICH IS GOING TO BE FOUND
* STRSOURCE ---> THE SOURCE STRING THAT HAS THE STRBEGIN AND STREND IN IT. THIS STRING ALSO HOLDS THE
* TARGET STRING WHICH IS GOING TO BE FOUND.
*
* OUTPUT: A STRING WHICH WAS BETWEEN STRBEGIN AND STREND AND CONTAINED IN STRSOURCE
*/
string result = "";
int iIndexOfBegin = strSource.IndexOf(strBegin);
if (iIndexOfBegin != -1)
{
strSource = strSource.Substring(iIndexOfBegin+strBegin.Length);
int iEnd = strSource.IndexOf(strEnd);
if (iEnd != -1)
{
result = strSource.Substring(0, iEnd);
}
}
else
// stay where we are
result = strSource;
return result;
}
public static string GetOnlineWebPage(string url)
{
/* THIS FUNCTION GETS ONLINEWEBPAGES AS LONG AS THEY ARE NOT HTTPS. THE NETDUINO AT THIS POINT DOESNT
* HANDLE DEALING WITH HTTPS PAGES OR SSL. THE WORK AROUND TO THIS IS TO USE AN PHP WEBSITE. THE FUNCITON
* RETURNS THE ENTIRE WEBSITE AS A LONG, LONG STRING. ALL OF THE HTML WILL BE RETURNED WITH THIS FUNCTION
* SUCH AS HEADER AND BODY BREAKS. THIS FUNCTION GOES HAND IN HAND WITH GETSTRINGINBETWEEN
*
* INPUT: URL ---> A STRING WHICH CONTAINS THE URL OF THE SITE SUCH AS HTTP://WWW.GMAIL.COM
*
* OUTPUT: A STRING WHICH CONTAINS ALL THE RAW DATA OF THE WEBSITE
*/
// used to build entire input
//clStringBuilder sb = new clStringBuilder();
// used on each read operation
byte[] buf = new byte[100]; //8192 was the original value but we ran out of memory.
// prepare the web page we will be asking for
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
// execute the request
HttpWebResponse response = (HttpWebResponse)
request.GetResponse();
// we will read data via the response stream
Stream resStream = response.GetResponseStream();
string tempString = null;
int count = 0;
string fullstring = "";
do
{
// fill the buffer with data
count = resStream.Read(buf, 0, buf.Length);
// make sure we read some data
if (count != 0)
{
// translate from bytes to ASCII text
//tempString = Encoding.ASCII.GetString //(buf, 0, count);
tempString = new string(Tools.Bytes2Chars(buf));
// continue building the string
fullstring += tempString; //sb.Append(tempString);
}
}
while (count > 0); // any more data to read?
return fullstring;
}
public static string GetOnlineWebPage(string url, int beginnigTrimAmmount, int maxStringLength)
{
/* THIS FUNCTION GETS ONLINEWEBPAGES AS LONG AS THEY ARE NOT HTTPS. THE NETDUINO AT THIS POINT DOESNT
* HANDLE DEALING WITH HTTPS PAGES OR SSL. THE WORK AROUND TO THIS IS TO USE AN PHP WEBSITE. THE FUNCITON
* RETURNS THE ENTIRE WEBSITE AS A LONG, LONG STRING. ALL OF THE HTML WILL BE RETURNED WITH THIS FUNCTION
* SUCH AS HEADER AND BODY BREAKS. THIS FUNCTION GOES HAND IN HAND WITH GETSTRINGINBETWEEN
*
* INPUT: URL ---> A STRING WHICH CONTAINS THE URL OF THE SITE SUCH AS HTTP://WWW.GMAIL.COM
*
* OUTPUT: A STRING WHICH CONTAINS ALL THE RAW DATA OF THE WEBSITE
*/
// used to build entire input
//clStringBuilder sb = new clStringBuilder();
// used on each read operation
byte[] buf = new byte[25]; //8192 was the original value but we ran out of memory.
//bool hasItBeenFound = false;
string fullstring = "";
//while (hasItBeenFound == false)
//{
try
{
// prepare the web page we will be asking for
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// execute the request
HttpWebResponse response = (HttpWebResponse)
request.GetResponse();
// we will read data via the response stream
Stream resStream = response.GetResponseStream();
int count = 0;
bool keepGoing = true;
bool hasFirstTrimHappened = false;
bool hasSecondTrimHappened = false;
do
{
// fill the buffer with data
count = resStream.Read(buf, 0, buf.Length);
// make sure we read some data
if (count != 0)
{
// translate from bytes to ASCII text
//tempString = Encoding.ASCII.GetString //(buf, 0, count);
fullstring += new string(Tools.Bytes2Chars(buf));
// continue building the string
//fullstring += tempString; //sb.Append(tempString);
}
else
keepGoing = false; //Add data has been read
//cuts off the worthless front end data
if ((hasFirstTrimHappened == false || hasSecondTrimHappened == false) && fullstring.Length > beginnigTrimAmmount / 2)
{
fullstring = fullstring.Substring(beginnigTrimAmmount / 2);
if (hasFirstTrimHappened == false)
hasFirstTrimHappened = true;
else
hasSecondTrimHappened = true;
}
if (fullstring.Length > maxStringLength && hasFirstTrimHappened == true)
keepGoing = false;
}
while (keepGoing == true); // any more data to read?
//fullstring = fullstring.Substring(beginnigTrimAmmount - 1);
if (maxStringLength < fullstring.Length)
fullstring = fullstring.Substring(0, maxStringLength - 1);
return fullstring;
}
catch
{
return "BADWEBPAGE";
}
}
//return fullstring;
//
}
}
clConstants.cs
using System;
using Microsoft.SPOT;
namespace EmailStockChecker
{
public static class clConstants
{
public const int STOCKUPDATETIME = 2;
public const int EMAILUPDATETIME = 60;
public const int DELAYBETWEENLCDWRITEMS = 200;
public const int LCDWIDTH = 20;
public const int LCDHEIGHT = 4;
}
}
clFinance.cs
using System;
using System.Threading;
using System.IO.Ports;
using System.Text;
using System.IO;
using Microsoft.SPOT;
using System.Net;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using Toolbox.NETMF;
namespace EmailStockChecker
{
public class clFinance
{
//MODIFED CODE FROM: http://www.jarloo.com/google-stock-api/
//USER DEFINED
private string Ticker;
private double OwnedShares;
//Gets from Online - GOOGLE
//private string Company;
//private string Exchange;
private double Last;
private double High;
private double Low;
private double Change;
private double PercentChange;
private double DailyChange;
private double MarketValue;
public clFinance(string ticker, double ownedShares)
{
//Constructor
Ticker = ticker;
OwnedShares = ownedShares;
//Updates the info for the first time.
UpdateStock();
}
public string GetTicker()
{
return Ticker;
}
public void UpdateStock(){
FetchQuote(Ticker);
}
public double GetLastPrice()
{
return Last;
}
public double GetDailyChange()
{
return DailyChange;
}
public double GetMarketValue()
{
return MarketValue;
}
public double GetPercentChange()
{
return PercentChange;
}
public double GetChange()
{
return Change;
}
private void FetchQuote(string symbol)
{
string url = "http://www.google.com/ig/api?stock=" + symbol;
string RawWebData = clMisc.GetOnlineWebPage(url,400,300);
string tempString = "";
//Parse the data
//temp = clMisc.GetStringInBetween("<symbol data=\"", "\"/>", temp);
//Company = clMisc.GetStringInBetween("<company data=\"","\"/>",RawWebData);
//Exchange = clMisc.GetStringInBetween("<exchange data=\"","\"/>",RawWebData);
try
{
string temp = clMisc.GetStringInBetween("<last data=\"", "\"/>", RawWebData);
Last = Convert.ToDouble(clMisc.GetStringInBetween("<last data=\"", "\"/>", RawWebData));
High = Convert.ToDouble(clMisc.GetStringInBetween("<high data=\"", "\"/>", RawWebData));
Low = Double.Parse(clMisc.GetStringInBetween("<low data=\"", "\"/>", RawWebData));
tempString = clMisc.GetStringInBetween("<change data=\"", "\"/>", RawWebData);
//Fixes for negatives. For some reasons converting with the negative sign is not working. Do not know what is causing this.
if (tempString.Substring(0, 1) == "-" && Double.Parse(tempString) >= 0)
Change = Double.Parse(tempString) * -1;
else
Change = Double.Parse(tempString);
tempString = clMisc.GetStringInBetween("<perc_change data=\"", "\"/>", RawWebData);
//Fixes for negatives. For some reasons converting with the negative sign is not working. Do not know what is causing this.
if (tempString.Substring(0, 1) == "-" && Double.Parse(tempString) >= 0)
PercentChange = Double.Parse(tempString) * -1; //PercentChange = ((int)((Double.Parse(tempString) * -1) * 100) / 100.0);
else
PercentChange = Double.Parse(tempString); //PercentChange = ((int)((Double.Parse(tempString)) * 100) / 100.0);
DailyChange = Change * OwnedShares; //* 100) / 100.0);
MarketValue = Last * OwnedShares; ; //* 100) / 100.0);
}
catch
{
Last = 1;
High = 2;
Low = 3;
Change = 4;
PercentChange = 5;
}
}
}
}
I finally got around to replacing my cardboard flag with an lexan one with imbedded LEDs. Here are a few pics of the 'finished' product. I'm sure I will keep tinkering with it.
All the LEDs ground sides are tacked together so only 5 wires have to run to the flag. I use a DO pin for each so they can be individually toggled.
A picture showing the LEDs on. There are 2 white and 2 red in the flag. A green LED shows power and a yellow blinks to notify the user the controller is working.
I have also just upgraded my N+ to 4.2 RC4 and loving it. It has more memory and syncs better. I haven't gotten one garbled lcd message with 4.2, fingers crossed.
I have also re-written some of my code to be smaller and more efficient. Below are all of the functions for my program.
Please comment or ask questions. Hope you enjoy it.
Progarm.cs
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.IO;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using FusionWare.SPOT.Hardware;
using MicroLiquidCrystal;
using System.Diagnostics;
using Servo_API;
namespace EmailStockChecker
{
public class Program
{
public static void Main()
{
//LCD SECCTION
Thread.Sleep(1000);
// initialize i2c bus (only one instance is allowed)
var bus = new I2CBus();
// initialize provider (multiple devices can be attached to same bus)
var lcdProvider = new MCP23008LcdTransferProvider(bus);
// create the LCD interface
var lcd = new Lcd(lcdProvider);
// set up the LCD's number of columns and rows:
lcd.Begin(20, 4);
lcd.BlinkCursor = true;
// Print a message to the LCD.
lcd.Clear();
lcd.Write("STARTING UP ... ");
lcd.SetCursorPosition(0, 2);
lcd.Write("PLEASE WAIT ... ");
//Stopwatch sw = Stopwatch.StartNew();
//END OF LCD SECTION
//Variable Decleration
//DECLARE ALL STOCKS
//int numberOfStocks = 6;
int currentStockOnLCD = 1;
//Thread.Sleep(1000);
clFinance stockEEM = new clFinance("EEM", 100);
clFinance stockEFA = new clFinance("EFA", 100);
clFinance stockIJJ = new clFinance("IJJ", 100);
clFinance stockIVV = new clFinance("IVV", 100);
clFinance stockIJK = new clFinance("IJK", 100);
clFinance stockVT = new clFinance("VT", 100);
int unreadEmailCount = 0;
Stopwatch StopWatchEmailChecker = Stopwatch.StartNew();
//Stopwatch StopWatchStockChecker = Stopwatch.StartNew();
Stopwatch StopWatchLCDChange = Stopwatch.StartNew();
Boolean BlinkLEDs = false;
int BlinkerCounter = 0;
//Declare Servo
Servo servo = new Servo(Pins.GPIO_PIN_D9);
//Brings the servo home.
servo.Degree = 0;
bool isServoDown = true;
//VARIABLE DECLERATION
//const int SDA = 10; //Analog Pin 4
//const int SCL = 11; //Analog Pin 5
//LED SECTION
//Already Hooked with On Board
OutputPort onBoardLED = new OutputPort(Pins.ONBOARD_LED, false);
OutputPort LED1 = new OutputPort(Pins.GPIO_PIN_D2, false);
OutputPort LED2 = new OutputPort(Pins.GPIO_PIN_D3, false);
OutputPort LED3 = new OutputPort(Pins.GPIO_PIN_D4, false);
OutputPort LED4 = new OutputPort(Pins.GPIO_PIN_D5, false);
OutputPort ActivityLED = new OutputPort(Pins.GPIO_PIN_D6, false);
//END OF LED SECTION
StopWatchLCDChange.Reset();
StopWatchLCDChange.Start();
StopWatchEmailChecker.Reset();
StopWatchEmailChecker.Start();
//Continuous Loop for the microcontroller
while (true)
{
//Email Checker
if (StopWatchEmailChecker.ElapsedMilliseconds > clConstants.EMAILUPDATETIME * 1000)
{
unreadEmailCount = clEmail.GetUnreadEmailCount("www.smarcus3.x10.mx");
if (unreadEmailCount > 0)
{
//You have a message
//Raise Flag
if (isServoDown == true)
{
isServoDown = false;
for (int i = 0; i <= 180; i++)
{
servo.Degree = i;
Thread.Sleep(50);
}
Thread.Sleep(1000);
}
servo.disengage();
//Blink LEDS
BlinkLEDs = true;
}
else
{
//No messages
LED1.Write(false);
LED2.Write(false);
LED3.Write(false);
LED4.Write(false);
//Lower Flag
if (isServoDown == false)
{
isServoDown = true;
for (int i = 180; i >= 0; i--)
{
servo.Degree = i;
Thread.Sleep(50);
}
Thread.Sleep(1000);
}
servo.disengage();
//Stop LEDS
BlinkLEDs = false;
}
StopWatchEmailChecker.Stop();
StopWatchEmailChecker.Reset();
StopWatchEmailChecker.Start();
}
//LCD SECTION
if (StopWatchLCDChange.ElapsedMilliseconds >= 1000 * clConstants.STOCKUPDATETIME) //every 60 seconds
{
if (BlinkLEDs == false)
{
LED1.Write(false);
LED2.Write(false);
LED3.Write(false);
LED4.Write(false);
}
else
{
LED1.Write(true);
LED2.Write(true);
LED3.Write(true);
LED4.Write(true);
}
switch (currentStockOnLCD)
{
case 1:
currentStockOnLCD += 1;
stockEEM.UpdateStock();
clMisc.updateLCDDisplay(stockEEM, lcd);
break;
case 2:
currentStockOnLCD += 1;
stockEFA.UpdateStock();
clMisc.updateLCDDisplay(stockEFA, lcd);
break;
case 3:
currentStockOnLCD += 1;
stockIJJ.UpdateStock();
clMisc.updateLCDDisplay(stockIJJ, lcd);
break;
case 4:
currentStockOnLCD += 1;
stockIJK.UpdateStock();
clMisc.updateLCDDisplay(stockIJK, lcd);
break;
case 5:
currentStockOnLCD += 1;
stockIVV.UpdateStock();
clMisc.updateLCDDisplay(stockIVV, lcd);
break;
case 6:
currentStockOnLCD = 1;
stockVT.UpdateStock();
clMisc.updateLCDDisplay(stockVT, lcd);
break;
}
StopWatchLCDChange.Stop();
StopWatchLCDChange.Reset();
StopWatchLCDChange.Start();
}
//END OF LCD SECTION
//LED SECTION
if (BlinkLEDs)
{
//Blinks half of the LEDs at a time.
if (BlinkerCounter == 0)
{
clMisc.ToggleDigitalPins(LED1);
clMisc.ToggleDigitalPins(LED2);
BlinkerCounter = 1;
}
else
{
clMisc.ToggleDigitalPins(LED3);
clMisc.ToggleDigitalPins(LED4);
BlinkerCounter = 0;
}
}
else
{
LED1.Write(false);
LED2.Write(false);
LED3.Write(false);
LED4.Write(false);
}
//LED SECTION
lcd.SetCursorPosition(19, 3);
lcd.Write(((int)(clConstants.STOCKUPDATETIME - StopWatchLCDChange.ElapsedMilliseconds/1000)).ToString());
//Blinks the onboard LED and ActivityLED
clMisc.ToggleDigitalPins(onBoardLED);
clMisc.ToggleDigitalPins(ActivityLED);
//adds a pause in the controllers thread
Thread.Sleep(100);
//Debug.Print("Memory Left (Bytes): " + Debug.GC(false).ToString());
}
}
}
}
clMisc.cs
using System;
//using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.IO;
using System.Text;
using MicroLiquidCrystal;
using System.Threading;
using Toolbox.NETMF.NET;
namespace EmailStockChecker
{
public static class clMisc
{
public static string setDecimalPlaceOfString(double number, int decimalPlaces, bool placeCommas)
{
/* THIS FUNCTION TAKES IN A DOUBLE AND RETURNS IT IN A STRING WITH A SPECIFIED NUMBER OF DECIMAL
* PLACES WITH OR WITHOUT COMMAS.
*
* INPUT: NUMBER ---> DOUBLE WHICH CONTAINS THE UNFORMATTED NUMBER
* DECIMALPLACES ---> INTEGER WHICH CONTAINS THE NUMBER OF WANTED DECIMALPLACES
* PLACECOMMAS ---> BOOL WHEN TRUE COMMAS ARE INSERTED INTO THE OUTPUTTED STRING
*
* OUTPUT: A STRING WHICH HAS THE APPROPRIATE NUMBER OF DECIMAL PLACES WITH COMMAS IF REQUESTED.
*/
//string tempstr = "";
StringBuilder builder = new StringBuilder();
//This path is for doubles which already have a decimal place. adds commas as needed to the string
if (number.ToString().IndexOf('.') >= 0)
{
if (number.ToString().Length - number.ToString().IndexOf('.') - 1 >= decimalPlaces)
builder.Append(number.ToString().Substring(0, number.ToString().IndexOf('.') + decimalPlaces + 1));
else
{
builder.Append(number.ToString());
for (int i = number.ToString().Length - 1; i < number.ToString().IndexOf('.') + decimalPlaces; i++)
{
builder.Append("0");
}
}
if (placeCommas == true)
{
string tempstr;
for (int i = builder.Length - 6; i > 0; i = i - 3)
{
//tempstr = tempstr.Substring(0, i) + "," + tempstr.Substring(i, tempstr.Length - i);
tempstr = builder.ToString();
builder.Clear();
builder.Append(tempstr.Substring(0, i));
builder.Append(",");
builder.Append(tempstr.Substring(i, tempstr.Length - i));
}
}
return builder.ToString(); //return number.ToString().Substring(0, number.ToString().IndexOf('.') + decimalPlaces + 1);
}
//If there isn't a deciaml in the number
else
{
builder.Append(number.ToString());
for (int i = 0; i < decimalPlaces; i++)
{
if (i == 0)
builder.Append(".");
builder.Append("0");
}
if (placeCommas == true)
{
string tempstr;
for (int i = builder.Length - 6; i > 0; i = i - 3)
{
//tempstr = tempstr.Substring(0, i) + "," + tempstr.Substring(i, tempstr.Length - i);
tempstr = builder.ToString();
builder.Clear();
builder.Append(tempstr.Substring(0, i));
builder.Append(",");
builder.Append(tempstr.Substring(i, tempstr.Length - i));
}
}
return builder.ToString();
}
}
public static string centerString(string sourceString1, string sourceString2)
{
/*THIS FUNCTION TAKES IN TWO STRINGS AND CENTERS IT IN THE OUTPUTTED STRING. THIS RETURNED STRING'S
* LENGTH IS DETERMINED BY THE INTEGER, FORMATTEDSTRINGLENGTH.
*
* INPUTS: SOURCESTRING1 ---> STRING CONTAINING A STRING NEEDED TO BE CENTERED
* SOURCESTRING2 ---> STRING CONTAINING A STRING NEEDED TO BE CENTERED
* FORMATTEDSTRINGLENGTH ---> INTEGER SPECIFING THE LENGTH OF THE RETURNED STRING
*
* OUTPUT: A STRING THE LENGTH OF FORMATTEDSTRINGLEGTH THAT CENTERS THE SOURCESTRINGS
*/
//string formattedString = "";
StringBuilder sb = new StringBuilder();
if (sourceString1.Length + sourceString2.Length < clConstants.LCDWIDTH)
{
int diference = (int) (clConstants.LCDWIDTH - sourceString1.Length - sourceString2.Length)/3;
//only 2 spaces
if (diference == 0 && clConstants.LCDWIDTH - sourceString1.Length - sourceString2.Length >= 2)
{
diference = 1;
}
//only 1 space
if (diference == 0 && clConstants.LCDWIDTH - sourceString1.Length - sourceString2.Length == 1)
return sourceString1 + " " + sourceString2;
for (int i = 0; i < clConstants.LCDWIDTH; i++)
{
if (i < diference)
{
//formattedString = formattedString + " ";
sb.Append(" ");
}
else if (i < sourceString1.Length + diference)
{
//formattedString = formattedString + sourceString1;
sb.Append(sourceString1);
i = diference + sourceString1.Length - 1;
}
else if (i < sourceString1.Length + 2 * diference)
{
//formattedString = formattedString + " ";
sb.Append(" ");
}
else if (i < sourceString1.Length + sourceString2.Length + 2 * diference)
{
//formattedString = formattedString + sourceString2;
sb.Append(sourceString2);
i = sourceString1.Length + sourceString2.Length + 2 * diference - 1;
}
else
{
//formattedString = formattedString + " ";
sb.Append(" ");
}
}
return sb.ToString();//formattedString;
}
else
return sourceString1 + sourceString2;
}
public static string centerString(string sourceString)
{
/*THIS FUNCTION TAKES IN ONE STRINGS AND CENTERS IT IN THE OUTPUTTED STRING. THIS RETURNED STRING'S
* LENGTH IS DETERMINED BY THE INTEGER, FORMATTEDSTRINGLENGTH.
*
* INPUTS: SOURCESTRING1 ---> STRING CONTAINING A STRING NEEDED TO BE CENTERED
* FORMATTEDSTRINGLENGTH ---> INTEGER SPECIFING THE LENGTH OF THE RETURNED STRING
*
* OUTPUT: A STRING THE LENGTH OF FORMATTEDSTRINGLEGTH THAT CENTERS THE SOURCESTRING
*/
//string formattedString = "";
StringBuilder sb = new StringBuilder();
if (sourceString.Length < clConstants.LCDWIDTH)
{
int diference = clConstants.LCDWIDTH - sourceString.Length;
for (int i = 0; i < clConstants.LCDWIDTH; i++)
{
if (i < (int)diference / 2)
{
sb.Append(" ");
//formattedString = formattedString + " ";
}
else if (i < sourceString.Length + (int)diference / 2)
{
sb.Append(sourceString);
//formattedString = formattedString + sourceString;
i = (int)diference / 2 + sourceString.Length - 1;
}
else
{
//formattedString = formattedString + " ";
sb.Append(" ");
}
}
return sb.ToString(); // formattedString = formattedString.Substring(0, clConstants.LCDWIDTH);
}
else
//forces it to be the right length
return sourceString.Substring(0, clConstants.LCDWIDTH);
}
public static void updateLCDDisplay(clFinance Stock, Lcd lcd) //needs LCD in it
{
/* THIS IS A HELPER FUNCTION WHICH IS CALLED TO UPDATE THE DISPLAY OF THE LCD DISPLAY WITH THE
* INPUTTED STOCK. THIS FUNCTION KEEPS THE MAIN FUNCTION CLEAN.
*
* // LCD Display //
*
* // LAYOUT //
* // STOCK NAME LAST //
* // CHANGE PERCENT //
* // DAILY - CHANGE //
* // MARKET VALUE //
*
*/
//20 x 4 size LCD
string formattedStockName = "";
string formattedMarketValue = "";
string formattedDailyChange = "";
string formattedChange = "";
string formattedPercChange = "";
string formattedLast = "";
//Stock Name
//if (Stock.GetStockName().Length > 20)
formattedStockName = Stock.GetTicker();
//else
// formattedStockName = Stock.GetStockName();
//Change
if (Stock.GetChange() > 0)
formattedChange = "$" + setDecimalPlaceOfString(Stock.GetChange(), 2, true);
else
formattedChange = "-$" + setDecimalPlaceOfString(Stock.GetChange() * -1,2, true);
//Percent
formattedPercChange = setDecimalPlaceOfString(Stock.GetPercentChange(), 2, true) +"%";
//Daily Change
if (Stock.GetDailyChange() > 0)
formattedDailyChange = "$" + setDecimalPlaceOfString(Stock.GetDailyChange(),2, true);
else
formattedDailyChange = "-$" + setDecimalPlaceOfString(Stock.GetDailyChange() * -1, 2, true);
//Market Value
if (Stock.GetMarketValue() > 0)
formattedMarketValue = "$" + setDecimalPlaceOfString(Stock.GetMarketValue(), 2,true);
else
formattedMarketValue = "-$" + setDecimalPlaceOfString(Stock.GetMarketValue() * -1, 2,true);
//Last
formattedLast = "$" + setDecimalPlaceOfString(Stock.GetLastPrice(), 2, true);
lcd.Clear();
//lcd.SetCursorPosition(0, 0);
Thread.Sleep(clConstants.DELAYBETWEENLCDWRITEMS);
//Row 1
clMisc.wrtieCharbyCharLCD(lcd, centerString(formattedStockName, formattedLast), 0);
//Row 2
clMisc.wrtieCharbyCharLCD(lcd, centerString(formattedChange, formattedPercChange), 1);
//Row 3
clMisc.wrtieCharbyCharLCD(lcd, centerString(formattedDailyChange), 2);
//Row 4
clMisc.wrtieCharbyCharLCD(lcd, centerString(formattedMarketValue), 3);
//TESTING CODE
lcd.SetCursorPosition(clConstants.LCDWIDTH - 1, clConstants.LCDHEIGHT - 1);
//string temp2 = center2String(formattedStockName,formattedLast, 20);
//string temp3 = center2String(formattedChange, formattedPercChange, 20);
//string temp1 = center1String(formattedDailyChange, 20);
//string temp = center1String(formattedMarketValue, 20);
}
public static void wrtieCharbyCharLCD(Lcd lcd, string inputString, int cursorStartRow)
{
lcd.SetCursorPosition(0, cursorStartRow); //COLUMN ROW
for (int i = 0; i < inputString.Length; i++)
{
if (inputString[i].ToString() != " ")
{
Thread.Sleep(clConstants.DELAYBETWEENLCDWRITEMS);
lcd.SetCursorPosition(i, cursorStartRow);
lcd.Write(inputString[i].ToString());
}
}
}
public static void ToggleDigitalPins(OutputPort outPort)
{
/* THIS FUNCTION TAKES IN A PORT AND SWAPS THE STATE OF THE DIGITAL PIN. THIS MEANS THAT IF A PIN
* IS HIGH (5V) IT IS SWITCHED TO LOW (0V). THE OPPOSITE IS ALSO TRUE.
*
* INPUT: OUTPORT ---> TAKES IN AN OUTPORT PIN WHICH IS GOING TO BE TOGGED TO THE STATE IT IS NOT
* CURRENTLY IN.
*/
if (outPort.Read())
outPort.Write(false);
else
outPort.Write(true);
}
public static string GetStringInBetween(string strBegin, string strEnd, string strSource)
{
/* THIS FUNCTION RETURNS A STRING WHICH IS BETWEEN TWO SPECIFIED STRINGS. THESE TWO SEARCH STRINGS ENCAPSULATE
* THE TARGET STRING WHICH IS GOING TO BE FOUND. THIS FUNCTION IS VERY USEFUL TO PULL INFORMATION
* FROM A LONG STRING SUCH AS THE OUTPUT FROM AN ONLINE WEBSITE. THIS USE IS THE REASON WHY THIS FUNCTION WAS
* WRITTEN FOR THIS EXPLICIT REASON.
*
* INPUTS: STRBEGIN ---> THE FIRST STRING THAT MARKS THE BEGINNING OF THE STRING WHICH IS GOING TO BE FOUND
* STREND ---> THE SECOND STRING THAT MARKS THE END OF THE STRING WHICH IS GOING TO BE FOUND
* STRSOURCE ---> THE SOURCE STRING THAT HAS THE STRBEGIN AND STREND IN IT. THIS STRING ALSO HOLDS THE
* TARGET STRING WHICH IS GOING TO BE FOUND.
*
* OUTPUT: A STRING WHICH WAS BETWEEN STRBEGIN AND STREND AND CONTAINED IN STRSOURCE
*/
string result = "";
int iIndexOfBegin = strSource.IndexOf(strBegin);
if (iIndexOfBegin != -1)
{
strSource = strSource.Substring(iIndexOfBegin+strBegin.Length);
int iEnd = strSource.IndexOf(strEnd);
if (iEnd != -1)
{
result = strSource.Substring(0, iEnd);
}
}
else
// stay where we are
result = strSource;
return result;
}
public static string GetOnlineWebPage(string url, string pageLocation)
{
/* THIS FUNCTION GETS ONLINEWEBPAGES AS LONG AS THEY ARE NOT HTTPS. THE NETDUINO AT THIS POINT DOESNT
* HANDLE DEALING WITH HTTPS PAGES OR SSL. THE WORK AROUND TO THIS IS TO USE AN PHP WEBSITE. THE FUNCITON
* RETURNS THE ENTIRE WEBSITE AS A LONG, LONG STRING. ALL OF THE HTML WILL BE RETURNED WITH THIS FUNCTION
* SUCH AS HEADER AND BODY BREAKS. THIS FUNCTION GOES HAND IN HAND WITH GETSTRINGINBETWEEN
*
* INPUT: URL ---> A STRING WHICH CONTAINS THE URL OF THE SITE SUCH AS HTTP://WWW.GMAIL.COM
*
* OUTPUT: A STRING WHICH CONTAINS ALL THE RAW DATA OF THE WEBSITE
*
* SAMPLE CALL: clMisc.getOnlineWebPage("www.smarcus3.x10.mx");
*
* BASED ON THE INTEGRATEDSOCKET EXAMPLE
*/
//string Text = "";
StringBuilder sb = new StringBuilder();
// Defines the socket, including the remote host and port
SimpleSocket Socket = new IntegratedSocket(url, 80); //SimpleSocket Socket = new IntegratedSocket("www.smarcus3.x10.mx", 80);
// Connects to the socket
Socket.Connect();
// /ig/api?stock=EEM for finance
// / for the root file i.e. emails
// Does a plain HTTP request
Socket.Send("GET " + pageLocation + " HTTP/1.1\r\n");
Socket.Send("Host: " + Socket.Hostname + "\r\n");
Socket.Send("Connection: Close\r\n");
Socket.Send("\r\n");
// Prints all received data to the debug window, until the connection is terminated and there's no data left anymore
while (Socket.IsConnected || Socket.BytesAvailable > 0)
{
sb.Append(Socket.Receive());
}
// Closes down the socket
Socket.Close();
return sb.ToString();
}
public static char[] Bytes2Chars(byte[] Input)
{
char[] Output = new char[Input.Length];
for (int Counter = 0; Counter < Input.Length; ++Counter)
Output[Counter] = (char)Input[Counter];
return Output;
}
/// <summary>
/// Converts a char array to a byte array
/// </summary>
/// <param name="Input">The char array</param>
/// <returns>The byte array</returns>
public static byte[] Chars2Bytes(char[] Input)
{
byte[] Output = new byte[Input.Length];
for (int Counter = 0; Counter < Input.Length; ++Counter)
Output[Counter] = (byte)Input[Counter];
return Output;
}
}
}
clEmail.cs
using System;
using Microsoft.SPOT;
namespace EmailStockChecker
{
public static class clEmail
{
public static int GetUnreadEmailCount(string url)
{
string rawData = clMisc.GetOnlineWebPage(url,"/");
try
{
return Int32.Parse(clMisc.GetStringInBetween("UNREAD_", "_UNREAD", rawData));
}
catch
{
//For when the webpage cannot be grabbed
return 0;
}
}
}
}
clFinance.cs
using System;
using System.Threading;
using System.IO.Ports;
using System.Text;
using System.IO;
using Microsoft.SPOT;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
namespace EmailStockChecker
{
public class clFinance
{
//MODIFED CODE FROM: http://www.jarloo.com/google-stock-api/
//USER DEFINED
private string Ticker;
private double OwnedShares;
//Gets from Online - GOOGLE
//private string Company;
//private string Exchange;
private double Last;
private double Change;
private double PercentChange;
private double DailyChange;
private double MarketValue;
public clFinance(string ticker, double ownedShares)
{
//Constructor
Ticker = ticker;
OwnedShares = ownedShares;
//Updates the info for the first time.
//UpdateStock();
}
public string GetTicker()
{
return Ticker;
}
public void UpdateStock(){
FetchQuote(Ticker);
}
public double GetLastPrice()
{
return Last;
}
public double GetDailyChange()
{
return DailyChange;
}
public double GetMarketValue()
{
return MarketValue;
}
public double GetPercentChange()
{
return PercentChange;
}
public double GetChange()
{
return Change;
}
private void FetchQuote(string symbol)
{
//string url = "www.google.com"; //ig/api?stock=" + symbol; //string url = "http://www.google.com/ig/api?stock=" + symbol;
//string temp = clMisc.GetOnlineWebPage("www.google.com","/ig/api?stock=EEM");
string RawWebData = clMisc.GetOnlineWebPage("www.google.com", "/ig/api?stock=" + symbol); //,400,300);
string tempString = "";
//Parse the data
//temp = clMisc.GetStringInBetween("<symbol data=\"", "\"/>", temp);
//Company = clMisc.GetStringInBetween("<company data=\"","\"/>",RawWebData);
//Exchange = clMisc.GetStringInBetween("<exchange data=\"","\"/>",RawWebData);
//Try Catch incase data couldn't be read from the website.
try
{
string temp = clMisc.GetStringInBetween("<last data=\"", "\"/>", RawWebData);
Last = Double.Parse(clMisc.GetStringInBetween("<last data=\"", "\"/>", RawWebData));
tempString = clMisc.GetStringInBetween("<change data=\"", "\"/>", RawWebData);
//Fixes for negatives. For some reasons converting with the negative sign is not working. Do not know what is causing this.
if (tempString.Substring(0, 1) == "-" && Double.Parse(tempString) >= 0)
Change = Double.Parse(tempString) * -1;
else
Change = Double.Parse(tempString);
tempString = clMisc.GetStringInBetween("<perc_change data=\"", "\"/>", RawWebData);
//Fixes for negatives. For some reasons converting with the negative sign is not working. Do not know what is causing this.
if (tempString.Substring(0, 1) == "-" && Double.Parse(tempString) >= 0)
PercentChange = Double.Parse(tempString) * -1; //PercentChange = ((int)((Double.Parse(tempString) * -1) * 100) / 100.0);
else
PercentChange = Double.Parse(tempString); //PercentChange = ((int)((Double.Parse(tempString)) * 100) / 100.0);
DailyChange = Change * OwnedShares; //* 100) / 100.0);
MarketValue = Last * OwnedShares; ; //* 100) / 100.0);
}
catch
{
Last = 1;
Change = 4;
PercentChange = 5;
DailyChange = 123;
MarketValue = 4556;
}
}
}
}
Servo.cs
/*
* Servo NETMF Driver
* Coded by Chris Seto August 2010
* <chris@chrisseto.com>
*
* Use this code for whatveer you want. Modify it, redistribute it, I don't care.
* I do ask that you please keep this header intact, however.
* If you modfy the driver, please include your contribution below:
*
* Chris Seto: Inital release (1.0)
* Chris Seto: Netduino port (1.0 -> Netduino branch)
*
*
* */
using System;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
namespace Servo_API
{
public class Servo : IDisposable
{
/// <summary>
/// PWM handle
/// </summary>
private PWM servo;
/// <summary>
/// Timings range
/// </summary>
private int[] range = new int[2];
/// <summary>
/// Set servo inversion
/// </summary>
public bool inverted = false;
/// <summary>
/// Create the PWM pin, set it low and configure timings
/// </summary>
/// <param name="pin"></param>
public Servo(Cpu.Pin pin)
{
// Init the PWM pin
servo = new PWM((Cpu.Pin)pin);
// See what the Netduino team say about this...
//servo.Set(false);
// Typical settings
range[0] = 1000;
range[1] = 2000;
}
public void Dispose()
{
servo.Dispose();
}
/// <summary>
/// Allow the user to set cutom timings
/// </summary>
/// <param name="fullLeft"></param>
/// <param name="fullRight"></param>
public void setRange(int fullLeft, int fullRight)
{
range[1] = fullLeft;
range[0] = fullRight;
}
/// <summary>
/// Disengage the servo.
/// The servo motor will stop trying to maintain an angle
/// </summary>
public void disengage()
{
// See what the Netduino team say about this...
servo.SetDutyCycle(0);
}
/// <summary>
/// Set the servo degree
/// </summary>
public double Degree
{
set
{
/// Range checks
if (value > 180)
value = 180;
if (value < 0)
value = 0;
// Are we inverted?
if (inverted)
value = 180 - value;
// Set the pulse
servo.SetPulse(20000, (uint)map((long)value, 0, 180, range[0], range[1]));
}
}
/// <summary>
/// Used internally to map a value of one scale to another
/// </summary>
/// <param name="x"></param>
/// <param name="in_min"></param>
/// <param name="in_max"></param>
/// <param name="out_min"></param>
/// <param name="out_max"></param>
/// <returns></returns>
private long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
}
}
Whats better than getting notified of emails and stock data ...
Getting the weather as well. I decided to parse yahoo's weather api data and add it along side the stock data on the LCD screen. Below are a few screenshots and the new clWeather.cs The code isn't optimized, but just a first pass. The number in the bottom right corner is the number of seconds till the screen updates.