.NET Gadgeteer Relay Actuator via REST Web Service

The .NET Gadgeteer Relay Module from Seeed Studio can be used to activate devices that are designed to run on common household electrical circuits of 120 volts AC or higher if necessary.  The four relays on the Seeed Relay Module are switches with the options, normally open or normally closed. You can power on or power off four electrical circuits with the relays on the module by assigning the boolean value of each relay.  To make this example more interesting and useful, we’ll implement a REST Web service that devices poll to get the relay state settings, which can be set remotely by any device that can send a POST request.

The .NET Gadgeteer components of this implementation are shown in the following illustration in the Visual Studio Designer (click to enlarge).

Relays, Buttons, and Wifi Module

Relays, Buttons, and Wifi Module

The abbreviations on the electrical terminals on the relay module are labeled by the number of the relay and NO, COM, and NC (Normally Open, Common, and Normally Closed).  To run devices remotly, we’ll assume that the circuits should normally be open, so wire the COM and NO terminals to the devices you want to control.  Maybe you want to turn on some lights in your house and a stereo occasionally while you are gone to give the appearance of activity.

On a normally open circuit, set the relay to true to close the circuit and turn on a lamp or stereo connected to that relay, as shown in the following button handler.  This button simply tests the circuit.  In the finished application we will set the state remotely from a Web service.

    void button_ButtonPressed(Button sender, Button.ButtonState state)
    {
        if (!button.IsLedOn)
        {
            relays.Relay1 = true;
            button.TurnLEDOn();
        }
        else
        {
            relays.Relay1 = false;
            button.TurnLEDOff();
        }
    }

Control the Relays from Remote Location by Setting State on Web Service
The .NET Gadgeteer networking library can support a Web service running on the device, but I prefer to have the device poll a server on the Internet.   This way you do not have to configure a router and DNS, which has the associated security risk of allowing Internet access to your local network.

I use the Visual Studio WCF REST Service Template 4 to implement these services.  Setting up a REST Web Service with this template is elementary, but there are configuration details that can be tricky.  You can install the Online Template from Visual Studio->New Project->Online Templates.  I have documented several of these Web service implementations.  For more information, see the following topics:

Using a Servo in a .NET Gadgeteer Camera Device 

Controlling the Servo using a Windows Phone application

REST Web Service to Record Data from a .NET Gadgeteer Sensor Device

Remote Control of .NET Gadgeteer Device via REST Web Service

The Web service that this application uses implements two Web methods: a GET method that the device uses to poll the server for the state of its relays; and a POST method that client applications use to set state.

I had to add a line to the Web.config file to get this service to run on my hosting service. Add the following line under <system.serviceModel>:

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>

The state item is defined in the followng class.

namespace WcfRemoteRelays
{
    public class Settings
    {
        public bool relay1 { get; set; }
        public bool relay2 { get; set; }
        public bool relay3 { get; set; }
        public bool relay4 { get; set; }
    }
}

The Web service GET and POST methods are defined in the followng code block. As indicated in the code comments, I have changed the InstanceContextMode to Single to process all requests using the same state object.  This service takes a POST request from a client and saves the relay state settings.  The service returns the state settings in response to GET requests from the device with the relays connected to electrical circuits.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace WcfRemoteRelays
{
    // Start the service and browse to http://Service/help to view
    // the service's generated help page.
    // NOTE: By default, a new instance of the service is created for each call; change
    // InstanceContextMode to Single if you want a single instance of the service
    // to process all calls.

    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

    public class Relays
    {
        Settings settings;

        [WebGet(UriTemplate = "settings")]
        public Settings GetSettings()
        {
            if (settings == null)
            {
                settings = new Settings { relay1 = false, relay2 = false, relay3 = false, relay4 = false };
                return settings;
            }
            else
                return settings;

        }

        [WebInvoke(UriTemplate = "setRelay/{number}/{setting}", Method = "POST")]
        public Settings Create(string number, string setting)
        {
            if (settings == null)
            {
                settings = new Settings { relay1 = false, relay2 = false, relay3 = false, relay4 = false };
                switch (number)
                {
                    case "1":
                        {
                            settings.relay1 = Boolean.Parse(setting);
                            break;
                        }
                    case "2":
                        {
                            settings.relay2 = Boolean.Parse(setting);
                            break;
                        }
                    case "3":
                        {
                            settings.relay3 = Boolean.Parse(setting);
                            break;
                        }
                    case "4":
                        {
                            settings.relay1 = Boolean.Parse(setting);
                            break;
                        }
                    default :
                        break;
                }
            }
            else
            {
                switch (number)
                {
                    case "1":
                        {
                            settings.relay1 = Boolean.Parse(setting);
                            break;
                        }
                    case "2":
                        {
                            settings.relay2 = Boolean.Parse(setting);
                            break;
                        }
                    case "3":
                        {
                            settings.relay3 = Boolean.Parse(setting);
                            break;
                        }
                    case "4":
                        {
                            settings.relay4 = Boolean.Parse(setting);
                            break;
                        }

                    default:
                        break;
                }
            }
            return settings;
        }
    }
}

Now you can set the desired state of the four relays by sending POST requests of the form:

    http://integral-data.com/remote-relays/setrelay/1/true

I used Fiddler2 to test these POST requests. I had to add a line to the request headers in the composer to indicate that the request contains no binary data, only the url string:

    content-length: 0

