mqroute


Namemqroute JSON
Version 0.2.0 PyPI version JSON
download
home_pageNone
SummaryMQRoute is a Python library designed to simplify working with MQTT
upload_time2024-12-15 22:29:45
maintainerNone
docs_urlNone
authorehyde74
requires_python>=3.8
licenseMIT License
keywords mqtt asyncio decorators
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # **MQRoute**

`MQRoute` is a Python MQTT routing library designed to simplify working with MQTT topics by abstracting complexity. It supports advanced topic matching (including wildcards and parameterized topics), allows easy registration of callbacks using decorators, and provides scalable asynchronous callback handling.

Whether you're building an IoT platform or a messaging service, `MQRoute` makes it easy to manage MQTT subscriptions and streamline message processing.

---

## **Features**

- **Dynamic Topic Matching:**  
  Supports `+` and `#` MQTT wildcards, as well as parameterized topics (`+parameter_name+`) for extracting parameters from topic strings.

- **Asynchronous by Design:**  
  Built with `asyncio` for responsive handling of incoming MQTT messages and user-defined asynchronous callbacks.

- **Decorator-Based Callbacks:**  
  Subscribe to MQTT topics effortlessly using Python decorators.

- **Type Safety:**  
  Includes type hints and validation with the `typeguard` library.

- **Extensive Logging and Debugging:**  
  Detailed logs for easy troubleshooting of MQTT operations and callbacks.

- **Customizable Payload Handling:**  
  Easy-to-use mechanisms for handling raw or JSON-formatted payloads.

---

## **Installation**

You can install MQRoute simply by using pip:

```shell
pip install mqroute
```

You may also down it from git for example when some local modification are needed. That's your call!
---

## **Getting Started**

Below are the steps to start using `MQRoute`. For more advanced usage, refer to detailed examples in [the `testclient.py`](./testclient.py).

### Initialize the MQTT Client

Use the `MQTTClient` class to connect to the MQTT broker, subscribe to topics, and handle messages.

```python
import asyncio
from mqroute.mqtt_client import MQTTClient

mqtt = MQTTClient(host="test.mosquitto.org", port=1883)
asyncio.run(mqtt.run())  # Establishes connection and starts listening
```

### Subscribe to Topics

Use the `@mqtt.subscribe` decorator to register a specific callback for a topic. The library supports `+` and `#` MQTT wildcards and parameterized topics.

```python
@mqtt.subscribe(topic="devices/+/status")
async def handle_device_status(topic, msg, params):
    print(f"Device {params[0]} status: {msg.message}")

@mqtt.subscribe(topic="sensors/+/data/+/type/#")
async def handle_sensor_data(topic, msg, params):
    print(f"Sensor {params[0]} data at {params[1]}: {msg.message}")
```

### Handle JSON Payloads Automatically

JSON payloads are converted automatically to dictionaries. In case this is not desired
 `convert_json` parameter in the decorator can be set to `False` to receive raw data in callback instead.
 The value of `convert_json` defaults to `True`. The callback can also be defined to be fallback; if so,
 the callback is only called if topic doesn't match any non-fallback topics. Note, multiple fallback methods
 can be defined, and multiple fallbacks may match and ths be called.

```python
@mqtt.subscribe(topic="config/update/json")
async def handle_config_update1(topic, msg, params):
    # Access the payload as a Python dictionary
    config_data_as_dict = msg.message
    print(f"Received config update: {config_data_as_dict}")

@mqtt.subscribe(topic="config/update/raw", raw_payload=True)
async def handle_config_update2(topic, msg, params):
    # Access the payload as a raw string
    config_data_as_raw = msg.message
    print(f"Received config update: {config_data_as_raw}")
    
@mqtt.subscribe(topic="config/#", raw_payload=True, fallback=True)
async def handle_config_update3(topic, msg, params):
    # Access the payload as a raw string
    config_data_as_raw = msg.message
    print(f"Received config update: {config_data_as_raw}")

```

---

### Custom signal handling for terminating application
Custom termination logic can be applied by using decorator sigstop:

```python
@mqtt.sigstop
async def sigstop_handler():
    # termination requested
    print(f"Received request to terminate application.")
```
---

## **Example: Full Client Code**

Below is a complete example that demonstrates how to use `MQRoute`:

