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

RaspberryPi 和 Windows IoT 上的 AllJoyn 平台入门——以及额外的美味低温慢煮烹饪

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (5投票s)

2016年8月6日

CPOL

13分钟阅读

viewsIcon

18606

我如何使用 Windows IoT 的 Raspberry PI 构建一个通过 Android 智能手机通过 AllJoyn 协议控制的慢煮烹饪设备。

引言

我最初的想法基本上是构建一个可编程的加热设备,可用于低温烹饪。我抽屉里有几个 Raspberry Pi 设备,我认为这可能是一个有趣且有用的项目。随着微软通过 Windows 10 IoT 的 RPi 版本进入 Raspberry Pi 世界,对于专注于微软平台的开发者来说,“设备”世界变得更加容易上手。

我最初不知道如何解决控制设备的问题(因为我不想购买会使整个设备成本翻倍的触摸屏),这就是我遇到 AllJoyn 的地方。在巨头们努力建立强大的物联网设备通信标准的时候,开源的 AllJoyn 框架可能是最早的或多或少完整的物联网连接标准之一。

AllJoyn 获得了微软的支持,并且被集成到第一个 Windows IoT SDK 中,因此它是我可以立即开始项目的完美平台。虽然它目前的未来尚不明朗,随着新的 OpenConnectivity Foundation(微软共同创立)的出现,AllJoyn 框架中实现的理念及其性能使其成为任何工程师和创客研究的有趣焦点。如果 AllJoyn 被 OpenConnectivity 取代,那么将项目移植到这个不同的连接平台应该会很自然。

背景

此项目引用的一些基本概念如下所列。

慢煮烹饪

慢煮(Sous-vide)是一种基于将水煮产品(主要是肉类)加热到严格控制的温度的烹饪技术。结果是获得均匀加工、风味浓郁的食物(因为所有的汁水和风味都与真空密封袋中的产品一起保留),从而可以实现精确且可重复的烹饪(例如,肉类不会“煮过头”)。

