Sending .NET Gadgeteer Sensor Data to a REST Web Service

Sending data to a Web service from a device with an embedded microprocessor is a very common and useful scenario.  This example demonstrates the procedures using the .NET Gadgeteer Pulse Oximeter manufactured by Seeed Studio and a REST Web service implemented on the Windows Communication Foundation (WCF) platform.

This post has been updated to use HttpHelper.CreateHttpPostRequest.

The Seeed Pulse Oximeter is a monitoring device that measures pulse and non-invasively detects oxygen saturation of the blood.  An earlier post shows how to use the the Pulse Oximeter in a .NET Gadgeteer application.  This example adds display of data using the Display_T35 module manufactured by GHI Electronics. This post also demonstrates the implementation of a REST Web service that records data about pulse and blood oxygenation from the Pulse Oximeter. The monitoring device can be near or far from the Web service that records data and provides display of the data in a Web browser.

The Web service implementation uses the Windows Communication Foundation (WCF) REST service template for C# and version 4.0 of the .NET Framework.  Data is recorded using programmable classes based on the .NET Entity Framework.  The Entity Framework (EF) is an object-relational mapping model supported by the .NET platform.  Visual Studio provides templates for using the Entity Framework and Entity Data Model (EDM) . The EDM maps programmable classes to a relational database, in this case the data is stored in SQL Server Express. Entity objects manage data in the methods stubbed out by the WCF template.

The display page for data recorded by the service is a simple ASP.NET Web form with a GridView control and the Entity Data Source control.  If you are interested in extensive use of the EDM and/or the Entity Data Source control, see The Entity Framework and ASP.NET for an introduction and tutorial.

This example also uses the .NET Micro Framework Interim Solution to Ethernet_J11D workaround for the Ethernet module limitations.  As soon as this is fixed, some of the Web request syntax will be replaced with objects based on the the .NET Gadgeteer.Networking Namespace.

Pulse Oximeter Probe Attached

Pulse Oximeter Probe Attached

Monitoring Pulse and Blood Oxygenation Data with the Seeed Pulse Oximeter

The following code block shows the initialization of the PulseOximeter ProbeAttached, ProbeDetached, and Heartbeat events and a timer to regulate pulse and blood oxygenation data posts at 10 second intervals to the Web service.  The ButtonPressed event handler starts the timer and initializes the PulseOximeter.HeartbeatHandler.  On each pulseOximeter_Heartbeat event, the pulse and blood oxygenation data are displayed on the screen of the GHI Electronics Display_T35 module. The EthernetConnection object, which is used to send data to the Web service, is an instance of the workaround class, which is shown after the code for the PulseOximeter sensor.

using System;
using Microsoft.SPOT;
using System.Net;
using GT = Gadgeteer;
using Gadgeteer.Modules.GHIElectronics;
using Gadgeteer.Modules.Seeed;

// These directives support the EthernetConnection class workaround: http://wp.me/p1TEdE-bj .
using Microsoft.SPOT.Net.NetworkInformation; // Add this using directive.
using GHINET = GHIElectronics.NETMF.Net; // Add a reference to this libaray and using directive.

namespace PulseOxToWebService
{
    public partial class Program
    {
        string name;
        string pulseRate;
        string oxSat;
        GT.Timer timer;

        uint xIndex = 5;

        EthernetConnection ethernet;
        static bool IsNetworkUp = false;
        static public bool ethernet_last_status = false;

        void ProgramStarted()
        {
            pulseOximeter.ProbeAttached +=
            new PulseOximeter.ProbeAttachedHandler(pulseOximeter_ProbeAttached);
            pulseOximeter.ProbeDetached +=
            new PulseOximeter.ProbeDetachedHandler(pulseOximeter_ProbeDetached);
            button.ButtonPressed +=
                new Button.ButtonEventHandler(button_ButtonPressed);

            timer = new GT.Timer(10000);
            timer.Tick += new GT.Timer.TickEventHandler(timer_Tick);

            ethernet = new EthernetConnection();

            name = "TestName-4";
            Debug.Print("Using name: " + name);
            Debug.Print("Program Started");

            display.SimpleGraphics.DisplayText("Name: " + name,
                Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Red, 50, 60);
                display.SimpleGraphics.DisplayText("Network up? " + IsNetworkUp,
                Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Red, 50, 75);
        }

