enzolarosa/mqtt-broadcast

Use the mqtt power in your projects

Installs: 327

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

pkg:composer/enzolarosa/mqtt-broadcast


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads

Production-ready MQTT integration for Laravel with robust supervisor architecture, multi-broker support, and automatic reconnection handling.

Built using the Laravel Horizon pattern for reliable, long-running processes with graceful shutdown and monitoring capabilities.

Features

  • 🚀 Horizon-Style Architecture - Battle-tested supervisor pattern from Laravel Horizon
  • 🔄 Multiple Broker Support - Connect to multiple MQTT brokers simultaneously
  • 📡 Pub/Sub Made Easy - Publish and subscribe to MQTT topics with Laravel queues
  • 🛡️ Auto-Reconnection - Exponential backoff with configurable retry limits
  • 💪 Graceful Shutdown - Clean termination with SIGTERM signal handling
  • 📊 Database Logging - Optional message logging to database
  • 🔐 TLS/SSL Support - Secure connections with certificate validation
  • Queue Integration - Async message publishing via Laravel queues
  • 🎯 Type-Safe - Full PHP 8.1+ type declarations

📊 Real-Time Dashboard

MQTT Broadcast includes a beautiful real-time monitoring dashboard built with React 19:

💡 Dashboard Preview: Add a screenshot to docs/images/dashboard-preview.png to display here

Access: http://your-app.test/mqtt-broadcast

Features:

  • 📈 Live Throughput Charts - Message rate over time (minute/hour/day views)
  • 🖥️ Broker Status - Real-time connection monitoring (connected/idle/reconnecting/disconnected)
  • 📝 Message Log - Recent messages with topic filtering and search
  • 💾 Memory Usage - Supervisor memory consumption with alerts
  • Queue Metrics - Pending jobs monitoring
  • 🌓 Dark Mode - Automatic theme switching

Dashboard Authentication

Local development: Dashboard is always accessible (no authentication required).

Production: Configure access control in app/Providers/MqttBroadcastServiceProvider.php:

// app/Providers/MqttBroadcastServiceProvider.php

protected function registerGate(): void
{
    Gate::define('viewMqttBroadcast', function ($user) {
        return in_array($user->email, [
            'admin@example.com',
            'devops@example.com',
        ]);
    });

    // Or check by role
    // Gate::define('viewMqttBroadcast', function ($user) {
    //     return $user->hasRole('admin');
    // });
}

Note: The MqttBroadcastServiceProvider is published when you run php artisan mqtt-broadcast:install.

Customize dashboard path:

MQTT_BROADCAST_PATH=my-mqtt-monitor

Access at: http://your-app.test/my-mqtt-monitor

Architecture

This package uses a three-tier supervisor architecture inspired by Laravel Horizon:

