7.9 KiB
7.9 KiB
MQTT Client - Hướng dẫn sử dụng
Tổng quan
MQTT Client (mqttClient) là một utility singleton được thiết kế để quản lý kết nối MQTT trong ứng dụng. File này nằm tại src/utils/mqttClient.ts.
Cài đặt
Package mqtt được cài đặt qua npm:
npm install mqtt
Cấu trúc
src/utils/
├── mqttClient.ts # MQTT Client utility
└── wsClient.ts # WebSocket Client utility (legacy)
Cách sử dụng
1. Import
import { mqttClient } from '@/utils/mqttClient';
2. Kết nối
// Lấy credentials từ user metadata
const { frontend_thing_id, frontend_thing_key } =
initialState?.currentUserProfile?.metadata || {};
// Kết nối
mqttClient.connect({
username: frontend_thing_id,
password: frontend_thing_key,
});
3. Đăng ký Event Handlers
// Khi kết nối thành công
const unConnect = mqttClient.onConnect(() => {
console.log('MQTT Connected!');
});
// Khi có lỗi
const unError = mqttClient.onError((error) => {
console.error('MQTT Error:', error);
});
// Khi kết nối đóng
const unClose = mqttClient.onClose(() => {
console.log('MQTT Closed');
});
// Cleanup khi component unmount
return () => {
unConnect();
unError();
unClose();
mqttClient.disconnect();
};
4. Publish Message
const topic = `channels/${cfg_channel_id}/messages/cameraconfig/gmsv6`;
const payload = JSON.stringify(senmlData);
if (mqttClient.isConnected()) {
mqttClient.publish(topic, payload);
}
5. Subscribe Topic
// Subscribe
mqttClient.subscribe('channels/123/messages/#');
// Nhận message
const unMessage = mqttClient.onMessage((topic, message, packet) => {
console.log('Received:', topic, message.toString());
});
// Unsubscribe
mqttClient.unsubscribe('channels/123/messages/#');
API Reference
| Method | Mô tả |
|---|---|
connect(credentials, url?) |
Kết nối MQTT với username/password |
disconnect() |
Ngắt kết nối |
subscribe(topic) |
Subscribe vào topic |
unsubscribe(topic) |
Unsubscribe khỏi topic |
publish(topic, payload) |
Publish message |
onConnect(callback) |
Đăng ký callback khi kết nối |
onClose(callback) |
Đăng ký callback khi đóng |
onError(callback) |
Đăng ký callback khi lỗi |
onMessage(callback) |
Đăng ký callback khi nhận message |
isConnected() |
Kiểm tra trạng thái kết nối |
getClient() |
Lấy MQTT client gốc |
Cấu hình Proxy (Development)
Trong môi trường development, MQTT được proxy qua config trong config/proxy.ts:
"/mqtt": {
target: "https://gms.smatec.com.vn",
changeOrigin: true,
ws: true,
},
Format SenML
Dữ liệu MQTT được format theo chuẩn SenML:
const senml = [
{
bn: `urn:dev:mac:${mac}:`, // Base name
n: 'ack', // Name
t: Date.now() / 1000, // Timestamp (seconds)
vs: uuidv4(), // Value string (ACK ID)
},
{
n: 'user@email.com', // Email (@ → :)
t: Date.now() / 1000,
vs: JSON.stringify(config), // Config dạng JSON string
},
];
Topic Structure
channels/${channel_id}/messages/${type}/${gw_type}
| Phần | Mô tả |
|---|---|
channel_id |
ID của kênh (từ thing.metadata.cfg_channel_id) |
type |
Loại message: cameraconfig, config, log, notify |
gw_type |
Loại gateway: gmsv6, gmsv5 |
Ví dụ hoàn chỉnh
import { mqttClient } from '@/utils/mqttClient';
import { useModel } from '@umijs/max';
import { useEffect, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
const MyComponent = ({ thing }) => {
const { initialState } = useModel('@@initialState');
const [connected, setConnected] = useState(false);
useEffect(() => {
const { frontend_thing_id, frontend_thing_key } =
initialState?.currentUserProfile?.metadata || {};
if (!frontend_thing_id || !frontend_thing_key) return;
mqttClient.connect({
username: frontend_thing_id,
password: frontend_thing_key,
});
const unConnect = mqttClient.onConnect(() => setConnected(true));
const unClose = mqttClient.onClose(() => setConnected(false));
return () => {
unConnect();
unClose();
mqttClient.disconnect();
};
}, [initialState]);
const handlePublish = () => {
const { cfg_channel_id, external_id } = thing.metadata;
const topic = `channels/${cfg_channel_id}/messages/cameraconfig/gmsv6`;
const payload = [
{
bn: `urn:dev:mac:${external_id.replaceAll('-', '')}:`,
n: 'ack',
t: Date.now() / 1000,
vs: uuidv4(),
},
{
n: initialState?.currentUserProfile?.email?.replaceAll('@', ':'),
t: Date.now() / 1000,
vs: JSON.stringify({ record_type: 'all' }),
},
];
if (mqttClient.isConnected()) {
mqttClient.publish(topic, JSON.stringify(payload));
}
};
return (
<button onClick={handlePublish} disabled={!connected}>
{connected ? 'Publish' : 'Connecting...'}
</button>
);
};
So sánh mqttClient vs wsClient
Dự án có 2 utilities để giao tiếp real-time:
Bảng so sánh
| Tiêu chí | mqttClient | wsClient |
|---|---|---|
| Thư viện | mqtt (MQTT.js) |
reconnecting-websocket |
| Protocol | MQTT over WebSocket | WebSocket thuần |
| Xác thực | Username/Password (MQTT credentials) | Token (access_token) hoặc không |
| Topics | Hỗ trợ MQTT topics, subscribe/unsubscribe | Không có khái niệm topic |
| Publish | publish(topic, payload) |
send(data) |
| Subscribe | subscribe(topic) + onMessage() |
subscribe(callback) |
| Reconnect | Tự động (built-in) | Tự động (reconnecting-websocket) |
| Use case | Giao tiếp với IoT Gateway/Devices | Giao tiếp WebSocket server |
Khi nào dùng mqttClient?
✅ Dùng mqttClient khi:
- Gửi/nhận dữ liệu với IoT Gateways (GMSv5, GMSv6)
- Cấu hình thiết bị (camera, nodes, schedules)
- Cần subscribe nhiều topics khác nhau
- Làm việc với Mainflux platform
Khi nào dùng wsClient?
✅ Dùng wsClient khi:
- Cần WebSocket connection đơn giản
- Giao tiếp với WebSocket server không phải MQTT broker
- Xác thực bằng access_token
Code comparison
mqttClient:
import { mqttClient } from '@/utils/mqttClient';
// Connect với username/password
mqttClient.connect({
username: 'thing_id',
password: 'thing_key',
});
// Subscribe topic
mqttClient.subscribe('channels/123/messages/#');
// Publish với topic
mqttClient.publish('channels/123/messages/config', payload);
// Nhận message
mqttClient.onMessage((topic, message) => {
console.log(topic, message.toString());
});
wsClient:
import { wsClient } from '@/utils/wsClient';
// Connect với hoặc không có token
wsClient.connect('/mqtt', false);
// Không có subscribe topic
// Chỉ nhận tất cả messages
wsClient.subscribe((data) => {
console.log(data);
});
// Gửi data (không có topic)
wsClient.send({ action: 'update', data: payload });
Xem thêm
- Mainflux.md - Tài liệu giao tiếp MQTT chi tiết
- mqttClient.ts - Source code MQTT Client
- wsClient.ts - Source code WebSocket Client