gaubuali
Published © GPL3+

Webserver controls DC motor

By setting up Raspberry Pi as a web server, you can connect your HTML page to control GPIO pin.

AdvancedProtip5 hours7,230
Webserver controls DC motor

Things used in this project

Hardware components

Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
DC motor (generic)
×1
ULN2003
or any transistors
×1

Software apps and online services

Windows 10 IoT Core
Microsoft Windows 10 IoT Core

Story

Read more

Code

AppService code

C#
public sealed class WebServerBGTask : IBackgroundTask
{
    public void Run(IBackgroundTaskInstance taskInstance)
    {
        // Associate a cancellation handler with the background task. 
        taskInstance.Canceled += OnCanceled;

        // Get the deferral object from the task instance
        serviceDeferral = taskInstance.GetDeferral();

        var appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
        if (appService != null &&
            appService.Name == "AppComService")
        {
            appServiceConnection = appService.AppServiceConnection;
            appServiceConnection.RequestReceived += OnRequestReceived;
        }
    }

    private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
    {
        var message = args.Request.Message;
        string command = message["Command"] as string;

        switch (command)
        {
            case "Initialize":
                {
                    var messageDeferral = args.GetDeferral();
                    //Set a result to return to the caller
                    var returnMessage = new ValueSet();
                    HttpServer server = new HttpServer(8003, appServiceConnection);
                    IAsyncAction asyncAction = Windows.System.Threading.ThreadPool.RunAsync(
                        (workItem) =>
                        {
                            server.StartServer();
                        });
                    returnMessage.Add("Status", "Success");
                    var responseStatus = await args.Request.SendResponseAsync(returnMessage);
                    messageDeferral.Complete();
                    break;
                }

            case "Quit":
                {
                    //Service was asked to quit. Give us service deferral
                    //so platform can terminate the background task
                    serviceDeferral.Complete();
                    break;
                }
        }
    }
    private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
    {
        //Clean up and get ready to exit
    }

    BackgroundTaskDeferral serviceDeferral;
    AppServiceConnection appServiceConnection;
}

public sealed class HttpServer : IDisposable
{
    string offHtmlString = "<html><head><title>DC Motor Demo</title></head><body><form action=\"dcmotor.html\" method=\"GET\"><h1>DC Motor Demo</h1><p>Active DC Motor</p><input type=\"radio\" name=\"state\" value=\"on\" onclick=\"this.form.submit()\"> On<br><input type=\"radio\" name=\"state\" value=\"off\" checked onclick=\"this.form.submit()\"> Off</form></body></html>";
    string onHtmlString = "<html><head><title>DC Motor Demo</title></head><body><form action=\"dcmotor.html\" method=\"GET\"><h1>DC Motor Demo</h1><p>Active DC Motor</p><input type=\"radio\" name=\"state\" value=\"on\" checked onclick=\"this.form.submit()\"> On<br><input type=\"radio\" name=\"state\" value=\"off\" onclick=\"this.form.submit()\"> Off</form></body></html>";
    private const uint BufferSize = 8192;
    private int port = 8003;
    private readonly StreamSocketListener listener;
    private AppServiceConnection appServiceConnection;

    public HttpServer(int serverPort, AppServiceConnection connection)
    {
        listener = new StreamSocketListener();
        port = serverPort;
        appServiceConnection = connection;
        listener.ConnectionReceived += (s, e) => ProcessRequestAsync(e.Socket);
    }

    public void StartServer()
    {
#pragma warning disable CS4014
        listener.BindServiceNameAsync(port.ToString());
#pragma warning restore CS4014
    }

    public void Dispose()
    {
        listener.Dispose();
    }

    private async void ProcessRequestAsync(StreamSocket socket)
    {
        // this works for text only
        StringBuilder request = new StringBuilder();
        using (IInputStream input = socket.InputStream)
        {
            byte[] data = new byte[BufferSize];
            IBuffer buffer = data.AsBuffer();
            uint dataRead = BufferSize;
            while (dataRead == BufferSize)
            {
                await input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);
                request.Append(Encoding.UTF8.GetString(data, 0, data.Length));
                dataRead = buffer.Length;
            }
        }

