Receiving Meraki MV Sense MQTT Messages with RabbitMQ

Soon after releasing the new MV cameras, Meraki announced MV Sense which allows developers to obtain real time MQ Telemetry Transport (MQTT) messages such as number of people detected, object location, and lux directly from the camera. In order to obtain these messages, a developer will need to build a MQTT broker, and there exists many MQTT brokers such as Mosquito, RabbitMQ with MQTT plugin, EMQ, VerneMQ, and many others. For production, it is an issue that RabbitMQ does not support Quality of Service level 2 (QoS2), but it is sufficient for testing purposes. Here are the steps to receive MQTT messages from Meraki MVs with RabbitMQ.

Environment

I will assume that you have already have Python 3 and Docker installed on the machine, and Pika, a python package, installed. To keep the number of dependencies to the minimum, I have used the docker version of RabbitMQ. The consumer code will run from the machine itself, and I am currently using a MacBook Pro.

  • macOS (High Sierra, 10.13.6)
  • Docker (18.09.2, build 6247962)
  • RabbitMQ (3.7.13)
  • Python (3.7.0)
  • Pika (0.13.1)

Step 1. Downloading RabbitMQ Image

First and foremost, we need to download the RabbitMQ image. This can be done using the following command through terminal. The current latest image equals to version 3.7.13, and I have specified the the exact version.

docker pull rabbitmq:3.7.13

Step 2. Run the RabbitMQ Container

Next, we will run the RabbitMQ container using the downloaded image. I will also map ports 1883, 4369, 5671, 5672, 15672, and 25672. See below for their usages and further details here.

PortUsage
1883MQTT
4369epmd, a peer discovery service used by RabbitMQ nodes and CLI tools
5671used by AMQP 0-9-1 and 1.0 client without and with TLS
5672used by AMQP 0-9-1 and 1.0 client without and with TLS
15672HTTP API clients, management UI and rabbitmqadmin (only if the management plugin is enabled)
25672used for inter-node and CLI tools communication

Run the following in terminal.

docker run --name rabbitmq \
           -itd \
           -p 1883:1883 \
           -p 4369:4369 \
           -p 5671:5671 \
           -p 5672:5672 \
           -p 15672:15672 \
           -p 25672:25672 \
           rabbitmq:3.7.13

Step 3. Install Plugins to RabbitMQ

In this example, we will use the management and MQTT plugin. Run the following commands and verify these plugins installed successfully from the output.

docker exec -i rabbitmq rabbitmq-plugins enable rabbitmq_management
docker exec -i rabbitmq rabbitmq-plugins enable rabbitmq_mqtt

You can also now access the management graphical user interface (GUI) via http://localhost:15672 with username guest and password guest.

rabbitmq_access_gui

Step 4. Configure Meraki MV Sense

Go to the dashboard, and view a specific camera by [Camera] > [Camera] > [select camera]. In order to configure MV Sense go to the [Settings] tab and click on [Sense]. Enable the Sense API and enable MQTT. You will need to add the MQTT broker, and in this case it will be the RabbitMQ container that just spun up. Add the IP address of the host running the container and port as 1883.

dashboard_configure_mv_sense

At this point, the camera should start sending MQTT messages to the docker container, and the RabbitMQ GUI should show messages coming into exchange amq.topic.

rabbitmq_exchange_amqtopic

Just a side note that the MQTT plugin uses exchange amq.topic by default, and uses the topic names replacing the ‘/’ with ‘.’ as routing keys.

Step 5: Retrieve the Messages with Python

The following script will create a queue named ‘mv-queue’ and retrieve all messages that match the routing key ‘.meraki.*.*’ which equals to all messages from the MV as it sends all messages with topics starting with ‘/meraki/’.

import pika

credentials = pika.PlainCredentials("guest", "guest")
conn_params = pika.ConnectionParameters("localhost",
                                        port=5672,
                                        credentials=credentials)
conn_broker = pika.BlockingConnection(conn_params)
channel = conn_broker.channel()
channel.exchange_declare(exchange="amq.topic",
                         exchange_type="topic",
                         durable=True)
channel.queue_declare(queue="mv-queue",
                      durable=True,
                      auto_delete=True)
channel.queue_bind(queue="mv-queue",
                   exchange="amq.topic",
                   routing_key=".merakimv.*.*")

def msg_consumer(channel, method, header, body):
    channel.basic_ack(delivery_tag=method.delivery_tag)
    if body == b"quit":
        channel.basic_cancel(consumer_tag="mv-consumer")
        channel.stop_consuming()
    else:
        print(method.routing_key.split('.')[2], body)
    return

channel.basic_consume(on_message_callback=msg_consumer,
                      queue="mv-queue",
                      consumer_tag="mv-consumer")
channel.start_consuming()

Run the script from terminal, and you should be seeing messages that include number of people detected, object location, and lux.

python_receive_mqtt

Do you see that type person? I am really excited what kind of objects the MV can detect next.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.