        void button_ButtonPressed(Button sender, Button.ButtonState state)
        {
            if (!button.IsLedOn && pulseOximeter.IsProbeAttached)
            {
                pulseOximeter.Heartbeat +=
                    new PulseOximeter.HeartbeatHandler(pulseOximeter_Heartbeat);
                button.TurnLEDOn();
                timer.Start();
            }
            else
            {
                pulseOximeter.Heartbeat -=
                    new PulseOximeter.HeartbeatHandler(pulseOximeter_Heartbeat);
                button.TurnLEDOff();
                timer.Stop();
            }
        }

        void timer_Tick(GT.Timer timer)
        {
            if (IsNetworkUp)
            {
                ethernet.SendPulseOximeterData(name, pulseRate, oxSat);
            }
            else
            {
                    display.SimpleGraphics.DisplayRectangle(GT.Color.Black, 2, GT.Color.Black, 50, 75, 150, 25);
                    display.SimpleGraphics.DisplayText("Network up? " + IsNetworkUp,
                    Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Red, 50, 75);

                pulseOximeter.Heartbeat -=
                        new PulseOximeter.HeartbeatHandler(pulseOximeter_Heartbeat);
                button.TurnLEDOff();
                timer.Stop();
            }
        }

        void pulseOximeter_Heartbeat(PulseOximeter sender, PulseOximeter.Reading reading)
        {
            pulseRate = reading.PulseRate.ToString();
            oxSat = reading.SPO2.ToString();

            display.SimpleGraphics.DisplayRectangle(GT.Color.Blue, 2, GT.Color.Black, 5, 5, 150, 25);
            display.SimpleGraphics.DisplayRectangle(GT.Color.Blue, 2, GT.Color.Black, 5, 30, 150, 25);

            display.SimpleGraphics.DisplayTextInRectangle("Oxygen Saturation: " + oxSat, 10, 10, 150, 50,
                                 GT.Color.Orange, Resources.GetFont(Resources.FontResources.small));
            display.SimpleGraphics.DisplayTextInRectangle("Pulse: " + pulseRate, 10, 35, 150, 50,
                                 GT.Color.Green, Resources.GetFont(Resources.FontResources.small));

            uint graph_x = xIndex++;

            if (graph_x + 5 > display.Width)
            {
                xIndex = 5;
                display.SimpleGraphics.Clear();
            }

            uint graph_y = (uint)reading.PulseRate;     // Scale the voltage to size of display.
            display.SimpleGraphics.SetPixel(GT.Color.Green, graph_x, display.SimpleGraphics.Height - graph_y);
            graph_y = (uint)reading.SPO2;
            display.SimpleGraphics.SetPixel(GT.Color.Orange, graph_x, display.SimpleGraphics.Height - graph_y);
        }

        void pulseOximeter_ProbeAttached(PulseOximeter sender)
        {
            display.SimpleGraphics.DisplayRectangle(GT.Color.Black, 2, GT.Color.Black, 25, 75, 150, 25);
            display.SimpleGraphics.DisplayText("Probe attached.",
                Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Green, 25, 75);

            display.SimpleGraphics.DisplayRectangle(GT.Color.Black, 2, GT.Color.Black, 25, 90, 150, 25);
            display.SimpleGraphics.DisplayText("Network up? " + IsNetworkUp,
                Resources.GetFont(Resources.FontResources.NinaB), IsNetworkUp? GT.Color.Green: GT.Color.Red, 25, 90);
        }

        void pulseOximeter_ProbeDetached(PulseOximeter sender)
        {
            display.SimpleGraphics.DisplayRectangle(GT.Color.Black, 2, GT.Color.Black, 25, 75, 150, 25);
            display.SimpleGraphics.DisplayText("Probe detached.",
                Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Red, 25, 75);

            display.SimpleGraphics.DisplayRectangle(GT.Color.Black, 2, GT.Color.Black, 25, 90, 150, 25);
                     display.SimpleGraphics.DisplayText("Network up? " + IsNetworkUp,
                     Resources.GetFont(Resources.FontResources.NinaB), IsNetworkUp ? GT.Color.Green : GT.Color.Red, 25, 90);

            timer.Stop();
            button.TurnLEDOff();
            pulseOximeter.Heartbeat -=
                    new PulseOximeter.HeartbeatHandler(pulseOximeter_Heartbeat);
        }
    }
}
Pulse Oximeter Data Display

Pulse Oximeter Data Display

Ethernet Connection Class

The EthernetConnection class contains the initialization of a network connection and a method to send PulseOximeter data to the Web service.  While debugging, the code prints IP and DNS information to the output window of Visual Studio.

