Connecting Embedded Devices to Windows Phone 7

Technorati Tags: .NET Micro Framework,NETMF,.NET,web Services,Windows Phone 7,Silverlight

For our recent trip to Maker Faire, the team built a number of demos.  One included controlling a remote device and exposing data collected from a set of sensors on Windows Phone 7.  There was a main controller device that communicated with distant sensors through a mesh network (802.15.4).  The controller device includes a camera mounted on a servo that moves back and forth raking pictures of the area.  The camera can also be directed to a specific area remotely through the interface described below:

The controller device hosts a web server and connects through WiFi or a wired connection.  The user browses to the .htm page that hosts the Silverlight application.  The Silverlight application is stored on an SD card connected to the embedded device.  Once this application has been downloaded to the desktop, it sends an http request to the web server which returns an xml document (shown below).  The camera can be moved to a specific position by adding a parameter to the url (e.g. https://192.168.1.108/module/remote.data?angle=-25)    If the Server finds a parameter named ‘angle, it instructs the servo accordingly.

(Much of this is built with on the work of Elze Kool whose NET libraries supply classes for HTTPHeader, HTTPServer, HTTPSEeverWorker, IRequestHandler, and RequestParameters which make the web service work much easier.  These libraries can be found at https://www.microframework.nl/projects/multithreaded-webserver-class/)

The XML that is returned looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<root>
  <module type="Camera" timestamp="Jan-01-2009 12:16:05 AM">
    <imageUrl>https://192.168.1.108/module/camera.jpg</imageUrl>
  </module>
  <module type="Motor" timestamp="Jan-01-2009 12:16:05 AM">
    <angle>0</angle>
  </module>
  <module type="Temperature" timestamp="Jan-01-2009 12:16:05 AM">
    <temperature>24.210000000000001</temperature>
    <humidity>60.350000000000001</humidity>
  </module>
</root>

and the PC Silverlight app looks like this:

clip_image002

Now for the Windows Phone part.

This also written in Silverlight keeps the same look.

clip_image002[5]         clip_image004         clip_image002[7]

And connecting the the web service and managing the data is very easy in .NET as you can see in this example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Media.Imaging;
using Gadgeteer.RemoteMonitor.ViewModels;
using System.Xml;
using System.IO;
using System.Xml.Linq;

namespace Gadgeteer.RemoteMonitor
{
    public partial class MainPage : PhoneApplicationPage
    {

       const string imageUrl = "https://…/Module/camera.jpg";
       const string remoteDataUrl = "https://…/Module/Remote.data";

        WebClient wc;

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Set the data context of the listbox control to the sample data
            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            sldrCameraAngle.IsEnabled = false;     
            wc = new WebClient();
            wc.DownloadStringAsync(new Uri(remoteDataUrl));
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
        }

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            double angle;
            sldrCameraAngle.IsEnabled = true;
            if (!(e.Result.Contains("root"))) return;
            string xml = e.Result; 
             XDocument xDoc = XDocument.Load(new StringReader(xml));         

            var q = from c in xDoc.Descendants("module")
                    select c;

            temperatureDisplay1.TemperatureInCelsius = (int)Double.Parse(q.Elements("temperature").First().Value);
            txtHumidity.Text =  Math.Round(Double.Parse(q.Elements("humidity").First().Value), 2).ToString();
            angle = double.Parse((q.Elements("angle").First().Value));
            txtCameraAngle.Text = angle.ToString();
            sldrCameraAngle.Value = angle;

            ImageSource img = new BitmapImage(new Uri(imageUrl, UriKind.Absolute));

            imgCamera.Source = img;

            switch (Settings.TemperatureUnit)
            {
                case "Farenheit":
                    temperatureDisplay1.TemperatureScale = Components.TemperatureTypes.Farenheit;
                    break;

                case "Celsius":
                    temperatureDisplay1.TemperatureScale = Components.TemperatureTypes.Celsius;
                    break;

                case "Kelvin":
                    temperatureDisplay1.TemperatureScale = Components.TemperatureTypes.Kelvin;
                    break;
            }
        }

        private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/Settings.xaml", UriKind.Relative));
        }

        private void sldrCameraAngle_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            sldrCameraAngle.IsEnabled = false;
            int angle = (int) Math.Round(sldrCameraAngle.Value, 0);
            wc = new WebClient();
            wc.DownloadStringAsync(new Uri(remoteDataUrl + "?angle=" + angle.ToString()));
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
        }

        private void imgRefresh_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            sldrCameraAngle.IsEnabled = false;
            wc = new WebClient();
            wc.DownloadStringAsync(new Uri(remoteDataUrl + "?Guid=" + Guid.NewGuid().ToString()));
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
        }

    }
}

With .NET and web services, we now quickly have embedded devices talking to PCs, phones and other services in the cloud.  With this, you can put together a device that lets you peer into your yard at home from wherever you are using your Windows Phone 7.  What more could you ask for?  The ‘Internet of Things’ is an exciting area to be thinking about.