```python
import asyncio
from mqroute.mqtt_client import MQTTClient

mqtt = MQTTClient(host="test.mosquitto.org", port=1883)


@mqtt.subscribe(topic="devices/+/status")
async def handle_device_status(topic, msg, params):
    print(f"Device {params[0]} status: {msg.message}")


@mqtt.subscribe(topic="sensors/+light+/status")
async def handle_light_status(topic, msg, params):
    sensor = params["light"]
    print(f"{sensor} sensor status: {msg.message}")

@mqtt.subscribe(topic="sensors/#", raw_payload=True, fallback=True)
async def handle_light_status(topic, msg, params):
    sensor = params["light"]
    print(f"{sensor} sensor status: {msg.message}")
    
@mqtt.sigstop
async def sigstop_handler():
    # termination requested
    print(f"Received request to terminate application.")



async def main():
    await mqtt.run()

    # Keep the client running
    while mqtt.running:
        await asyncio.sleep(0.1)


if __name__ == "__main__":
    asyncio.run(main())
```

---

## **Advanced Features**

### 1. **Parameterized Topics**
Extract dynamic portions of a topic using parameterized syntax:
```python
@mqtt.subscribe(topic="room/+room+/device/+device+/status")
async def handle_parametrized(topic, msg, params):
    print(f"Device {params['device']} in room {params['room']} has status: {msg.message}")
```

### 2. **Custom Callback Runner**
For advanced use cases, directly manage callbacks using the `CallbackRunner` class.

---

## **Testing**

Integration and unit testing can be performed using `pytest`. Sample test cases are provided in the repository.

Run the tests:
```bash
pytest tests/
```

---

## **Planned Improvements**

- **Message Publishing API:** Simple methods for publishing MQTT messages.
- **Customization and extendability:** Allow easy means  to support for example custom payload formats
- **Dynamic subscriptions:** Subscribe MQTT topics without decorators in order to allow dynamic
   construction of mqroute application.
---

## **Contributing**

Contributions and feedback are welcome! If you'd like to contribute, please follow these steps:

1. Fork the repository.
2. Create a feature branch (`git checkout -b feature-name`).
3. Commit your changes (`git commit -m 'Add new feature'`).
4. Push to the branch (`git push origin feature-name`).
5. Submit a pull request.

For major changes, please open an issue first to discuss what you'd like to improve.

---

## **License**

This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.

---

## **Additional Notes**

