需求场景
例如,用户要出停车场,进行扫码支付,但是需要在支付之前判断一下起杆设备是否在线。
如果不在线需要给出提示,防止收了钱,但是没有起杆。
TODO
- [x] 腾讯云 MQTT 接口
- [x] golang api
- [x] controller 更名为 mqtt.go, 把 mqtt 相关的操作都放在这个 controller 里,方便共用一些配置
- [x] 封装 DescribeDevice。参数为 deviceId,获取 device,从而得到设备名,然后 mqtt 查询在线状态
- [x] 线上测试
- [x] 小程序端:预支付这里调用了两个 http 微信接口,可能等待时间有点长,导致用户点两次按钮,所以加个防止重复点击的功能
腾讯云 MQTT 接口
找到一个接口:查看设备详情
https://cloud.tencent.com/document/product/634/31583
可以通过产品名、加设备名,查询设备是否在线。 返回值里包含 Online 字段,设备是否在线,0不在线,1在线。
golang api
https://github.com/TencentCloud/tencentcloud-sdk-go/blob/master/tencentcloud/iotcloud/v20180614/client.go
// DescribeDevice
// 本接口(DescribeDevice)用于查看设备信息
//
// 可能返回的错误码:
// INTERNALERROR = "InternalError"
// INVALIDPARAMETERVALUE = "InvalidParameterValue"
// RESOURCENOTFOUND_DEVICENOTEXIST = "ResourceNotFound.DeviceNotExist"
// RESOURCENOTFOUND_PRODUCTNOTEXIST = "ResourceNotFound.ProductNotExist"
func (c *Client) DescribeDevice(request *DescribeDeviceRequest) (response *DescribeDeviceResponse, err error) {
if request == nil {
request = NewDescribeDeviceRequest()
}
response = NewDescribeDeviceResponse()
err = c.Send(request, response)
return
}
参数 DescribeDeviceRequest 通过 NewDescribeDeviceRequest 初始化获得,这样就不需要自己手动填写 Version 和 Action 了。
func NewDescribeDeviceRequest() (request *DescribeDeviceRequest) {
request = &DescribeDeviceRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("iotcloud", APIVersion, "DescribeDevice")
return
}
腾讯云的 golang SDK 代码质量非常差,代码没有规范 ProductId ProductID 混着写,类型瞎定义。 浪费时间。
设备是否在线接口封装
// 通过 MQTT 接口,判断设备是否在线
// 逻辑:
// 参数为 deviceId,获取 device,从而得到设备名,然后 mqtt 查询在线状态
func isDeviceOnline(deviceId int) bool {
var device models.Device
err := models.DB.Where("`id` = ?", deviceId).First(&device).Error
if err != nil {
// record not found
log.Println(err)
return false
}
cpf := profile.NewClientProfile()
cpf.HttpProfile.ReqMethod = "POST"
cpf.HttpProfile.ReqTimeout = 10
cpf.HttpProfile.Endpoint = "iotcloud.tencentcloudapi.com"
client, _ := iotcloud.NewClient(credential, "", cpf)
request := iotcloud.NewDescribeDeviceRequest()
request.ProductID = common.StringPtr(mqttProductId)
request.DeviceName = common.StringPtr(device.DeviceName)
response, err := client.DescribeDevice(request)
// 处理异常
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Printf("An API error has returned: %s", err)
return false
}
// 非SDK异常,直接失败。实际代码中可以加入其他的处理。
if err != nil {
panic(err)
return false
}
// 打印返回的json字符串
fmt.Printf("%s\n", response.ToJsonString())
if *response.Response.Online == uint64(1) {
return true
} else {
return false
}
}
极端情况
如果设备断线,但是恰好在两次心跳之间,进行 MQTT 在线状态查询,那么还是显示在线,但是此时支付,并不能通过下发指令使设备启动。
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式