Notes About Working with Various Arduino & Netduino Microcontroller Boards

Monday, November 26, 2012

ePIR Motion Detector & Netduino Plus 2: Example 2

The following sample code builds on my previous example using the Zilog ePIR motion detector with a Netduino Plus 2.

This version adds a couple bits of functionality: it sets the Netduino's clock to the correct time by calling a network time server and logs detections (with date & time) to an SD card, using the card slot provided by the Netduino Plus 2..

As noted in my previous post about writing to an SD card with a Netduino Plus, don't forget to add a reference to System.IO in the project.

Connections:

ePIR   -->  Netduino Plus 2   
pin 1       GND
pin 2       3.3V
pin 3       Digital 1 (TX)
pin 4       Digital 0 (RX) + 100k pull-up resistor
pin 6       3.3V  (no light level correction)

C# Code:

using System;

using System.IO;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;

namespace ePIR
{
    public class Program
    {
        const byte STATUS_CMD = 0x61;       // ePIR command to read status
        const int DELAY = 1000;
        const String NTP = "time.nist.gov"; // NTP server
        const int TZ = -6;                  // Offset from GMT
        const String COM_PORT = "COM1";     // COM port to use with ePIR

        // Network time update code from 
        // http://www.jaypm.com/2011/09/setting-the-netduinos-datetime-automatically/
        public static bool UpdateTimeFromNtpServer(string server, int timeZoneOffset)
        {
            try
            {
                var currentTime = GetNtpTime(server, timeZoneOffset);
                Microsoft.SPOT.Hardware.Utility.SetLocalTime(currentTime);
                return true;
            }
            catch(Exception ex)
            {
                Debug.Print(ex.Message);
                return false; 
            }
        }

        private static DateTime GetNtpTime(String timeServer, int timeZoneOffset)
        {
            // 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 20s send/receive timeout and connect
                s.SendTimeout = s.ReceiveTimeout = 20000;
                s.Connect(ep);
                ntpData[0] = 0x1B;   // Set protocol version
                s.Send(ntpData);     // Send Request
                s.Receive(ntpData);  // Receive Time
                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;
        }

        public static bool writeToLog(String msg)
        {
            DateTime now = DateTime.Now;
            String fileName = @"SD\" + now.Year.ToString() + now.Month.ToString() + now.Day + ".log";
            // FileMode.Append will create file if it does not exist
            using (var filestream = new FileStream(fileName, FileMode.Append))
            {
                StreamWriter streamWriter = new StreamWriter(filestream);
                streamWriter.WriteLine(msg + "\n");
                streamWriter.Close();
            }
            return true;
        }

        public static void Main()
        {
            if (UpdateTimeFromNtpServer(NTP, TZ))
            {
                SerialPort serialPort = new SerialPort(COM_PORT, 9600, Parity.None, 8, StopBits.One);
                serialPort.Open();
                while (true)
                {
                    serialPort.WriteByte(STATUS_CMD);
                    Thread.Sleep(100);
                    char result = (char)serialPort.ReadByte();
                    // Reponse 'Y' means that motion was detected
                    if (result == 'Y')
                    {
                        String msg = "Motion detected: " + DateTime.Now.ToString();
                        Debug.Print(msg);
                        writeToLog(msg);
                    }
                    Thread.Sleep(DELAY);
                }
            }
            else
            {
                Debug.Print("Error getting time.");
            }
        }
    }
}

No comments:

Post a Comment