طراحی تاپیک و قالب پیام JSON در MQTT
قواعد عملی برای نامگذاری تاپیکهای MQTT، استفاده درست از + و #، جدا کردن داده، فرمان و وضعیت، و طراحی پیام JSON که بعداً دردسرساز نشود.
چرا طراحی تاپیک مهم است؟#
در MQTT تاپیک تنها راه آدرسدهی است: فرستنده و گیرنده همدیگر را نمیشناسند و فقط روی نام تاپیک توافق دارند. اگر از روز اول ساختار مشخصی نداشته باشید، با اضافه شدن هر دستگاه، اشتراکها پیچیدهتر و تغییر دادنشان سختتر میشود؛ چون باید کد همه دستگاهها را عوض کنید.
ساختار پیشنهادی#
تاپیک را از کلی به جزئی بنویسید. در mqttcloud.ir بخش اول همیشه نام کاربری اکانت MQTT است:
alice/<site>/<device>/<kind>[/<name>]
alice/warehouse/esp32-01/telemetry/temp
alice/warehouse/esp32-01/telemetry/humidity
alice/warehouse/esp32-01/cmd/fan
alice/warehouse/esp32-01/statusبا این ساختار هر سطح از سیستم با یک اشتراک قابل دسترسی است:
alice/warehouse/#: همه چیز در انبارalice/+/+/telemetry/temp: دمای همه دستگاهها در همه محلهاalice/+/+/status: وضعیت آنلاین همه دستگاهها
قواعد نامگذاری#
- فقط حروف کوچک انگلیسی، عدد،
-و_. تاپیکها به حروف بزرگ و کوچک حساساند وTempوtempدو تاپیک جدا هستند. - فاصله، حروف فارسی و نویسههای خاص نگذارید؛ بعضی کتابخانهها و ابزارها با آنها مشکل دارند.
/اول تاپیک نگذارید و//(سطح خالی) نسازید.- شناسه دستگاه را در تاپیک بیاورید، نه فقط داخل پیام؛ اینطور میتوانید روی یک دستگاه خاص مشترک شوید.
- تاپیکهایی که با
$شروع میشوند مخصوص بروکرند و در mqttcloud.ir قابل اشتراک نیستند.
+ و #: فقط در اشتراک#
+ دقیقاً یک سطح را میپذیرد و # هر تعداد سطح را، اما فقط در انتهای تاپیک. هر دو فقط در اشتراک معنا دارند و نمیتوانید روی تاپیکی با + منتشر کنید.
چون هر اکانت فقط به فضای نام خودش دسترسی دارد، اشتراک باید با نام کاربری شروع شود. alice/# و alice/+/status پذیرفته میشوند، ولی # یا +/status رد میشوند (بروکر کد خطا در SUBACK برمیگرداند و اتصال قطع نمیشود). انتشار خارج از فضای نام اما اتصال را قطع میکند.
داده، فرمان و وضعیت را جدا کنید#
سه نوع پیام را در سه شاخه جدا بگذارید:
telemetry: دادهای که دستگاه میفرستد. معمولاً QoS 0 یا 1، بدون retain.cmd: فرمانی که به دستگاه داده میشود. QoS 1 تا گم نشود؛ معمولاً بدون retain، وگرنه دستگاه بعد از هر بار وصل شدن فرمان قدیمی را دوباره اجرا میکند.statusیاstate: وضعیت فعلی (آنلاین بودن، روشن یا خاموش بودن رله). با retain تا هر مشترک جدید فوراً وضعیت را بداند؛ الگوی کامل آن در مقاله وضعیت آنلاین دستگاه با Last Will آمده است.
برای فرمانها بهتر است دستگاه بعد از اجرا، وضعیت جدید را در state منتشر کند؛ اینطور فرستنده مطمئن میشود فرمان واقعاً اجرا شده.
قالب پیام: JSON کوچک و قابل گسترش#
MQTT به محتوای پیام کاری ندارد و هر بایتی را جابهجا میکند، اما JSON برای بیشتر پروژهها انتخاب خوبی است:
{"v": 1, "ts": 1767225600, "temp": 24.8, "unit": "C"}vنسخه قالب پیام است؛ اگر روزی قالب را عوض کردید، گیرنده میفهمد با کدام نسخه طرف است.tsزمان اندازهگیری به ثانیه یونیکس (UTC). MQTT 3.1.1 زمان ارسال را همراه پیام نمیفرستد و اگر پیام دیرتر برسد، زمان دریافت با زمان اندازهگیری فرق دارد. دستگاه برای این کار باید ساعتش را با NTP تنظیم کند.- واحد را مشخص کنید یا در نام فیلد بیاورید.
- پیام را کوچک نگه دارید. بافر پیشفرض PubSubClient ۲۵۶ بایت است و پیام بزرگتر بیصدا ارسال نمیشود.
یک پیام JSON با چند مقدار یا یک تاپیک برای هر مقدار؟ اگر مقادیر همیشه با هم اندازهگیری میشوند، یک پیام کمهزینهتر است. اگر گیرندههای مختلف به مقادیر مختلف نیاز دارند، تاپیک جدا اشتراک را سادهتر میکند.
بررسی در داشبورد#
صفحه «پیامها» در داشبورد mqttcloud.ir تاپیک و محتوای پیامهای اخیر را تا ۷ روز نشان میدهد (تا ۴۰۰۰ کاراکتر اول هر پیام). قبل از نوشتن کد گیرنده، همانجا ببینید تاپیکها و JSON دقیقاً همانی هستند که انتظار دارید. برای تست دستی تاپیکها هم ابزارهای تست MQTT را ببینید.
