An asyncio Python implementation of a MQTT-SN Gateway
We built this since we needed a nice way to interface MQTT-SN devices into our data stream. It is not feature complete as we wrote it quite quick but we hope to add onto it as our need grows. We used a transparent gateway before we built this and once we got over 1000 devices we got problems with the underlying I/O implementation. So this gateway is built as an aggregating gateway with multiple connections to the MQTT broker.
- CONNECT - In-memory store of clients
- REGISTER - In-memory store of registered topics in clients
- PUBLISH - Receive a PUBLISH and forward it to MQTT broker
- Gateway ADVERTISE
- LAST WILL and TESTAMENT
- QoS 2 and QoS-1
- SUBSCRIBE
- PINGREG/PINGRESP
- Encapsulated messages
- DTLS encryption
We would like a Redis-backed client and topic store. This would make it possible to run several instances of the gateway with shared and persistent state for handling higher loads and services outages.
Requires Python 3.7 and higher (since we use asyncio and it is much nicer in 3.7+)
pip install mqtt-sn-gateway
After installing via pip you can run the server via the command mqtt-sn-server
mqtt-sn-gateway --help
>
Usage: mqtt-sn-gateway [OPTIONS]
Will assume there is a .env file in the root of the package. This is for
simple development. To use .env files as in production use the --env-file
arg to specify path. To make force the application to discard all .env files
use the --no-env-files flag.
Options:
--debug Enable debug logging
--env-file TEXT Path to .env file
--no-env-files Discard all use of .env files.
--help Show this message and exit.
You can pull the latest docker-image and run via docker if needed.
docker pull quay.io/u9n/mqtt-sn-gateway
You can use either an .env file or environment variables to set up the gateway.
- HOST: str, Example 0.0.0.0
- PORT: int, Port so serve the gateway. Ex 2883
- BROKER_HOST: str, Broker host, Ex: test.mosquitto.com
- BROKER_PORT: int, Borker port, Default=1883
- BROKER_CONNECTIONS: int: How many connections the gatewat should have to the broker, default=10
- BACK_PRESSURE_LIMIT: int: How many unhandled UDP-packets should be queued up before not receiving more traffic, Default=1000
It is possible to implement your own client and topic stores. Just supply the gateway an object the follows the correct Protocol.
class ClientStore(Protocol):
def add_client(self, client: MqttSnClient) -> None:
...
def get_client(self, remote_addr: Tuple[str, int]) -> Optional[MqttSnClient]:
...
def delete_client(self, remote_addr: Tuple[str, int]) -> None:
...
class TopicStore(Protocol):
def add_topic_for_client(self, client_id: bytes, topic_name: str) -> int:
...
def get_topic_for_client(self, client_id: bytes, topic_id: int) -> Optional[str]:
...
We appreciate all contributions. File a bug report or fix the issue yourself and submit a pull request.
We at Utilitarian can help your company with integrating the gateway to your systems. Contact us if you wish to speed up development or make sure your solution has long-term support.