曾经有这样一则新闻,一男子智能养鱼遇断网,4万余斤鱼或因缺氧死亡。这个塘主通过手机App监控鱼塘情况并利用智能插座控制增氧机进行增氧;但因遇到网络故障,无法及时为鱼塘启动增氧设备而造成重大经济损失。这是个典型的物联网案例,利用物联网平台远程监控数据,并基于数据进行设备控制。在大多数情况下,它能够很好地工作,但当网络连接丢失时,智能将变得无能为力。生活中类似的场景很多,我们有没有办法既享受物联网带来的便捷和智能,又能够摆脱网络依赖带来的局限性呢?
本文将介绍如何利用 Amazon IoT Greengrass 的边缘计算能力,实现远程监控的同时,在边缘侧进行智能控制。为了便于大家有一个直观、清晰的理解,全文以DIY自动浇花为主线展开介绍。
概述
Amazon IoT Greengrass是Amazon IoT服务系列中的一员,它可将亚马逊云科技无缝扩展至边缘设备,因此可以在本地操作其生成的数据,同时仍可将云用于管理、分析和持久存储。借助Amazon IoT Greengrass,您可以构建IoT解决方案,从而将不同类型的设备和云连接起来,并实现设备互连。运行Linux的设备和支持Arm或x86架构的设备可以托管Amazon IoT Greengrass Core。Amazon IoT Greengrass可在本地执行Amazon Lambda代码、消息收发、数据管理和安全策略,甚至在没有连接Internet的情况下,也可实现这些功能。运行Amazon IoT Greengrass Core的设备充当枢纽,与其他运行Amazon FreeRTOS或已安装Amazon IoT Device SDK的设备进行通信。这些设备的尺寸可能不同,从较小的基于微控制器的设备到大型设备。如果Amazon IoT Greengrass Core设备与云之间的连接断开,Amazon IoT Greengrass组中的设备还可通过本地网络继续相互通信。
想学习 Amazon IoT Greengrass 的更多玩法?来2021亚马逊云科技中国峰会与业内领先的技术践行者们一起探讨交流吧!点击图片报名吧~
Amazon IoT Greengrass具有以下优势:
- 近乎实时地响应本地事件。本地资源访问功能让部署在Amazon IoT Greengrass Core设备上的Amazon Lambda函数使用本地设备资源,这样设备应用程序就能够快速访问和处理本地数据。
- 本地运行。Amazon IoT Greengrass设备可以在本地设备无法连接到云的情况下收集、处理和导出数据流。在设备重新连接到云后,Amazon IoT Greengrass可将设备上的数据与Amazon云服务同步。
- 安全通信。Amazon IoT Greengrass可对本地和云通信的设备进行身份验证和加密,包括采用硬件保护的端到端加密。
- 简化设备编程。您可以在云中开发代码,然后使用Amazon Lambda、Docker容器,无缝地将其部署到您的设备上。
- 降低运行IoT应用程序的成本。通过对设备进行编程以在本地过滤或汇总数据,并只将应用程序所需的数据传输到云,从而以较低的成本获得丰富的见解。
- 多平台支持。您可以在支持最低硬件和软件要求的任何硬件设备上运行Amazon IoT Greengrass软件。
自动浇花思路
- 通过树莓派和Amazon IoT Core建立连接
- 利用光传感器、温度传感器和土壤湿度传感器检测环境亮度、温度及花盆中湿度,通过树莓派汇总后上传
- 利用LCD屏在本地显示传感器数据信息,并以不同颜色醒目提示土壤湿度状况
- 利用继电器控制小水泵进行浇水
- 在树莓派上运行自动控制逻辑,根据亮度、温度和湿度确定继电器状态
- 通过topic来设置湿度阈值,这样可以很方便地实现通过手机App或Web应用进行参数设置
- 将传感器数据和继电器状态通过Amazon IoT的规则引擎发送到Amazon Elasticsearch,建立监控仪表板,这样可以很方便地通过手机或浏览器进行可视化监控
方案架构如下图所示:
材料准备
- 树莓派Raspberry Pi 3B/3B+ 一个,MicroSD卡一张
- GrovePi+ 树莓派扩展板一个
- 三个Grove传感器配件:温度传感器,土壤湿度传感器,亮度传感器
- Grove 1602 LCD RGB背光显示屏一个
- 一个继电器配件(Grove Ralay)
- 微型水泵一个(3V/5V/6V),水泵水管一条
设备连接
首先将GrovePi+安装在Raspberry Pi上。堆叠GrovePi+时,注意引脚对齐,如下图所示。
- 按照以下对应端口连接设备配件:
- 温度传感器:A0
- 土壤湿度传感器:A1
- 亮度传感器:A2
- 继电器:D6
- LCD显示屏:I2C-2
- 水泵的地线与水泵电源线(可使用USB电源线)的地线分别接入继电器的端子
安装和配置树莓派设备
树莓派运行系统建议使用原生Raspbian,目前最新版本为buster。请从Raspberry Pi官方网站下载并使用Etcher工具制作启动镜像。
为方便后续使用和调试,建议启用SSH:
1$sudo systemctl enable ssh
一键安装全部驱动:
1$sudo curl -kL dexterindustries.com/update_grovepi | bash
安装Amazon IoT SDK:
1$ pip3 install AWSIoTPythonSDK
记得安装好所有依赖后reboot一下,以刷新系统驱动。
Amazon IoT Greengrass环境配置
首先设置Amazon IoT Greengrass运行环境,增加以下用户和组:
1$sudo adduser --system ggc_user
2$sudo addgroup --system ggc_group
为树莓派设置hardlink和softlink保护,在 /etc/sysctl.d/98-rpi.conf中增加以下两行:
1fs.protected_hardlinks = 1
2fs.protected_symlinks = 1
编辑 /boot/cmdline.txt,在行末尾,增加如下参数,激活memory cgroups:
1cgroup_enable=memory cgroup_memory=1
配置完成后,重启树莓派。
运行Greengrass dependency checker,确保树莓派环境满足所有依赖条件:
1$cd /home/pi/Downloads
2$wget https://github.com/aws-samples/aws-greengrass-samples/raw/master/greengrass-dependency-checker-GGCv1.10.x.zip
3$unzip greengrass-dependency-checker-GGCv1.10.x.zip
4$cd greengrass-dependency-checker-GGCv1.10.x
5$sudo modprobe configs
6$sudo ./check_ggc_dependencies
安装Amazon IoT Greengrass核心软件
首先在Amazon IoT控制台配置Amazon IoT Greengrass。在Greengrass界面,创建组waterflower,详细步骤可参见链接。
创建过程中,会下载安全资源tar.gz文件,并下载Amazon IoT Greengrass核心软件安装包(适用于 Raspbian 的 Armv7l 软件包)。
将下载的文件利用scp上传到树莓派设备上:
1$scp greengrass-linux-armv7l-1.10.0.tar.gz pi@raspberry-IP-address:/home/pi
2$scp -setup.tar.gz pi@raspberry-IP-address:/home/pi
登录到树莓派设备,进入到对应下载文件的目录并解压这两个到相应路径下:
1$sudo tar -xzvf greengrass-linux-armv7l-1.10.0.tar.gz -C /
2$sudo tar -xzvf -setup.tar.gz -C /greengrass
下载Amazon IoT服务器根证书:
1$cd /greengrass/certs/
2$sudo wget -O root.ca.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem
启动Amazon IoT Greengrass:
1$cd /greengrass/ggc/core/
2$sudo ./greengrassd start
确定传感器和Amazon IoT Greengrass的交互模式
传感器作为本地设备,和Amazon IoT Greengrass之间可以采用两种交互模式:一种是标准的IoT模式,即每个传感器作为独立的设备,有自己的X.509证书,通过MQTT协议与Amazon IoT Greengrass Core进行通信,Amazon IoT Greengrass Core则通过MQTT协议对继电器设备发出控制命令。如果需要,Amazon IoT Greengrass Core也负责对收集的各个传感器消息进行汇总并上传给Amazon IoT Core。另一种是简化模式,即每个传感器作为树莓派本地设备,Amazon IoT Greengrass上的Amazon Lambda函数利用本地资源访问功能通过GrovePi SDK对传感器和继电器设备进行读取和写入操作。
第一种模式的扩展性好,支持容器化部署,每个传感器作为IoT设备加入到Amazon IoT Greengrass组中,但每个设备都需要编写相应的代码。这种模式的参考范例也比较容易找到。第二种模式编程简单,两个Lambda函数就可以搞定。在本文中将介绍如何用第二种模式实现。
编写和打包Amazon Lambda函数
首先编写读取和报告传感器状态的Lambda函数,这里命名为wfSensorLambda.py。
为了利用GrovePi SDK来读取传感器数据,并在本地LCD屏上设置文本和颜色,需要引入两个包:
1import grovepi
2from grove_rgb_lcd import *
读取传感器数据的代码如下:
1# Get value from temperature sensor
2temp_value = grovepi.temp(temp_sensor,"1.2")
3
4# Get value from moisture sensor
5mois_value = grovepi.analogRead(mois_sensor)
6
7# Get value from light sensor
8light_value = grovepi.analogRead(light_sensor)
9
10# Get status from relay
11switch_status = grovepi.digitalRead(relay)
在LCD屏上设置颜色和文本的代码如下:
1setRGB(R, G, B)
2setText("Temp: %.1f C *%s\nMoisture: %d " %(temp_value,moment,mois_value))
由于LCD屏的RGB背光色有255个值,为了通过LCD屏的颜色能一目了然地了解当前土壤湿度情况,我们需要将土壤湿度值按照颜色梯度映射到这255个值然后进行显示,从而实现土壤湿度值的颜色显示。这里实现了两个函数来计算最终的RGB值,代码如下:
1def calcColorAdj(variance): # Calc the adjustment value of the background color
2 "Because there is 200 mapping to 255 values, 1.275 is the factor for 400 spread"
3 factor = 1.275;
4 adj = abs(int(factor * variance));
5 if adj > 255:
6 adj = 255;
7 return adj;
8
9def calcBG(humidity):
10 "This calculates the color value for the background"
11 variance = humidity - justRight; # Calculate the variance
12 adj = calcColorAdj(variance); # Scale it to 8 bit int
13 bgList = [0,0,0] # initialize the color array
14 if(variance < 0):
15 bgR = 0; # too dry, no red
16 bgB = adj; # green and blue slide equally with adj
17 bgG = 255 - adj;
18
19 elif(variance == 0): # perfect, all on green
20 bgR = 0;
21 bgB = 0;
22 bgG = 255;
23
24 elif(variance > 0): #too wet - no blue
25 bgB = 0;
26 bgR = adj; # Red and Green slide equally with Adj
27 bgG = 255 - adj;
28
29 bgList = [bgR,bgG,bgB] #build list of color values to return
30 return bgList;
报告传感器状态则比较简单,直接调用greengrass SDK的publish函数即可。
由于需要周期性地采集传感器的数据,因此,这个Lambda函数需要长时间运行,这里我们利用threading的Timer实现每5秒采集一次传感器数据:
1Timer(5, greengrass_sensor_run).start()
wfSensorLambda.py的完整源代码可以从这里获取。
为了实现对继电器和水泵的控制,我们还需要编写一个实现设备控制的Amazon Lambda函数,这里命名为wfSwitchLambda.py。它有两个作用:一是根据传感器数据和设定阈值,执行相应的决策逻辑,控制继电器状态以启动或关闭水泵;二是接收来自Amazon IoT的阈值设置消息,更新阈值。
为了避免浇水过快而传感器不能及时感知的问题,在控制逻辑中针对不同环境条件采取了反转模式或步进模式来启停水泵。主要代码如下:
1temp_value = float(event['temp'])
2 mois_value = int(event['moisture'])
3 light_value = int(event['light'])
4 status = int(event['switch'])
5 if mois_value < threshold:
6 if ((light_value > light_threshold) and (temp_value > temp_threshold)): ##反转模式
7 if status:
8 state = "off"
9 else:
10 state = "on"
11 else: ## 步进模式
12 state = "on-1"
13 else:
14 if status:
15 state = "off"
16
17 grovepi.pinMode(relay,"OUTPUT")
18 if state == "on": # 反转模式
19 try:
20 grovepi.digitalWrite(relay,1)
21 logger.info("Triggering relay turned ON!")
22 except Exception as e:
23 logger.error("Failed to switch ON relay: " + repr(e))
24 elif state == "on-1": # 步进模式
25 try:
26 grovepi.digitalWrite(relay,1)
27 logger.info("Triggering relay turned ON - one time!")
28 time.sleep(1)
29 grovepi.digitalWrite(relay,0)
30 except Exception as e:
31 logger.error("Failed to switch ON relay[one time]: " + repr(e))
32 elif state == "off":
33 try:
34 grovepi.digitalWrite(relay,0)
35 logger.info("Triggering relay turned OFF!")
36 except Exception as e:
37 logger.error("Failed to switch OFF relay: " + repr(e))
38 else:
39 logger.info("No need to change!")
在编写好Lambda函数后,需要将其打包成zip文件。打包时,需要注意将greengrasssdk目录一起打包到zip文件中,greengrasssdk目录可以从Amazon Greengrass Core SDK for Python中获取。打包命令如下:
1$zip -r wf_sensor_lambda.zip greengrasssdk wfSensorLambda.py
2$zip -r wf_switch_lambda.zip greengrasssdk wfSwitchLambda.py
然后,打开Amazon Lambda控制台,分别创建这两个函数wfSensor和 wfSwitch:
- Runtime请选择 Python 3.7
- 对于代码输入种类,请选择上传zip文件
- 对于Handler(处理程序),分别输入wfSensorLambda.function_handler和 wfSwitchLambda.switch_handler
- 分别上传wf_sensor_lambda.zip 和 wf_switch_lambda.zip
- 发布函数后,建议为函数创建别名
为Amazon IoT Greengrass配置和部署Lambda函数
选择之前创建的Greengrass组,在配置页面上,选择Lambdas,然后点击两次Add Lamba,分别将wfSensor 和 wfSwitch 加入,添加时注意以下要点:
- 选择Use existing Lambda
- 在选择版本时,不要选择具体版本号,而是选择Alias:xxx
- 在加入的函数右上角点击省略号(…),选择Edit Configuration(编辑配置)
- 对于“Run as”,请选择Another user ID/group ID,在下方输入两个0,对于“containerization”,选择No container(always)。这个修改只是针对第二种交互模式,对于第一种交互模式,无需修改。
- Timeout超时值改为10秒
- 对于Lamba生命周期,wfSensor需要改为long-lived;wfSwitchLambda不用修改。
配置如下订阅:
针对本文的第二种交互模式,需要在树莓派上修改Amazon IoT Greengrass的参数。打开 /greengrass/config/config.json,在 “runtime”部分,增加:
1"allowFunctionsToRunAsRoot" : "yes"
在Amazon IoT控制台上,在相应greengrass组中,点击Deploy部署,将云配置部署到树莓派设备。第一次部署可能需要几分钟。当部署完成后,您应该在部署页面上的状态列中看到已成功完成。
您可以验证Lambda函数是否在设备上运行,详细步骤参见下方链接。
- 链接
https://docs.aws.amazon.com/z... check.html。
创建和配置Amazon Elasticsearch
在Amazon Elasticsearch控制台上,创建一个新域,名称为waterflower,网络配置选择“Public access”,并输入以下 Access policy(访问策略):
1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Effect": "Allow",
6 "Principal": {
7 "AWS": "*"
8 },
9 "Action": "es:*",
10 "Resource": "arn:aws-cn:es:::domain/waterflower/*",
11 "Condition": {
12 "IpAddress": {
13 "aws:SourceIp": [
14 "x.x.x.x/32"
15 ]
16 }
17 }
18 }
19 ]
20}
上面“x.x.x.x”请输入您的电脑对应的公网IP地址,您可以输入https://checkip.amazonaws.com获得。
访问Kibana界面,创建index,命名为wf-sensor:
1PUT /wf-sensor
2{
3 "mappings": {
4 "properties": {
5 "timestamp": { "type": "long", "copy_to": "datetime" },
6 "datetime": { "type": "date", "store": true },
7 "clientId": { "type": "text" },
8 "temp": { "type": "float" },
9 "moisture": { "type": "integer" },
10 "light": { "type": "integer" },
11 "switch": { "type": "integer" },
12 "state": { "type": "integer" }
13 }
14 }
15}
创建index pattern:
- 名称:wf-sensor*
- 时间过滤器字段名称:datetime
配置IoT规则引擎
在Amazon IoT控制台中,点击Act->Rules,创建规则:
- 规则查询条件:SELECT * FROM ‘waterflower/sensor/telemetry’
- 添加Action,选择 Send a message to the Amazon Elasticsearch Service
- 选择Domain(域)waterflower
- ID: ${newuuid()}
- Index: wf-sensor
- Type: _doc
创建可视化报表
在Kibana界面,点击左边菜单栏的Discover(发现),您现在可以看到上传的设备状态数据,它们按时间顺序显示在屏幕上。
点击左边菜单栏的Visualize,您现在可以创建可视化图表,并可以添加到仪表板中,以远程监控和查看传感器状态和继电器/水泵工作情况。如下图示例:
测试和验证
您可以通过以下几个方法验证自动浇花效果:
- 利用Amazon IoT控制台的test功能发布消息到waterflower/setting,修改湿度阈值,测试水泵工作情况
- 通过Amazon Elasticsearch的Kibana界面,查看传感器数据变化情况和水泵工作情况
- 关闭树莓派的互联网连接,验证连接丢失的条件下,自动浇花是否正常工作
资源清理
在您成功搭建了本文介绍的自动浇花系统后,根据您的使用需求,可以按照如下两种情况对创建的资源进行清理,以免产生不必要的费用。
如果您想继续使用自动浇花功能,但不再需要进行远程监控,请按以下步骤删除资源:
- 打开Amazon IoT控制台,依次选择Act -> Rules,点击之前创建的规则waterflower的右上角省略号(…),点击删除并确认
- 打开Amazon Elasticsearch控制台,可以看到之前创建的域 waterflower,点击进入。然后,点击最上面一排的“Delete domain(删除域)”按钮,在弹出窗口中,选中checkbox框,然后点击删除
如果您不再使用整个自动浇花系统,请先按上面步骤删除远程监控相关的资源,然后按以下步骤继续清理所有资源:
- SSH到树莓派,输入以下命令停止greengrass进程:
1$sudo /greengrass/ggc/core/greengrassd stop
- 打开Amazon IoT控制台,点击左边菜单栏中的Greengrass -> Groups,点击之前创建的组waterflower,进入组管理界面,点击右上角的Actions -> Reset Deployments,在弹出窗口中,选中checkbox框,点击Reset deployment
- 接着点击右上角的Actions -> Delete Group,在弹出窗口中,点击“Yes, Continue to delete”按钮,确认删除
- 继续在Amazon IoT控制台,点击左边的Manage -> Things,点击waterflower_Core的右上角省略号(…),点击删除并确认
小结
根据上面的方案实现,您可能会发现在树莓派系统上运行Amazon IoT Greengrass可以构建更多的IoT解决方案。从基本的遥测到执行机器学习推理,我们的客户正在构建多种多样的Amazon IoT Greengrass解决方案,以便不断创新并扩展解决方案的价值。
在本文中,您学习了如何利用Amazon IoT Greengrass DIY一个自动浇花系统。现在,您可以扩展这个方案,增加手机App实现对浇花参数控制和远程监控自动浇花工作状况,并利用Amazon IoT Greengrass不断改进您的边缘功能。
本篇作者
张红杰
亚马逊云科技解决方案架构师
负责基于亚马逊云科技的云计算方案架构咨询和设计,同时致力于亚马逊云科技物联网服务和无服务器架构在国内和全球商业客户的应用和推广,推进企业服务迁移上云进程。有10年以上的数据中心基础架构设计,企业级应用系统设计开发等经验。