MasterSupervisor (Process Orchestrator)
    ├── BrokerSupervisor (MQTT Connection #1)
    ├── BrokerSupervisor (MQTT Connection #2)
    └── BrokerSupervisor (MQTT Connection #3)
  • MasterSupervisor: Manages multiple broker connections, handles signals, persists state
  • BrokerSupervisor: Manages single MQTT connection with auto-reconnection
  • MqttClientFactory: Creates configured MQTT clients with auth/TLS support

For detailed architecture documentation, see ARCHITECTURE.md.

Requirements

  • PHP 8.3 or higher
  • Laravel 11.x (Laravel 9.x and 10.x also supported)
  • MQTT Broker (e.g., Mosquitto, HiveMQ, AWS IoT Core)

Quick Start

Get up and running in 2 minutes:

1. Install the package:

composer require enzolarosa/mqtt-broadcast

2. Install the package resources:

php artisan mqtt-broadcast:install

This will:

  • Publish the configuration file to config/mqtt-broadcast.php
  • Publish the service provider to app/Providers/MqttBroadcastServiceProvider.php
  • Publish dashboard assets to public/vendor/mqtt-broadcast/
  • Register the service provider in your application

3. Run migrations:

php artisan migrate

4. Configure your MQTT broker in .env:

MQTT_HOST=127.0.0.1
MQTT_PORT=1883

# Optional: if your broker requires authentication
MQTT_USERNAME=your_username
MQTT_PASSWORD=your_password

5. Authorize dashboard access (production only):

Edit app/Providers/MqttBroadcastServiceProvider.php to control who can access the dashboard:

protected function registerGate(): void
{
    Gate::define('viewMqttBroadcast', function ($user) {
        return in_array($user->email, [
            'admin@example.com',
        ]);
    });
}

6. Start the subscriber:

php artisan mqtt-broadcast

7. Listen to messages in your code:

// app/Providers/EventServiceProvider.php or routes/console.php

use enzolarosa\MqttBroadcast\Events\MqttMessageReceived;
use Illuminate\Support\Facades\Event;

Event::listen(MqttMessageReceived::class, function ($event) {
    logger()->info('MQTT Message:', [
        'topic' => $event->topic,
        'message' => $event->message,
        'broker' => $event->broker,
    ]);
});

8. View the dashboard:

Open http://your-app.test/mqtt-broadcast to see real-time monitoring!

Complete Examples

IoT Temperature Monitoring System

Learn how to build a complete IoT system with MQTT in 15 minutes:

View Complete Example →

This end-to-end guide shows you how to:

  • Connect ESP32/Arduino sensors to your Laravel app
  • Store temperature readings in database
  • Create real-time dashboards
  • Send email alerts on threshold violations
  • Deploy to production with Supervisor

Includes:

  • Laravel event listeners and API endpoints
  • ESP32 Arduino sketch with WiFi and MQTT
  • Testing and deployment instructions
  • Troubleshooting guide

Configuration

The config file has been simplified into clear sections:

Quick Start Section (Required)

// config/mqtt-broadcast.php

'connections' => [
    'default' => [
        'host' => env('MQTT_HOST', '127.0.0.1'),
        'port' => env('MQTT_PORT', 1883),
        'username' => env('MQTT_USERNAME'),  // Optional
        'password' => env('MQTT_PASSWORD'),  // Optional
        'prefix' => env('MQTT_PREFIX', ''),  // Optional
    ],
],

That's it! Everything else has sensible defaults.

Environment-Specific Brokers

The package automatically selects which brokers to use based on your APP_ENV:

'environments' => [
    'local' => ['default'],
    'staging' => ['default'],
    'production' => ['default', 'backup'],
],

How it works:

  • By default, uses the environment from config('app.env') (your APP_ENV)
  • If local: Connects to brokers listed in 'local' array
  • If production: Connects to brokers listed in 'production' array
  • Override with command flag: php artisan mqtt-broadcast --environment=staging

Example:

# Use APP_ENV (automatic)
php artisan mqtt-broadcast

# Force production brokers (even in local)
php artisan mqtt-broadcast --environment=production

Adding new environments:

'environments' => [
    'local' => ['default'],
    'staging' => ['staging-broker'],
    'production' => ['default', 'backup'],
    'testing' => ['test-broker'],  // Add your custom environment
],

If your APP_ENV is not listed (e.g., APP_ENV=development), the supervisor will throw an error. Add it to the config or use the --environment flag.

Multiple Brokers

Configure multiple connections for redundancy:

'connections' => [
    'primary' => [
        'host' => env('MQTT_PRIMARY_HOST', 'mqtt.example.com'),
        'port' => env('MQTT_PRIMARY_PORT', 8883),
        'username' => env('MQTT_PRIMARY_USERNAME'),
        'password' => env('MQTT_PRIMARY_PASSWORD'),
        'use_tls' => true,
    ],
    'backup' => [
        'host' => env('MQTT_BACKUP_HOST', 'mqtt-backup.example.com'),
        'port' => env('MQTT_BACKUP_PORT', 8883),
        'username' => env('MQTT_BACKUP_USERNAME'),
        'password' => env('MQTT_BACKUP_PASSWORD'),
        'use_tls' => true,
    ],
],

'environments' => [
    'production' => ['primary', 'backup'],  // Both brokers in production
    'staging' => ['primary'],               // Only primary in staging
    'local' => ['default'],                 // Local broker for development
],

The supervisor will connect to ALL brokers defined for your environment.

Usage

Starting the Subscriber

Start the MQTT subscriber daemon:

# Use default environment (from APP_ENV)
php artisan mqtt-broadcast

# Specify environment explicitly
php artisan mqtt-broadcast --environment=production

# The command will:
# ✓ Connect to all brokers configured for the environment
# ✓ Subscribe to topics with prefix (if configured)
# ✓ Dispatch Laravel events for received messages
# ✓ Handle reconnection automatically
# ✓ Respond to SIGTERM for graceful shutdown

Publishing Messages

Method 1: Using Facade (Async via Queue)

use enzolarosa\MqttBroadcast\Facades\MqttBroadcast;

// Simple publish
MqttBroadcast::publish('sensors/temperature', '25.5');

// Publish with custom broker
MqttBroadcast::publish('alerts/critical', 'High temperature!', 'backup');

// Publish with custom QoS
MqttBroadcast::publish('important/data', $data, 'default', qos: 2);

Method 2: Using Job Directly

use enzolarosa\MqttBroadcast\Jobs\MqttMessageJob;

MqttMessageJob::dispatch(
    topic: 'home/livingroom/temperature',
    message: json_encode(['value' => 22.5, 'unit' => 'celsius']),
    broker: 'default',
    qos: 1
);

Method 3: Synchronous Publish

// Publish immediately (not queued)
MqttBroadcast::publishSync('urgent/alert', 'System down!');

Receiving Messages

Listen to the MqttMessageReceived event:

use enzolarosa\MqttBroadcast\Events\MqttMessageReceived;
use Illuminate\Support\Facades\Event;

Event::listen(MqttMessageReceived::class, function ($event) {
    echo "Topic: {$event->topic}\n";
    echo "Message: {$event->message}\n";
    echo "Broker: {$event->broker}\n";

    // Your business logic here
    if ($event->topic === 'sensors/temperature') {
        $data = json_decode($event->message, true);
        // Store to database, trigger actions, etc.
    }
});

Or create a dedicated listener:

php artisan make:listener HandleMqttMessage
namespace App\Listeners;

use enzolarosa\MqttBroadcast\Events\MqttMessageReceived;

class HandleMqttMessage
{
    public function handle(MqttMessageReceived $event): void
    {
        match(true) {
            str_starts_with($event->topic, 'sensors/') => $this->handleSensor($event),
            str_starts_with($event->topic, 'alerts/') => $this->handleAlert($event),
            default => logger()->info('Unknown MQTT topic', ['topic' => $event->topic]),
        };
    }

    private function handleSensor(MqttMessageReceived $event): void
    {
        // Handle sensor data
    }

    private function handleAlert(MqttMessageReceived $event): void
    {
        // Handle alert
    }
}

Register in EventServiceProvider:

protected $listen = [
    MqttMessageReceived::class => [
        HandleMqttMessage::class,
    ],
];

Managing the Process

Stop Gracefully

# Terminate all brokers on this machine
php artisan mqtt-broadcast:terminate

# Terminate specific broker
php artisan mqtt-broadcast:terminate worker-hostname-abc123

Process Management

Use a process manager like Supervisor for production:

[program:mqtt-broadcast]
process_name=%(program_name)s
command=php /path/to/artisan mqtt-broadcast --environment=production
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/path/to/storage/logs/mqtt-broadcast.log
stopwaitsecs=60

Or use systemd:

[Unit]
Description=MQTT Broadcast Worker
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/php artisan mqtt-broadcast --environment=production
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Advanced Usage

Topic Prefixes

Automatically prefix all topics:

'connections' => [
    'default' => [
        'prefix' => 'myapp/production/',
    ],
],
// Publishes to: myapp/production/sensors/temp
MqttBroadcast::publish('sensors/temp', '25.5');

QoS Levels

// QoS 0: At most once (fire and forget)
MqttBroadcast::publish('logs/info', 'message', qos: 0);

// QoS 1: At least once (acknowledged delivery)
MqttBroadcast::publish('sensors/data', 'message', qos: 1);

// QoS 2: Exactly once (guaranteed delivery)
MqttBroadcast::publish('financial/transaction', 'message', qos: 2);

Retained Messages

'connections' => [
    'default' => [
        'retain' => true, // Last message persists on broker
    ],
],

Message Logging

Enable database logging:

'logs' => [
    'enable' => true,
    'connection' => 'mysql',
    'table' => 'mqtt_loggers',
],

Query logged messages:

use enzolarosa\MqttBroadcast\Models\MqttLogger;

$recentMessages = MqttLogger::latest()->limit(100)->get();
$sensorData = MqttLogger::where('topic', 'like', 'sensors/%')->get();

Testing

Run the test suite:

composer test

Run specific test suites:

# Unit tests only
vendor/bin/pest tests/Unit

# Integration tests (some require real MQTT broker)
vendor/bin/pest tests/Integration

For testing limitations and manual testing guide, see docs/TESTING_LIMITATIONS.md.

Upgrading

From 2.x to 3.0

Version 3.0 introduces breaking changes. See UPGRADE.md for detailed migration guide.

Key changes:

  • Model renamed: BrokersBrokerProcess
  • Service class deprecated (use new architecture)
  • Command usage updated (--environment flag)

Troubleshooting

❌ "Connection refused" or "Broker unreachable"

Problem: Cannot connect to MQTT broker.

Solutions:

  1. Check broker is running:
# Test with mosquitto_sub
mosquitto_sub -h 127.0.0.1 -p 1883 -t '#' -v

# Or check if port is open
nc -zv 127.0.0.1 1883
  1. Check firewall:
# Allow MQTT port
sudo ufw allow 1883
  1. Verify .env configuration:
MQTT_HOST=127.0.0.1  # Not 'localhost' if broker requires IP
MQTT_PORT=1883

❌ "Authentication failed"

Problem: Broker requires credentials but authentication fails.

Solutions:

  1. Check credentials in .env:
MQTT_USERNAME=your_username
MQTT_PASSWORD=your_password
  1. Verify broker ACL (if using Mosquitto):
# Check mosquitto.conf
cat /etc/mosquitto/mosquitto.conf | grep -A 5 "allow_anonymous"

# Should be:
allow_anonymous false
password_file /etc/mosquitto/passwd
  1. Test credentials manually:
mosquitto_sub -h 127.0.0.1 -p 1883 -u your_username -P your_password -t '#'

❌ "Address already in use" or Process won't start

Problem: Another process is using the required port or database.

Solutions:

  1. Check if supervisor is already running:
php artisan mqtt-broadcast:terminate --dry-run
  1. Kill existing processes:
php artisan mqtt-broadcast:terminate
  1. Find process using port:
lsof -i :1883
# or
netstat -tulpn | grep 1883

❌ Messages not being received

Problem: Supervisor running but no messages appear.

Solutions:

  1. Check subscription:
# View supervisor output for subscription confirmation
# You should see: "✓ Subscribed to topic: # (QoS: 0)"
  1. Verify topic prefix:
// config/mqtt-broadcast.php
'prefix' => 'myapp/',

// If prefix is set, messages to 'sensors/temp'
// must be published to 'myapp/sensors/temp'
  1. Check event listener is registered:
// Make sure your listener is in EventServiceProvider
use enzolarosa\MqttBroadcast\Events\MqttMessageReceived;

protected $listen = [
    MqttMessageReceived::class => [
        YourListener::class,
    ],
];
  1. Test publishing manually:
mosquitto_pub -h 127.0.0.1 -p 1883 -t "test/topic" -m "Hello World"

❌ "No processes found" when terminating

Problem: mqtt-broadcast:terminate says no processes found.

Solutions:

Check database for stale records:

php artisan tinker
>>> \enzolarosa\MqttBroadcast\Models\BrokerProcess::all();
>>> \enzolarosa\MqttBroadcast\Models\BrokerProcess::truncate(); // Clear stale

❌ Memory issues or crashes

Problem: Supervisor crashes or uses too much memory.

Solutions:

  1. Monitor memory via dashboard:

    • Go to http://your-app.test/mqtt-broadcast
    • Check "Memory Usage" card
  2. Adjust memory limit:

// config/mqtt-broadcast.php
'memory' => [
    'threshold_mb' => 256,  // Increase from 128MB default
    'auto_restart' => true,
],
  1. Enable auto-restart:
    • Already enabled by default
    • Supervisor will gracefully restart when memory exceeds limit

📚 More Help

  • Dashboard: Check http://your-app.test/mqtt-broadcast for real-time diagnostics
  • Logs: Check storage/logs/laravel.log for detailed error messages
  • GitHub Issues: Report a bug
  • Testing: Run tests locally with ./test.sh (see tests/README.md)

Testing

The package includes 356 tests (327 unit + 29 integration tests).

Quick Testing

# Run unit tests (no external dependencies)
composer test

# Or use the helper script
./test.sh unit

Integration Tests with Real Broker

Integration tests require a real MQTT broker (Mosquitto).

Start test environment:

./test.sh start  # Starts Mosquitto + Redis via Docker

Run all tests:

./test.sh all

Run only integration tests:

./test.sh integration

Stop test environment:

./test.sh stop

Helper Script Commands

./test.sh start       # Start Mosquitto and Redis
./test.sh stop        # Stop services
./test.sh status      # Check if services are running
./test.sh unit        # Run unit tests only
./test.sh integration # Run integration tests only
./test.sh all         # Run all tests with broker
./test.sh clean       # Stop and clean volumes

CI/CD

Integration tests run automatically on GitHub Actions with Mosquitto service container.

For more details, see tests/README.md.

FAQ

How to install MQTT in Laravel?

Install via Composer:

composer require enzolarosa/mqtt-broadcast
php artisan migrate

Then configure your broker in .env:

MQTT_HOST=127.0.0.1
MQTT_PORT=1883

Start the subscriber:

php artisan mqtt-broadcast

See Quick Start for complete installation guide.

What is the best Laravel MQTT package?

MQTT Broadcast is a production-ready Laravel package using the proven Laravel Horizon supervisor pattern. It provides:

  • ✅ Automatic reconnection with exponential backoff
  • ✅ Multiple broker support for redundancy
  • ✅ Real-time monitoring dashboard
  • ✅ Graceful shutdown and signal handling
  • ✅ Memory management and auto-restart
  • ✅ 356 tests (327 unit + 29 integration)
  • ✅ Battle-tested in production environments

How to connect ESP32 to Laravel?

  1. Laravel side: Install MQTT Broadcast and start subscriber
  2. ESP32 side: Use PubSubClient library to publish messages

Complete tutorial: IoT Temperature Monitoring Example

Quick ESP32 code:

#include <WiFi.h>
#include <PubSubClient.h>

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  WiFi.begin("SSID", "password");
  client.setServer("192.168.1.100", 1883);
}

void loop() {
  client.publish("sensors/temp", "25.5");
  delay(5000);
}

How to use MQTT with Laravel IoT projects?

MQTT Broadcast is perfect for IoT projects:

Supported devices:

  • ESP32, ESP8266
  • Arduino with WiFi/Ethernet
  • Raspberry Pi
  • Industrial PLCs
  • Smart home devices

Common use cases:

  • Temperature/humidity monitoring
  • Industrial automation (Industry 4.0)
  • Smart home control
  • Fleet tracking
  • Environmental sensors

See examples/iot-temperature-monitor for a complete working example.

How does Laravel MQTT Broadcast compare to other packages?

Feature MQTT Broadcast Other Packages
Supervisor Architecture ✅ Horizon-style ❌ Simple loops
Auto-reconnection ✅ Exponential backoff ⚠️ Basic retry
Multiple Brokers ✅ Simultaneous ❌ Single only
Graceful Shutdown ✅ SIGTERM handling ❌ Force kill
Memory Management ✅ Auto-restart ❌ Manual restart
Real-time Dashboard ✅ React 19 ❌ No dashboard
Tests ✅ 356 tests ⚠️ Limited

How to deploy Laravel MQTT to production?

Use Supervisor to keep the subscriber running:

[program:mqtt-broadcast]
command=php /var/www/html/artisan mqtt-broadcast
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/mqtt-broadcast.log

Reload Supervisor:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start mqtt-broadcast

See Production Deployment Guide for complete instructions.

Can I use multiple MQTT brokers?

Yes! Configure multiple brokers for redundancy:

'connections' => [
    'primary' => [
        'host' => 'mqtt-primary.example.com',
        'port' => 8883,
        'use_tls' => true,
    ],
    'backup' => [
        'host' => 'mqtt-backup.example.com',
        'port' => 8883,
        'use_tls' => true,
    ],
],

'environments' => [
    'production' => ['primary', 'backup'],
],

The supervisor will connect to both brokers simultaneously.

How to secure MQTT with TLS/SSL?

Enable TLS in configuration:

'connections' => [
    'secure' => [
        'host' => 'mqtt.example.com',
        'port' => 8883,
        'use_tls' => true,
        'username' => 'user',
        'password' => 'secure_password',
    ],
],

Or in .env:

MQTT_HOST=mqtt.example.com
MQTT_PORT=8883
MQTT_USE_TLS=true
MQTT_USERNAME=user
MQTT_PASSWORD=secure_password

What MQTT brokers are supported?

All standard MQTT brokers are supported:

Self-hosted:

  • Mosquitto (recommended)
  • EMQX
  • VerneMQ
  • HiveMQ Community Edition

Cloud services:

  • AWS IoT Core
  • Azure IoT Hub
  • HiveMQ Cloud
  • CloudMQTT

Requirements:

  • MQTT 3.1.1 protocol
  • Standard ports (1883 for plain, 8883 for TLS)

How to handle high-volume MQTT messages?

For high-volume systems:

  1. Increase memory limit:
'memory' => [
    'threshold_mb' => 512,
    'gc_interval' => 500,
],
  1. Use dedicated queues:
MQTT_JOB_QUEUE=mqtt-high-volume
MQTT_LISTENER_QUEUE=mqtt-processing
  1. Scale queue workers:
php artisan queue:work --queue=mqtt-high-volume --processes=4
  1. Disable logging if not needed:
MQTT_LOG_ENABLE=false

Does it work with Laravel 9/10/11?

Yes! MQTT Broadcast supports:

  • ✅ Laravel 11.x (latest)
  • ✅ Laravel 10.x
  • ✅ Laravel 9.x
  • ✅ PHP 8.1, 8.2, 8.3

How to monitor MQTT connections?

Use the built-in dashboard:

  1. Access: http://your-app.test/mqtt-broadcast
  2. View real-time metrics:
    • Messages per minute/hour/day
    • Broker connection status
    • Memory usage
    • Queue pending jobs
    • Recent messages log

Configure authentication in production:

Gate::define('viewMqttBroadcast', fn($user) => $user->isAdmin());

More questions?

Documentation

📚 Comprehensive Guides

Getting Started:

Tutorials:

🇮🇹 Guide in Italiano:

📖 GitHub Documentation

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

Inspired by Laravel Horizon architecture.

License

The MIT License (MIT). Please see License File for more information.