实践:语音控制智能风扇
1. 概述
本文将介绍如何打造一个语音控制的智能风扇,涵盖了硬件配置、解决方案架构以及具体的实现步骤。通过该项目,我们可以实践配置 ESP32 的 GPIO 引脚,连接本地 Wi-Fi 网络,开发 AWS 云端的后端服务,并利用 Amazon Alexa 实现语音控制功能。
2. 技术要求
2.1 代码和库
- 章节代码可在 GitHub 仓库获取: https://github.com/PacktPublishing/Internet-of-Things-with-ESP32/tree/main/ch12
- 外部库可在以下链接找到: https://github.com/PacktPublishing/Internet-of-Things-with-ESP32/tree/main/common
2.2 硬件清单
面包板原型阶段
- ESP32 开发板
- 面包板、四个触觉按钮和跳线
- 至少带有三个继电器的继电器模块(5V DC 输入驱动 230V AC 输出)
- 3.3V 到 5V 的逻辑转换器(如 AZ - Delivery TXS0108E 逻辑电平转换模块)
- 电源(如 ELEGOO 套件中的电源模块)
最终成品阶段
- 具有三个速度档位的风扇(如 Daewoo 12 英寸台式便携式风扇)
- 电源模块(如 AZ - Delivery 220V 到 5V 迷你电源模块)
- 第一个原型中的组件:ESP32 开发板、继电器模块和逻辑转换器
- 用于组装组件、电线和接头的通用 PCB
2.3 注意事项
在第二个原型中,将组件组装到通用 PCB 上需要焊接设备和一定的焊接技能,并且涉及高压电操作,测试由市电供电的风扇时需采取所有必要的预防措施。
2.4 账户准备
如果之前未完成相关示例,需要创建 Amazon 和 Alexa 开发者账户,可参考: https://developer.amazon.com/en-US/docs/alexa/smarthome/steps-to-build-a-smart-home-skill.html#prerequisites
2.5 代码演示视频
查看代码运行效果的视频: https://bit.ly/3xsLbdI
3. 智能风扇功能列表
| 功能 | 描述 |
|---|---|
| 停止按钮 | 有一个按钮开关用于停止风扇 |
| 速度调节按钮 | 有三个按钮用于改变风扇速度,分别为低速、正常速度和高速 |
| 语音控制 | 支持 Alexa 语音控制,可通过语音命令改变风扇速度 |
| 状态同步 | 在 AWS IoT Core 上跟踪风扇的当前状态,保持设备和云端状态一致 |
4. 解决方案架构
4.1 设备固件
设备固件主要由以下组件构成:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(GPIO 控制器):::process --> B(Wi-Fi 通信模块):::process
A --> C(AWS 通信模块):::process
B --> C
D(输入引脚 - 按钮):::process --> A
A --> E(输出引脚 - 继电器):::process
C --> F(云端):::process
- GPIO 控制器 :配置和驱动 ESP32 的 GPIO 引脚,四个输入引脚读取按钮状态,三个输出引脚控制继电器。按下停止按钮时,所有继电器关闭;按下速度按钮时,相应继电器打开。同时与 AWS 模块通信,发送按钮状态信息并接收 Alexa 语音命令。
- Wi-Fi 通信模块 :根据 SSID 和密码连接本地 Wi-Fi 网络,连接成功后通知 AWS 模块连接 AWS 云端。
- AWS 通信模块 :监控云端请求,将请求传递给 GPIO 模块设置/重置继电器引脚;用户按下按钮时,将风扇速度信息传递给云端。
4.2 云架构
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(智能风扇):::process --> B(AWS IoT Core - 设备):::process
B --> C(Lambda 函数):::process
C --> D(Alexa Voice Service):::process
D --> E(用户):::process
E --> D
D --> C
C --> B
B --> A
- 创建 IoT 事物 :在 Amazon IoT Core 上创建一个事物作为智能风扇的云端表示,风扇和事物的状态变化将同步。
- Lambda 函数 :作为事物和 Alexa Voice Service (AVS) 之间的桥梁,解析来自 Alexa 技能的请求并根据上下文回复,根据 Alexa 命令更新事物状态,最终实现物理设备的速度变化。在 Lambda 函数中实现 Alexa.PowerLevelController 接口,参考文档: https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-powerlevelcontroller.html
- Alexa 智能家庭技能 :创建并配置 Alexa 智能家庭技能,提供现成的语音交互模型,用户可以使用百分比形式的语音命令,如“Alexa,将智能风扇设置为 40%”或“Alexa,将智能风扇速度提高 10%”。
5. 实现步骤
5.1 创建智能家庭技能
- 登录 Amazon 开发者控制台: https://developer.amazon.com/alexa/console/ask
- 创建名为 myhome_smartfan 的技能,选择 Smart Home 模型
- 记录页面上的技能 ID,格式类似 amzn1.ask.skill.
5.2 创建 Lambda 函数
- 创建角色
- 编辑文件 lambda_trust_policy.json,内容如下:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
}
- 使用以下命令创建角色:
$ aws iam create-role --role-name smartfan_lambda_role --assume-role-policy-document file://lambda_trust_policy.json
- 记录角色的 Amazon Resource Name (ARN),格式类似 arn:aws:iam::<your_account_id>:role/smartfan_lambda_role
- 创建策略
- 编辑文件 lambda_permissions.json,内容如下:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"iot:*"
],
"Resource": "arn:aws:iot:*:*:*"
}
]
}
- 使用以下命令创建策略:
$ aws iam create-policy --policy-name smartfan_lambda_policy --policy-document file://lambda_permissions.json
- 记录策略 ARN,格式类似 arn:aws:iam::<your_account_number>:policy/smartfan_lambda_policy
- 附加策略到角色
$ aws iam attach-role-policy --role-name smartfan_lambda_role --policy-arn <the_policy_ARN>
- 创建临时代码文件
创建文件 lambda_function.py,内容如下:
import json
def lambda_handler(request, context):
pass
- 创建代码包
$ zip lambda_package.zip lambda_function.py
- 创建 Lambda 函数
$ aws lambda create-function --function-name smartfan_lambda \
--zip-file fileb://lambda_package.zip \
--handler 'lambda_function.lambda_handler' \
--runtime python3.8 \
--role <the_role_ARN>
记录 Lambda 函数的 ARN,格式类似 arn:aws:lambda:
:
:function:smartfan_lambda
7.
创建触发
由于没有命令行选项,需要登录 AWS 网页控制台(
https://aws.amazon.com/console/ ),导航到 Lambda 服务中的 smartfan_handler 函数,从 Alexa 开发者控制台复制技能 ID,点击 + Add trigger 后使用技能 ID 作为触发配置参数。
8.
关联 Lambda ARN 到技能
复制 Lambda ARN 并返回技能配置页面,将 Lambda ARN 粘贴到标记为 Default endpoint* 的文本框中,点击保存按钮。
5.3 账户关联
- 在 Alexa 开发者控制台中导航到技能的 ACCOUNT LINKING,填写以下信息:
- Web Authorization URI: https://www.amazon.com/ap/oa
- Access Token URI: https://api.amazon.com/auth/o2/token
- Client ID: 安全配置文件中的客户端 ID
- Secret: 安全配置文件中的客户端密钥
- Authentication Scheme: HTTP basic
- Scope: profile:user_id
- 点击配置页面上的保存按钮完成账户关联
- 登录 https://alexa.amazon.com/ ,在 DEV SKILLS 中找到 myhome_smartfan,点击 ENABLE 按钮,若配置正确,页面将显示成功消息,关闭成功页面时跳过发现过程。
5.4 创建事物
- 创建事物
$ aws iot create-thing --thing-name myhome_fan1
- 创建策略文件 myhome_fan1_policy.json,内容如下:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"iot:*"
],
"Resource": "arn:aws:iot:*:*:*"
}
]
}
- 创建策略
$ aws iot create-policy \
--policy-name myhome_fan1_policy \
--policy-document file://myhome_fan1_policy.json
- 创建证书和公私钥对
$ aws iot create-keys-and-certificate \
--certificate-pem-outfile "certificate.pem.crt" \
--public-key-outfile "public.pem.key" \
--private-key-outfile "private.pem.key" \
--set-as-active
记录证书 ARN,将密钥嵌入设备固件中。
5. 附加策略到证书
$ aws iot attach-policy \
--policy-name myhome_fan1_policy \
--target <certificate_ARN>
- 附加证书到事物
$ aws iot attach-thing-principal \
--thing-name myhome_fan1 \
--principal <certificate_ARN>
5.5 开发 Lambda 函数
在 Lambda 函数中,需要回复来自 AVS 的以下请求:
- 来自 Alexa.Discovery 命名空间的发现请求,用于查找与用户账户关联的风扇。
- 来自 Alexa.Authorization 命名空间的 AcceptGrant 请求,用于获取识别用户的凭证。
- 来自 Alexa.PowerLevelController 命名空间的 SetPowerLevel 请求,用于设置风扇的功率级别。
- 来自 Alexa.PowerLevelController 命名空间的 AdjustPowerLevel 请求,用于按指定量更改功率级别。
- 来自 Alexa 命名空间的 ReportState 请求,用于发送设备状态。
- 来自 Alexa.EndpointHealth 命名空间的连接状态。
import logging
import time
import json
import uuid
import boto3
from fan1_responses import *
logger = logging.getLogger()
logger.setLevel(logging.INFO)
client = boto3.client('iot-data')
def lambda_handler(request, context):
try:
logger.info("Directive:")
logger.info(json.dumps(request, indent=4, sort_keys=True))
request_namespace = request["directive"]["header"]["namespace"]
request_name = request["directive"]["header"]["name"]
corrTkn = ""
if "correlationToken" in request["directive"]["header"]:
corrTkn = request["directive"]["header"]["correlationToken"]
if request_namespace == "Alexa.Discovery" and request_name == "Discover":
response = gen_discovery_response()
elif request_namespace == "Alexa.Authorization" and request_name == "AcceptGrant":
response = gen_acceptgrant_response()
elif request_namespace == "Alexa.PowerLevelController" and request_name == "SetPowerLevel":
response = set_power_level(request["directive"]["payload"]["powerLevel"], corrTkn)
elif request_namespace == "Alexa.PowerLevelController" and request_name == "AdjustPowerLevel":
response = adj_power_level(request["directive"]["payload"]["powerLevelDelta"], corrTkn)
elif request_namespace == "Alexa" and request_name == "ReportState":
response = gen_report_state(corrTkn)
else:
logger.error("unexpected request")
return response
logger.info("Response:")
logger.info(json.dumps(response, indent=4, sort_keys=True))
return response
except ValueError as error:
logger.error(error)
raise
下面详细介绍几个重要的辅助函数:
处理 SetPowerLevel 请求
def set_power_level(power_level, tkn):
power_level = update_power(power_level)
set_power_level_shadow(power_level)
response = init_response(set_power_level_response, tkn, power_level)
return response
在 set_power_level 函数中,首先调用 update_power 函数将功率级别归一化为以下值之一:
| 输入范围 | 归一化值 | 对应模式 |
| ---- | ---- | ---- |
| 0 | 0 | 风扇关闭 |
| 1 - 33 | 33 | 低速模式 |
| 34 - 66 | 66 | 正常速度模式 |
| > 66 | 100 | 高速模式 |
归一化后,调用 set_power_level_shadow 函数更新设备影子的期望状态:
def set_power_level_shadow(power_level):
payload = json.dumps({'state': { 'desired': { 'powerlevel': power_level } }})
response = client.update_thing_shadow(
thingName = endpoint_id,
payload = payload)
logger.info("update shadow result: " + response['payload'].read().decode('utf-8'))
5.6 更新和测试 Lambda 函数
- 更新 Lambda 代码包
$ zip -u lambda_package.zip *.py
- 更新 AWS 上的 Lambda 代码
$ aws lambda update-function-code --function-name smartfan_lambda --zip-file fileb://./lambda_package.zip
- 测试所有请求类型
示例请求可在 https://github.com/PacktPublishing/Internet-of-Things-with-ESP32/tree/main/ch12/smart_fan/aws 找到。
$ aws lambda invoke \
--cli-binary-format raw-in-base64-out \
--function-name smartfan_lambda \
--payload file://./discovery_request.json \
response.json
所有测试应返回状态码 200。
5.7 开发智能风扇固件
根据前面介绍的设备固件架构,开发智能风扇固件,实现 GPIO 控制、Wi-Fi 连接和 AWS 通信等功能。
5.8 语音命令测试
完成上述步骤后,使用 Alexa 语音命令测试智能风扇,验证风扇是否能根据语音指令正确调整速度。
总结
通过以上步骤,我们成功实现了一个语音控制的智能风扇。整个过程涵盖了硬件配置、云架构搭建、Lambda 函数开发和固件编程等多个方面。在实际操作中,需要注意 AWS 资源的配置和权限管理,以及设备固件与云端服务的通信协调。希望本文能为你开发智能设备提供有价值的参考。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(创建智能家庭技能):::process --> B(创建 Lambda 函数):::process
B --> C(账户关联):::process
C --> D(创建事物):::process
D --> E(开发 Lambda 函数):::process
E --> F(更新和测试 Lambda 函数):::process
F --> G(开发智能风扇固件):::process
G --> H(语音命令测试):::process
这个流程图展示了实现语音控制智能风扇的主要步骤,从技能创建到最终测试,各个步骤依次进行,形成一个完整的开发流程。
超级会员免费看
1369

被折叠的 条评论
为什么被折叠?



