The STOMP (Simple Text Oriented Messaging Protocol) is a messaging system that is similar to MQTT (Message Queue Telemetric Transport) and AMQP (Advanced Message Queue Protocol).
STOMP uses a send and subscribe mechanism to pass messages and like other messaging systems, the STOMP server is called a broker. Open Source STOMP brokers are available with ActiveMQ and RabbitMQ.
In this blog I wanted to document my setup that used the STOMP plug-in to RabbitMQ and show examples of getting Python and Node-Red subscribing and sending data.
Why use STOMP?
MQTT and AMQP are very commonly used messaging protocol, so why use STOMP?
AMQP has a lot of great features but for many simple IoT (Internet of Things) applications AMQP may be overkill. Also AMQP is not supported with any mainstream Arduino libraries whereas Arduino Libraries exist for STOMP.
Both STOMP and MQTT are really light-weight, however STOMP has the advantage of being able to add headers and properties along with the message (a feature missing in MQTT but available in AMQP). So you could send a STOMP sensor message and include things like: quality, status, area, and comments along with the value.
RabbitMQ Setup with STOMP
RabbitMQ is a very popular open source messaging middle-ware. By default RabbitMQ loads AMQP (Advanced Message Queue Protocol) but it can also load MQTT and STOMP protocols. RabbitMQ offers Web Administration and an environment that allows different messaging protocols to intercommunicate.
RabbitMQ can be installed on Window, Linux, MacOS systems and there are also some cloud based offerings. For small systems lower end hardware like a Raspberry Pi can be used. For complete RabbitMQ installation instructions see: https://www.rabbitmq.com/download.html . To install and run RabbitMQ on a Ubuntu system enter:
sudo apt-get update sudo apt-get install rabbitmq-server sudo service rabbitmq-server start
The next step is to add some plug-ins. For this project I loaded the STOMP plug-in and the Web Administration plug-in:
sudo rabbitmq-plugins enable rabbitmq_stomp sudo rabbitmq-plugins enable rabbitmq_management
The rabbitmqctl command line tool allows you to configure and review the RabbitMQ server. To add a user admin1, with password admin1, that has config, write and read rights for management and administrator access, enter:
sudo rabbitmqctl add_user admin1 admin1 sudo rabbitmqctl set_permissions -p / admin1 ".*" ".*" ".*" sudo rabbitmqctl set_user_tags admin1 management administrator
At this point a super-user (admin1) has been defined and that user has been given rights to talk to all features of RabbitMQ including STOMP. See the STOMP documentation for STOMP specific user and system configuration.
After you’ve defined an administrative user the RabbitMQ web management plug-in can be accessed by: http://ip_address:15672 . The Overview tab should show STOMP running on the default port of 61613.
For clarity it is good to define a RabbitMQ exchange that is to be used for STOMP. There are a lot of options but the easiest thing is to make a DIRECT exchange that is DURABLE (available after a restart).
Python and STOMP
Python has a library component : stompy.py that is both a standalone STOMP testing client and a library component. To install the component:
pip install stomp.py
Once loaded stomp.py can be used to connect to a server and test subscribing and send data. Below is an example connecting to host 192.168.0.105 with user: pete and password pete.
pete@lubuntu:~$ stomp -H 192.168.0.105 -U pete -W pete > subscribe /exchange/stomp1/tag1 Subscribing to '/exchange/stomp1/tag1' with acknowledge set to 'auto', id set to '1' > send /exchange/stomp1/tag1 hi from python > message-id: T_1@@session-8xhCjj0giLAiOFg8E6OGPQ@@1 subscription: 1 hi from python >
For this example the exchange stomp1 was defined. The topic tag1 was dynamically defined and a message was sent and subscribe to. The topic (tag1) doesn’t need to be defined in RabbitMQ.
A Python STOMP test program would be:
# # stomp_test.py - test STOMP # import time import sys import stomp import random class MyListener(stomp.ConnectionListener): def on_error(self, headers, message): print('received an error "%s"' % message) def on_message(self, headers, message): print('received a message "%s"' % message) # Define a STOMP connection and port conn = stomp.Connection([("192.168.0.105", 61613)]) conn.set_listener('', MyListener()) conn.connect('pete', 'pete', wait=True) # define the username/password # Setup a subscription conn.subscribe(destination='/exchange/stomp1/tag1', id=1, ack='auto') while True: time.sleep(15) # send a random message every 15 seconds conn.send(body=str(random.randint(1,11)), destination='/exchange/stomp1/tag1') #conn.disconnect()
Node-Red and STOMP
The Node-Red STOMP node can be installed using the menu option “Manage Palette” or manually:
npm install node-red-node-stomp
A simple Node-Red test circuit would include:
- an injector node – manually send in a test string
- a STOMP output node – to send messages to a broker
- a STOMP input node – subscribe to messages
- a debug node – to show messages in the debug tab
The logic requires the STOMP node to be defined, and the STOMP nodes need to have a valid exchange and topic:
Node-Red can be used to configure Web dashboards that can show trending and charting of STOMP values.
Testing STOMP with RabbitMQ
Once I had both Python and Node-Red working with STOMP I was able to go back to my RabbitMQ and view the connections.
It is also possible to use RabbitMQ to publish STOMP messages. In this example I included in the header: status, quality and units.
I then was able to check the message in Node-Red.
Compared to AMQP and MQTT there aren’t nearly as many examples so I needed to do a little bit of experimentation. As an example I found that if I send and subscribe to a queue (use: /queue/my_queue) this was only a 1-to-1 connection, if I had 2 subscribers each subscriber would only get 1/2 the messages. So I’m recommend using RabbitMQ exchanges for STOMP messaging.