维基百科提供了关于慢煮的相当全面的专著(https://en.wikipedia.org/wiki/Sous-vide)。

由于慢煮通常被视为一种高档、美食风格的烹饪技术,因此市面上主要有专业、高端(即昂贵)的慢煮加热设备。然而,制造这样的设备并非难事,对于“创客”来说似乎是一个引人注目的挑战。

AllJoyn 框架

AllJoyn 是由 Allseen Alliance(https://allseenalliance.org)设计的一个开源框架,旨在为物联网设备提供统一的连接平台。它涵盖(但不限于)以下方面:

  • 设备通信 - 通过提供定义包含属性、操作和事件的接口的框架。
  • 设备广告和发现 - 通过设备服务总线概念。
  • 设备入网 - 即如何将新设备插入我的网络。
  • 安全

AllSeen Alliance 门户网站(https://allseenalliance.org/framework/documentation)提供了相当全面的文档,并且有 AllJoyn SDK 中包含的示例作为补充。

它是如何构建的

概念

慢煮烹饪的挑战在于在精确控制温度的水中浸泡长时间来加热水煮食物。烹饪设备实际上是以下组件的简单组合:

  • 加热器
  • 温度传感器
  • 设备控制单元 - 实现PID控制器 - 基于温度传感器的输入,控制器通过加热器组件设置功率输出(PID 控制器是该问题的最典型也是默认的解决方案,维基百科上也可以找到 PID 控制器的专著 - https://en.wikipedia.org/wiki/PID_controller)。
  • 水泵 - 为了实现水中热量的均匀分布,水需要保持持续循环。
  • 用户控制单元 - 一个允许编程加热模式的用户界面设备。

注意:用于烹饪的产品的真空密封可以使用廉价的现成设备实现,这超出了本文的范围。

AllJoyn 框架 - 它提供了什么?

我在此项目中的主要挑战之一是从外部移动控制器连接到加热设备。我假设我会使用基于 TCP 的连接,即我的 RPi 需要通过 WiFi 连接到网络,并且我的移动设备(智能手机或平板电脑)也可以连接到该网络。因此,我需要构建一种由加热设备公开的 API,以便控制器 UI 可以连接到它并发送“命令”以及收集状态(至少通过轮询)。我曾考虑过某种 Web 服务(可能是 HTTP,RESTful),我的控制器将连接到该服务。这将需要用服务 URL 配置我的控制器。MS 示例演示了将设备的 API 发布到 Azure(当然 :))),但这对我来说似乎不合适。然后我开始阅读 AllJoyn……

事实证明,AllJoyn 引入了设备服务总线的概念,该总线由一个或多个 AllJoyn 路由器节点在网络中虚拟组装和公开。任何 AllJoyn “生产者”设备(一种电器)都可以动态定位总线并将其接口发布到总线。另一方面,任何 AllJoyn “消费者”(一种控制面板设备)都可以连接到总线并查询可用的设备。

Windows IoT 附带 AllJoyn 支持,这意味着任何 Windows IoT 设备都可以作为 AllJoyn 路由器。因此,我的 RPi 烹饪设备也可以发布 Alljoyn 总线,我可以使用为 Android 编写的控制面板连接到它。

实际上,这意味着只要我的加热设备和我的控制设备在同一个 WiFi 网络中,它们就会立即看到并连接——这个项目就演示了这样的场景。无需用户提供的 API URL 配置等。

注意:RPi 设备仍需要插入 WiFi 网络,这意味着它需要初步设置(提供 WiFi SSID 和密钥)。这使得加热设备的初始设置更加麻烦——如果我想在自己的 WiFi 之外演示我的设备,我需要一个屏幕、键盘和鼠标,或者至少一个以太网电缆和远程 PowerShell 会话才能将我的设备插入 WiFi。

AllJoyn 框架定义了 WiFi 入网场景,其中使用带 UI 的“入网器”设备将 WiFi 设置传递给“无 UI”的“被入网”设备,但在本项目中我没有深入研究。

硬件

每个概念的组件都使用了常见设备实现,总结如下。

加热器

使用了一个简单的便携式浸入式 500 瓦加热器(“旅行加热器”)。类似的电器可以在 eBay 上找到(http://www.ebay.co.uk/itm/500W-Electric-Water-Heater-Liquids-Immersion-Travel-Portable-Boiler-Element-Hot-/351790910762?hash=item51e85f4d2a:g:O64AAOSwARZXk0gW)。

温度传感器

使用了一个流行的 DS18B20 防水数字温度传感器。由于此传感器通过 OneWire 协议通信,因此无法直接将其作为 RPi 的输入(RPi 没有 OneWire 的硬件支持)。因此,需要一个 OneWire-2-I2C 桥(如下所列)。

设备控制单元

运行 Windows IoT 的 Raspberry Pi 2 和一个实现伪 PID 控制器算法和基于 AllJoyn 的连接的软件(SoViAgent)。RPi 使用官方 RPi WiFi 适配器连接到网络。

水泵

使用了一个简单的水族馆泵。由于使用的温度不超过 70 摄氏度,一个简单的鱼缸设备工作可靠,并且似乎不受高温影响。

其他设备

  • 两个大电流继电器开关,用于从 Raspberry Pi 的引脚输出控制大功率设备(加热器和水泵)。
  • OneWire-2-I2C 桥设备 - 基于 DS2482 芯片。连接温度传感器到 WPi 的 I2C 接口是必需的。

用户控制单元

运行在 Android 智能手机或平板电脑上的定制 SoVi Controller 应用程序,如下文所述。

下方显示了组装好的设备(SoViAgent 部分)。

SoViAgent - Windows IoT 应用

必备组件

概述

解决方案的 SoViAgent 部分聚合到 SoViAgent.sln Visual Studio 解决方案中。它包含以下组件:

  • SoViAgent.UI - SoViAgent 应用程序项目,实现为 WinIoT 有界面应用程序(即带 UI)。此应用程序实例化 SoViAgentService 类,该类管理 AllJoyn Bus 和设备“引擎”之间的所有通信。
  • SoViAgent.Headless - SoViAgent 无界面实现的占位符。
  • SoViAgent.AllJoyn - 包含 PID 控制器实现和 AllJoyn 设备包装器类的主要应用程序“引擎”。
  • SoViAgent.Devices - 实现硬件特定的输入和输出(例如,DS18B20 温度传感器通信包装器)。
  • org.stranger80.SoViAgent - 由 AllJoyn 代码生成工具生成的 AllJoyn 连接实现。
  • SoViAgent.Test - 一些基本的单元测试类。

使用 AllJoyn Studio 包提供的工具支持为 Windows IoT 构建支持 AllJoyn 的应用程序。过程是基于获取或创建的接口定义(内省 XML)生成代理代码。代码生成器用于生成处理 AllJoyn 通信细节的原生 C++ 代码。这遵循典型的“合同优先”集成方法。

注意:一个很好的分步教程,介绍如何为 Windows IoT 构建支持 AllJoyn 的应用程序,可以在此处找到:https://channel9.msdn.com/Blogs/Internet-of-Things-Blog/Using-the-AllJoyn--Studio-Extension

支持 AllJoyn 的应用程序的 AllJoyn 接口“合同” - 内省 XML

内省 XML 是定义设备在 AllJoyn 设备总线上公开的“API”的一种方式。

SoViAgent.AllJoyn 项目中的 SoViAgent.xml 定义了我烹饪设备的 API。XML 必须遵循 D-Bus 规范,并定义接口的以下基本元素:

  • 方法 - 设备发布的端点,可用于向设备发送“命令”。例如:
    <method name="ExecuteHeatPattern">
      <description language="en">
        Programs the device to start executing a heat pattern defined via array of 'heat points'.
      </description>
      <arg name="heatPointArray" type="a(di)" direction="in">
        <description language="en">
          Array of heat points.
          A 'heat point' is a single order to set a given temperature to T and maintain it for S seconds.
          Thus it is a struct of 2 integers:
          - Target temperature (degrees Celsius)
          - Temperature sustain period (seconds)
        </description>
      </arg>
      <arg name="success" type="b" direction="out">
        <description language="en">
          Result of operation (success = true/false).
        </description>
      </arg>
    </method>

请注意,输入和输出参数(<arg> 元素)如何被指定为值序列和模式。

  • 属性 - 设备的可读写属性。例如:
    <property name="Temperature" type="d" access="read">
      <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
      <description language="en">
        Current temperature measured by device (degrees Celsius).
      </description>
    </property>

请注意,属性可能会发出其值变化的信号,客户端应用程序可以监听这些信号,而不是反复轮询设备。

  • 事件 - 由设备主动发出信号,以便客户端应用程序可以被动地监听事件信号。
    <signal name="DeviceErrorOccurred" sessioncast="true">
      <description>
        Signal to notify the controller about a device error.
      </description>
      <arg name="errorDescription" type="(is)" direction="out">
        Error description struct:
        - error code (integer)
        - error description (string)
      </arg>
    </signal>

一旦 AllJoyn 管道代码从内省 XML 生成,org.stranger80.SoViAgent 就包含了处理上述元素的代码。然后,C# 包装器(SoViAgentService 类)可以引用此代码来公开设备功能。

DS18B20 温度传感器 - 输入

SoViAgent 引用 Rinsen.OneWire 库(https://github.com/Rinsen/OneWire)与温度传感器进行通信。包装此功能的代码位于 OneWireDevice 类中。

加热器和水泵 - 输出

加热器和水泵都是开关设备,因此可以从 RPi 的输出引脚进行控制。来自引脚的信号通过大电流继电器传递,继电器为实际设备供电。这在 SimpleRelayOutputDevice 类中处理。

PID 控制器实现

温度控制器的“大脑”是 DefaultController 类,它以“滴答”为单位工作。每个滴答测量来自输入传感器的输入,根据硬编码的 PID 设置执行输出计算,并将更新的输出设置发送到输出设备。

有界面 vs. 无界面

虽然此原型仅作为有界面应用程序实现,但值得注意的是,无界面实现会更轻量,并且可能缩短设备启动时间。无论哪种情况,将应用程序配置为在 RPi 启动时自动运行都很有用。

SoViController - Android 应用

必备组件

概述

代码是基于 Android 版 AllJoyn SDK 中包含的“Observer”示例编写的。

Android 应用程序由以下组件组成:

  • SoViAgent 接口和 org.stranger80.sovicontroller.model 命名空间 - 处理设备合同的类定义。这些是手动编写的——我没有花太多时间寻找合适的代码生成工具,幸运的是,除了许多 AllJoyn 特定的注释之外,这里没有什么需要写的。
  • AllJoynBusHandler - 负责与 AllJoyn 总线的所有通信。
  • BusHandlerService - 一个 Android Service 类,负责将 SoVi 设备通信嵌入到后台线程中,与 UI 活动分离。
  • DevicePanelActivity - 显示设备控制面板。
  • MainActivity - 主应用程序活动,负责搜索可用设备并将用户重定向到实际 SoViAgent 实例的控制面板。

操作 (Operation)

一旦 SoVi Controller 连接到 SoVi Agent 设备,控制面板就会显示出来。

用户可以转动“旋钮”控件来设置目标温度,然后点击“旋钮”来打开或关闭设备。就是这么简单……:)

面板会显示设备属性的所有更改,并且温度会绘制在图表上以说明加热曲线。可以观察到 PID 控制器实现的效果——当编程为保持固定温度 T 时,控制器能够将温度保持在 +-0.5°C 的范围内,这可能是用简单的开关加热器所能达到的最好效果。

注意:目前控制器应用程序不处理设备通知。

SoVi Agent 实战

最后,可以把整个设备投入使用了!下面是一个慢煮牛肉菲力烹饪的小图示。

将一小块牛肉菲力切好并调味。

真空包装的食材在 SoVi Agent 设备中以 52 摄氏度烹饪 1 小时。

然后将每块肉在煎锅上煎至表皮酥脆并增加风味。

……切成看起来美味的薄片即可上桌。

尽情享用!

摘要

总而言之,我非常享受构建这个原型。从这次的尝试中可以突出几个经验教训:

  • AllJoyn 似乎是一个非常强大的框架,它提供的解决方案似乎是连贯且完整的。虽然我没有深入研究安全和设备入网领域,但框架涵盖了它们,并且可以进行探索。
  • 我接触过的 AllJoyn 实现(Windows 和 Android)似乎性能非常高,当观察到控制器中的用户操作与设备对其的响应之间的延迟时,这一点就很明显——点击控制旋钮会立即触发加热器开关。令人印象深刻。
  • AllJoyn 入门似乎相当复杂,而且支持有限。
  • 坦白说,我不是 Android 开发专家,编写控制器应用程序需要维护一个持续连接的后台服务来处理 AllJoyn 总线流量对我来说是一项艰巨的任务。我最终得到了一张由处理程序和监听器组成的蜘蛛网,它们(或多或少)工作正常,但我一直在问自己一个问题——能否用更简单的方式编写它,或者 Android 的编程模型是否就是设计得如此复杂?
  • 通用 Windows 平台是一个让我皱眉的框架。例如,我无法将 UWP 程序集写成单元测试,并且使用我喜欢的模拟框架——FakeItEasy 没有兼容的版本能在 UWP API 上运行(我认为主要原因是缺乏反射和代码发射 API)——我不得不从头开始编写模拟类,这有点令人失望。
  • 发布的代码确实是“原型”,即不稳定(尤其是 Android 部分)。
  • 随着微软加入了 OpenConnectivity Foundation 的行列,AllJoyn 的未来变得模糊。至少我们可以预期在未来的 Windows IoT 版本中会支持 OpenConnectivity。

 

© . All rights reserved.