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.
Port | Usage |
---|---|
1883 | MQTT |
4369 | epmd, a peer discovery service used by RabbitMQ nodes and CLI tools |
5671 | used by AMQP 0-9-1 and 1.0 client without and with TLS |
5672 | used by AMQP 0-9-1 and 1.0 client without and with TLS |
15672 | HTTP API clients, management UI and rabbitmqadmin (only if the management plugin is enabled) |
25672 | used 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.
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.
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.
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.
Do you see that type person? I am really excited what kind of objects the MV can detect next.