【问题标题】:Google Cloud IoT - Invalid MQTT publish topicGoogle Cloud IoT - MQTT 发布主题无效
【发布时间】:2018-04-18 19:23:13
【问题描述】:

我正在使用带有 paho-mqtt 的 Python 客户端在 Google Cloud IoT 的这个特定主题中发布:projects/my_project/topics/sm1。我的代码如下,基于 Google IoT 文档的示例:

import paho.mqtt.client as mqtt
import ssl, random, jwt_maker
from time import sleep

root_ca = './../roots.pem'
public_crt = './../my_cert.pem'
private_key = './../my_pr.pem'

mqtt_url = "mqtt.googleapis.com"
mqtt_port = 8883
mqtt_topic = "/projects/my_project/topics/sm1"
project_id   = "my_project"
cloud_region = "us-central1"
registry_id  = "sm1"
device_id    = "sm1"

connflag = False

def error_str(rc):
    """Convert a Paho error to a human readable string."""
    return "Some error occurred. {}: {}".format(rc, mqtt.error_string(rc))

def on_disconnect(unused_client, unused_userdata, rc):
    """Paho callback for when a device disconnects."""
    print("on_disconnect", error_str(rc))

def on_connect(client, userdata, flags, response_code):
    global connflag
    connflag = True
    print("Connected with status: {0}".format(response_code))

def on_publish(client, userdata, mid):
    print("User data: {0} -- mid: {1}".format(userdata, mid))
    #client.disconnect()

if __name__ == "__main__":

    client = mqtt.Client("projects/{}/locations/{}/registries/{}/devices/{}".format(
                         project_id,
                         cloud_region,
                         registry_id,
                         device_id))

    client.username_pw_set(username='unused',
                           password=jwt_maker.create_jwt(project_id,
                                               private_key,
                                               algorithm="RS256"))

    client.tls_set(root_ca,
                   certfile = public_crt,
                   keyfile = private_key,
                   cert_reqs = ssl.CERT_REQUIRED,
                   tls_version = ssl.PROTOCOL_TLSv1_2,
                   ciphers = None)

    client.on_connect = on_connect
    client.on_publish = on_publish
    client.on_disconnect = on_disconnect

    print("Connecting to Google IoT Broker...")
    client.connect(mqtt_url, mqtt_port, keepalive=60)
    client.loop_start() 

    while True:
        sleep(0.5)
        print connflag
        if connflag == True:
            print("Publishing...")
            ap_measurement = random.uniform(25.0, 150.0)
            #payload = "sm1/sm1-payload-{}".format(ap_measurement)
            res = client.publish(mqtt_topic, ap_measurement, qos=1)
            if not res.is_published():
               print("Data not published!!")
            else:
               print("ActivePower published: %.2f" % ap_measurement)
        else:
            print("Waiting for connection...")

当我运行时,客户端连接但不发布。在 Google IoT Console 中,我可以看到以下错误消息:

MQTT 发布主题无效:projects/my_project/topics/sm1

这是输出:

正在连接到 Google IoT Broker...
已连接状态:0 -- 消息:已接受连接。
真的
出版...
数据未公布!!
('on_disconnect', '发生了一些错误。1: 内存不足。')

真的很奇怪,因为主题在那里,被创建,并且有一个与之关联的订阅!

任何帮助将不胜感激。我已经阅读了以下文档和代码:

【问题讨论】:

    标签: google-cloud-platform mqtt iot paho google-cloud-iot


    【解决方案1】:

    您的主题名称不正确。

    这很混乱(我也刚打了这个)。

    客户 ID(如您所愿)必须是:

    "projects/{}/locations/{}/registries/{}/devices/{}".format(
      project_id,
      cloud_region,
      registry_id,
      device_id
    )
    

    主题必须是以下形式:

    /devices/{}/config
    /devices/{}/state
    /devices/{}/events
    /devices/{}/events/some/other/topic
    

    正如@ptone 的评论所述:

    在云物联网核心中,MQTT 主题与 Cloud PubSub 主题是多对一的。出于安全考虑 - 设备只能发布到以设备命名空间为前缀的 MQTT 主题。然后,您可以匹配 sub-topics to other Cloud PubSub topics as noted here,但最多只能匹配 10 个。这不是为了让设备与 PubSub 主题进行 1:1 映射。

    【讨论】:

    • 你好,达兹。但是我们在 Google Core IoT 控制台上创建的主题会发生什么?我想发布和订阅我自己的主题,不同于那些“标准”(事件、配置或状态)。如果只有这三个是可能的,我认为谷歌物联网太受限制了。同意?顺便说一句,您知道如何正确订阅这些主题之一吗?我没有成功完成这项任务。
    • 是的,您可以使用子文件夹发布到多个 Pub/Sub 主题,此处解释:cloud.google.com/iot/docs/how-tos/…
    • 您不能(当前)使用任意主题名称。您必须遵循 /events/... 子文件夹机制。明天我将与工程团队核实,看看是否有满足您需求的功能请求。为什么无法映射 /events/...?
    • 我会在与工程部确认我的回答后更新它。
    • 在云物联网核心中,MQTT 主题与 Cloud PubSub 主题是多对一的。出于安全考虑 - 设备只能发布到以设备命名空间为前缀的 MQTT 主题。然后,您可以将子主题与其他 Cloud PubSub 主题匹配,如下所述:cloud.google.com/iot/docs/how-tos/…,但最多只能匹配 10 个。这不是为了让设备与 PubSub 主题进行 1:1 映射。
    【解决方案2】:

    当我将mqtt_topicevents 更改为state 时,我的python 代码有效。在此示例中,我尝试将当前温度和湿度从我的设备上传到 Google IoT Core。

      ...
      data =  {'temp': temperature, 'humid': humidity}
      device_id = 'freedgePrototype'
      topic = 'state'
    
      mqtt_topic = '/devices/{}/{}'.format(device_id, topic)
      payload = json.dumps(data)
      print('Publishing message  {}'.format(payload))
    
      client.publish(mqtt_topic, payload, qos=1)
    

    结果应该是这样的。

    【讨论】:

    • 你能看到你的events主题消息吗?