python3.7 使用paho.mqtt 连接到腾讯云

一. 腾讯云登录流程

  1. 登录 物联网通信控制台。您可在控制台创建产品、添加设备、并获取设备密钥。

  2. 按照物联网通信约束生成 username 字段,username 字段格式如下:

    username字段的格式为: p r o d u c t i d {productid} {devicename}; s d k a p p i d ; {sdkappid}; {connid}; e x p i r y {expiry} 注意: {}表示变量,并非特定的拼接符号。

    其中各字段含义如下:
    productid:产品 ID。
    devicename: 设备名称。
    sdkappid:固定填12010126。
    connid :一个随机字符串。
    过期时间 :表示签名的有效期, 从1970年1月1日00:00:00 UTC 时间至今秒数的 UTF8 字符串。

  3. 用 base64 对设备私钥进行解码得到原始密钥 raw_key。

  4. 用第3步生成的 raw_key,通过 HMAC-SHA1 或者 HMAC-SHA256 算法对 username 生成一串摘要,简称 token。

  5. 按照物联网通信约束生成 password 字段,password 字段格式为:

    password字段格式为: ${token};hmac签名方法
    其中hmac签名方法字段填写第三步用到的摘要算法,可选的值有 hmacsha256 和 hmacsha1

  6. 最终将上面生成的参数填入对应的 mqtt connect 报文中。
    将 clientid 填入到 MQTT 协议的 clientid 字段。
    将 username 填入到 mqtt 的 username 字段。
    将 password 填入到 mqtt 的 password 字段,即可接入到物联云通信平台。

    通过 psk 方式接入端口默认为1883。若客户端支持 ca 证书,您也可以使用8883端口接入。

二. 使用Python3.7生成登录三元组

  • 注意,Python3和Python2在使用的过程中,有比较大区别,Python2默认进行了类型转换,所以腾讯官网的Python2的例子在Python3中不能直接使用。
# 生成指定长度的随机字符串, 范围为数字和字母
def RandomConnid(length):
    msg = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
    return msg

# 生成接入腾讯物联云平台需要的各参数
def tos_IotHmac(productID, devicename, devicePsk):
    # 1. 生成connid为一个随机字符串,方便后台定位问题
    connid = RandomConnid(5)

    # 2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串
    expiry = int(time.time()) + 60*60

    # 3. 生成MQTT的clientid部分, 格式为${productid}${devicename}
    clientid = "{}{}".format(productID, devicename)

    # 4. 生成mqtt的username部分, 格式为${clientid};${sdkappid};${connid};${expiry}
    username = "{};12010126;{};{}".format(clientid, connid, expiry)

    # 5. 对username进行签名,生成token
    # 此处为Python3 的写法, 需要进行类型转换
    psk_b = base64.b64decode(devicePsk.encode('utf-8'))# 解码后为二进制串
    psk1 = str(psk_b,"utf-8")# 按utf8编码成字符串
    token = hmac.new( bytes(psk1, 'utf-8'), bytes(username, 'utf-8'), digestmod=hashlib.sha256).hexdigest()# 转换成utf-8的字节串
    # 此处为Python2 的写法, Python2 隐式转换了数据编码
    # token = hmac.new(devicePsk.decode("base64"), username, digestmod=hashlib.sha256).hexdigest()

    # 6. 根据物联云通信平台规则生成password字段
    password = "{};{}".format(token, "hmacsha256")
    return {
        "clientid": clientid,
        "username": username,
        "password": password
    }
    pass

# 腾讯云MQTT客户端信息结构
class Tos_CreatDevInfo(object):
    def __init__(self, productID, devicename, devicePsk):
        self.productID = productID
        self.devicename = devicename
        self.devicePsk = devicePsk
        self.iotsite = '{}.iotcloud.tencentdevices.com'.format(productID)
        self.iotport = 1883
        
    def get_IotHmac_tos(self):
        # 产生登录用信息
        IotHmac_tos_list = tos_IotHmac(self.productID, self.devicename, self.devicePsk)
        # print(IotHmac_tos_list)
        return IotHmac_tos_list
  • 通过调用以上的函数或者类,可以得到登录三元组信息, 用于后边的MQTT登录操作

