Свяжите Raspberry Pi #1 с Rapsberry Pi #2, используя AWS в качестве брокера MQTT

Итак, у меня есть Raspberry Pi #1, который будет публиковать сообщение MQTT в AWS через тему sensors/Button. Это сработает при нажатии кнопки, как показано ниже.

# Import SDK packages
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
from time import sleep
from gpiozero import Button
from signal import pause

button = Button(13, pull_up=False)

def callMQTT():
    print("button is pressed.Sending to MQTT")
    mqtt_message = "{\"message\":\"button_pressed\"}"
    print(mqtt_message)
    my_rpi.publish("sensors/Button", mqtt_message, 1)
    print("Message Published!")
    sleep(5)


host="host.amazonaws.com"
rootCAPath = "rootca.pem"
certificatePath = "certificate.pem.crt"
privateKeyPath = "private.pem.key"

try:
    my_rpi = AWSIoTMQTTClient("basicPubSub")
    my_rpi.configureEndpoint(host,8883)
    my_rpi.configureCredentials(rootCAPath, privateKeyPath, certificatePath)

    my_rpi.configureOfflinePublishQueueing(-1)  # Infinite offline Publish queueing
    my_rpi.configureDrainingFrequency(2)  # Draining: 2 Hz

    # Connect and subscribe to AWS IoT
    my_rpi.connect()
    print("Connection Succesful")
except:
    print("Unexpected error:", sys.exc_info()[0])

button.when_pressed = callMQTT
pause()

На Raspberry Pi #2 он попытается подписаться на MQTT от AWS, используя тот же хост, ту же вещь, тот же ключ и тот же сертификат, что и Raspbery Pi #1. Если сообщение получено, прозвучит звуковой сигнал и загорится светодиод, как показано ниже.

# Import SDK packages
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
from time import sleep
from gpiozero import Buzzer,LED
import random
import sys
from datetime import datetime

bz = Buzzer(22)
led = LED(18)

# Custom MQTT message callback
def customCallback(client, userdata, message):
    print("Received a new message: ")
    print(message.payload)
    print("from topic: ")
    print(message.topic)
    print("--------------\n\n")
        timestring = str(datetime.now())
    print("Doorbell pressed")
    bz.on()
    led.blink()
    sleep(1)
    bz.off()
    led.off()

host="host.amazonaws.com"
rootCAPath = "rootca.pem"
certificatePath = "certificate.pem.crt"
privateKeyPath = "private.pem.key"

try:
    my_rpi = AWSIoTMQTTClient("basicPubSub")
    my_rpi.configureEndpoint(host, 8883)
    my_rpi.configureCredentials(rootCAPath, privateKeyPath, certificatePath)

    my_rpi.configureOfflinePublishQueueing(-1)  # Infinite offline Publish queueing
    my_rpi.configureDrainingFrequency(2)  # Draining: 2 Hz
    my_rpi.configureConnectDisconnectTimeout(10)  # 10 sec
    my_rpi.configureMQTTOperationTimeout(5)  # 5 sec

    # Connect and subscribe to AWS IoT
    my_rpi.connect()
except:
    print("Unexpected error:", sys.exc_info()[0])

while True:
my_rpi.subscribe("sensors/Button", 1, customCallback)
sleep(2)

Однако это невозможно. Когда обе программы запускаются одновременно, Rasberry Pi #2 всегда будет отключаться по тайм-ауту. По какой-то причине он разрешает только 1 соединение за раз. Я пытаюсь подписаться на тему напрямую через AWS, когда запускаю код Raspberry Pi #1. Он отображает сообщение на AWS. Кроме того, если я попытаюсь опубликовать сообщение непосредственно на AWS и запустить только код Raspberry Pi # 2, он также будет работать, но не тогда, когда оба запускают код. Ошибка, которую я получил на Raspberry Pi # 2, такова:

Не удалось найти обработчики для регистратора «AWSIoTPythonSDK.core.protocol.mqttCore». Трассировка (последний последний вызов): Файл «Doorbell_Indoor.py», строка 72, в файле my_rpi.subscribe("sensors/Button", 1, customCallback) "/usr/local/lib/python2.7/dist-packages/AWSIoTPythonSDK/MQTTLib.py", строка 491, в подписке return self._mqttCore.subscribe(topic, QoS, callback) File "/usr/local/lib/ python2.7/dist-packages/AWSIoTPythonSDK/core/protocol/mqttCore.py", строка 416, в подписке поднять subscribeTimeoutException() AWSIoTPythonSDK.exception.AWSIoTExceptions.subscribeTimeoutException

Кто-нибудь знает, как это исправить? Заранее спасибо!


person Aster Tan    schedule 28.07.2017    source источник
comment
Каждый клиент должен иметь уникальный идентификатор клиента, лучше всего предположить, что строка, переданная в AWSIoTMQTTClient(), является идентификатором клиента, сделайте их разными и посмотрите, что произойдет.   -  person hardillb    schedule 28.07.2017


Ответы (2)


Я не вижу, чтобы это было задокументировано в документах Python SDK, но в документах Java SDK говорится:

clientId — идентификатор клиента, однозначно идентифицирующий соединение MQTT. Два клиента с одинаковым идентификатором клиента не могут одновременно подключаться к одной и той же конечной точке.

Попробуйте использовать уникальное значение clientId для каждого подключения вместо "basicPubSub".

person Mark B    schedule 28.07.2017
comment
где я могу найти clientId? У AWS, похоже, его нет. Придумываю ли я свой clientId? - person Aster Tan; 28.07.2017
comment
Вы делаете это. Вы должны использовать разные идентификаторы для каждого запущенного скрипта. - person Mark B; 28.07.2017

Из http://docs.aws.amazon.com/iot/latest/developerguide/protocols.html

Брокер сообщений использует идентификатор клиента для идентификации каждого клиента. Идентификатор клиента передается от клиента к брокеру сообщений как часть полезной нагрузки MQTT. Два клиента с одинаковым идентификатором клиента не могут одновременно подключаться к брокеру сообщений. Когда клиент подключается к брокеру сообщений, используя идентификатор клиента, который использует другой клиент, сообщение CONNACK будет отправлено обоим клиентам > и текущий подключенный клиент будет отключен.

Вы должны либо передать уникальную строку для каждого клиента в AWSIoTMQTTClient(), либо пустую строку. Если вы передадите пустую строку для идентификатора клиента, шлюз AWS IoT назначит вам случайный идентификатор клиента при подключении.

Измените вызов AWSIoTMQTTClient с

my_rpi = AWSIoTMQTTClient("basicPubSub")

to

my_rpi = AWSIoTMQTTClient("")

и каждому из RPI будет присвоен уникальный случайный идентификатор клиента при подключении. AWS не рекомендует делать это в больших масштабах, но для тестов это нормально. Вы также теряете возможность использовать clientid в политиках.

person Graham    schedule 29.07.2017