Kevin D Wolf
Published © MIT

Motorized Blinds by Cortana and Windows 10 IoT Core

At around 5PM every day I talk to my computer and the blinds are lowered thanks to Cortana and a Windows 10 IoT core app

BeginnerShowcase (no instructions)4,721
Motorized Blinds by Cortana and Windows 10 IoT Core

Things used in this project

Hardware components

Raspberry Pi 2 Model B
Raspberry Pi 2 Model B
×1
Light Filtering Motorized Blinds
×1

Hand tools and fabrication machines

Soldering Gun
Wire Cutters

Story

Read more

Schematics

First draft of connection diagarm

Code

Blind Controller

C#
This all in one file handles a query string and then manipulates the GPIO of a Raspberry PI 2 running Windows 10 IoT core to raise and lower blinds. The approach is probably a little basic and there is room for refacotring, but it works!

Note the source code for this project (along with a number of other Home Automation libraries) will be released in the coming months. These will be released on GitHub, if you are interested in getting early access or want to help contribute to the project, please contact kevinw@software-logistics.com.
using LagoVista.Common.UWP.Services;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Gpio;

namespace LagoVista.ManCave.Services
{
    public class BlindsServer : SimpleRest
    {
        const int LED1 = 26;
        const int LED2 = 27;
        const int LED3 = 13;
        const int LED4 = 6;
        const int LED5 = 5;


        const int CENTER_BUTTON = 16;
        const int DOWN_BUTTON = 22;
        const int RIGHT_BUTTON = 18;
        const int UP_BUTTON = 12;
        const int LEFT_BUTTON = 25;


        private GpioPin _led1In;
        private GpioPin _led2In;
        private GpioPin _led3In;
        private GpioPin _led4In;
        private GpioPin _led5In;

        private GpioPin _btnCntrOut;
        private GpioPin _btnUpOut;
        private GpioPin _btnDownOut;
        private GpioPin _btnLeftOut;
        private GpioPin _btnRightOut;

        private static BlindsServer _instance = new BlindsServer();

        private BlindsServer()
        {

        }

        public static BlindsServer Instance { get { return _instance; } }


        public void Init(int port)
        {
            Port = port;
            StartServer();

            var gpio = GpioController.GetDefault();

            _led1In = gpio.OpenPin(LED1);
            _led2In = gpio.OpenPin(LED2);
            _led3In = gpio.OpenPin(LED3);
            _led4In = gpio.OpenPin(LED4);
            _led5In = gpio.OpenPin(LED5);

            _btnCntrOut = gpio.OpenPin(CENTER_BUTTON);
            _btnDownOut = gpio.OpenPin(DOWN_BUTTON);
            _btnLeftOut = gpio.OpenPin(LEFT_BUTTON);
            _btnRightOut = gpio.OpenPin(RIGHT_BUTTON);
            _btnUpOut = gpio.OpenPin(UP_BUTTON);

            _led1In.SetDriveMode(GpioPinDriveMode.Input);
            _led2In.SetDriveMode(GpioPinDriveMode.Input);
            _led3In.SetDriveMode(GpioPinDriveMode.Input);
            _led4In.SetDriveMode(GpioPinDriveMode.Input);
            _led5In.SetDriveMode(GpioPinDriveMode.Input);

            _btnCntrOut.SetDriveMode(GpioPinDriveMode.Output);
            _btnDownOut.SetDriveMode(GpioPinDriveMode.Output);
            _btnLeftOut.SetDriveMode(GpioPinDriveMode.Output);
            _btnUpOut.SetDriveMode(GpioPinDriveMode.Output);
            _btnRightOut.SetDriveMode(GpioPinDriveMode.Output);

            _btnCntrOut.Write(GpioPinValue.Low);
            _btnDownOut.Write(GpioPinValue.Low);
            _btnUpOut.Write(GpioPinValue.Low);
            _btnRightOut.Write(GpioPinValue.Low);
            _btnLeftOut.Write(GpioPinValue.Low);
        }

        private async Task MoveToPosition(int position)
        {
            var correctPosition = false;
            var loopCount = 0;

            Debug.WriteLine("MOVING TO POSITION: " + position);

            while (!correctPosition && loopCount++ < 12)
            {
                _btnRightOut.Write(GpioPinValue.High);
                await Task.Delay(100);
                _btnRightOut.Write(GpioPinValue.Low);
                await Task.Delay(100);

                if (position == 0 && _led1In.Read() == GpioPinValue.Low && _led2In.Read() == GpioPinValue.Low && _led3In.Read() == GpioPinValue.Low && _led4In.Read() == GpioPinValue.Low && _led5In.Read() == GpioPinValue.Low)
                    correctPosition = true;

                if (position == 1 && _led1In.Read() == GpioPinValue.Low && _led2In.Read() == GpioPinValue.High && _led3In.Read() == GpioPinValue.High && _led4In.Read() == GpioPinValue.High && _led5In.Read() == GpioPinValue.High)
                    correctPosition = true;

                if (position == 2 && _led1In.Read() == GpioPinValue.High && _led2In.Read() == GpioPinValue.Low && _led3In.Read() == GpioPinValue.High && _led4In.Read() == GpioPinValue.High && _led5In.Read() == GpioPinValue.High)
                    correctPosition = true;

                if (position == 3 && _led1In.Read() == GpioPinValue.High && _led2In.Read() == GpioPinValue.High && _led3In.Read() == GpioPinValue.Low && _led4In.Read() == GpioPinValue.High && _led5In.Read() == GpioPinValue.High)
                    correctPosition = true;

                if (position == 4 && _led1In.Read() == GpioPinValue.High && _led2In.Read() == GpioPinValue.High && _led3In.Read() == GpioPinValue.High && _led4In.Read() == GpioPinValue.Low && _led5In.Read() == GpioPinValue.High)
                    correctPosition = true;

                if (position == 5 && _led1In.Read() == GpioPinValue.High && _led2In.Read() == GpioPinValue.High && _led3In.Read() == GpioPinValue.High && _led4In.Read() == GpioPinValue.High && _led5In.Read() == GpioPinValue.Low)
                    correctPosition = true;

                Debug.WriteLine("FOUND MATCH: " + correctPosition);
            }
        }

        private async void MoveBlind(int blind, String command, int? ms = null)
        {
            Debug.WriteLine("COMMAND => " + command);

            await MoveToPosition(blind);
            if (command == "up")
            {
                _btnUpOut.Write(GpioPinValue.High);
                await Task.Delay(1000);
                _btnUpOut.Write(GpioPinValue.Low);
            }
            else if (command == "down")
            {
                Debug.WriteLine("DOWN");
                _btnDownOut.Write(GpioPinValue.High);
                await Task.Delay(1000);
                _btnDownOut.Write(GpioPinValue.Low);
                Debug.WriteLine("DONE");
            }
            else if (command == "stop")
            {
                _btnCntrOut.Write(GpioPinValue.High);
                await Task.Delay(1000);
                _btnCntrOut.Write(GpioPinValue.Low);
            }

            if (ms.HasValue)
            {
                await Task.Delay(ms.Value);
                _btnCntrOut.Write(GpioPinValue.High);
                await Task.Delay(500);
                _btnCntrOut.Write(GpioPinValue.Low);
            }
        }

        public override String Process(String queryString)
        {
            Debug.WriteLine(queryString);
            queryString = queryString.Trim('/');

            var parts = queryString.ToLower().Split('/');

            if (parts.Length > 0)
            {
                if (parts[0] == "blind")
                {
                    int blind = 0;
                    if (int.TryParse(parts[1], out blind))
                    {
                        var command = parts[2];
                        if (parts.Length > 3)
                        {
                            int ms = 0;
                            if (int.TryParse(parts[3], out ms))
                            {
                                MoveBlind(blind, command, ms);
                                return "{'result':'ok'}";
                            }
                            else
                            {
                                return "{'result':'invalidQUeryString'}";
                            }
                        }

                        MoveBlind(blind, command);
                        return "{'result':'ok'}";
                    }
                    else
                        return "{'result':'invalidQUeryString'}";
                }
                return "{'result':'unknownCommand'}";

            }
            return "{'result':'invalidQUeryString'}";
        }

    }
}

Very Simple REST Server

C#
Very quick and dirty approach to listen on a port and provide query string into an IoT app.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using System.Runtime.InteropServices.WindowsRuntime;

namespace LagoVista.Common.UWP.Services
{
    public abstract class SimpleRest
    {
        private const uint BUFFER_SIZE = 8192;
        private readonly StreamSocketListener _streamSocketListener;

        protected SimpleRest()
        {
            _streamSocketListener = new StreamSocketListener();
            _streamSocketListener.ConnectionReceived += (s, e) => ProcessRequestAsync(e.Socket);
        }

        public int Port { get; set; }


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

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

        private async void ProcessRequestAsync(StreamSocket socket)
        {
            var request = new StringBuilder();
            using (var input = socket.InputStream)
            {
                var data = new byte[BUFFER_SIZE];
                var buffer = data.AsBuffer();
                var dataRead = BUFFER_SIZE;
                while (dataRead == BUFFER_SIZE)
                {
                    await input.ReadAsync(buffer, BUFFER_SIZE, InputStreamOptions.Partial);
                    request.Append(Encoding.UTF8.GetString(data, 0, data.Length));
                    dataRead = buffer.Length;
                }
            }

            using (var output = socket.OutputStream)
            {
                if (request.ToString().ToLower().Contains("favicon"))
                    await WriteResponseAsync(output, 404, "NOT FOUND");
                else
                {
                    var requestMethod = request.ToString().Split('\n')[0];
                    var requestParts = requestMethod.Split(' ');

                    var resposneContent = Process(requestParts[1]);

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

        public abstract String Process(String queryString);

        private async Task WriteResponseAsync(IOutputStream os, int responseCode, String resposneContent)
        {
            using (var resp = os.AsStreamForWrite())
            {
                var bodyArray = Encoding.UTF8.GetBytes(resposneContent);
                using (var stream = new MemoryStream(bodyArray))
                {
                    var header = String.Format("HTTP/1.1 {0} OK\r\n" +
                                      "Content-Length: {1}\r\n" +
                                      "Connection: close\r\n\r\n",
                                      responseCode, stream.Length);
                    var headerArray = Encoding.UTF8.GetBytes(header);
                    await resp.WriteAsync(headerArray, 0, headerArray.Length);
                    await stream.CopyToAsync(resp);
                    await resp.FlushAsync();
                }
            }
        }
    }
}

Credits

Kevin D Wolf

Kevin D Wolf

3 projects • 25 followers
Windows Embedded MVP Out of Tampa FL. Full time consultant.

Comments