三. 创建客户端, 连接到腾讯云

# MQTT客户端类
class Tos_MqttClient(Tos_CreatDevInfo):
    def __init__(self, productID, devicename, devicePsk):
        super(Tos_MqttClient,self).__init__(productID, devicename, devicePsk)
        # 密钥认证为1883, 证书认证为8883
        self.port = 1883
        # 云地址为 productID.iotcloud.tencentdevices.com
        self.host = self.iotsite
        # 生成客户端连接信息
        self.client_dict = self.get_IotHmac_tos()
        # 创建客户端
        self.client = mqtt.Client(self.client_dict['clientid'])
        # 设置用户名密码
        self.client.username_pw_set(self.client_dict.get('username'), self.client_dict.get('password'))

        # 定义Mqtt相关的回调函数
        self.client.on_connect = on_connect_callback # 连接回调
        self.client.on_message = on_message_callback # 收到消息回调
        self.client.on_publish = on_publish_callback # 发布消息回调
        self.client.on_subscribe = on_subscribe_callback # 订阅回调
        self.client.on_disconnect = on_disconnect_callback # 断开连接回调
        self.client.on_unsubscribe = on_unsubscribe_callback # 取消订回调
        self.client.on_log = on_log_callback # 日志回调
        pass

    def connect(self):
        self.client.connect(self.host, self.port, 60)
        # self.client.loop_forever() # 阻塞式循环等待, 运行到这里, 后面的代码都运行不了
        self.client.loop_start() # 非阻塞式循环等待
        
# 当代理响应连接请求时调用
def on_connect_callback(client, userdata, flags, ret):
    print("Connected with result code " + str(ret))
    print("userdata: {}, flags: {}".format(userdata, flags))
    # 创建主题过滤器
    topic_filter = "HRDQBHLDHS/Dev_001/data"
    # 订阅该主题
    client.subscribe(topic_filter)
    pass

# 当与代理断开连接时调用
def on_disconnect_callback(client, userdata, flags, ret):
    print("unConnected with result code " + str(ret))
    print("userdata: {}, flags: {}".format(userdata, flags))
    pass

# 当收到关于客户订阅的主题的消息时调用
index = 0
def on_message_callback(client, userdata, msg):
    # print("client: {}; userdata: {}".format(client, userdata))
    print(msg.topic + " " + msg.payload.decode("utf-8"))
    # 发布消息(主题, 内容, qos)
    global index
    index += 1
    # 创建主题过滤器
    topic_filter = "HRDQBHLDHS/Dev_001/data"
    # 收到一条订阅, 发布一条消息
    client.publish(topic_filter , "hello world ...{}".format(index), 0)
    print("send hello world {}...".format(index))

# 当使用使用publish()发送的消息已经传输到代理时被调用
def on_publish_callback(client, userdata, mid):
    pass

# 当代理响应订阅请求时被调用
def on_subscribe_callback(client, userdata, mid, granted_qos):
    pass

# 当代理响应取消订阅请求时调用
def on_unsubscribe_callback(client, userdata, mid):
    pass

# 当客户端有日志信息时调用
def on_log_callback(client, userdata, level, buf):
    pass




if __name__ == '__main__':
    '''
    产品ID: 	腾讯物联网平台自动分配
    设备名称:    自己起的设备名称
    base64后密钥: 可以自己设置或者腾讯分配
    '''
    # 以下是的测试设备, 请换成自己的
    tos_info = Tos_MqttClient("HRDQBHLDHS", "Dev_001", "dGlnZXJvdHMwMTIzNDU2Nzg5")
    tos_info.connect()

  • 以上实现了收到一条订阅的消息, 同时发布一条消息, 可以另外创建一个设备, 两个设备互相传递信息,(后面的回调函数, 根据使用需要,填写自己的内容)。

猜你喜欢

转载自blog.csdn.net/tigerots/article/details/103211564
今日推荐