        using (IOutputStream output = socket.OutputStream)
        {
            string requestMethod = request.ToString().Split('\n')[0];
            string[] requestParts = requestMethod.Split(' ');

            if (requestParts[0] == "GET")
                await WriteResponseAsync(requestParts[1], output);
            else
                throw new InvalidDataException("HTTP method not supported: "
                                               + requestParts[0]);
        }
    }

    private async Task WriteResponseAsync(string request, IOutputStream os)
    {
        // See if the request is for blinky.html, if yes get the new state
        string state = "Unspecified";
        bool stateChanged = false;
        if (request.Contains("dcmotor.html?state=on"))
        {
            state = "On";
            stateChanged = true;
        }
        else if (request.Contains("dcmotor.html?state=off"))
        {
            state = "Off";
            stateChanged = true;
        }

        if (stateChanged)
        {
            var updateMessage = new ValueSet();
            updateMessage.Add("State", state);
            var responseStatus = await appServiceConnection.SendMessageAsync(updateMessage);
        }

        string html = state == "On" ? onHtmlString : offHtmlString;
        // Show the html 
        using (Stream resp = os.AsStreamForWrite())
        {
            // Look in the Data subdirectory of the app package
            byte[] bodyArray = Encoding.UTF8.GetBytes(html);
            MemoryStream stream = new MemoryStream(bodyArray);
            string header = String.Format("HTTP/1.1 200 OK\r\n" +
                              "Content-Length: {0}\r\n" +
                              "Connection: close\r\n\r\n",
                              stream.Length);
            byte[] headerArray = Encoding.UTF8.GetBytes(header);
            await resp.WriteAsync(headerArray, 0, headerArray.Length);
            await stream.CopyToAsync(resp);
            await resp.FlushAsync();
        }

    }
}

Main UI app code

C#
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        InitGPIO();
        InitAppSvc();
    }
    AppServiceConnection appServiceConnection;
    private int LEDStatus = 0;
    private const int LED_PIN = 8;
    private GpioPin pin;
    private SolidColorBrush redBrush = new SolidColorBrush(Windows.UI.Colors.Red);
    private SolidColorBrush grayBrush = new SolidColorBrush(Windows.UI.Colors.LightGray);
    private void InitGPIO()
    {
        var gpio = GpioController.GetDefault();

        // Show an error if there is no GPIO controller
        if (gpio == null)
        {
            pin = null;
            return;
        }

        pin = gpio.OpenPin(LED_PIN);
        pin.Write(GpioPinValue.Low);
        pin.SetDriveMode(GpioPinDriveMode.Output);
    }

    private async void InitAppSvc()
    {
        var listing = await AppServiceCatalog.FindAppServiceProvidersAsync("AppComService");

        var packageName = "";
        // there may be cases where other applications could expose the same App Service Name, in our case
        // we only have the one
        if (listing.Count == 1)
        {
            packageName = listing[0].PackageFamilyName;
        }
        // Initialize the AppServiceConnection
        appServiceConnection = new AppServiceConnection();
        appServiceConnection.PackageFamilyName = packageName;
        appServiceConnection.AppServiceName = "AppComService";

        // Send a initialize request 
        var res = await appServiceConnection.OpenAsync();
        if (res == AppServiceConnectionStatus.Success)
        {
            var message = new ValueSet();
            message.Add("Command", "Initialize");
            var response = await appServiceConnection.SendMessageAsync(message);
            if (response.Status != AppServiceResponseStatus.Success)
            {
                throw new Exception("Failed to send message");
            }
            appServiceConnection.RequestReceived += OnMessageReceived;
        }
    }
    private async void OnMessageReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
    {
        var message = args.Request.Message;
        string newState = message["State"] as string;
        switch (newState)
        {
            case "On":
                {
                    await Dispatcher.RunAsync(
                          CoreDispatcherPriority.High,
                         () =>
                         {
                             TurnOnDcMotor();
                         });
                    break;
                }
            case "Off":
                {
                    await Dispatcher.RunAsync(
                    CoreDispatcherPriority.High,
                    () =>
                    {
                        TurnOffDcMotor();
                    });
                    break;
                }
            case "Unspecified":
            default:
                {
                    // Do nothing 
                    break;
                }
        }
    }

    private void TurnOffDcMotor()
    {
        if (LEDStatus == 1)
        {
            FlipGpio();
        }
    }

    private void TurnOnDcMotor()
    {
        if (LEDStatus == 0)
        {
            FlipGpio();
        }
    }

    private void FlipGpio()
    {
        if (LEDStatus == 0)
        {
            LEDStatus = 1;
            if (pin != null)
            {
                // to turn on the LED, we need to push the pin 'low'
                pin.Write(GpioPinValue.High);
            }
        }
        else
        {
            LEDStatus = 0;
            if (pin != null)
            {
                pin.Write(GpioPinValue.Low);
            }
        }
    }
}

GitHub source code

Credits

gaubuali

gaubuali

6 projects • 15 followers

Comments