The SendPulseOximeterData method initializes and sends an HttpWebRequest POST that contains the name of the subject whose vital signs are being monitored and the pulse and blood oxygenation data.  You can use the static CreateHttpPostRequest method of HttpHelper to create the request to the Web service.  The account identifier is specified by the URL  (the URL template is described in the Web service implementation following this code).  This example doesn’t need any information in the body of the POST request, so the POSTContent parameter is created without content.  Content type is null. This is an asynchronous method that gets the response in the delegate method, HttpRequest.ResponseReceived. The delegate is assigned before calling HttpRequest.SendRequest.

    class EthernetConnection
    {
        NetworkInterface[] netif = NetworkInterface.GetAllNetworkInterfaces();
        static public bool network_is_read = false;

        public EthernetConnection()
        {
            if (!GHINET.Ethernet.IsEnabled)
            {
                GHINET.Ethernet.Enable();
            }

            if (!GHINET.Ethernet.IsCableConnected)
            {
                Debug.Print("Cable is not connected!");
                IsNetworkUp = false;
            }

            Debug.Print("Ethernet cable is connected!");
            Debug.Print("Enable DHCP");
            try
            {
                if (!netif[0].IsDhcpEnabled)
                netif[0].EnableDhcp();  // This function is blocking
                else
                {
                    netif[0].RenewDhcpLease();  // This function is blocking
                }
                network_is_read = true;
                Debug.Print("Network settings:");
                Debug.Print("IP Address: " + netif[0].IPAddress);
                Debug.Print("Subnet Mask: " + netif[0].SubnetMask);
                Debug.Print("Default Getway: " + netif[0].GatewayAddress);
                Debug.Print("DNS Server: " + netif[0].DnsAddresses[0]);

                IsNetworkUp = true;
            }
            catch
            {
                IsNetworkUp = false;
                Debug.Print("DHCP Faild");
            }
        }

        public void SendPulseOximeterData(string name, string pulse, string oxg)
        {
            led.BlinkRepeatedly(GT.Color.White);

            POSTContent emptyPost = new POSTContent();
            var req =
                HttpHelper.CreateHttpPostRequest("http://integral-data.com/PulseOxData/reading/" +
                           name + "/" + pulse + "/" + oxg, emptyPost, null);

            req.ResponseReceived += new HttpRequest.ResponseHandler(req_ResponseReceived);
            req.SendRequest();
        }

        void req_ResponseReceived(HttpRequest sender, HttpResponse response)
        {
            if (response.StatusCode != "200")
            {
                Debug.Print(response.StatusCode);
                IsNetworkUp = false;
            }

            led.TurnOff();
        }
    }

Web Service to Record Pulse Oximeter Data and ASP.NET WebForm to Display the Data

Implementation of a Web service based on the Visual Studio WCF REST Web Service template has been detailed in a previous post: REST Web Service to Record Data from a .NET Gadgeteer Sensor Device.  As in the previous example, this Web service implements a POST method to record data. The URL syntax of the POST method contains the name of the subject and pulse and blood oxygenation data obtained from the PulseOximeter sensor.  The Web service also implements a GET method that can be used to get the data for a particular subject in XML format.  It also implements a ASP.NET Web Form to display the data in a datagrid control.

The data is contained by a database in SQL Server Express and mapped to Entity Data Model objects.  The Visual Studio tools and templates make this process quite simple.  See the post REST Web Service to Record Data from a .NET Gadgeteer Sensor Device for details of using the template, and see The Entity Framework and ASP.NET for more on the Entity Data Model (EDM) and ASP.NET.

The following illustration show the Entity Data Model for the Pulse Oximeter data in Visual Studio after a wizard creates it.

Entity Data Model in WCF REST Template

Entity Data Model in WCF REST Template

The following code contains the implentation of the GET and  POST methods for the REST PulseOxDataService.  The POST method URL syntax includes the path: “reading” and three parameters that follow forward slash (/) characters: {name}, {pulse}, and {ox}.  The path element, “reading”, is used literally in the URL string, and the parameters inside brackets {} are replaced by the actual values of subject name, pulse, and blood oxygenation.   All the parameters are sent as strings in accord with the text-based format of Internet protocol and REST.

