# MQTT Publisher
[](https://badge.fury.io/py/ronschaeffer-mqtt-publisher)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
[](https://github.com/astral-sh/ruff)
[](https://github.com/ronschaeffer/mqtt_publisher/actions)
MQTT publishing library with MQTT 5.0 support and Home Assistant MQTT Discovery integration.
## Features
### MQTT Publishing
- MQTT 5.0, 3.1.1, and 3.1 protocol support with backwards compatibility for paho-mqtt versions
- Default QoS and retain flag configuration for publish operations
- Exponential backoff retry logic with configurable maximum attempts
- Non-blocking loop management with proper cleanup
- Connection state tracking with timeout handling
### Configuration Management
- Automatic type conversion for string values from environment variables
- Configuration validation with specific error messages
- Multiple security modes: none, username/password, TLS, TLS with client certificates
- Environment variable support with `${VARIABLE_NAME}` syntax
- YAML configuration file support
### Enhanced Logging
- Topic-specific logging levels with pattern matching
- Module-specific loggers for connection, publishing, and discovery operations
- Structured logging with configurable levels
- Connection error messages with configuration guidance
### Home Assistant Integration
- MQTT Discovery framework for automatic entity creation
- Device and entity management with lifecycle support
- 18+ Home Assistant entity types supported
- Status sensor publishing for application health monitoring
- One-time discovery publishing to prevent configuration flooding
### Connection Management
- Last Will and Testament (LWT) support for offline detection
- SSL/TLS encryption with certificate verification
- Multiple authentication methods
- Automatic reconnection with connection state callbacks
## Installation
### Using pip
```bash
pip install ronschaeffer-mqtt-publisher
```
### Using Poetry
```bash
poetry add ronschaeffer-mqtt-publisher
```
### Development Installation
```bash
git clone https://github.com/ronschaeffer/mqtt_publisher.git
cd mqtt_publisher
poetry install
```
## Configuration
### Environment Variables
Create a `.env` file in your project root:
```bash
# MQTT Broker Configuration
MQTT_BROKER_URL=localhost
MQTT_BROKER_PORT=1883
MQTT_CLIENT_ID=my_mqtt_client
# Authentication (for username security mode)
MQTT_USERNAME=your_username
MQTT_PASSWORD=your_password
# Home Assistant Discovery (optional)
HA_DISCOVERY_PREFIX=homeassistant
```
### Configuration File
Create `config/config.yaml`:
```yaml
mqtt:
broker_url: "${MQTT_BROKER_URL}"
broker_port: "${MQTT_BROKER_PORT}"
client_id: "${MQTT_CLIENT_ID}"
security: "username" # Options: none, username, tls, tls_with_client_cert
# Default publishing settings
default_qos: 1
default_retain: false
# Connection settings
max_retries: 3
protocol: "MQTTv311" # Options: MQTTv31, MQTTv311, MQTTv5
# Authentication
auth:
username: "${MQTT_USERNAME}"
password: "${MQTT_PASSWORD}"
# TLS Configuration (for tls security modes)
tls:
ca_cert: null
client_cert: null
client_key: null
verify: false
# Last Will and Testament
last_will:
topic: "status/${MQTT_CLIENT_ID}"
payload: "offline"
qos: 1
retain: true
# Enhanced Logging Configuration
logging_config:
connection_level: "INFO"
publish_level: "DEBUG"
discovery_level: "WARNING"
topic_specific:
"sensors/*": "DEBUG"
"status": "INFO"
# Home Assistant Discovery (optional)
ha_discovery:
discovery_prefix: "${HA_DISCOVERY_PREFIX}"
device:
name: "My MQTT Device"
identifier: "mqtt_device_001"
manufacturer: "Custom"
model: "MQTT Publisher"
sw_version: "1.0.0"
```
### Security Modes
| Mode | Description | Required Settings |
| ---------------------- | ------------------------------------- | -------------------------------- |
| `none` | No authentication | None |
| `username` | Username/password authentication | `auth.username`, `auth.password` |
| `tls` | TLS encryption with username/password | `auth.*`, `tls.verify` |
| `tls_with_client_cert` | TLS with client certificates | `auth.*`, `tls.*` |
## Usage
### Basic Publishing
```python
from mqtt_publisher import MQTTPublisher
# Direct parameter initialization
publisher = MQTTPublisher(
broker_url="localhost",
broker_port=1883,
client_id="my_client",
security="none"
)
# Connect and publish
if publisher.connect():
# Basic message publishing
publisher.publish("sensors/temperature", "23.5")
# JSON data publishing with retain flag
publisher.publish("sensors/humidity", {"value": 65.2, "unit": "%"}, retain=True)
# Custom QoS level
publisher.publish("alerts/motion", "detected", qos=2)
publisher.disconnect()
```
### Configuration-Based Setup
```python
from mqtt_publisher import MQTTConfig, MQTTPublisher
# Load from YAML configuration
config = MQTTConfig.from_yaml_file("config/config.yaml")
# Context manager ensures proper cleanup
with MQTTPublisher(config=config) as publisher:
# Publisher automatically connects and disconnects
publisher.publish("sensors/temperature", {"value": 23.5, "unit": "°C"})
```
### Home Assistant Discovery
```python
from mqtt_publisher.ha_discovery import HADiscoveryPublisher, Device, Entity
# Initialize discovery publisher
discovery = HADiscoveryPublisher(
publisher=publisher,
discovery_prefix="homeassistant"
)
# Create device
device = Device(
name="Weather Station",
identifier="weather_001",
manufacturer="Custom",
model="ESP32"
)
# Create sensor entity
temperature_sensor = Entity(
entity_type="sensor",
object_id="temperature",
name="Temperature",
device_class="temperature",
unit_of_measurement="°C",
state_topic="weather/temperature"
)
# Publish discovery configuration
discovery.publish_entity_config(device, temperature_sensor)
# Publish sensor data
publisher.publish("weather/temperature", "23.5")
```
### Error Handling
```python
from mqtt_publisher import MQTTPublisher
try:
publisher = MQTTPublisher(
broker_url="localhost",
broker_port="invalid_port" # Will be validated
)
except ValueError as e:
print(f"Configuration error: {e}")
# Output: broker_port must be integer 1-65535, got: invalid_port
try:
publisher = MQTTPublisher(
broker_url="", # Invalid empty URL
broker_port=1883,
client_id="test"
)
except ValueError as e:
print(f"Configuration error: {e}")
# Output: broker_url is required
```
## Testing
### Run All Tests
```bash
poetry run pytest
```
### Run with Coverage
```bash
poetry run pytest --cov=mqtt_publisher --cov-report=html
```
### Run Specific Test Module
```bash
poetry run pytest tests/test_mqtt_publisher_enhanced.py -v
```
### Test Configuration
```bash
# Test environment variables
export MQTT_BROKER_URL=test.mosquitto.org
export MQTT_BROKER_PORT=1883
export MQTT_CLIENT_ID=test_client
poetry run pytest tests/test_environment_handling.py
```
## Development
### Setup Development Environment
```bash
git clone https://github.com/ronschaeffer/mqtt_publisher.git
cd mqtt_publisher
poetry install --with dev
```
### Code Quality Checks
```bash
# Linting and formatting
poetry run ruff check .
poetry run ruff format .
# Spell checking
poetry run codespell
```
### Version Management
```bash
# Update version and create release
./release.sh patch # or minor, major
```
## Troubleshooting
### Common Connection Issues
**Connection Refused - Bad Username/Password**
```
Error: Connection refused - bad username or password
```
- Verify `MQTT_USERNAME` and `MQTT_PASSWORD` environment variables
- Check broker authentication settings
- Ensure security mode is set to "username"
**TLS Port Mismatch Warnings**
```
Warning: TLS enabled but using non-TLS port 1883. Consider port 8883 for TLS
```
- Use port 8883 for TLS connections
- Use port 1883 for non-TLS connections
- Update `MQTT_BROKER_PORT` environment variable
**Connection Timeout**
```
Warning: Connection timeout after 5 seconds
```
- Verify broker URL and port accessibility
- Check network connectivity
- Increase `max_retries` in configuration
### Configuration Validation
The library validates configuration and provides specific error messages:
```python
# Missing required fields
ValueError: broker_url is required
# Invalid port range
ValueError: broker_port must be integer 1-65535, got: 99999
# Security/authentication mismatch
ValueError: username and password required when security='username'
```
## License
MIT License - see [LICENSE](LICENSE) file for details.
## Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature-name`
3. Make changes with tests
4. Run quality checks: `poetry run ruff check . && poetry run pytest`
5. Submit a pull request
See [GitHub Issues](https://github.com/ronschaeffer/mqtt_publisher/issues) for bug reports and feature requests.
## Support
- **Issues**: [GitHub Issues](https://github.com/ronschaeffer/mqtt_publisher/issues)
- **Documentation**: [Examples Directory](examples/)
- **Source Code**: [GitHub Repository](https://github.com/ronschaeffer/mqtt_publisher)
Raw data
{
"_id": null,
"home_page": null,
"name": "ronschaeffer-mqtt-publisher",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": "mqtt, publisher, iot",
"author": "ronschaeffer",
"author_email": "ron@ronschaeffer.com",
"download_url": "https://files.pythonhosted.org/packages/10/ba/46ea889cc34539e76e82e8eec5b494cdb5d8d5a83cbefd103f68abfa1a3e/ronschaeffer_mqtt_publisher-0.2.0.tar.gz",
"platform": null,
"description": "# MQTT Publisher\n\n[](https://badge.fury.io/py/ronschaeffer-mqtt-publisher)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/astral-sh/ruff)\n[](https://github.com/ronschaeffer/mqtt_publisher/actions)\n\nMQTT publishing library with MQTT 5.0 support and Home Assistant MQTT Discovery integration.\n\n## Features\n\n### MQTT Publishing\n\n- MQTT 5.0, 3.1.1, and 3.1 protocol support with backwards compatibility for paho-mqtt versions\n- Default QoS and retain flag configuration for publish operations\n- Exponential backoff retry logic with configurable maximum attempts\n- Non-blocking loop management with proper cleanup\n- Connection state tracking with timeout handling\n\n### Configuration Management\n\n- Automatic type conversion for string values from environment variables\n- Configuration validation with specific error messages\n- Multiple security modes: none, username/password, TLS, TLS with client certificates\n- Environment variable support with `${VARIABLE_NAME}` syntax\n- YAML configuration file support\n\n### Enhanced Logging\n\n- Topic-specific logging levels with pattern matching\n- Module-specific loggers for connection, publishing, and discovery operations\n- Structured logging with configurable levels\n- Connection error messages with configuration guidance\n\n### Home Assistant Integration\n\n- MQTT Discovery framework for automatic entity creation\n- Device and entity management with lifecycle support\n- 18+ Home Assistant entity types supported\n- Status sensor publishing for application health monitoring\n- One-time discovery publishing to prevent configuration flooding\n\n### Connection Management\n\n- Last Will and Testament (LWT) support for offline detection\n- SSL/TLS encryption with certificate verification\n- Multiple authentication methods\n- Automatic reconnection with connection state callbacks\n\n## Installation\n\n### Using pip\n\n```bash\npip install ronschaeffer-mqtt-publisher\n```\n\n### Using Poetry\n\n```bash\npoetry add ronschaeffer-mqtt-publisher\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/ronschaeffer/mqtt_publisher.git\ncd mqtt_publisher\npoetry install\n```\n\n## Configuration\n\n### Environment Variables\n\nCreate a `.env` file in your project root:\n\n```bash\n# MQTT Broker Configuration\nMQTT_BROKER_URL=localhost\nMQTT_BROKER_PORT=1883\nMQTT_CLIENT_ID=my_mqtt_client\n\n# Authentication (for username security mode)\nMQTT_USERNAME=your_username\nMQTT_PASSWORD=your_password\n\n# Home Assistant Discovery (optional)\nHA_DISCOVERY_PREFIX=homeassistant\n```\n\n### Configuration File\n\nCreate `config/config.yaml`:\n\n```yaml\nmqtt:\n broker_url: \"${MQTT_BROKER_URL}\"\n broker_port: \"${MQTT_BROKER_PORT}\"\n client_id: \"${MQTT_CLIENT_ID}\"\n security: \"username\" # Options: none, username, tls, tls_with_client_cert\n\n # Default publishing settings\n default_qos: 1\n default_retain: false\n\n # Connection settings\n max_retries: 3\n protocol: \"MQTTv311\" # Options: MQTTv31, MQTTv311, MQTTv5\n\n # Authentication\n auth:\n username: \"${MQTT_USERNAME}\"\n password: \"${MQTT_PASSWORD}\"\n\n # TLS Configuration (for tls security modes)\n tls:\n ca_cert: null\n client_cert: null\n client_key: null\n verify: false\n\n # Last Will and Testament\n last_will:\n topic: \"status/${MQTT_CLIENT_ID}\"\n payload: \"offline\"\n qos: 1\n retain: true\n\n # Enhanced Logging Configuration\n logging_config:\n connection_level: \"INFO\"\n publish_level: \"DEBUG\"\n discovery_level: \"WARNING\"\n topic_specific:\n \"sensors/*\": \"DEBUG\"\n \"status\": \"INFO\"\n\n# Home Assistant Discovery (optional)\nha_discovery:\n discovery_prefix: \"${HA_DISCOVERY_PREFIX}\"\n device:\n name: \"My MQTT Device\"\n identifier: \"mqtt_device_001\"\n manufacturer: \"Custom\"\n model: \"MQTT Publisher\"\n sw_version: \"1.0.0\"\n```\n\n### Security Modes\n\n| Mode | Description | Required Settings |\n| ---------------------- | ------------------------------------- | -------------------------------- |\n| `none` | No authentication | None |\n| `username` | Username/password authentication | `auth.username`, `auth.password` |\n| `tls` | TLS encryption with username/password | `auth.*`, `tls.verify` |\n| `tls_with_client_cert` | TLS with client certificates | `auth.*`, `tls.*` |\n\n## Usage\n\n### Basic Publishing\n\n```python\nfrom mqtt_publisher import MQTTPublisher\n\n# Direct parameter initialization\npublisher = MQTTPublisher(\n broker_url=\"localhost\",\n broker_port=1883,\n client_id=\"my_client\",\n security=\"none\"\n)\n\n# Connect and publish\nif publisher.connect():\n # Basic message publishing\n publisher.publish(\"sensors/temperature\", \"23.5\")\n\n # JSON data publishing with retain flag\n publisher.publish(\"sensors/humidity\", {\"value\": 65.2, \"unit\": \"%\"}, retain=True)\n\n # Custom QoS level\n publisher.publish(\"alerts/motion\", \"detected\", qos=2)\n\n publisher.disconnect()\n```\n\n### Configuration-Based Setup\n\n```python\nfrom mqtt_publisher import MQTTConfig, MQTTPublisher\n\n# Load from YAML configuration\nconfig = MQTTConfig.from_yaml_file(\"config/config.yaml\")\n\n# Context manager ensures proper cleanup\nwith MQTTPublisher(config=config) as publisher:\n # Publisher automatically connects and disconnects\n publisher.publish(\"sensors/temperature\", {\"value\": 23.5, \"unit\": \"\u00b0C\"})\n```\n\n### Home Assistant Discovery\n\n```python\nfrom mqtt_publisher.ha_discovery import HADiscoveryPublisher, Device, Entity\n\n# Initialize discovery publisher\ndiscovery = HADiscoveryPublisher(\n publisher=publisher,\n discovery_prefix=\"homeassistant\"\n)\n\n# Create device\ndevice = Device(\n name=\"Weather Station\",\n identifier=\"weather_001\",\n manufacturer=\"Custom\",\n model=\"ESP32\"\n)\n\n# Create sensor entity\ntemperature_sensor = Entity(\n entity_type=\"sensor\",\n object_id=\"temperature\",\n name=\"Temperature\",\n device_class=\"temperature\",\n unit_of_measurement=\"\u00b0C\",\n state_topic=\"weather/temperature\"\n)\n\n# Publish discovery configuration\ndiscovery.publish_entity_config(device, temperature_sensor)\n\n# Publish sensor data\npublisher.publish(\"weather/temperature\", \"23.5\")\n```\n\n### Error Handling\n\n```python\nfrom mqtt_publisher import MQTTPublisher\n\ntry:\n publisher = MQTTPublisher(\n broker_url=\"localhost\",\n broker_port=\"invalid_port\" # Will be validated\n )\nexcept ValueError as e:\n print(f\"Configuration error: {e}\")\n # Output: broker_port must be integer 1-65535, got: invalid_port\n\ntry:\n publisher = MQTTPublisher(\n broker_url=\"\", # Invalid empty URL\n broker_port=1883,\n client_id=\"test\"\n )\nexcept ValueError as e:\n print(f\"Configuration error: {e}\")\n # Output: broker_url is required\n```\n\n## Testing\n\n### Run All Tests\n\n```bash\npoetry run pytest\n```\n\n### Run with Coverage\n\n```bash\npoetry run pytest --cov=mqtt_publisher --cov-report=html\n```\n\n### Run Specific Test Module\n\n```bash\npoetry run pytest tests/test_mqtt_publisher_enhanced.py -v\n```\n\n### Test Configuration\n\n```bash\n# Test environment variables\nexport MQTT_BROKER_URL=test.mosquitto.org\nexport MQTT_BROKER_PORT=1883\nexport MQTT_CLIENT_ID=test_client\n\npoetry run pytest tests/test_environment_handling.py\n```\n\n## Development\n\n### Setup Development Environment\n\n```bash\ngit clone https://github.com/ronschaeffer/mqtt_publisher.git\ncd mqtt_publisher\npoetry install --with dev\n```\n\n### Code Quality Checks\n\n```bash\n# Linting and formatting\npoetry run ruff check .\npoetry run ruff format .\n\n# Spell checking\npoetry run codespell\n```\n\n### Version Management\n\n```bash\n# Update version and create release\n./release.sh patch # or minor, major\n```\n\n## Troubleshooting\n\n### Common Connection Issues\n\n**Connection Refused - Bad Username/Password**\n\n```\nError: Connection refused - bad username or password\n```\n\n- Verify `MQTT_USERNAME` and `MQTT_PASSWORD` environment variables\n- Check broker authentication settings\n- Ensure security mode is set to \"username\"\n\n**TLS Port Mismatch Warnings**\n\n```\nWarning: TLS enabled but using non-TLS port 1883. Consider port 8883 for TLS\n```\n\n- Use port 8883 for TLS connections\n- Use port 1883 for non-TLS connections\n- Update `MQTT_BROKER_PORT` environment variable\n\n**Connection Timeout**\n\n```\nWarning: Connection timeout after 5 seconds\n```\n\n- Verify broker URL and port accessibility\n- Check network connectivity\n- Increase `max_retries` in configuration\n\n### Configuration Validation\n\nThe library validates configuration and provides specific error messages:\n\n```python\n# Missing required fields\nValueError: broker_url is required\n\n# Invalid port range\nValueError: broker_port must be integer 1-65535, got: 99999\n\n# Security/authentication mismatch\nValueError: username and password required when security='username'\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch: `git checkout -b feature-name`\n3. Make changes with tests\n4. Run quality checks: `poetry run ruff check . && poetry run pytest`\n5. Submit a pull request\n\nSee [GitHub Issues](https://github.com/ronschaeffer/mqtt_publisher/issues) for bug reports and feature requests.\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/ronschaeffer/mqtt_publisher/issues)\n- **Documentation**: [Examples Directory](examples/)\n- **Source Code**: [GitHub Repository](https://github.com/ronschaeffer/mqtt_publisher)\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "An MQTT publisher package",
"version": "0.2.0",
"project_urls": {
"Homepage": "https://github.com/ronschaeffer/mqtt_publisher",
"Repository": "https://github.com/ronschaeffer/mqtt_publisher"
},
"split_keywords": [
"mqtt",
" publisher",
" iot"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "5080f6ee91ffb812295821ea1d2ebd88dc5cdd2e8ce80a454d11bf11b8c6dd09",
"md5": "bfa1b4adc57f8c9c7bb5c069d92730a6",
"sha256": "cba5148a4cc3a5334123e9be1a5f73ac43c7dc19164ec122fe8558a856cce363"
},
"downloads": -1,
"filename": "ronschaeffer_mqtt_publisher-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "bfa1b4adc57f8c9c7bb5c069d92730a6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 27344,
"upload_time": "2025-08-08T16:18:22",
"upload_time_iso_8601": "2025-08-08T16:18:22.841632Z",
"url": "https://files.pythonhosted.org/packages/50/80/f6ee91ffb812295821ea1d2ebd88dc5cdd2e8ce80a454d11bf11b8c6dd09/ronschaeffer_mqtt_publisher-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "10ba46ea889cc34539e76e82e8eec5b494cdb5d8d5a83cbefd103f68abfa1a3e",
"md5": "7e8d35de4b5c46af81672ab9326bf617",
"sha256": "9959b937150ec4b98763fed3cf2bc7b58cdc33d991c72b2616ddb97840e30ea8"
},
"downloads": -1,
"filename": "ronschaeffer_mqtt_publisher-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "7e8d35de4b5c46af81672ab9326bf617",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 24910,
"upload_time": "2025-08-08T16:18:23",
"upload_time_iso_8601": "2025-08-08T16:18:23.898860Z",
"url": "https://files.pythonhosted.org/packages/10/ba/46ea889cc34539e76e82e8eec5b494cdb5d8d5a83cbefd103f68abfa1a3e/ronschaeffer_mqtt_publisher-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-08 16:18:23",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ronschaeffer",
"github_project": "mqtt_publisher",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "ronschaeffer-mqtt-publisher"
}