微信小程序支付前,使用 MQTT 检测设备是否在线

更新日期: 2021-12-01 阅读次数: 3184 字数: 564 分类: 物联网

需求场景

例如,用户要出停车场,进行扫码支付,但是需要在支付之前判断一下起杆设备是否在线。

如果不在线需要给出提示,防止收了钱,但是没有起杆。

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 在线状态查询,那么还是显示在线,但是此时支付,并不能通过下发指令使设备启动。

tags: 腾讯云 MQTT MQTT

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式