Wind River Helix 设备云应用程序部署:POC 零售自动售货机
本文将探讨一个利用 Helix Device Cloud (HDC) 功能的概念验证 (POC),并使用 UP Squared 开发板作为自动售货机网关。
引言
安全便捷地管理全球多个网关上的物联网软件解决方案可能是一项挑战。然而,对于运行 Wind River Helix Device Cloud* 的网关来说,有一条明确的路径可以遵循,从而减小这一挑战。Wind River Helix Device Cloud 允许完全的设备生命周期管理,从部署、监控、更新到退役。Wind River Helix Device Cloud 还具有遥测功能,可以接收和存储数据到云端,并通过触发器和警报对数据进行操作。本文将探讨一个利用 Helix Device Cloud (HDC) 功能的概念验证 (POC),并使用 UP Squared* 开发板作为自动售货机网关。HDC 将允许监控自动售货机的库存,并设置自动触发器以自动补货,以及在仪表板中查看库存数据。
要了解更多关于 Helix Device Cloud 的信息
https://www.helixdevicecloud.com
要了解更多关于 UP Squared 开发板的信息
https://software.intel.com/en-us/iot/hardware/up-squared-grove-dev-kit
Helix Device Cloud*
本节将简要概述 Helix Device Cloud 以及本次 POC 所需的组件。有关更深入的指南,请参阅 https://knowledge.windriver.com/en-us/000_Products/040/080/000/000_Wind_River_Helix_Device_Cloud_Getting_Started
在 Helix Device Cloud 中需要配置两个主要部分:Thing Definition(设备定义)和 Application(应用程序)。这两个都可以在开发者(developer)选项卡下找到(见图 2)。
Thing Definition(设备定义)定义了物联网解决方案的特性:属性(attributes)、警报(alarms)、属性值(properties)、方法(methods)等。
- 属性 (Attributes) 用于字符串数据,通常是静态的,例如操作系统版本或 MAC 地址。
- 属性值 (Properties) 用于会随时间变化的整数值,例如温度。
- 警报 (Alarms) 用于事件和通知,例如指示温度过高。
- 方法 (Methods) 定义了在设备或客户端应用程序上调用的行为,例如重启设备或向自动售货机发送更多库存。方法在设备级别用代码实现,但可以从云端触发。
Application(应用程序)定义了该设备(Thing)的使用方式,具有不同的访问和权限级别。通过此模型,一个 Thing Definition 可以有多个 Application,例如一个具有“Org Admin”权限的,以及一个没有的。运行在设备上的每个客户端应用程序也将获得自己的唯一设备 ID。这个 ID 与应用程序名称结合,将成为云端应用程序的密钥。推荐的模型是有一个独立的 Device Manager 应用程序和客户端应用程序,以隔离“重启”和“退役”等设备权限。
下方的图 3 概述了这些关键部分。
设置
本文假设已在不同地点部署了巧克力棒自动售货机,并且它们由安装了 HDC 代理并运行了 Device Manager 应用程序的网关控制。Device Manager 能够发送和接收文件、重启设备、远程登录、更新设备软件等。POC 使用运行 Ubuntu* 16.04 Server OS 的 UP Squared 开发板(该板默认安装)。自动售货机功能由 Wind River Helix Device Cloud Python 代理以及 Seeed* Studio 的 Grove* 传感器提供。UP Squared 开发板有一个按钮传感器,用于指示产品购买。它还使用 LED 作为指示灯。绿色 LED 在购买成功时亮起,红色 LED 在产品缺货时亮起。温度传感器将监控自动售货机的温度,以查看巧克力棒是否有融化的危险。此外,它还有一个运动传感器,用于统计经过自动售货机的客流,当检测到运动时,会点亮一个蓝色 LED。自动售货机的软件是用 Python* 编写的,并使用了 HDC Python 设备云 API。
有关如何在 Ubuntu 上安装和配置 HDC Agent 和示例 Device Manager 应用程序的说明,请参阅 Wind River Knowledge Library 中的指南
此外,请参阅以下链接,了解如何将示例 Device Manager 应用程序和 Thing Definition 导入 HDC。
要与 Grove 传感器进行接口,需要在 UP Squared 开发板上安装 MRAA 和 UPM。如果它们不存在,请使用以下命令
sudo add-apt-repository ppa:mraa/mraa sudo apt-get update sudo apt-get install libmraa1 libmraa-dev mraa-tools python-mraa python3-mraa sudo apt-get install libupm-dev libupm-java python-upm python3-upm node-upm upm-examples
在 Helix Device Cloud 中,需要为 POC Vending Thing 添加 Thing Definition。图 4 显示了该设备的完整概览,包括警报和需要配置的状态。有一个 chocobar_out_of_stock(巧克力棒缺货)警报,用于提示所有巧克力棒已售罄。图 5 显示了遥测属性,正在收集的数据是 telemetry_motion(遥测运动)、telemetry_temp(遥测温度)和 telemetry_stock_chocobars(遥测巧克力棒库存)。图 6 显示了 method_restock(补货)方法,该方法需要配置以便可以补货巧克力棒。标有“Key”的字段将在客户端应用程序的代码中使用。请注意,Thing Definition 也可以导出和导入为 json 文件,因此也可以通过代码 2 导入 thing_defs.json,并用您的组织 ID 更新它,而不是手动输入所有内容。
[{"ownerOrgId":"yourOrgIdHere","key":"poc_vending_thing","name":"POC Vending Thing","version":13,"autoDefProps":true,"autoDefAttrs":true,"properties":{"telemetry_motion":{"name":"auto:telemetry_motion","calcAggregates":false},"telemetry_stock_chocobars":{"name":"auto:telemetry_stock_chocobars","calcAggregates":false},"telemetry_temp":{"name":"auto:telemetry_temp","calcAggregates":false}},"alarms":{"chocobar_out_of_stock":{"name":"Chocolate Bars Out of Stock","states":[{"name":"Out of Stock","color":"#E61717"},{"name":"Stock Available","color":"#3BBD1B"}]},"high_temp":{"name":"High Temperature Alarm","states":[{"name":"Melted","color":"#EB0505"},{"name":"Normal","color":"#46E61E"}]}},"methods":{"method_restock":{"name":"Restock Chocolate Bars","description":"Send more stock to the vending machine","notificationVariables":{"num_chocobars_sent":{"name":"num_chocobars_sent","type":"int","uiType":"text"}}}}}]
接下来,按照图 7 配置应用程序定义,并将其链接到 POC Vending Thing Definition。创建后将自动生成一个应用程序令牌,见图 8。该令牌将在设备上使用,以便客户端应用程序知道它将使用哪个应用程序和设备定义。
自动售货机遥测
从自动售货机收集的数据是真正有价值的地方。网关应用程序将收集运动、温度和库存数据,并将其发送到 Helix Device Cloud。该应用程序是一个 Python 脚本 'iot-poc-vending.py',它将被转换为一个服务。然后,在 HDC 中,可以设置各种触发器和警报来处理传入的值。例如,如果库存用完,可以设置一个触发器来自动发送更多库存到机器。Grove 传感器将提供要上传的数据。要通过 Grove shield 与传感器接口,请在代码中添加以下行。这将与 MRAA 和 GROVEPI 结合使用。GROVEPI 将允许传感器与网关通信,而 MRAA 处理 IO 引脚通信。请注意,默认情况下需要 root 权限才能访问 shield,因此在运行 Python 脚本时,必须以 sudo 方式运行。
import upm import mraa # Interface with Grove Sensors mraa.addSubplatform(mraa.GROVEPI, "0")
使用 GROVEPI 会将所有引脚号偏移 512,因此温度传感器的引脚 A0 实际上是引脚 512 + 0。
Grove shield 引脚
- 温度传感器:A0
- 按钮传感器:D8
- 运动传感器:D7
- 蓝色运动指示 LED:D2
- 红色缺货指示 LED:D4
- 绿色购买指示 LED:D3
temperature_sensor = grove.GroveTemp(512 + 0) button_sensor = grove.GroveButton(512 + 8) motion_sensor = upmMotion.BISS0001(512 + 7) blue_motion_led = grove.GroveLed(512 + 2) red_stock_led = grove.GroveLed(512 + 4) green_stock_led = grove.GroveLed(512 + 3)
程序的循环将收集传感器数据,处理购买的商品,在需要时发布警报,然后每 10 秒将数据发送到 HDC。
counter = 0 while running and client.is_alive(): counter += 1 #purchase flow green_stock_led.off() customer_purchase = button_sensor.value() if (stock_chocobars > 0): red_stock_led.off() if (customer_purchase): client.info("Customer purchasing item") green_stock_led.on() stock_chocobars -= 1 else: red_stock_led.on() client.alarm_publish("chocobar_out_of_stock", 0) current_motion= motion_sensor.value() if(current_motion): motion +=1 blue_motion_led.on() else: blue_motion_led.off() celsius = temperature_sensor.value() fahrenheit = celsius * 9.0/5.0 + 32.0; if (fahrenheit >= 90): client.alarm_publish("high_temp", 0) if counter >= TELEMINTERVAL: send_telemetry() # Reset counter after sending telemetry counter = 0 sleep(1)
要将遥测数据发送到 HDC,只需一行代码 telemetry_publish。如果该属性尚未在 HDC 中注册,第一次发布将失败,然后它将自动注册该属性(如果 Thing Definition 中已启用,请参见图 4)。
# temperature telemetry to send client.info("Publishing Property: %s to %s", fahrenheit, "telemetry_temp") ts = datetime.datetime.utcnow() status = client.telemetry_publish("telemetry_temp", fahrenheit, cloud_response, timestamp=ts) # Log response from cloud if cloud_response: if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Telemetry Publish - SUCCESS") else: client.log(iot.LOGERROR, "Telemetry Publish - FAIL")
属性可以在 Helix Device Cloud 的 Thing 视图中以图表形式查看。
方法
方法可以直接从云端调用,或者通过触发器自动调用,这将在下一节讨论。
除了在云端配置方法外,还必须在客户端应用程序中注册要调用的函数,以便 HDC 知道在调用时执行哪个函数。
client.action_register_callback("method_restock", method_restock)
接下来,添加当从网关接收到方法调用时要执行的操作。这里模拟了巧克力棒的补货,因此发送的数量将加到当前库存值中。
def method_restock(client, params): """ Restocks Chocolate Bars """ global stock_chocobars message = params.get("num_chocobars_sent") stock_chocobars += message p = {} p['chocobars'] = "RESTOCKED" msgstr = "Chocolate Bars Restocked" client.info(msgstr) client.event_publish(msgstr) return (iot.STATUS_SUCCESS, "", p)
触发器
现在云端和设备上的数据和方法都已设置完毕,就可以利用触发器功能了。这将有助于在收到需要关注的数据时监控自动售货机。
自动售货机需要发送电子邮件警报,如果温度过高,巧克力可能会融化。要创建一个新规则,请转到 **Developer** -> **Triggers**,然后单击 **New Trigger**。
将触发器命名为 'POC Vending High Temperature Alarm'。右键单击触发器事件,选择 Event type 为 alarm.change,添加 Thing key、Alarm Key 为 high_temp、Alarm State 为 0(表示已融化,如在 Thing Definition 中配置的),以及 Time in condition 为 0(见图 10)。从侧面的 Trigger actions 菜单中,进入 **Networking** 并拖出 email.send 节点。或者,也可以发送 http、mqtt 或 sms 消息。使用消息、主题和收件人电子邮件配置电子邮件节点(见图 11)。然后,在 Trigger actions 的底部,展开 **End** 并拖出 Success 和 Failure 节点。最后,单击节点底部的三角形并将其拖到相应的节点(请参阅图 12 作为参考)。现在触发器已创建,查看它并单击 **Start** 来激活它。
自动补货巧克力棒的触发器非常相似,但增加了一个 method.exec 节点(来自 Method actions)和一个 alarm.publish 节点(来自 Alarm)。选择 POC Vending Thing 作为 Thing Definition。这样就知道有哪些方法可用。然后选择 method_restock 作为方法。添加要执行方法的 Thing Key、Ack Timeout 和方法输入(即 num_chocobars_sent)。还添加 alarm.publish 以将 chocobar_out_of_stock 的警报状态更改为 1,表示它们已重新有货。参见图 13、14 和 15 作为参考。
部署
要在设备上运行客户端应用程序,需要 4 个文件:iot-vending-connect.cfg、iot-poc-vending.py、device_id 和 HDC_VendingMachine.service。service 文件会将代码转换为一个持续运行的服务,即使在重启后也会在网关上运行。device_id 文件应该已经在 device-cloud 文件夹中的设备上。iot-vending-connect.cfg 将应用程序链接到云端,并包含 HDC 主机名和应用程序令牌;有关更多信息,请参阅入门指南和代码 9。确保 device_id 和 iot-vending-connect.cfg 在同一个目录中,并在 iot-poc-vending.py 中更新 config_dir 指向它们的位置。
{ "cloud": { "host": "yourHostName", "port": 8883, "token": "yourAppToken" }, "qos_level": 1, "validate_cloud_cert": true }
#!/usr/bin/python from __future__ import print_function import argparse import errno import random import signal import sys import os import math import mraa import time, sys, signal, atexit from upm import pyupm_grove as grove from upm import pyupm_biss0001 as upmMotion # Interface with Grove sheild mraa.addSubplatform(mraa.GROVEPI, "0") import datetime import time from time import sleep head, tail = os.path.split(os.path.dirname(os.path.realpath(__file__))) sys.path.insert(0, head) import device_cloud as iot #from device_cloud import osal B=3975 temperature_sensor = grove.GroveTemp(512 + 0) button_sensor = grove.GroveButton(512 + 8) motion_sensor = upmMotion.BISS0001(512 + 7) blue_motion_led = grove.GroveLed(512 + 2) red_stock_led = grove.GroveLed(512 + 4) green_stock_led = grove.GroveLed(512 + 3) running = True # Return status once the cloud responds cloud_response = False # Second intervals between telemetry TELEMINTERVAL = 10 def sighandler(signum, frame): """ Signal handler for exiting app """ global running if signum == signal.SIGINT: print("Received SIGINT, stopping application...") running = False def method_restock(client, params): """ Restocks Chocolate Bars """ global stock_chocobars message = params.get("num_chocobars_sent") stock_chocobars += message p = {} p['chocobars'] = "RESTOCKED" msgstr = "Chocolate Bars Restocked" client.info(msgstr) client.event_publish(msgstr) return (iot.STATUS_SUCCESS, "", p) def send_telemetry(): global motion, stock_chocobars, temperature # temperature telemetry to send client.info("Publishing Property: %s to %s", fahrenheit, "telemetry_temp") ts = datetime.datetime.utcnow() status = client.telemetry_publish("telemetry_temp", fahrenheit, cloud_response, timestamp=ts) # Log response from cloud if cloud_response: if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Telemetry Publish - SUCCESS") else: client.log(iot.LOGERROR, "Telemetry Publish - FAIL") # motion telemetry to send client.info("Publishing Property: %s to %s", motion, "telemetry_motion") ts = datetime.datetime.utcnow() status = client.telemetry_publish("telemetry_motion", motion, cloud_response, timestamp=ts) motion = 0 # Log response from cloud if cloud_response: if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Telemetry Publish - SUCCESS") else: client.log(iot.LOGERROR, "Telemetry Publish - FAIL") # chocolate bar stock telemetry to send client.info("Publishing Property: %s to %s", stock_chocobars, "telemetry_stock_chocobars") ts = datetime.datetime.utcnow() status = client.telemetry_publish("telemetry_stock_chocobars", stock_chocobars, cloud_response, timestamp=ts) # Log response from cloud if cloud_response: if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Telemetry Publish - SUCCESS") else: client.log(iot.LOGERROR, "Telemetry Publish - FAIL") if __name__ == "__main__": global motion, stock_chocobars, temperature stock_chocobars = 2 temperature = 0 motion = 0 signal.signal(signal.SIGINT, sighandler) # Initialize client app_id = "iot-poc-vending" client = iot.Client(app_id) # Use the .cfg file inside the directory config_file = "iot-vending-connect.cfg" client.config.config_file = config_file # Look in this directory config_dir = "/home/upsquared/device_cloud/demo/" client.config.config_dir = config_dir # Finish configuration and initialize client client.initialize() # Set action callbacks client.action_register_callback("method_restock", method_restock) # Connect to Cloud if client.connect(timeout=10) != iot.STATUS_SUCCESS: client.error("Failed") sys.exit(1) counter = 0 while running and client.is_alive(): counter += 1 #purchase flow green_stock_led.off() customer_purchase = button_sensor.value() if (stock_chocobars > 0): red_stock_led.off() if (customer_purchase): client.info("Customer purchasing item") green_stock_led.on() stock_chocobars -= 1 else: red_stock_led.on() client.alarm_publish("chocobar_out_of_stock", 0) current_motion= motion_sensor.value() if(current_motion): motion +=1 blue_motion_led.on() else: blue_motion_led.off() celsius = temperature_sensor.value() fahrenheit = celsius * 9.0/5.0 + 32.0; if (fahrenheit >= 90): client.alarm_publish("high_temp", 0) if counter >= TELEMINTERVAL: send_telemetry() # Reset counter after sending telemetry counter = 0 sleep(1) client.disconnect(wait_for_replies=True)
HDC_VendingMachine.service 文件如下所示。该服务应在 network.target 启动后启动,然后启动 python 代码。使用 sudo cp 将此文件放在 /lib/systemd/system/ 目录中。
[Unit] Description=HDC POC After=network.target [Service] ExecStart=/home/upsquared/device_cloud/demo/iot-poc-vending.py Restart=always User=root StandardOutput=journal StandardError=journal KillMode=process KillSignal=SIGINT [Install] WantedBy=multi-user.target
使 python 文件和服务文件可执行,然后启用并启动服务。查看 /var/log/syslog 中是否有启动错误,以及应用程序的信息日志。
chmod +x /home/upsquared/device_cloud/demo/iot-poc-vending.py chmod +x /lib/systemmd/system/HDC_VendingMachine.service
sudo systemctl enable HDC_VendingMachine.service sudo systemctl start HDC_VendingMachine.service
仪表板
现在客户端应用程序已在云端配置并在设备上运行,可以设置一个仪表板来一目了然地查看数据、警报和其他重要信息。仪表板在布局和颜色方面提供了一些自定义选项,但它更多的是为测试设计的,而不是工业级解决方案。
创建仪表板时,只需要 Name(名称)、Thing definition(设备定义)和 Date/Time(日期/时间)。
接下来,可以根据需要设计布局,使用不同的仪表板小部件类型。property graph(属性图)小部件用于所有三个遥测属性:温度、库存和运动。current alarm state(当前警报状态)小部件用于温度警报,Alarm History(警报历史)用于缺货警报。
每个小部件都需要配置 Thing Key 和要显示的属性或警报。
最终的仪表板(包含数据和警报)如下所示(图 21)。
摘要
我们的自动售货机代码现已成功部署到 Helix Device Cloud。温度和库存数据正在通过自动触发器进行监控。运动数据可以随着时间的推移进行参考,以监控自动售货机周围的客流量。程序和整体网关健康的任何未来更新都可以使用 HDC 进行部署和监控。
要购买 HDC,请访问 https://www.windriver.com/company/contact/index.html 或发送电子邮件至 sales@windriver.com
关于作者
Whitney Foster 是 Intel 软件和服务部门的一名软件工程师,致力于物联网的规模化赋能项目。
注意事项
本文档不授予任何知识产权的许可(明示或暗示,禁止反言或以其他方式)。
Intel 对所有明示和暗示的保证,包括但不限于适销性、特定用途的适用性和非侵权性的暗示保证,以及任何由履行过程、交易过程或商业惯例产生的保证,概不负责。
本文档包含有关正在开发的产品、服务和/或流程的信息。此处提供的所有信息如有更改,恕不另行通知。请联系您的 Intel 代表以获取最新的预测、计划、规格和路线图。
所描述的产品和服务可能包含称为勘误的缺陷或错误,这可能导致与公布的规格不符。当前的已特性化勘误可应要求提供。
带有订单号且在本文件中引用的文件副本可通过致电 1-800-548-4725 或访问 www.intel.com/design/literature.htm 获取。
Intel、Intel 标识和 Intel RealSense 是英特尔公司在美国和/或其他国家的商标。
*其他名称和品牌可能被声明为他方财产
© 2018 Intel Corporation。