The path element, “data”, indicates the GET method, and is followed by (/) and {name}, to spevcify the name of the subject of the tests for which to query.

    public class PulseOxDataService
    {
        // TODO: Implement the collection resource that will contain the SampleItem instances.
        // We don't need this collection because we're using Entity Data Model
        // mapped to SQL Server Compact Edition.

        [WebInvoke(UriTemplate = "reading/{name}/{pulse}/{ox}", Method = "POST")]
        public PulseOxReading Create(string name, string pulse, string ox)
        {
            using (PulseOxDatabaseEntities objectContext = new PulseOxDatabaseEntities())
            {
                PulseOxReading newReading = new PulseOxReading();
                newReading.Name = name;
                newReading.Pulse = int.Parse(pulse);
                newReading.OxygenSaturation = int.Parse(ox);
                newReading.Time = DateTime.Now;

                objectContext.PulseOxReadings.AddObject(newReading);
                objectContext.SaveChanges();

                return newReading;
            }
        }

        [WebGet(UriTemplate = "data/{name}")]
        public List GetCollection(string name)
        {
            using(PulseOxDatabaseEntities objectContext = new PulseOxDatabaseEntities())
            {
                List<PulseOxReading> list =
                    objectContext.PulseOxReadings.Where(item => item.Name == name).ToList<PulseOxReading>();
                return list;
            }
        }
    }

The GET method returns entity data serialized as XML as shown in the following example.

<ArrayOfPulseOxReading xmlns="http://schemas.datacontract.org/2004/07/PulseOxData"
                       xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <PulseOxReading z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
    <EntityKey z:Id="i2" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses"
               xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
      <a:EntityContainerName>PulseOxDatabaseEntities</a:EntityContainerName>
      <a:EntityKeyValues>
        <a:EntityKeyMember>
          <a:Key>Id</a:Key>
          <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">5</a:Value>
        </a:EntityKeyMember>
      </a:EntityKeyValues>
      <a:EntitySetName>PulseOxReadings</a:EntitySetName>
    </EntityKey>
    <Id>5</Id>
    <Name>TestName-4</Name>
    <OxygenSaturation>73</OxygenSaturation>
    <Pulse>63</Pulse>
    <Time>2011-12-12T18:07:03.843</Time>
  </PulseOxReading>
  <PulseOxReading z:Id="i3" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
    <EntityKey z:Id="i4" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses"
               xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
      <a:EntityContainerName>PulseOxDatabaseEntities</a:EntityContainerName>
      <a:EntityKeyValues>
        <a:EntityKeyMember>
          <a:Key>Id</a:Key>
          <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">6</a:Value>
        </a:EntityKeyMember>
      </a:EntityKeyValues>
      <a:EntitySetName>PulseOxReadings</a:EntitySetName>
    </EntityKey>
    <Id>6</Id>
    <Name>TestName-4</Name>
    <OxygenSaturation>99</OxygenSaturation>
    <Pulse>63</Pulse>
    <Time>2011-12-12T18:07:12.813</Time>
  </PulseOxReading>
  <PulseOxReading z:Id="i5" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
    <EntityKey z:Id="i6" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses"
               xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
      <a:EntityContainerName>PulseOxDatabaseEntities</a:EntityContainerName>
      <a:EntityKeyValues>
        <a:EntityKeyMember>
          <a:Key>Id</a:Key>
          <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">7</a:Value>
        </a:EntityKeyMember>
      </a:EntityKeyValues>
      <a:EntitySetName>PulseOxReadings</a:EntitySetName>
    </EntityKey>
    <Id>7</Id>
    <Name>TestName-4</Name>
    <OxygenSaturation>100</OxygenSaturation>
    <Pulse>65</Pulse>
    <Time>2011-12-12T18:07:22.813</Time>
  </PulseOxReading>
  <PulseOxReading z:Id="i7" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
    <EntityKey z:Id="i8" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses"
               xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
      <a:EntityContainerName>PulseOxDatabaseEntities</a:EntityContainerName>
      <a:EntityKeyValues>
        <a:EntityKeyMember>
          <a:Key>Id</a:Key>
          <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">8</a:Value>
        </a:EntityKeyMember>
      </a:EntityKeyValues>
      <a:EntitySetName>PulseOxReadings</a:EntitySetName>
    </EntityKey>
    <Id>8</Id>
    <Name>TestName-4</Name>
    <OxygenSaturation>100</OxygenSaturation>
    <Pulse>64</Pulse>
    <Time>2011-12-12T18:07:32.813</Time>
  </PulseOxReading>
  <PulseOxReading z:Id="i9" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
    <EntityKey z:Id="i10" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses"
               xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
      <a:EntityContainerName>PulseOxDatabaseEntities</a:EntityContainerName>
      <a:EntityKeyValues>
        <a:EntityKeyMember>
          <a:Key>Id</a:Key>
          <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">9</a:Value>
        </a:EntityKeyMember>
      </a:EntityKeyValues>
      <a:EntitySetName>PulseOxReadings</a:EntitySetName>
    </EntityKey>
    <Id>9</Id>
    <Name>TestName-4</Name>
    <OxygenSaturation>99</OxygenSaturation>
    <Pulse>61</Pulse>
    <Time>2011-12-12T18:07:42.813</Time>
  </PulseOxReading>
