在本节课中,我们将设计和实现从设备注册到接入 IotHub 的主要流程。
首先我们定义一下设备注册到接入 IotHub 的流程。
注册流程
- 业务系统调用 Maque IotHub Server API 的设备注册 API,提供要注册设备的 ProductName。
- Maque IotHub Server 根据业务系统提供的参数生成一个三元组(ProductName, DeviceName, Secret),然后将该三元组存储到 MongoDB,同时存储到 MongoDB 的还有该设备接入 EMQ X 的用户名: ProductName/DeviceName。
- Maque IotHub Server API 将生成的三元组返回给业务系统,业务系统应该保存这个三元组,以后调用 Maque IotHub Server API 时需要使用。
- 业务系统通过某种方式,例如烧写 Flash,将这个三元组"写"到物联网设备上。
- 设备应用代码调用 Maque IotHub DeviceSDK,传入三元组。
- Maque IotHub DeviceSDK 使用 username: ProductName/DeviceName, password: Secret连接到 EMQ X Broker。
- EMQ X Broker 到 MongoDB 里面查询 ProductName/DeviceName 和 Secret,如果匹配,则允许连接。
注册流程如下图所示。
设备注册 API
接下在 IotHub_Server 项目里实现 Maque IotHub Server API 的设备注册 API:
我们在 MongoDB 里创建一个名为 IotHub 的数据来存储设备信息。
定义设备模型
这里,我们使用 mongoose 来做 MongoDB 相关的操作,首先定义 Device 模型:
// IotHub_Server/models/device.js
const deviceSchema = new Schema({
//ProductName
product_name: {
type: String,
required: true
},
//DeviceName
device_name: {
type: String,
required: true,
},
//接入 EMQ X 时使用的 username
broker_username: {
type: String,
required: true
},
//secret
secret: {
type: String,
required: true,
}
})
Restful API 实现
每次在生成新设备的时候,由系统自动生成 DeviceName 和 Secret,DeviceName 和 Secret 应该是随机且唯一的字符串,例如 UUID,这里,我们用 shortid 来生成稍短一点的随机唯一字符:
// routes/devices.js
...
router.post("/", function (req, res) {
var productName = req.body.product_name
var deviceName = shortid.generate();
var secret = shortid.generate();
var brokerUsername = `${productName}/${deviceName}`
var device = new Device({
product_name: productName,
device_name: deviceName,
secret: secret,
broker_username: brokerUsername
})
device.save(function (err) {
if(err){
res.status(500).send(err)
}else{
res.json({product_name: productName, device_name: deviceName, secret: secret})
}
})
})
...
接着我们将这个 router 挂载到 /devices 下面,并连接到 MongoDB:
//app.js
...
mongoose.connect('mongodb://iot:iot@localhost:27017/iothub', { useNewUrlParser: true })
var deviceRouter = require('./routes/devices');
app.use('/devices', deviceRouter);
...
运行 bin/www
启动 Web 服务器,然后在命令行用 curl 调用这个接口:
curl -d "product_name=IotApp" -X POST http://localhost:3000/devices
输出为:{"product_name":"IotApp","device_name":"V5MyuncRK","secret":"GNxU20VYTZ"}
ProductName 包含的字符是有限制的,不能包含
# / +
以及 IotHub 预留的一些字符,为了演示,这里跳过了输入参数的校验,但是在实际项目中,是需要加上的。
到这里,设备注册就成功了,我们需要记录下这个三元组。
修改 emqx_auth_mongo.conf
接下来需要按照我们定义的数据库结构来修改 EMQ X MongoDB 认证插件的配置,下面是需要在上一节内容上修改的项:
# 存储用户名和密码的 database
auth.mongo.database = iothub
# 存储用户名和密码的 collection
auth.mongo.auth_query.collection = devices
# 密码字段
auth.mongo.auth_query.password_field = secret
# 查询记录时的 selector
auth.mongo.auth_query.selector = broker_username=%u
编辑完成以后重载下 MongDB 认证插件: <EMQ X 安装目录>/bin/emqx_ctl plugins reload emqx_auth_mongo
。
修改 DeviceSDK
接下在 IoTHub_Device 项目里对 DeviceSDK 进行修改,接受三元组作为初始化参数:
// sdk/iot_device.js
...
class IotDevice extends EventEmitter {
constructor({serverAddress = "127.0.0.1:8883", productName, deviceName, secret} = {}) {
super();
this.serverAddress = `mqtts://${serverAddress}`
this.productName = productName
this.deviceName = deviceName
this.secret = secret
this.username = `${this.productName}/${this.deviceName}`
}
connect() {
this.client = mqtt.connect(this.serverAddress, {
rejectUnauthorized: false
username: this.username,
password: this.secret
})
...
}
...
}
...
然后我们用刚才记录下的三元组作为参数调用 DeviceSDK 接入 Maque IotHub:
// samples/connect_to_server.js
...
var device = new IotDevice({productName: "IotApp", deviceName: "V5MyuncRK", secret: "GNxU20VYTZ"})
...
然后再运行samples/connect_to_server.js
,会得到以下输出:
device is online
这说明设备已经完成注册并成功接入 IotHub 了。
这一节我们完成了设备注册到接入的主要流程,下一节,我们将继续完善细节。
**推荐阅读