Prečo MQTT a nie HTTP polling?
HTTP polling — každých 5 sekúnd pýtať server „sú nové dáta?" — plytváva batériu ESP32 a zaťažuje server. MQTT je lightweight publish/subscribe protokol navrhnutý pre IoT: ESP32 publikuje správu, broker ju okamžite doručí všetkým odberateľom. Latencia pod 100 ms, spotreba energie zlomok oproti HTTP.
| Vlastnosť | HTTP polling | MQTT |
|---|---|---|
| Latencia | podľa intervalu (5–60 s) | < 100 ms |
| Spotreba ESP32 | vysoká (stále aktívny WiFi) | nízka (publish + sleep) |
| Škálovateľnosť | 1 server ← N zariadení | broker distribuuje N→M |
| Protokol | TCP/HTTP | TCP/MQTT (port 1883/8883) |
Architektúra systému
Stack pozostáva zo štyroch vrstiev: ESP32 senzor publikuje na MQTT topic, Mosquitto broker distribuuje správy, Laravel subscriber prijíma dáta a ukladá ich do databázy, Reverb WebSocket pushuje živé dáta do Blade dashboardu.
ESP32 (DHT22)
└─ publish → topic: home/livingroom/temp
│
Mosquitto broker (VPS port 1883)
│
Laravel artisan command (php-mqtt/client)
│
MySQL + Reverb broadcast
│
Blade dashboard (EventSource / Echo)
1. Mosquitto broker — inštalácia na VPS
sudo apt install -y mosquitto mosquitto-clients # /etc/mosquitto/conf.d/default.conf listener 1883 allow_anonymous false password_file /etc/mosquitto/passwd # Vytvor používateľa sudo mosquitto_passwd -c /etc/mosquitto/passwd gear_iot sudo systemctl restart mosquitto # Test mosquitto_pub -h localhost -u gear_iot -P tajneheslo -t test/hello -m "OK" mosquitto_sub -h localhost -u gear_iot -P tajneheslo -t test/hello
2. ESP32 — publikovanie dát (PubSubClient)
Knižnica PubSubClient od Nicka O'Learyho je štandard pre MQTT na Arduino/ESP32. Inštalácia cez Arduino IDE Library Manager alebo PlatformIO.
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
const char* ssid = "WIFI_SSID";
const char* password = "WIFI_PASS";
const char* mqtt_server = "vps.example.com";
const char* mqtt_user = "gear_iot";
const char* mqtt_pass = "tajneheslo";
DHT dht(4, DHT22);
WiFiClient espClient;
PubSubClient client(espClient);
void reconnect() {
while (!client.connected()) {
if (client.connect("esp32-livingroom", mqtt_user, mqtt_pass)) {
Serial.println("MQTT connected");
} else {
delay(5000);
}
}
}
void setup() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
client.setServer(mqtt_server, 1883);
dht.begin();
}
void loop() {
if (!client.connected()) reconnect();
client.loop();
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (!isnan(temp) && !isnan(hum)) {
String payload = "{\"temp\":" + String(temp, 1)
+ ",\"hum\":" + String(hum, 1)
+ ",\"ts\":" + String(millis()) + "}";
client.publish("home/livingroom/sensor", payload.c_str());
}
delay(30000); // každých 30 sekúnd
}
3. Laravel — MQTT subscriber
Nainštaluj knižnicu php-mqtt/laravel-client, ktorá obaľuje php-mqtt/client a integruje sa s Laravel service containerom.
composer require php-mqtt/laravel-client
# config/mqtt-client.php — hlavné nastavenia
'default_connection' => 'default',
'connections' => [
'default' => [
'host' => env('MQTT_HOST', 'vps.example.com'),
'port' => env('MQTT_PORT', 1883),
'username' => env('MQTT_USER'),
'password' => env('MQTT_PASS'),
'client_id' => 'laravel-subscriber',
],
],
// app/Console/Commands/MqttSubscribe.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use PhpMqtt\Client\Facades\MQTT;
use App\Models\SensorReading;
use App\Events\SensorUpdated;
class MqttSubscribe extends Command
{
protected $signature = 'mqtt:subscribe';
protected $description = 'Počúva MQTT správy zo senzorov';
public function handle(): void
{
MQTT::subscribe('home/+/sensor', function (string $topic, string $message) {
$data = json_decode($message, true);
if (!$data) return;
// Extrahuj miestnosť z topicu: home/livingroom/sensor
$room = explode('/', $topic)[1];
$reading = SensorReading::create([
'room' => $room,
'temperature' => $data['temp'],
'humidity' => $data['hum'],
]);
broadcast(new SensorUpdated($reading))->toOthers();
});
MQTT::loop(); // blokujúca slučka
}
}
Spustenie cez Supervisor
[program:laravel-mqtt] command=php /var/www/gear/artisan mqtt:subscribe autostart=true autorestart=true stderr_logfile=/var/log/mqtt-subscribe.err.log stdout_logfile=/var/log/mqtt-subscribe.out.log
4. Reverb WebSocket + broadcast event
# Inštalácia Reverb composer require laravel/reverb php artisan reverb:install # .env BROADCAST_DRIVER=reverb REVERB_APP_ID=gear-iot REVERB_APP_KEY=tajny-kluc REVERB_APP_SECRET=tajny-secret REVERB_HOST=0.0.0.0 REVERB_PORT=8080
// app/Events/SensorUpdated.php
use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class SensorUpdated implements ShouldBroadcast
{
public function __construct(public SensorReading $reading) {}
public function broadcastOn(): Channel
{
return new Channel('sensors.' . $this->reading->room);
}
public function broadcastWith(): array
{
return [
'room' => $this->reading->room,
'temperature' => $this->reading->temperature,
'humidity' => $this->reading->humidity,
'updated_at' => $this->reading->created_at->toIso8601String(),
];
}
}
5. Blade dashboard — live aktualizácie
<!-- resources/views/dashboard.blade.php -->
<div id="temp-display">--°C</div>
<div id="hum-display">--%</div>
<script src="https://js.pusher.com/8.2.0/pusher.min.js"></script>
<script>
const pusher = new Pusher('{{ config("broadcasting.connections.reverb.key") }}', {
wsHost: '{{ config("broadcasting.connections.reverb.options.host") }}',
wsPort: {{ config("broadcasting.connections.reverb.options.port") }},
cluster: '',
forceTLS: false,
enabledTransports: ['ws'],
});
const channel = pusher.subscribe('sensors.livingroom');
channel.bind('App\\Events\\SensorUpdated', function(data) {
document.getElementById('temp-display').textContent = data.temperature + '°C';
document.getElementById('hum-display').textContent = data.humidity + '%';
});
</script>
6. Bezpečnosť — TLS pre MQTT
Na produkciu nikdy nepoužívaj MQTT na porte 1883 bez šifrovania. Mosquitto podporuje TLS cez Let's Encrypt certifikáty na porte 8883.
# /etc/mosquitto/conf.d/tls.conf listener 8883 cafile /etc/letsencrypt/live/vps.example.com/chain.pem certfile /etc/letsencrypt/live/vps.example.com/cert.pem keyfile /etc/letsencrypt/live/vps.example.com/privkey.pem tls_version tlsv1.2
V ESP32 kóde prepni na port 8883 a použi WiFiClientSecure s CA certifikátom. V Laravel config nastav 'port' => 8883, 'tls' => ['enabled' => true].
Zhrnutie
- Mosquitto broker beží na VPS s autentifikáciou používateľa
- ESP32 publikuje JSON payload každých 30 sekúnd cez PubSubClient
- Laravel artisan command počúva topic
home/+/sensorpomocou wildcard - Každá správa sa uloží do MySQL a broadcastne cez Reverb
- Blade dashboard sa aktualizuje bez reloadu stránky