Polling the Web Service from the Device

The device polls the service at an interval set by a timer on the device.  In this application an interval of 15 seconds or more is frequent enough to let you turn on lights or other appliances.  If you have the relays connected to some device that needs to be turned on and off at a faster rate, it is feasible up to the speed of the Internet connection that the device uses.  The following code shows the device polling the service.  It is elementary.  Note the startup code for the GHI Electronics Wifi module, or you can use the Ethernet J11D Module.

The code initializes the network connection and indicates success by turning a LED green.  Push button1 to start a timer.  The Timer.Tick event calls the GetRelayStates method.  The WebClient.GetFromWeb method is asynchronous.  When it returns successfully, the states of the relays are read by using an XMLReader object to parse the response.  The .NET Micro Framework does not support all the conversion methods of the full .NET Framework, so a simple method is implemented to get a boolean value from the response string.

using Microsoft.SPOT;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

using System.Xml;
using Gadgeteer.Modules.Seeed;

namespace RemoteRelays
{
    public partial class Program
    {
        GT.Timer timer;

        void ProgramStarted()
        {
            wifi.UseDHCP();
            Gadgeteer.Modules.GHIElectronics.WiFi_RS21.WiFiNetworkInfo info =
                                                    new WiFi_RS21.WiFiNetworkInfo();
            info.SSID = "securityId";
            info.SecMode = WiFi_RS21.SecurityMode.WEP;
            info.networkType = WiFi_RS21.NetworkType.AccessPoint;
            wifi.Join(info, "passphrase");

            wifi.NetworkUp += new GTM.Module.NetworkModule.NetworkEventHandler(wifi_NetworkUp);
            led.TurnRed();
            button.ButtonPressed += new Button.ButtonEventHandler(button_ButtonPressed);
            button1.ButtonPressed += new Button.ButtonEventHandler(button1_ButtonPressed);
            timer = new GT.Timer(15000);
            timer.Tick += new GT.Timer.TickEventHandler(timer_Tick);

            Debug.Print("Program Started");
        }

        void wifi_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            led.TurnGreen();
        }

        void GetRelayStates()
        {
            WebClient.GetFromWeb("http://integral-data.com/remote-relays/settings").ResponseReceived +=
                new HttpRequest.ResponseHandler(Program_ResponseReceived);
        }

        void Program_ResponseReceived(HttpRequest sender, HttpResponse response)
        {
            if (response.StatusCode == "200")
            {
                XmlReader reader = XmlReader.Create(response.Stream);

                while (reader.Read())
                {
                    if (reader.Name == "relay1")
                        relays.Relay1 = ToBool(reader.ReadElementString());

                    if (reader.Name == "relay2")
                        relays.Relay2 = ToBool(reader.ReadElementString());

                    if (reader.Name == "relay3")
                        relays.Relay3 = ToBool(reader.ReadElementString());

                    if (reader.Name == "relay4")
                        relays.Relay4 = ToBool(reader.ReadElementString());
                }
            }
            else
            {
                Debug.Print(response.StatusCode);
            }
        }

        void timer_Tick(GT.Timer timer)
        {
            GetRelayStates();
        }

        bool ToBool(string inString)
        {
            if (inString == "true")
                return true;
            else
                return false;
        }

        void button1_ButtonPressed(Button sender, Button.ButtonState state)
        {
            if (!button1.IsLedOn)
            {
                timer.Start();
                button1.TurnLEDOn();
            }
            else
            {
                timer.Stop();
                button1.TurnLEDOff();
            }
        }

        void button_ButtonPressed(Button sender, Button.ButtonState state)
        {
            if (!button.IsLedOn)
            {
                relays.Relay1 = true;
                button.TurnLEDOn();
            }
            else
            {
                relays.Relay1 = false;
                button.TurnLEDOff();
            }
        }
    }
}
Advertisements

, , , , ,

  1. #1 by Carlo Hutsebaut on November 17, 2012 - 12:11 PM

    Hi,

    I really like your posts I already learned a lot from the previous posts I had raid. But with this post I got a problem the service just wont work it creates a new settings object every time I call the Get or Post method but probably it’s because I cant read something in your post. You said “I had to add a line to the Web.config file to get this service to run on my hosting service. Add the following line under :” but after that line there need to be some code i guess but i just see a gray line with no code in it. I guess thats my problem. I’m missing something. Or is it something else?

    kind regards, Carlo

  2. #2 by Michael Dodaro on November 17, 2012 - 12:41 PM

    Carlo,
    Thanks for pointing this out. The code was missing by my error or some glitch in the production process. The missing line should be visible now.

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>

  3. #3 by Carlo Hutsebaut on November 17, 2012 - 1:28 PM

    thanks for the fast response and the fix. I will try it again

  4. #4 by said on August 5, 2013 - 1:53 AM

    Hello,

    First, sorry for my english. I’m French

    I developed an windows phone application for the activation the electrical relays.

    I modified the web services because i want that returned response having the json format. And then, i modified the algorithm for decode the json for fez spider.

    It’s easy. Set the url of web service in the options and let’s go 🙂

    And the project is open-source => https://github.com/oyoun/SeedRelaysWP/tree/dev

    If you have questions, contact me 🙂

    ([WebGet(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)])

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: