65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Windows Azure 的电器自动化 - 一个 IoT 项目

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.86/5 (4投票s)

2015年3月5日

CPOL

3分钟阅读

viewsIcon

29037

随时随地控制家用电器。

目的

从世界任何地方控制家用电器

硬件和软件要求

  1. 迷你电脑 - 我们可以使用 Arduino 板 / Raspberry Pi / Minix neo z64 迷你电脑

    照片 由 Nick Hubbard / CC BY

    图片来源:Minix.com.hk
  2. 兼容 Insteon 的家庭自动化设备
    1. Insteon 2413U 或 2413S 模块
    2. Insteon 2635-222 开/关模块

    图片来源:tech69.net
     
  3. 扬声器
  4. Azure 云托管订阅
  5. 互联网连接
  6. Visual Studio 2010

引言

在本文中,我们将通过 ASP.NET MVC 创建的一个小型 API 工具集,探讨通过 HTTP 远程控制家用电器。此外,我们还将使用 SignalR(托管的 Windows 服务)将当前设备状态实时推送到客户端。

我们将通过 Windows 服务控制以下家用电器

1. **风扇** - 开/关,风速调节

2. **灯** - 开/关

3. **空调** - 开/关,温度控制

4. **扬声器** – 开/关,播放/暂停/停止歌曲

计划

我们将创建一个 Windows 服务来控制 Insteon 设备,然后构建一个 SignalR Web 服务来与 Windows 服务交互,最后构建一个移动应用程序来向 Web 服务发送命令,以便我们可以从网络上的任何地方控制设备。

第一部分 构建用于控制 Insteon 设备的 Windows 服务

第二部分 构建用于从 ASP.NET MVC 和 SignalR 向 Windows 服务发送命令的远程控制服务

第三部分 构建用于与 Web API 服务交互的移动 Web 应用程序

实施

首先,我们将只实现灯的开/关控制

第一部分 构建用于控制 Insteon 设备的 Windows 服务

1. 在 Visual Studio 中创建一个新的 .NET 4.0 控制台应用程序项目,并使用 NuGet 包管理器为其添加 TopShelf 的引用(使用 TopShelf,我们可以轻松构建可调试的 Windows 服务)。

2. 添加对 FluentDwelling API dll 文件的引用。通过编程方式与 Insteon 硬件设备交互很容易,因为互联网上的一些伟大灵魂已经创建了 API 结构。我偶然发现了一个名为 FluentDwelling 的优秀项目。
http://soapboxautomation.com/products/fluentdwelling/

3. 我们将在 Windows 服务中托管 SignalR 客户端。
在 NuGet 包管理器控制台中键入以下命令

Install-Package Microsoft.AspNet.SignalR.Client -Version 1.2.2

4. 向 Windows 服务项目添加一个名为 "InsteonService.cs" 的新类。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using Microsoft.AspNet.SignalR.Client;
using SoapBox.FluentDwelling;
using Topshelf;

namespace IoT.WindowsService
{
    public class InsteonService : ServiceControl
    {
        private static string ServiceUri;
        private static Connection connection;

        //Insteon related
        private static Plm plm = new Plm("COM4");

        public bool Start(HostControl hostControl)
        {
            ServiceUri = ConfigurationManager.AppSettings["ServiceUri"];

            connection = new Connection(ServiceUri, "name=Client");
            connection.Received += connection_Received;
            connection.StateChanged += connection_StateChanged;
            Console.WriteLine("Connecting...");
            connection.Start().Wait();
            string inputMsg;
            while (!string.IsNullOrEmpty(inputMsg = Console.ReadLine()))
            {
                connection.Send(inputMsg).Wait();
            }
            connection.Stop();

            return true;
        }

        static void connection_StateChanged(StateChange state)
        {
            if (state.NewState == ConnectionState.Connected)
            {
                Console.WriteLine("Connected.");
            }
        }
        static void connection_Received(string data)
        {
            //Parse the commands
            //Format: 
            //Name,Command,DeviceName(optional),Port(optional)
            string[] command = data.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (command.Length > 0)
                if (command[0].Equals("Server", StringComparison.InvariantCultureIgnoreCase))
                {
                    string commandName = command[1].ToLower();
                    if (command.Length > 2)
                    {
                        string deviceid = command[2];
                        switch (commandName)
                        {
                            case "turnoff":
                                {
                                    plm.Network.X10
                                            .House("A")
                                            .Unit(2)
                                            .Command(X10Command.Off);
                                }
                                break;
                            case "turnon":
                                {
                                    plm.Network.X10
                                            .House("A")
                                            .Unit(2)
                                            .Command(X10Command.On);
                                }
                                break;
                        }
                    }
                    else
                    {
                        switch (commandName)
                        {
                            case "getlist"://not tested
                                {
                                    var database = plm.GetAllLinkDatabase();
                                    string devices = "";
                                    if (!plm.Error)
                                    {
                                        foreach (var record in database.Records)
                                        {
                                            devices += record.DeviceId.ToString();
                                        }
                                    }
                                    else
                                    {
                                        devices += "Error";
                                    }

                                    connection.Send(devices).Wait();
                                }
                                break;
                        }
                    }
                }
        }

        public bool Stop(HostControl hostControl)
        {
            if (connection.State == ConnectionState.Connected)
                connection.Stop();
            return true;
        }
    }
}

5. 在 "Program.cs" 中编写以下代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Topshelf;
using Topshelf.HostConfigurators;
using Topshelf.ServiceConfigurators;

namespace IoT.WindowsService
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = HostFactory.New(ConfigureHost);
            host.Run();
        }

        private static void ConfigureHost(HostConfigurator x)
        {
            x.Service(ConfigureService);
            x.SetDisplayName("Insteon Service");
            x.SetDescription("Insteon Controller Service");
            x.SetInstanceName("Insteon");
            x.SetServiceName("Insteon");
            x.StartAutomatically();
            x.RunAsPrompt();
        }

        private static void ConfigureService(ServiceConfigurator sc)
        {
            sc.ConstructUsing(() => new InsteonService());

            // the start and stop methods for the service
            sc.WhenStarted((s, hostControl) => s.Start(hostControl));
            sc.WhenStopped((s, hostControl) => s.Stop(hostControl));
        }
    }
}

6. 最后,在 "App.config" 文件的 "AppSettings" 部分,我们需要添加以下代码行。

<add key="ServiceUri" value="http://insteoniot.azurewebsites.net/echo"/>

 

第二部分 构建用于从 ASP.NET MVC 和 SignalR 向 Windows 服务发送命令的远程控制服务。

1. 我们将在 asp.net mvc4 Web 应用程序中托管 SignalR 服务。

2. 在 Visual Studio 中创建一个新的 asp.net MVC4 项目。

3. 使用包管理器控制台在项目中安装 SignalR 服务器。

Install-Package Microsoft.AspNet.SignalR -Version 1.2.2

4. 在项目中创建一个名为 "SignalR" 的新文件夹,并向项目中添加一个名为 "MyConnection.cs" 的类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.SignalR;

namespace IoT.Mobile.SignalR
{
    public class MyConnection : PersistentConnection 
    {
        protected override Task OnConnected(IRequest request, string connectionId)
        {
            return Connection.Broadcast(string.Empty);
        }
        protected override Task OnReceived(IRequest request, string connectionId, string data)
        {
            // Broadcast data to all clients
            string msg = string.Format(
                "{0},{1}", request.QueryString["name"], data);
            return Connection.Broadcast(msg);
        }
    }
}

上面的类只是将接收到的所有消息广播给客户端。

第三部分 构建用于与 Web API 服务交互的移动 Web 应用程序。

1. 在先前创建的 MVC4 Web 应用程序中,我们将创建一个名为 "HomeController" 的控制器,然后添加一个名为 "Index.cshtml" 的视图。

视图 "Index.cshtml" 包含用于打开和关闭灯的单选按钮以及用于调用 SignalR 服务的代码。

@{
    ViewBag.Title = "Control Home - IoT Azure";
}
<table class="ui-widget ui-widget-content">
    <tr>
    <td colspan="2" class="ui-widget-header">@ViewBag.Title</td>
    <tr>
        <td style="padding:10px">
            Lights:
        </td>
        <td style="padding:10px">
            <div id="radio">
                <input type="radio" class="radio" id="radio1" name="radio"><label for="radio1">On</label>
                <input type="radio" class="radio" id="radio2" name="radio" checked="checked"><label for="radio2">Off</label>
            </div>
        </td>
    </tr>
</table>
<br/>
<br/>
Debug info:
<ul id="messages"></ul>
@section scripts
{
    <script type="text/javascript">
        function htmlEncode(value) {
            return $("<div/>").text(value).html();
        }

        function addMsg(msg) {
            if (msg != "") {
                $("#messages").append("<li>" + htmlEncode(msg) + "</li>");
            }
        }

        $(function() {
            var connection = $.connection("/echo", "name=Server", true);;

            connection.received(function(data) {
                addMsg(data);
            });
            connection.error(function(err) {
                addMsg("Error: " + err);
            });

            addMsg("Connecting...");
            connection.start(function() {
                addMsg("Connected.");
            });

            //UI
            $("#radio").buttonset();
            $('#radio').change(function () {                
                var $this = $('.radio:checked');

                if ($this.attr("id")=="radio1") {
                    connection.send("turnon,com4");
                } else {
                    connection.send("turnoff,com4");
                }
            });
        });
    </script>

}

 

硬件/软件设置

1. 使用 USB 线将 Insteon 2413U 与 Minix neo z64 Windows 迷你电脑连接。

2. 使用命令行在 Minix Neo z64 Windows 迷你电脑上安装 Windows 服务。

IoT.WindowsService.exe install

3. 使用 Windows Azure 云托管在云中托管移动应用程序。

4. 该网站已发布在:http://insteoniot.azurewebsites.net

参考

1. FluentDwelling:http://soapboxautomation.com/products/fluentdwelling/

2. SignalR 教程:https://codeproject.org.cn/Articles/633378/ASP-NET-SignalR-Basis-Step-by-Step-Part

3. Minix Neo Z64:http://www.minix.com.hk/Products/MINIX-NEO-Z64-WIN-PC.html

4. Insteon 2413U:http://www.amazon.com/Insteon-2413U-PowerLinc-Dual-Band-Interface/dp/B002XA8XNQ

© . All rights reserved.