【问题标题】:Azure IoT Hub - "Subscribe" code not working: "connection was refused"Azure IoT 中心 - “订阅”代码不起作用:“连接被拒绝”
【发布时间】:2018-05-18 19:08:21
【问题描述】:

当某些数据发布到 MQTT 主题 devices/device_id/messages/events/ 时,我正在尝试从 IoT 中心接收“通知”。为了接收数据,我使用了以下主题:devices/device_id/messages/devicebound/。我的订阅代码如下(Python):

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

root_ca = "./certs/digicertbaltimoreroot.pem"
public_crt = './certs/rsa_cert.pem'
private_key = './certs/rsa_private.pem'

iothub_name = "myhub"
device_id = "mydevice"
mqtt_url = "{}.azure-devices.net".format(iothub_name)
mqtt_port = 8883
topic = "devices/{}/messages/devicebound/#".format(device_id)

def error_str(rc):
    return "Some error occurred. {}: {}".format(rc, mqtt.error_string(rc))

def on_disconnect(unused_client, unused_userdata, rc):
    print("on_disconnect", error_str(rc))

def on_connect(client, userdata, flags, response_code):
    print("Connected with status: {0}".format(response_code))
    client.subscribe(topic, 1)

def on_subscribe(client, userdata, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_message(client, userdata, msg):
    print("Topic: {0} -- Payload: {1}".format(msg.topic, str(msg.payload)))

if __name__ == "__main__":    
    client = mqtt.Client(device_id, protocol=mqtt.MQTTv311)

    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_message = on_message
    client.on_disconnect = on_disconnect

    print("Connecting to Azure IoT Hub...")
    client.connect(mqtt_url, mqtt_port, keepalive=60)
    client.loop_forever()

当我运行时,我得到以下输出:

正在连接到 Azure IoT 中心...
已连接状态:3
('on_disconnect', '发生了一些错误。5: 连接被拒绝。')
已连接状态:3
('on_disconnect', '发生了一些错误。5: 连接被拒绝。')

谁能建议我缺少什么?

【问题讨论】:

  • 也许这个文档可能会有所帮助:docs.microsoft.com/en-us/azure/iot-hub/…
  • 你好,@juunas。在我在这里发布我的问题之前,我已经读过了。这对发布过程很有帮助。 “订阅”部分(接收云到设备的消息)不够好。

标签: azure iot publish-subscribe azure-iot-hub subscribe


【解决方案1】:

基于文档"Using the MQTT protocol directly",需要

下载并参考 DigiCert Baltimore 根证书。此证书是 Azure 用来保护连接的证书。

就像你在发布过程中所做的那样:

client.tls_set(ca_certs=path_to_root_cert,     
               certfile=None, keyfile=None, 
               cert_reqs=ssl.CERT_REQUIRED,       
               tls_version=ssl.PROTOCOL_TLSv1, 
               ciphers=None)

另外,您需要设置用户名和密码

client.username_pw_set(username=iot_hub_name+".azure-devices.net/" + device_id, password=sas_token)

最后,您可以像这样订阅

client.subscribe(topic=topic, qos=0)

安全密钥认证设备的示例代码

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

path_to_root_cert = "./certs/digicertbaltimoreroot.cer"

iothub_name = "your hub name"
device_id = "device1"
sas_token = "SharedAccessSignature sr=[your hub name].azure-devices.net%2Fdevices%2Fdevice1&sig=[sig]&se=1526955728"
mqtt_url = "{}.azure-devices.net".format(iothub_name)
mqtt_port = 8883
topic = "devices/{}/messages/devicebound/#".format(device_id)

def error_str(rc):
    return "Some error occurred. {}: {}".format(rc, mqtt.error_string(rc))

def on_disconnect(unused_client, unused_userdata, rc):
    print("on_disconnect", error_str(rc))

def on_connect(client, userdata, flags, response_code):
    print("Connected with status: {0}".format(response_code))
    client.subscribe(topic, 1)

def on_subscribe(client, userdata, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_message(client, userdata, msg):
    print("Topic: {0} -- Payload: {1}".format(msg.topic, str(msg.payload)))

if __name__ == "__main__":    
    client = mqtt.Client(device_id, protocol=mqtt.MQTTv311)

    client.username_pw_set(username=iothub_name+".azure-devices.net/" + device_id, password=sas_token)

    client.tls_set(ca_certs=path_to_root_cert, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1, ciphers=None)

    client.on_connect = on_connect
    client.on_message = on_message
    client.on_disconnect = on_disconnect


    print("Connecting to Azure IoT Hub...")
    client.connect(mqtt_url, mqtt_port, keepalive=60)
    client.subscribe(topic=topic, qos=0)
    client.loop_forever()

x509 认证设备的示例代码: (需要提供设备证书和私钥文件。不需要SAS令牌作为密码;留空即可。但仍需要设置用户名。)

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

root_ca = "./certs/digicertbaltimoreroot.cer"
public_crt = './certs/mydevice-public.pem'
private_key = './certs/mydevice-private.pem'

iothub_name = "your hub name"
device_id = "mydevice"
mqtt_url = "{}.azure-devices.net".format(iothub_name)
mqtt_port = 8883
topic = "devices/{}/messages/devicebound/#".format(device_id)

def error_str(rc):
    return "Some error occurred. {}: {}".format(rc, mqtt.error_string(rc))

def on_disconnect(unused_client, unused_userdata, rc):
    print("on_disconnect", error_str(rc))

def on_connect(client, userdata, flags, response_code):
    print("Connected with status: {0}".format(response_code))
    client.subscribe(topic, 1)

def on_subscribe(client, userdata, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_message(client, userdata, msg):
    print("Topic: {0} -- Payload: {1}".format(msg.topic, str(msg.payload)))

if __name__ == "__main__":    
    client = mqtt.Client(device_id, protocol=mqtt.MQTTv311)

    client.on_connect = on_connect
    client.on_message = on_message
    client.on_disconnect = on_disconnect

    client.username_pw_set(username=iothub_name+".azure-devices.net/" + device_id, password="")

    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.tls_insecure_set(False)


    print("Connecting to Azure IoT Hub...")
    client.connect(mqtt_url, mqtt_port, keepalive=60)
    client.subscribe(topic=topic, qos=0)
    client.loop_forever()

注意:主题为“devices/{device-id}/messages/devicebound/#”。

如何创建设备证书文件可以参考here

更新:这些示例代码用于接收D2C messages,您可以这样发送以进行简单测试:

来自device explorer

来自天蓝色的门户:

更新:接收 D2C 消息:

正如我在我的 cmets 中指出的,Azure IoT Hub 不是通用的 MQTT brober,因此您不能直接订阅从设备发送的消息。 要解决此问题,您可以使用 IoT 中心公开的与事件中心兼容的终结点,例如“Read the telemetry from your hub " 部分可以。但不幸的是,Python 不支持这种方式。您可以使用 iothub-explorer CLI 实用程序或创建 Node.js.NETJava 基于事件中心的控制台应用程序来读取设备从 IoT 中心到云端的消息。

【讨论】:

  • 但是我做了你提到的所有事情,从我的代码@Rita 中可以看出。唯一的区别是我使用 x509 证书而不是 SAS 进行身份验证。因此,我不需要用户名/密码...
  • @DaltonCézane 您还需要设置用户名,但不需要 SAS 令牌作为密码。您可以查看我的更新答案。
  • 你是对的。我添加了用户名并连接。但是,不幸的是,我看不到通知(收到的发布值)。你有什么建议吗?值正在通过发布脚本发布,订阅脚本的输出为:Connecting to Azure IoT Hub... Connected with status: 0 ('on_disconnect', 'Some error occurred. 1: Out of memory.') Connected with status: 0 ('on_disconnect', 'Some error occurred. 1: Out of memory.')
  • 您无法订阅设备发送到 Azure IoT Hub 的消息。(我的意思是在这个问题中发布脚本。)Azure IoT Hub 不是常见的 MQTT 代理。您可以订阅我们在此处讨论的消息是可以从设备资源管理器或 Azure 门户发送的 D2C 消息。请参阅我的更新答案。
  • 那么,如果我想在某种通知中接收“已发布”消息(devices/device_id/messages/events/)怎么办?不可能吗?或者即使我想以编程方式执行您所说的由设备资源管理器/天蓝色门户制作的内容?
【解决方案2】:

正如 Rita 已经提到的,目前设备端不支持接收 D2C 消息。

Azure IoT hub 是 IoT 解决方案中的一种云网关方式,如下图所示:

Azure IoT 中心基于endpoints 为支持的解决方案和设备端提供服务。目前它提供device to cloud feature like D2C 消息Device Twin 的报告属性文件上传。在云端,我们可以使用 cloud to device feature 类似直接方法、Twin 所需属性云端到设备消息

当某些数据发布到 MQTT 主题 devices/device_id/messages/events/ 时,我正在尝试从 IoT 中心接收“通知”

这取决于您希望接收消息的哪一方。目前 Azure IoT 中心支持两种场景。

  1. 在设备端发送Device-to-Cloud消息,在云端后端接收消息(D2C消息只支持AMQP协议)

  2. 在云后端解决方案上发送可能到设备的消息并在设备端接收消息。

    如果您对 Azure IoT Hub 有任何想法或反馈,可以通过Azure IoT Hub - user voice 提交。

【讨论】:

    猜你喜欢
    • 2020-10-06
    • 1970-01-01
    • 1970-01-01
    • 2019-04-27
    • 2021-04-24
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多