Posts tagged Microcontrollers


I’ve needed a clock that shows multiple time zones so I can schedule meetings with remote offices during times that overlap regular business hours. I couldn’t find anything on the market that did that, so I decided to build this product myself. This blog post shows how it was built.

Programming with .Net Gadgeteer

The software was written in C# for the .Net Micro Framework. It uses hardware that is compatible with the .Net Gadgeteer platform.

Shematic Diagram

This is the view from the designer in Visual Studio

image

Location Configuration

Each RFID card has an associated location stored on the Micro SD card. Here is an example of the configuration file stored on the card:

<configuration>
  <appSettings>
    <add key="LogLevel" value="Debug" />
    <add key="Wifi.Network" value="ssid-here" />
    <add key="Wifi.Password" value="network-password-here" />
    <add key="RFID.4D00559A66.Location" value="Portland, OR" />
    <add key="RFID.4D006CE088.Location" value="Georgia, GA" />
    <add key="RFID.4D005589A1.Location" value="Auckaland, New Zealand" />
    <add key="RFID.4D0055D211.Location" value="Bangalore, India" />
    <add key="RFID.4D0055D01C.Location" value="Tel Aviv, Israel" />
    <add key="RFID.4D00558F43.Location" value="London, UK" />
  </appSettings>
</configuration>

You’ll notice the pattern of “RFID.car id.Location”, the “card id” is what is read when you place an RFID card over a reader. This is used to get the corresponding location, like “Portland, OR” from the configuration file. The location is then used to get the current time and sun profile.

private TimeZoneInfo GetTimeZone(string cardId)
{
    string location;
    TimeZoneInfo timeZoneInfo;
    if (!locations.Contains(cardId))
    {
        var cacheKey = "RFID." + cardId + ".Location";
        location = configurationManager.GetSetting(cacheKey);
        locations.Put(cardId, location);
    }
    else
        location = (string) locations.Get(cardId);

    if (!timeZones.Contains(cardId))
    {
        var geoPoint = geoLocationService.GetLocationGeoPoint(location);
        timeZoneInfo = geoTimeZoneService.GetTimeZoneInfo(geoPoint);
        timeZones.Put(cardId, timeZoneInfo);
    }
    else
        timeZoneInfo = (TimeZoneInfo) timeZones.Get(cardId);

    return timeZoneInfo;
}

The current time is displayed on the LED matrix modules. The sun profile is used to display “sunny hours” with blue dots.

Green dots are used to show “standard work hours” (8am to 5pm / Mon-Fri). This is helpful when arranging ad hock meetings with various locations because it gives a quick indicator when there will be overlap during standard business hours. 

The main part of the program

private void ProgramStarted()
{
    configurationManager = new XmlConfigurationManager(sdCard);
    logger = new DebugLogger(configurationManager);
    networkManager = new WifiNetworkManager(wifi, configurationManager, logger);
    timeManager = new NativeTimeManager(configurationManager, logger);
    geoLocationService = new GoogleGeoLocationService(logger);
    geoTimeZoneService = new EarthToolsGeoTimeZoneService(logger);
    bitmapProvider = new DoubleNumberBitmapProvider();

    RFID1.DebugPrintEnabled = true;
    RFID2.DebugPrintEnabled = true;
    RFID3.DebugPrintEnabled = true;

    RFID1.CardIDReceived += (sender, id) =>
                                {
                                    if (timeZoneId1 == id) return;
                                    timeZoneId1 = id;
                                    multipleTimeZoneDisplay.UpdateTimeZoneForRow(0, GetTimeZone(id));
                                };
    RFID2.CardIDReceived += (sender, id) =>
                                {
                                    if (timeZoneId2 == id) return;
                                    timeZoneId2 = id;
                                    multipleTimeZoneDisplay.UpdateTimeZoneForRow(1, GetTimeZone(id));
                                };
    RFID3.CardIDReceived += (sender, id) =>
                                {
                                    if (timeZoneId3 == id) return;
                                    timeZoneId3 = id;
                                    multipleTimeZoneDisplay.UpdateTimeZoneForRow(2, GetTimeZone(id));
                                };

    networkManager.Connected += (sender, args) =>
                                    {
                                        timeManager.ApplySettings();
                                        timeManager.StartTimeService();
                                    };
    timeManager.TimeServiceStarted += OnTimeServiceStarted;

    timeManager.MinuteChanged += (sender, args) => multipleTimeZoneDisplay.WriteCurrentTime();

    networkManager.Connect();
}

As you can see in the above code each RFID card can raise an event “CardIDReceived”, which is programmed to update the display for the specific row it’s on.

There are several “managers” that abstract the details of things, like a geoTimeZoneService that integrates with Earth Tools to get the current offset (daylight time) and sunrise/sunset hours. Another geoLocationService that integrates with Google to get latitude and longitude for a given location. The timeManager synchronizes time with a time server. Finally, the wifiNetworkManager is used to establish a internet connection with a local Wifi network.

Parts / Costs

The whole thing has about $500 worth of electronics, and about $75 worth of wood. Here is the invoice of some key parts I bought from GHI Electronics:

  • FEZ Spider Mainboard (1 @ $119.95) $119.95
  • Gadgeteer Standoff Pack (3 @ $1.95) $5.85
  • Extender Module (1 @ $4.95) $4.95
  • 5x Breakout Module Set (1 @ $4.99) $4.99
  • USB Client DP Module (1 @ $24.95) $24.95
  • RFID Reader Module (3 @ $24.95) $74.85
  • SD Card Module (1 @ $6.95) $6.95
  • LED Matrix Module (DaisyLink) (6 @ $19.95) $119.70
  • WiFi RS21 Module (1 @ $79.95) $79.95

From Amazon.com, you can find the RGB LED strips: