Hello World Wide Web?! Do you have the time?

The Keeping track part was fun, but for a real time system we need to be able to send the data over the network.
And it seems not only for that reason, as you might have noticed in my earlier published code there is a comment about logging the current date time.
There isn’t a Real Time Clock on the Netduino so you have to sync it with the real world when starting.

Especially if you want to keep a local log of temperature. In which case the Date & Time is very relevant.
So I have searched and found this way to go to one of the popular time servers and retrieve the date & time.

So I’m going to start with that and make a seperate post about sending the data.

Based on the code I made following controller.

I’ve added 4 popular time servers, so the code basically gets the time from time server(currently NTP is selected) and updates the internal clock using Microsoft.SPOT.Hardware.Utility.SetLocalTime().

public static class DateTimeController
{
public static void UpdateInternalClock()
{
UpdateTimeFromNtpServer(GetUrlFor(TimeServerEnum.Ntp),1);
}

private static string GetUrlFor(TimeServerEnum setting)
{
switch (setting)
{
case TimeServerEnum.Ntp:
return "pool.ntp.org";
case TimeServerEnum.Nist:
return "time.nist.gov";
case TimeServerEnum.NistA:
return "time-a.nist.gov";
case TimeServerEnum.NistB:
return "time-b.nist.gov";
default:
return string.Empty;
}
}

private static bool UpdateTimeFromNtpServer(string server, int timeZoneOffset)
{
try
{
var currentTime = GetTimeFromServer(server, timeZoneOffset);
Microsoft.SPOT.Hardware.Utility.SetLocalTime(currentTime);
Debug.Print("Time updated to : " + currentTime);
Debug.Print("Testing local time : " + DateTime.Now);
return true;
}
catch (Exception ex)
{
var error = "Error updating time from server " + server + ". Possible cause: " + ex.Message;
Debug.Print(error);
StorageController.WriteLogLine(error);
return false;
}
}

/// <summary>
/// Get DateTime from NTP Server
/// Based on:
/// http://weblogs.asp.net/mschwarz/archive/2008/03/09/wrong-datetime-on-net-micro-framework-devices.aspx
/// </summary>
/// <param name="timeServer">Time Server (NTP) address</param>
/// <param name="timeZoneOffset">Difference in hours from UTC</param>
/// <returns>Local NTP Time</returns>
private static DateTime GetTimeFromServer(String timeServer, int timeZoneOffset)
{
try
{
// Find endpoint for TimeServer
var ep = new IPEndPoint(Dns.GetHostEntry(timeServer).AddressList[0], 123);

// Make send/receive buffer
var ntpData = new byte[48];

// Connect to TimeServer
using (var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
// Set 10s send/receive timeout and connect
s.SendTimeout = s.ReceiveTimeout = 10000; // 10,000 ms
s.Connect(ep);

// Set protocol version
ntpData[0] = 0x1B;

// Send Request
s.Send(ntpData);

// Receive Time
s.Receive(ntpData);

// Close the socket
s.Close();
}

const byte offsetTransmitTime = 40;

ulong intpart = 0;
ulong fractpart = 0;

for (var i = 0; i <= 3; i++)
intpart = (intpart << 8) | ntpData[offsetTransmitTime + i];

for (var i = 4; i <= 7; i++)
fractpart = (fractpart << 8) | ntpData[offsetTransmitTime + i];

ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);

var timeSpan = TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond);
var dateTime = new DateTime(1900, 1, 1);
dateTime += timeSpan;

var offsetAmount = new TimeSpan(timeZoneOffset, 0, 0);
var networkDateTime = (dateTime + offsetAmount);

return networkDateTime;
}
catch (Exception ex)
{
Debug.Print("Couldn't get time from timeserver because " + ex.Message);
return DateTime.Now;
}

}

Of course the time zone needs to be adjusted to your local time.

