蜂窝网关默认使用IoT Hub Device Twin的desired property同步设备I/O状态,定义了下面Device Twin协议格式用于分别控制4路I/O:
{
"desired": {
"devconfig": {
"Lock1": true,
"Lock2": false,
"Lock3": false,
"Lock4": false
}
}
}
IoT Hub支持三种不同的方式实现云到设备的控制执行,分别是1)发送C2D消息,2)通过Device Twin Desired property同步状态和3)执行Direct Method远程调用。这些方法各有优缺点,理解他们的特点可以正确的选择在不同的场景下使用合适的方法。
Direct Method发送命令并同步地等待回应,适合需要设备立刻反馈执行结果的场景使用。比如读取设备实时状态、控制设备做一个具有时效性的动作,比如开灯。如果设备此时不在线,也能得到即时的反馈,知道命令执行失败了。它的另一个显著优点是并发能力支持相对Device Twin和C2D更好。在实际使用过程中,Direct Method一般是控制设备优先考虑的方法。
Device Twin Desired Properties通过Twin作为中间媒介通知操作设备进入某一种状态,不管设备此时是否在线,这个指令已经写入了Twin文档中,当设备上线后会收到通知,再进行状态的同步(通过reported proerty回报状态)。显而易见,Twin更适合长期和稳定状态的操作,比如通知设备有固件更新,设定温度计报警阈值等操作。
Cloud To Device Message消息支持云到设备的单向通讯,它支持消息缓冲,同时具有可编程的时效性,支持消息重传,比较适合设备在弱网环境下接收可靠的消息,但是C2D的缺点也比较明显,设备无法回传数据同时并发性能比较低。
在Portal上创建一个默认的HTTP Trigger Function,详细操作可以参照实验5中的步骤。
修改Trigger binding的Route template为{device}/control/{lockn}/{onoff}
,方法保留PUT
,详细操作可以参照实验5中的步骤。
通过Portal创建的Function中只是一个简单的index.js,要使用Azure IoT Node.js SDK需要先在项目中安装依赖库。
返回Function App服务主页面,左侧导航栏在Development Tools下选择Advanced Tools,点击 Go-> 进入Kudu网页文件管理页面。
上面选择Debug console->CMD,进入文件系统。
点击目录site->wwwroot进入Function文件根目录。
在CMD中输入npm init
开始npm包项目创建向导。首先输入任意项目名称,其他内容按回车键略过,完成后可以看到文件目录中多出了npm包工程的package.json文件。
继续在CMD中输入npm install azure-iothub
开始下载安装Azure IoT Node.js SDK以及它的依赖包,等待几分钟,CMD中可以看到完成提示信息,此时再点开package.json可以看到依赖已经更新:
"dependencies": {
"azure-iothub": "^1.15.0"
}
💡当你在做Azure Function本地开发时,工具可以把本地安装的npm package在部署的时候自动同步上去,不用麻烦的再进入Kudu后台手动安装。
当我们在Function代码使用IoT SDK的时候需要获得IoT hub的API授权,这里需要用到IoT Hub Service Connection String。为了避免在代码中直接存储机密信息,通常的做法是将其保存为一个Application Settings环境变量供给Function访问。
进入之前创建的IoT hub服务,左侧导航栏在Security settings下选择Shared access policies,在新开的页面中点击 iothubowner,再从新开页面中复制Primary connection string。
返回Function App服务主页面,左侧导航栏在Settings下选择Configurfation,在打开的窗口中点击 +New Applicaiton setting 按钮新增一个环境变量。
Name输入变量名IOTHUB_CONNECTION_STRING
(稍后在代码中会用到),Value输入复制的Connection string,点击OK后,再点击Save保存。
💡除了使用SAS的方式,IoT hub和Azure Function之间还支持使用Managed Identity通过Azure AD的RBAC方式进行认证和授权。
根据协议编写Function代码,代码使用IoT SDK访问device registry更新Device Twin的实现对锁的控制。代码如下,复制到index.js,点击Save保存。
// 载入IoT SDK模块
var iothub = require('azure-iothub');
module.exports = async function (context, req) {
// 获取route path的变量
const deviceId = context.bindingData.device;
const lockn = context.bindingData.lockn;
const onoff = context.bindingData.onoff === "on" ? true : false;
// 获取route path的变量
const iothub_cs = process.env["IOTHUB_CONNECTION_STRING"];
// 准备IoT hub对象
var registry = iothub.Registry.fromConnectionString(iothub_cs);
// 准备要修改twin的内容
const twinpatch = {
properties: {
desired: {
devconfig: {
// ES6支持变量作为属性的语法
[lockn]: onoff,
}
}
}
}
// 异步等待更新twin的操作,"*"表示忽略Etag直接更新
const ret = await registry.updateTwin(deviceId, twinpatch, "*");
// 透传状态码
context.res = {
status: ret.httpResponse.statusCode,
body: ret.httpResponse.statusCode == 200 ? `Operation succeed` : "Operation failed"
};
};
同样的,操作设备I/O也应该作为一个API提供给开发者使用,通过API Management托管。
回到之前创建的API Management服务,进入上一个实验创建的API,点击API名称右边的 … 按钮,选择Import
在Import API页面中选择Function App,进入向导后选择之前创建的Function App实例,仅勾选上一步中创建的新Function,点击Import导入
可以看到一个新的PUT Operation被导入,点击这个方法名称后在点击Test开始测试
Template parameters中device输入自己设备的deviceid,lockn输入Lock1
-Lock4
,onoff输入on
或者off
点击Send发送请求,正常执行能听到继电器动作,LED灯亮起/熄灭,同时在下面HTTP response能看到HTTP 200和Operation succeed的返回