</ArrayOfPulseOxReading>

The forgoing data could be parsed by various scripting languages for display by a Web browser.  Since the project we use to implement the REST Web service contains the SQL Server Express database with the data after it is generated by posts from the PulseOximeter, we can create an ASP.NET WebForm and access the data using the Entity Data Source control for display by a GridView control.

The following illustration shows the controls on the Visual Studio design surface.

Entity Data Source and GridView Controls

Entity Data Source and GridView Controls

The controls on the page include a TextBox for entry of the subject’s name; name is used in the Where clause to get data for a single subject.  The following code shows the TextBox1_TextChanged event handler. When the user enters a name and presses Enter, the code in the handler generates an entity query for all readings where name equals the name in the TextBox. The query loads the Entity Data Source and returns only the Pulse Oximeter readings for the given name.

using System;

namespace PulseOxData
{
    public partial class PulseOxDisplay : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void TextBox1_TextChanged(object sender, EventArgs e)
        {
            EntityDataSource1.Where = "it.Name = '" + TextBox1.Text + "'";
        }
    }
}

The following illustration shows the Web form running in a browser.

Pulse Blood Oxygen Data Display

Advertisements

, , , , ,

  1. #1 by Michael Dodaro on January 24, 2012 - 12:39 PM

    This post has been updated to use HttpHelper.CreateHttpPostRequest.

  2. #2 by Francisca on February 8, 2012 - 5:33 PM

    Hi! I buhogt a pulse sensor at Maker Faire this past Saturday (I think I was the first one to buy it too). I was wondering where I could find the processing code?

  3. #3 by Michael Dodaro on February 8, 2012 - 5:41 PM

    I have the following example that runs the Seeed Pulse Oximeter module with the GHI Spider mainboard: http://wp.me/p1TEdE-9Z

  4. #4 by mario on February 13, 2012 - 7:38 PM

    Hi,
    I can’t get my Pulse Oximeter to correctly detect the probe attached and detached conditions. It seems to always detect a pulse even with no finger. The three values returned are all over the range.
    pulseOximeter_Heartbeat:67==8==67
    pulseOximeter_Heartbeat:67==8==67
    pulseOximeter_Heartbeat:56==8==94
    pulseOximeter_Heartbeat:65==8==95
    pulseOximeter_Heartbeat:60==5==94
    pulseOximeter_Heartbeat:65==8==95
    When a finger is in, it would sometimes show these same values and sometimes it thinks that there is no finger. It actually thinks that there is no finger when there is a finger more than when there is no finger.
    I also have similar handlers for the probe connected and disconnected events. But they are rarely invoked. Probe connected happens when the Spider powers on and then almost never again.
    Do I have a bad sensor?

    I have posted at the seeed forum and at tinyCLR but so far no luck. Should I request an RMA?
    Thanks,
    Mario

    Here’s my test code, am I missing something?

    pulseOximeter.Heartbeat += new PulseOximeter.HeartbeatHandler(pulseOximeter_Heartbeat);

    void pulseOximeter_Heartbeat(PulseOximeter sender, PulseOximeter.Reading reading)
    {
    string s;
    if (!pulseOximeter.IsProbeAttached)
    {
    s = “pulseOximeter_HeartbeatLast:” + pulseOximeter.LastReading.PulseRate.ToString() + “==” + pulseOximeter.LastReading.SignalStrength.ToString() + “==” + pulseOximeter.LastReading.SPO2.ToString();
    }
    else
    {
    s = “pulseOximeter_Heartbeat:” + reading.PulseRate.ToString() + “==” + reading.SignalStrength.ToString() + “==” + reading.SPO2.ToString();
    }

    Debug.Print(s);

    }

    • #5 by Michael Dodaro on February 13, 2012 - 8:39 PM

      I have sometimes got bad results too. I have seen the events fire eratically. But, I just tried my module with the following code and results:

      using Microsoft.SPOT;
      using GTM = Gadgeteer.Modules;

      namespace PulseOximeter
      {
      public partial class Program
      {
      void ProgramStarted()
      {
      pulseOximeter.ProbeDetached += new GTM.Seeed.PulseOximeter.ProbeDetachedHandler(pulseOximeter_ProbeDetached);
      pulseOximeter.ProbeAttached += new GTM.Seeed.PulseOximeter.ProbeAttachedHandler(pulseOximeter_ProbeAttached);
      pulseOximeter.Heartbeat += new GTM.Seeed.PulseOximeter.HeartbeatHandler(pulseOximeter_Heartbeat);
      Debug.Print(“Program Started”);
      }

      void pulseOximeter_ProbeDetached(GTM.Seeed.PulseOximeter sender)
      {
      Debug.Print(“Probe detached”);
      Debug.Print(“”);
      }

      void pulseOximeter_Heartbeat(GTM.Seeed.PulseOximeter sender, GTM.Seeed.PulseOximeter.Reading reading)
      {
      Debug.Print(“Pulse rate: ” + sender.LastReading.PulseRate.ToString());
      Debug.Print(“Oxigenation: ” + sender.LastReading.SPO2.ToString());
      }

      void pulseOximeter_ProbeAttached(GTM.Seeed.PulseOximeter sender)
      {
      Debug.Print(“Probe attached.”);
      }

      }
      }

      As you can see, the results are dubious at first, but they improve after a while. If you don’t get better results after more testing, it seems that your module is defective.

      ‘Microsoft.SPOT.Debugger.CorDebug.dll’ (Managed): Loaded ‘C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.1\Assemblies\le\Microsoft.SPOT.Touch.dll’, Symbols loaded.
      The thread ” (0x2) has exited with code 0 (0x0).
      Using mainboard GHIElectronics-FEZSpider version 1.0
      Program Started
      Probe attached.
      Pulse rate: 135
      Oxigenation: 44
      Pulse rate: 135
      Oxigenation: 44
      Pulse rate: 135
      Oxigenation: 44
      Pulse rate: 135
      Oxigenation: 44
      Pulse rate: 135
      Oxigenation: 44
      Pulse rate: 135
      Oxigenation: 44
      Pulse rate: 65
      Oxigenation: 89
      Pulse rate: 65
      Oxigenation: 89
      Pulse rate: 65
      Oxigenation: 89
      Pulse rate: 65
      Oxigenation: 89
      Pulse rate: 65
      Oxigenation: 89
      Pulse rate: 65
      Oxigenation: 89
      Pulse rate: 65
      Oxigenation: 89
      Probe detached

      Probe attached.
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 55
      Oxigenation: 100
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 54
      Oxigenation: 99
      Pulse rate: 52
      Oxigenation: 99
      Pulse rate: 52
      Oxigenation: 99
      Pulse rate: 52
      Oxigenation: 99
      Probe detached

      Probe attached.
      Pulse rate: 52
      Oxigenation: 99
      Pulse rate: 52
      Oxigenation: 99
      Pulse rate: 52
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Pulse rate: 56
      Oxigenation: 99
      Probe detached

  5. #6 by mario on February 14, 2012 - 2:21 PM

    Still getting silly data. Will ask for rma…
    Thank you for your help,
    Mario

    Using mainboard GHIElectronics-FEZSpider version 1.0
    Program Started
    timer:1
    pulseOximeter_Heartbeat:73==6==76
    pulseOximeter_Heartbeat:73==8==76
    pulseOximeter_Heartbeat:73==8==76
    pulseOximeter_ProbeDetached:
    pulseOximeter_ProbeAttached:
    pulseOximeter_Heartbeat:73==8==76
    pulseOximeter_Heartbeat:73==6==76
    pulseOximeter_Heartbeat:73==3==76
    pulseOximeter_Heartbeat:72==5==85
    pulseOximeter_Heartbeat:72==7==85
    pulseOximeter_Heartbeat:72==5==85
    pulseOximeter_Heartbeat:72==7==85
    pulseOximeter_Heartbeat:72==5==85
    pulseOximeter_Heartbeat:72==5==85
    pulseOximeter_Heartbeat:72==5==85
    pulseOximeter_Heartbeat:72==6==85
    pulseOximeter_Heartbeat:72==8==85
    pulseOximeter_Heartbeat:61==7==88
    pulseOximeter_Heartbeat:61==5==88
    pulseOximeter_Heartbeat:61==6==88
    pulseOximeter_Heartbeat:61==4==88
    pulseOximeter_Heartbeat:61==8==88
    pulseOximeter_Heartbeat:61==6==88
    pulseOximeter_Heartbeat:61==3==88
    pulseOximeter_Heartbeat:61==4==88
    pulseOximeter_Heartbeat:61==6==88
    pulseOximeter_Heartbeat:65==6==90
    pulseOximeter_Heartbeat:65==6==90
    pulseOximeter_Heartbeat:65==5==90
    pulseOximeter_Heartbeat:65==3==90
    pulseOximeter_Heartbeat:65==5==90
    pulseOximeter_Heartbeat:65==5==90
    pulseOximeter_Heartbeat:65==7==90
    pulseOximeter_Heartbeat:65==5==90
    pulseOximeter_Heartbeat:65==5==90
    pulseOximeter_Heartbeat:70==1==76
    pulseOximeter_Heartbeat:70==2==76
    pulseOximeter_Heartbeat:70==6==76
    pulseOximeter_Heartbeat:70==8==76
    pulseOximeter_Heartbeat:70==8==76
    pulseOximeter_Heartbeat:70==8==76
    pulseOximeter_Heartbeat:70==8==76
    pulseOximeter_Heartbeat:70==8==76
    pulseOximeter_Heartbeat:70==6==76
    pulseOximeter_Heartbeat:56==2==77
    pulseOximeter_Heartbeat:56==7==77
    pulseOximeter_Heartbeat:56==5==77
    pulseOximeter_Heartbeat:56==7==77
    pulseOximeter_Heartbeat:56==6==77
    pulseOximeter_Heartbeat:56==6==77
    pulseOximeter_Heartbeat:56==8==77
    pulseOximeter_Heartbeat:56==8==77
    pulseOximeter_Heartbeat:56==8==77
    pulseOximeter_Heartbeat:102==8==81 <—-inserted finger
    pulseOximeter_Heartbeat:102==7==81
    pulseOximeter_Heartbeat:102==7==81<—-froze, no more pulses, rest of system still running my timer LED brinker…
    The program '[4] Micro Framework application: Managed' has exited with code 0 (0x0).

  6. #7 by mario on February 17, 2012 - 2:53 PM

    Hi Michael,
    Just wanted to update the comments and say that the sensor is now working pretty close to the way yours work. The problem was that the Spider was connected to my computer via an unpowered hub.
    Thanks again,
    Mario

    • #8 by Michael Dodaro on February 17, 2012 - 3:11 PM

      Oh, yes, that module draws a lot of amps. I should have thought of that!! I ran pulse oximeter with a nine volt battery for a while, and it misbehaved in similar fashion. Good to know that you found the problem before you sent the unit back for a replacement.

  7. #9 by Mike O on May 21, 2012 - 8:07 PM

    Hi Michael,
    Great article – this got me started, now I have tried for hours to find an example of sending and receiving a user defined type to a a rest webservice – I cant work out how to serialize/deserialize this on the netmf and webserver – do you have any examples of this by any chance?

    • #10 by Michael Dodaro on May 21, 2012 - 8:23 PM

      Have you looked at the Web service implementation in this article? Using a Servo in a .NET Gadgeteer Camera Device
      http://wp.me/p1TEdE-df
      The CreateData method of the service takes Stream data from a POST request and reads the bytes into a MemoryStream object. In this case it is bitmap data, but your data type should be feasible in this way.

  8. #11 by Lin on October 2, 2012 - 10:12 PM

    Hi Michael,
    I am rewriting your webservice for my project,but have some question.
    For this objectContext.PulseOxReadings.AddObject(newReading);
    Does the .PulseOxReadings is a method of objectContext?
    I have established a Entity Framework Model, where and how to crate .PulseOxReadings in the Entities?
    could you give your example for .PulseOxReadings?
    Thanks.

    • #12 by Michael Dodaro on October 3, 2012 - 9:26 AM

      Please see the section titled Web service Implementation to Record Sensor Data in the post linked from this post: http://wp.me/p1TEdE-5L
      That example explains how to create an entity data model. The Visual Studio tools make it pretty easy.

      • #13 by Lin on October 3, 2012 - 6:45 PM

        Dear Michael:
        In you post, “When the SensorDataModel.edmx designer page opens, in the properties pane, rename SensorDataTables to SensorDataItems and SensorDataTable to SensorDataItem. ”
        I real don’t understand what it means.Because I have only one table, in My properties pane,the Entity Set Name and the Name are both SensorDataTable. So I don’t know how to rename it.
        After I google , I fund http://stackoverflow.com/questions/4451534/difference-between-entity-name-and-entity-set-name
        Then I know what is the difference between Entity Set Name and the entity Name.
        May you can explain the Entity Set Name and the entity Name in your post maybe some readers can easy to understand it. Just a little recommendation,.
        Your blog is always amazing ,thanks.

      • #14 by Michael Dodaro on October 3, 2012 - 8:55 PM

        Yes, one table, but SensorDataItems represents the table and SensorDataItem represents the rows.

  9. #15 by Lin on October 3, 2012 - 8:19 PM

    Sorry, more question, in this code

    public List GetCollection(string name)
    {
    using(PulseOxDatabaseEntities objectContext = new PulseOxDatabaseEntities())
    {
    List list =
    objectContext.PulseOxReadings.Where(item => item.Name == name).ToList();
    return list;
    }
    }

    I have an error,

    • #16 by Michael Dodaro on October 3, 2012 - 9:01 PM

      I think this error may be related to the naming used in the entity type and entity set, as in your previous question.

      • #17 by Lin on October 3, 2012 - 9:39 PM

        Dear Michael:
        Thanks, I change my code to below, no error.
        But I don’t know what difference with you code
        For example, in your code, public List GetCollection(string name), it shows error in VS,but when I change to public List GetCollection(string name), it is fine.
        and
        objectContext.PulseOxReadings.Where(item => item.Name == name).ToList();
        change to
        objectContext.XbeeSensors.Where(XbeeSensor => XbeeSensor.SensorID == name).ToList();

        [WebGet(UriTemplate = “data/{name}”)]
        public List GetCollection(string name)
        {
        using (myDBEntities2 objectContext = new myDBEntities2())
        {
        List list =
        objectContext.XbeeSensors.Where(XbeeSensor => XbeeSensor.SensorID == name).ToList();
        return list;
        }
        }

      • #18 by Lin on October 10, 2012 - 7:44 PM

        Dear Michael:
        I can run my webservice in ASP.NET Development Server(Localhost).
        But when I run in IIS it shows error
        “The page cannot be found”
        HTTP Error 404
        My IIS is 6.0
        Does any configuration need to set in Web.config or Global.asax?

        <!–
        Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
        via the attributes on the element below
        –>

        namespace WCFRESTService
        {
        public class Global : System.Web.HttpApplication
        {

        protected void Application_Start(object sender, EventArgs e)
        {
        RegisterRoutes();
        }

        private void RegisterRoutes()
        {
        // Edit the base address of Service1 by replacing the “Service1” string below
        RouteTable.Routes.Add(new ServiceRoute(“Service1”, new WebServiceHostFactory(), typeof(XbeeService)));
        }
        }
        }

      • #19 by Michael Dodaro on October 10, 2012 - 8:12 PM

        I had to add the following line in the web.config file under system.serviceModel as below:
        I see now that the comment won’t accept the XML. See the web.config file in this example:
        http://wp.me/p1TEdE-df

        The line you need is: serviceHostingEnvironment aspNetCompatibilityEnabled=”true” multipleSiteBindingsEnabled=”true”

      • #20 by Lin on October 10, 2012 - 8:19 PM

        Sorry, can’t see it. could you re post again?

      • #21 by Michael Dodaro on October 10, 2012 - 8:40 PM

        I had to add:
        system.serviceModel
        serviceHostingEnvironment aspNetCompatibilityEnabled=”true” multipleSiteBindingsEnabled=”true”

        See the web.config file in this example: http://wp.me/p1TEdE-df

  10. #22 by Lin on October 10, 2012 - 10:44 PM

    The same, not works, do you deploy in IIS7?
    My is II6, I review many sites in google,but can’t solve it.
    very frustrated

    • #23 by Michael Dodaro on October 10, 2012 - 11:27 PM

      Using IIS 7 hosted by Discount ASP.NET service. Uploads from VS 2010 have been successful after some early glitches.

  11. #24 by Jona on April 14, 2013 - 8:18 AM

    Hi, I was wondering if you could use this board to get the raw SpO₂ curve or if it is just able to retrieve the averaged SpO₂ value?

  1. Blog J.Schweiss | Sending .NET Gadgeteer Sensor Data to a REST Web Service

Leave a Reply

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

%d bloggers like this: