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

IoT Starter Raspberry Pi Lumi

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2018年2月2日

CPOL

6分钟阅读

viewsIcon

14204

IoT.Starter.Pi.Thing 正在成长为一个通用红外遥控器的雏形

引言

本系列文章面向运行 Linux 的树莓派,始于使用 API 优先设计策略的 IoT.Starter.Pi.Core,该策略通过 Swagger Hub 自动生成 ASP.NET Core Web 服务器。

第二部分介绍了 IoT.Starter.Pi.Thing,它是面向智能家居的雏形,运行在 Linux 的树莓派上。它被设计为物联网项目的入门套件,提供了一个坚实且结构化的平台,以加速产品开发。这个 入门套件概念 鼓励团队立即开始产品开发。

第三部分是 IoT.Starter.Pi.Lirc,专门用于需要红外设备的物联网项目。通过由 Lirc(Linux 红外遥控)驱动的控制台,创建了一个测试环境。现在是时候利用这些测试中学到的东西了。

作为第三部分的补充,本次的目标是扩展 `Thing` Web 服务,以便 API 能够考虑红外遥控器及其相应的代码。由 Lirc 驱动的 `IoT.Starter.Pi.Lumi` 在需要红外支持的物联网项目中非常有用。

届时将有两个 `Things`,作为物联网入门套件提供:

API 优先

遵循 API 优先战略,创建了一个新的 API 版本 1.0.2,并在下面进行了总结,向现有规范添加了一个 `RemoteApi` 控制器。`GET` 操作应该能够识别遥控器及其相应的红外代码。`POST` 操作反映了向已安装在 RPI 主机上的遥控器发送红外信号的意图,使用 Lirc 软件。

生成 RemoteApi

在我们将 swagger 文件更改为 1.0.2 版本后,`SwaggerHub` 自动生成了 `RemoteApi` 控制器代码。您还记得“升级 API”吗?这在 IoT.Starter.Pi.Core 中已经解释过,如果您有任何疑问,请参考那里。

然后,对生成的代码进行了修改以适应目标,产生了以下四个操作:

public class RemoteApiController : Controller
{ 
    /// <summary>
    /// 
    /// </summary>
    /// <remarks>returns ir code from remote</remarks>
    /// <param name="remote">Lirc remote</param>
    /// <param name="code">ir code</param>
    /// <response code="200">All the codes</response>
    [HttpGet]
    [Route("/motta/home/1.0.1/remotes/{remote}/{code}")]
    [ValidateModelState]
    [SwaggerOperation("GetRemoteCode")]
    [SwaggerResponse(200, typeof(List<string>), "All the codes")]
    public virtual IActionResult GetRemoteCode
                   ([FromRoute]string remote, [FromRoute]string code)
    {
        string example = ("/usr/bin/irsend list " + remote + " " + code).Bash();

        return new ObjectResult(example);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <remarks>returns all ir codes from remote</remarks>
    /// <param name="remote">Lirc remote</param>
    /// <response code="200">All the codes</response>
    [HttpGet]
    [Route("/motta/home/1.0.1/remotes/{remote}")]
    [ValidateModelState]
    [SwaggerOperation("GetRemoteCodes")]
    [SwaggerResponse(200, typeof(List<string>), "All the codes")]
    public virtual IActionResult GetRemoteCodes([FromRoute]string remote)
    {
        string example = (@"/usr/bin/irsend list " + remote + @" """"").Bash();

        return new ObjectResult(example);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <remarks>returns all installed remotes</remarks>
    /// <param name="skip">number of records to skip</param>
    /// <param name="limit">max number of records to return</param>
    /// <response code="200">All the installed remotes</response>
    [HttpGet]
    [Route("/motta/home/1.0.1/remotes")]
    [ValidateModelState]
    [SwaggerOperation("GetRemotes")]
    [SwaggerResponse(200, typeof(List<string>), "All the installed remotes")]
    public virtual IActionResult GetRemotes([FromQuery]int? skip, [FromQuery]int? limit)
    {
        string example = (@"/usr/bin/irsend list """" """"").Bash();

        return new ObjectResult(example);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <remarks>flashes ir code simulating the remote control</remarks>
    /// <param name="remote">Lirc remote</param>
    /// <param name="code">ir code</param>
    /// <response code="200">response</response>
    [HttpPost]
    [Route("/motta/home/1.0.1/remotes/{remote}/{code}")]
    [ValidateModelState]
    [SwaggerOperation("SendRemoteCode")]
    [SwaggerResponse(200, typeof(ApiResponse), "response")]
    public virtual IActionResult SendRemoteCode([FromRoute]string remote, 
                                                [FromRoute]string code)
    {
        string example = (@"/usr/bin/irsend send_once " + remote + " " + code).Bash();

        return new ObjectResult(example);
    }
}

您可以看到 `irsend` 命令在所有操作中都使用了!`HttpGet` 操作识别红外遥控器及其相应的代码。例如,要列出所有已安装的遥控器,应在主机上通过 Bash 执行以下命令:

pi@lumi:~ $ irsend list "" ""

等效代码如下所示:

    public virtual IActionResult GetRemotes([FromQuery]int? skip, [FromQuery]int? limit)
    {
        string example = (@"/usr/bin/irsend list """" """"").Bash();

        return new ObjectResult(example);
    }

`HttpPost` 操作具有 `remote` 和 `code` 参数,以便通过输出的 IR LED 正确地发送红外代码。在这种情况下,RPI 主机上的 `irsend` 命令将是:

pi@lumi:~ $ irsend SEND_ONCE LED_44_KEY CYAN

`SendRemoteCode` 显示了如下的等效代码:

    public virtual IActionResult SendRemoteCode
           ([FromRoute]string remote, [FromRoute]string code)
    {
        string example = (@"/usr/bin/irsend send_once " + remote + " " + code).Bash();

        return new ObjectResult(example);
    }

正如在 `Lirc-Console` 中已经展示的,由 loune.net 发布的 `ShellHelper` 负责繁重的工作,启动一个 bash 进程,捕获响应,并返回 `string` 结果。

public static class ShellHelper
{
    public static string Bash(this string cmd)
    {
        var escapedArgs = cmd.Replace("\"", "\\\"");

        var process = new Process()
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "/bin/bash",
                Arguments = $"-c \"{escapedArgs}\"",
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true,
            }
        };
        process.Start();
        string result = process.StandardOutput.ReadToEnd();
        process.WaitForExit();
        return result;
    }
}

home-web-ir:由 Lirc 驱动

为了将 Lirc 支持添加到项目中,我们采用了之前相同的策略,即在构建 Web 服务之前安装 Lirc。Dockerfile 和 docker-compose 中所做的更改如下所示。

lirc-web.dockerfile

下面显示的 `lirc-web.dockerfile` 使用 `dotnet:2.0.0-runtime-stretch-arm32v7` 镜像作为基础。在安装 Lirc 之前,会更新和升级操作系统。安装 Lirc 包后,会将 RPI 配置复制到容器中,确保 RPI 主机上安装的遥控器能够被识别。`/boot/config.txt` 和 `/etc/lirc/lirc_options.conf` 会被更新,远程配置文件会被移动到 `/etc/lirc/lircd.conf.d`,以保持与 RPI 主机上安装的相同设置。

FROM microsoft/dotnet:2.0.0-runtime-stretch-arm32v7 AS base
ENV DOTNET_CLI_TELEMETRY_OPTOUT 1
ENV ASPNETCORE_URLS "http://*:5010"
WORKDIR /app

RUN \
  apt-get update \
  && apt-get upgrade -y \
  && apt-get install -y \
       lirc \
  --no-install-recommends && \
  rm -rf /var/lib/apt/lists/*

RUN \
  mkdir -p /var/run/lirc \
  && rm -f /etc/lirc/lircd.conf.d/devinput.*

COPY Lirc/setup/config.txt /boot/config.txt
COPY Lirc/setup/lirc_options.conf /etc/lirc/lirc_options.conf 
COPY Lirc/setup/ir-remote.conf /etc/modprobe.d/ir-remote.conf
COPY Lirc/remotes /etc/lirc/lircd.conf.d

FROM microsoft/dotnet:2.0-sdk AS build
ENV DOTNET_CLI_TELEMETRY_OPTOUT 1
ENV ASPNETCORE_URLS "http://*:5010"
WORKDIR /src
COPY *.sln ./
COPY *.dcproj ./
COPY src/IO.Swagger/IO.Swagger.csproj src/IO.Swagger/
RUN dotnet restore src/IO.Swagger/
COPY . .
WORKDIR /src/src/IO.Swagger
RUN dotnet build -c Release -r linux-arm -o /app

FROM build AS publish
RUN dotnet publish -c Release -r linux-arm -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "IO.Swagger.dll"]

然后,与 `IoT.Starter.Pi.Thing` 中使用的相同构建会完成 `home-web-ir` 的构建。

lirc-compose.yml

如下所示,`io.swagger` 服务是 `lirc-compose.yml` 中唯一的更改。由 Lirc 驱动的 Web 服务的镜像已更改为 `home-web-ir`,以区别于之前没有 Lirc 支持的 `home-web`。

<services:
  io.swagger:
    container_name: home-web-ir
    image: josemottalopes/home-web-ir
    build:
      context: .
      dockerfile: Lirc/lirc-web.Dockerfile
    ports:
    - "5010"
    network_mode: bridge
    privileged: true
    restart: always
    volumes:
    - /var/run/lirc:/var/run/lirc
    environment:
      - ASPNETCORE_ENVIRONMENT=Release

在 `/var/run/lirc` 创建了一个 Docker 卷,确保正在运行 `irsend` 命令的容器与 RPI 主机上安装的 Lirc 输出套接字之间能够正确通信。由于 `IoT.Starter.Pi.Thing` 中的其他服务保持不变,因此从 `IoT.Starter.Pi.Thing` 到 `IoT.Starter.Pi.Lumi` 的唯一更改是从 `home-web` 到 `home-web-ir`。

在 RPI 上运行

在运行测试之前,请注意,Lirc 应根据 RPI 设置说明 正确安装和配置。以下是下载并运行 `home-web-ir` 的命令,包括 Docker 卷配置:

docker run --privileged -p 5010:5010 -d -it 
    --name=home-web-ir -v /var/run/lirc:/var/run/lirc josemottalopes/home-web-ir:latest

下面的会话展示了实时操作。

root@lumi:~# docker run --privileged -p 5010:5010 -d -it 
    --name=home-web-ir -v /var/run/lirc:/var/run/lirc josemottalopes/home-web-ir:latest
Unable to find image 'josemottalopes/home-web-ir:latest' locally
latest: Pulling from josemottalopes/home-web-ir
0d9fbbfaa2cd: Already exists
b015fdc7d33a: Already exists
60aaa226f085: Already exists
01963091a185: Already exists
a289a8a5c81a: Already exists
9432c55829c7: Already exists
87334e3159b5: Already exists
08a216585c0f: Pull complete
ac1e370475ca: Pull complete
ed21dfb3a130: Pull complete
885b38cb4c35: Pull complete
f8526fd2a07f: Pull complete
Digest: sha256:c374826cfd091ed89fb9da3992bad4d06488fb0152a44d5110401f5ff41de793
Status: Downloaded newer image for josemottalopes/home-web-ir:latest
3c11eeecbc26b258e3d57191f2d4ec5d96e60c1bd4478e334da6ebc77a9c222c
root@lumi:~#

请参考有关 使用最新镜像更新 RPI 的进一步说明,以优化您的 RPI 内存。

检查结果

有几种方法可以使用 Internet 浏览器检查 `home-web-ir`。我们可以使用 Swagger IO 中的“立即试用!”按钮,查看详细响应,例如消息体、响应代码和标头等。另一种简单的方法是直接在浏览器中访问该服务,使用 `curl` 命令或 Swagger IO 提供的“请求 URL”字段。

以下是从运行 Windows 10 的 x64 机器上截取的示例,显示了 RPI 主机上已安装的遥控器。

我们只需在之前的地址后面加上 `remote` 名称即可 `GET` 其相应的红外代码,如下所示:

测试红外输出需要使用 swagger IO 接口,通过“立即试用!”按钮生成 `POST` 命令。您可以看到三星显示器按照预期响应了“KEY_VOLUMEUP”命令。

结论

首先,在此任务中,我们将 API 改进到了新版本,为 `Thing` 设备添加了红外支持。SwaggerHub 为我们自动生成了代码,并添加了一个新的控制器,该控制器已合并到 `home-web` 项目中。

生成的代码被修改成了一个简单的解决方案,该方案展示了一个连接到红外 LED 的 RPI,它正在成长为一个通用红外遥控器的雏形。然后,您可以使用 `http` 向大量的旧式红外控制家居设备发送命令,例如空调、加热器、RGB 灯、电视、家庭影院等。Lirc 数据库 中有超过 2500 个遥控器,您的遥控器很可能已经包含在其中!

根据您的应用程序目标,您现在应该开发一个自定义的 `home-ui` 项目来处理用户界面,以 `RemoteApi` 作为起点!当前的 ASP.NET MVC `home-ui` 是一个建议,当然还有许多其他工具可以利用 `home-web` API。但请记住,由于两者都使用相同的 .NET 平台,当前的 `home-web` 和 `home-ui` 共享一些镜像层,从而优化了内存。

希望您喜欢这一系列文章,我肯定学到了很多。

尽情享受 **IoT.Starter.Pi.Thing 和 **IoT.Starter.Pi.Lumi**,以加速您的物联网项目!

物联网入门套件

入门套件 IoT.Starter.Pi.Thing IoT.Starter.Pi.Lumi
适用于 所有项目 红外 (IR) 项目
描述 物联网的雏形 由 Lirc 驱动的物联网红外雏形
SSL 代理 nginx-proxy nginx-proxy
用户界面 home-ui home-ui
Web服务 home-web home-web-ir

请评论、fork 仓库并使用 Docker 镜像来启动美好的物联网项目!

玩得开心!

历史

© . All rights reserved.