- For complete functionality and advanced examples, refer to the `testclient.py` file provided in the repository.
- MQRoute is in active development. Feel free to report bugs.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mqroute",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "mqtt, asyncio, decorators",
    "author": "ehyde74",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/7b/d0/cbb3659336f563fad8089cc0f064426f71b57c384cac9e3c97c6df0ca413/mqroute-0.2.0.tar.gz",
    "platform": null,
    "description": "# **MQRoute**\r\n\r\n`MQRoute` is a Python MQTT routing library designed to simplify working with MQTT topics by abstracting complexity. It supports advanced topic matching (including wildcards and parameterized topics), allows easy registration of callbacks using decorators, and provides scalable asynchronous callback handling.\r\n\r\nWhether you're building an IoT platform or a messaging service, `MQRoute` makes it easy to manage MQTT subscriptions and streamline message processing.\r\n\r\n---\r\n\r\n## **Features**\r\n\r\n- **Dynamic Topic Matching:**  \r\n  Supports `+` and `#` MQTT wildcards, as well as parameterized topics (`+parameter_name+`) for extracting parameters from topic strings.\r\n\r\n- **Asynchronous by Design:**  \r\n  Built with `asyncio` for responsive handling of incoming MQTT messages and user-defined asynchronous callbacks.\r\n\r\n- **Decorator-Based Callbacks:**  \r\n  Subscribe to MQTT topics effortlessly using Python decorators.\r\n\r\n- **Type Safety:**  \r\n  Includes type hints and validation with the `typeguard` library.\r\n\r\n- **Extensive Logging and Debugging:**  \r\n  Detailed logs for easy troubleshooting of MQTT operations and callbacks.\r\n\r\n- **Customizable Payload Handling:**  \r\n  Easy-to-use mechanisms for handling raw or JSON-formatted payloads.\r\n\r\n---\r\n\r\n## **Installation**\r\n\r\nYou can install MQRoute simply by using pip:\r\n\r\n```shell\r\npip install mqroute\r\n```\r\n\r\nYou may also down it from git for example when some local modification are needed. That's your call!\r\n---\r\n\r\n## **Getting Started**\r\n\r\nBelow are the steps to start using `MQRoute`. For more advanced usage, refer to detailed examples in [the `testclient.py`](./testclient.py).\r\n\r\n### Initialize the MQTT Client\r\n\r\nUse the `MQTTClient` class to connect to the MQTT broker, subscribe to topics, and handle messages.\r\n\r\n```python\r\nimport asyncio\r\nfrom mqroute.mqtt_client import MQTTClient\r\n\r\nmqtt = MQTTClient(host=\"test.mosquitto.org\", port=1883)\r\nasyncio.run(mqtt.run())  # Establishes connection and starts listening\r\n```\r\n\r\n### Subscribe to Topics\r\n\r\nUse the `@mqtt.subscribe` decorator to register a specific callback for a topic. The library supports `+` and `#` MQTT wildcards and parameterized topics.\r\n\r\n```python\r\n@mqtt.subscribe(topic=\"devices/+/status\")\r\nasync def handle_device_status(topic, msg, params):\r\n    print(f\"Device {params[0]} status: {msg.message}\")\r\n\r\n@mqtt.subscribe(topic=\"sensors/+/data/+/type/#\")\r\nasync def handle_sensor_data(topic, msg, params):\r\n    print(f\"Sensor {params[0]} data at {params[1]}: {msg.message}\")\r\n```\r\n\r\n### Handle JSON Payloads Automatically\r\n\r\nJSON payloads are converted automatically to dictionaries. In case this is not desired\r\n `convert_json` parameter in the decorator can be set to `False` to receive raw data in callback instead.\r\n The value of `convert_json` defaults to `True`. The callback can also be defined to be fallback; if so,\r\n the callback is only called if topic doesn't match any non-fallback topics. Note, multiple fallback methods\r\n can be defined, and multiple fallbacks may match and ths be called.\r\n\r\n```python\r\n@mqtt.subscribe(topic=\"config/update/json\")\r\nasync def handle_config_update1(topic, msg, params):\r\n    # Access the payload as a Python dictionary\r\n    config_data_as_dict = msg.message\r\n    print(f\"Received config update: {config_data_as_dict}\")\r\n\r\n@mqtt.subscribe(topic=\"config/update/raw\", raw_payload=True)\r\nasync def handle_config_update2(topic, msg, params):\r\n    # Access the payload as a raw string\r\n    config_data_as_raw = msg.message\r\n    print(f\"Received config update: {config_data_as_raw}\")\r\n    \r\n@mqtt.subscribe(topic=\"config/#\", raw_payload=True, fallback=True)\r\nasync def handle_config_update3(topic, msg, params):\r\n    # Access the payload as a raw string\r\n    config_data_as_raw = msg.message\r\n    print(f\"Received config update: {config_data_as_raw}\")\r\n\r\n```\r\n\r\n---\r\n\r\n### Custom signal handling for terminating application\r\nCustom termination logic can be applied by using decorator sigstop:\r\n\r\n```python\r\n@mqtt.sigstop\r\nasync def sigstop_handler():\r\n    # termination requested\r\n    print(f\"Received request to terminate application.\")\r\n```\r\n---\r\n\r\n## **Example: Full Client Code**\r\n\r\nBelow is a complete example that demonstrates how to use `MQRoute`:\r\n\r\n```python\r\nimport asyncio\r\nfrom mqroute.mqtt_client import MQTTClient\r\n\r\nmqtt = MQTTClient(host=\"test.mosquitto.org\", port=1883)\r\n\r\n\r\n@mqtt.subscribe(topic=\"devices/+/status\")\r\nasync def handle_device_status(topic, msg, params):\r\n    print(f\"Device {params[0]} status: {msg.message}\")\r\n\r\n\r\n@mqtt.subscribe(topic=\"sensors/+light+/status\")\r\nasync def handle_light_status(topic, msg, params):\r\n    sensor = params[\"light\"]\r\n    print(f\"{sensor} sensor status: {msg.message}\")\r\n\r\n@mqtt.subscribe(topic=\"sensors/#\", raw_payload=True, fallback=True)\r\nasync def handle_light_status(topic, msg, params):\r\n    sensor = params[\"light\"]\r\n    print(f\"{sensor} sensor status: {msg.message}\")\r\n    \r\n@mqtt.sigstop\r\nasync def sigstop_handler():\r\n    # termination requested\r\n    print(f\"Received request to terminate application.\")\r\n\r\n\r\n\r\nasync def main():\r\n    await mqtt.run()\r\n\r\n    # Keep the client running\r\n    while mqtt.running:\r\n        await asyncio.sleep(0.1)\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    asyncio.run(main())\r\n```\r\n\r\n---\r\n\r\n## **Advanced Features**\r\n\r\n### 1. **Parameterized Topics**\r\nExtract dynamic portions of a topic using parameterized syntax:\r\n```python\r\n@mqtt.subscribe(topic=\"room/+room+/device/+device+/status\")\r\nasync def handle_parametrized(topic, msg, params):\r\n    print(f\"Device {params['device']} in room {params['room']} has status: {msg.message}\")\r\n```\r\n\r\n### 2. **Custom Callback Runner**\r\nFor advanced use cases, directly manage callbacks using the `CallbackRunner` class.\r\n\r\n---\r\n\r\n## **Testing**\r\n\r\nIntegration and unit testing can be performed using `pytest`. Sample test cases are provided in the repository.\r\n\r\nRun the tests:\r\n```bash\r\npytest tests/\r\n```\r\n\r\n---\r\n\r\n## **Planned Improvements**\r\n\r\n- **Message Publishing API:** Simple methods for publishing MQTT messages.\r\n- **Customization and extendability:** Allow easy means  to support for example custom payload formats\r\n- **Dynamic subscriptions:** Subscribe MQTT topics without decorators in order to allow dynamic\r\n   construction of mqroute application.\r\n---\r\n\r\n## **Contributing**\r\n\r\nContributions and feedback are welcome! If you'd like to contribute, please follow these steps:\r\n\r\n1. Fork the repository.\r\n2. Create a feature branch (`git checkout -b feature-name`).\r\n3. Commit your changes (`git commit -m 'Add new feature'`).\r\n4. Push to the branch (`git push origin feature-name`).\r\n5. Submit a pull request.\r\n\r\nFor major changes, please open an issue first to discuss what you'd like to improve.\r\n\r\n---\r\n\r\n## **License**\r\n\r\nThis project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.\r\n\r\n---\r\n\r\n## **Additional Notes**\r\n\r\n- For complete functionality and advanced examples, refer to the `testclient.py` file provided in the repository.\r\n- MQRoute is in active development. Feel free to report bugs.\r\n",
    "bugtrack_url": null,
    "license": "MIT License",
    "summary": "MQRoute is a Python library designed to simplify working with MQTT",
    "version": "0.2.0",
    "project_urls": {
        "Homepage": "https://github.com/ehyde74/mqroute"
    },
    "split_keywords": [
        "mqtt",
        " asyncio",
        " decorators"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f9ec89a81c70442216bf7d4b9e5153753e3c14a530faf477f426ac5f3af885f4",
                "md5": "dc4baf3a74e7801805c5f4ab65f330ea",
                "sha256": "c3bd3bf509ec6499a63f99e81acdaf7062d7be3a8854ebb9102e1788a510e6c9"
            },
            "downloads": -1,
            "filename": "mqroute-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "dc4baf3a74e7801805c5f4ab65f330ea",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 21174,
            "upload_time": "2024-12-15T22:29:42",
            "upload_time_iso_8601": "2024-12-15T22:29:42.089140Z",
            "url": "https://files.pythonhosted.org/packages/f9/ec/89a81c70442216bf7d4b9e5153753e3c14a530faf477f426ac5f3af885f4/mqroute-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7bd0cbb3659336f563fad8089cc0f064426f71b57c384cac9e3c97c6df0ca413",
                "md5": "fa8c40a9909d5c8042d352dd12ed8581",
                "sha256": "7c977140d4bff4303bb722d642ea110f50932a38f5b92e11c7511ec8caa515ba"
            },
            "downloads": -1,
            "filename": "mqroute-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "fa8c40a9909d5c8042d352dd12ed8581",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 20420,
            "upload_time": "2024-12-15T22:29:45",
            "upload_time_iso_8601": "2024-12-15T22:29:45.047390Z",
            "url": "https://files.pythonhosted.org/packages/7b/d0/cbb3659336f563fad8089cc0f064426f71b57c384cac9e3c97c6df0ca413/mqroute-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-15 22:29:45",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ehyde74",
    "github_project": "mqroute",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "mqroute"
}
        
Elapsed time: 0.38318s