This caused me to update my StorageController because I can now add relevant Date & Time data about the logged Temperature.
So now logging the date time happens on files created each day and loglines contain datetime info. I’ve also added the creation of loglines when exceptions occur.

    public static class StorageController
    {
        public static void SaveTemperature(double value, TemperatureEnum setting)
        {
            WriteTemperatureLine(value, setting);
        }

        public static void PrintTodayLogToDebug()
        {
            Debug.Print("----");
            ReadTextFile(GetTodayFileName(), true);
        }

        public static void WriteLogLine(string line)
        {
            WriteTextFile(GetTodayLogFileName(), line);
        }

        private static string GetTodayFileName()
        {
            return @"\SD\" + DateTime.Today.ToString("yyyyMMdd ") + ".log"; ;
        }
        private static string GetTodayLogFileName()
        {
            return @"\SD\" + DateTime.Today.ToString("yyyyMMdd") + "_Error.log"; ;
        }

        private static void WriteTemperatureLine(double value, TemperatureEnum setting)
        {
            var line = value + TemperatureController.GetTemperatureFormat(setting) + "-" + DateTime.Now;
            WriteTextFile(GetTodayFileName(), line);
        }


        public static void CleanFile()
        {
            try
            {
                var path = GetTodayFileName();
                File.Create(path).Close();
            }
            catch (Exception ex)
            {
                var error = "Error Cleaning file : " + ex.Message;
                Debug.Print(error);
                WriteLogLine(error);
            }

        }

        private static void WriteTextFile(string fileName, string line)
        {
            try
            {
                var existingContent = ReadTextFile(fileName, false);

                using (var filestream = new FileStream(fileName, FileMode.Create))
                {
                    var streamWriter = new StreamWriter(filestream);
                    if (existingContent != null && existingContent != string.Empty) // string.IsNullOrEmpty is not available in .NET MF 4.1
                        streamWriter.WriteLine(existingContent);
                    streamWriter.WriteLine(line);
                    Debug.Print("Wrote line " + line);
                    streamWriter.Close();
                }
            }
            catch (Exception ex)
            {
                var error = "WriteTextFile Error:" + ex.Message;
                Debug.Print(error);
                WriteLogLine(error);
            }
        }

        private static string ReadTextFile(string fileName, bool readoutToDebugWindow)
        {
            var content = string.Empty;
            try
            {
                if (!File.Exists(fileName)) return string.Empty;
                using (var reader = new StreamReader(fileName))
                {
                    content = reader.ReadToEnd();
                    reader.Close();
                }
            }
            catch (Exception ex)
            {
                var error = "ReadTextFile Error:" + ex.Message;
                Debug.Print(error);
                WriteLogLine("Read Error: " + error);

            }

            return TrimOutDoubleNewLines(content, readoutToDebugWindow);
        }

        private static string TrimOutDoubleNewLines(string content, bool readoutToDebugWindow)
        {
            try
            {
                var sb = new StringBuilder(content);
                sb.Replace("\r\n\r\n", "\n");
                var returnString = sb.ToString();
                if (readoutToDebugWindow) Debug.Print(returnString);
                return returnString;
            }
            catch (Exception ex)
            {
                var error = "Error trimming out double lines : " + ex.Message;
                Debug.Print(error);
                WriteLogLine(error);
                return content;
            }

        }

        public static void IndexFolderToDebug()
        {
            var list = Directory.GetFiles(@"\SD\");
            Debug.Print(@"Existing files");
            foreach (var s in list)
            {
                Debug.Print(s);
            }
        }

        public static void DeleteAllFilesOnNetduino()
        {
            try
            {
                var list = Directory.GetFiles(@"\SD\");
                Debug.Print(@"Erasing all files");
                foreach (var s in list)
                    File.Delete(s);
            }
            catch (Exception ex)
            {
                Debug.Print("Error erasing all files " + ex.Message);
            }

        }
    }

And in case you are wondering this is what my Program.cs looks like

public static class Program
    {
        private static Timer _tmr;
        private static OneWireTemperatureSensorController _tempertureController;

        public static void Main()
        {
            RegisterControllers();
            RunStartupLeds();

            //StorageController.DeleteAllFilesOnNetduino();
            //StorageController.CleanFile();
            StorageController.IndexFolderToDebug();

            while (true)
            {
                Tick(null);
                //Thread.Sleep(10 * 1000 ); //sleep 10 seconds
                Thread.Sleep(1000 * 60 * 30); //sleep 30 minutes
            }


        }

        private static void RegisterControllers()
        {
            _tempertureController = new OneWireTemperatureSensorController(Pins.GPIO_PIN_D0);
        }


        private static void Tick(object state)
        {
            LedController.BlinkLight(50);
            var temp = ReadHumidityAndTemperature();
            DateTimeController.UpdateInternalClock();
            StorageController.SaveTemperature(temp, TemperatureEnum.Celcius);
            StorageController.PrintTodayLogToDebug();
            LedController.BlinkPowerLight(50);
        }

        private static void DisablePowerLed()
        {
            PowerManagementController.SetPowerLedState(false);
        }

        private static void RunStartupLeds()
        {
            LedController.BlinkAllLights(3, 50);
        }

        private static double ReadHumidityAndTemperature()
        {
            try
            {
                return _tempertureController.ReadTemperatureToConsole(TemperatureEnum.Celcius, false);
            }
            catch (Exception ex)
            {
                Debug.Print("ReadHumidityAndTemperature " + ex.Message);
                
            }
            return -999;
        }

    }
About these ads

Care to comment?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s