پروژه با ESP32, پروژه با آردوینو, طراحی خانه هوشمند

5/1 خانه هوشمند اتصال سنسور dht11 به اپلکیشن فلاتر

قسمت 5 بخش اول آموزش کد آردوینو برای dt11 برای دریافت دما و رطوبت برای خانه هوشمن

مقدمه

مدل‌های اینترنت اشیاء (IoT) به شما امکان می‌دهند سنسورها را به اپلیکیشن موبایل یا وب متصل کنید تا داده‌ها را در لحظه ببینید. در این مقاله، می‌خواهم نشان دهم چگونه سنسور DHT11 (برای اندازه‌گیری دما و رطوبت) را به یک برد ESP32 متصل کنید، داده‌ها را از طریق پروتکل MQTT ارسال کنید، و یک اپلیکیشن فلاتر بسازید که آن داده‌ها را نمایش دهد.

کد شما ساختار چندوظیفه‌ای (FreeRTOS tasks) در ESP32 را پیاده کرده است تا خواندن سنسور و ارسال MQTT را به صورت موازی انجام دهد. من این ساختار را تشریح می‌کنم، سپس بخش اپلیکیشن فلاتر را طراحی می‌کنم تا اطلاعات را از MQTT بگیرد و نمایش دهد.

این پروژه برای کسانی مناسب است که می‌خواهند بر ترکیب سخت‌افزار، شبکه (MQTT) و موبایل تسلط بیشتری پیدا کنند.

ابتدا بررسی مختصر اجزای پروژه:

  • سنسور DHT11: سنسوری ساده برای خواندن دما و رطوبت.

  • برد ESP32: میکروکنترولی با امکانات WiFi مناسب برای پروژه‌های IoT.

  • پروتکل MQTT: پروتکلی سبک برای ارسال پیام بین دستگاه‌ها با الگوی publish/subscribe.

  • اپلیکیشن فلاتر: رابط کاربری موبایل که بتواند پیام‌های MQTT را دریافت کند و داده‌ها را نشان دهد.

ماژول هایی که در این پروژه نیاز دارید

 


اصولی درباره DHT11 و محدودیت‌ها

قبل از هر چیز، سنسور DHT11 محدودیت‌هایی دارد که باید در نظر بگیرید:

  • نرخ به‌روزرسانی پایین: تا حدود هر ۱ ثانیه می‌توان خواند.

  • دقت محدود: دقت دما ±2 درجه سلسیوس و رطوبت ±5٪.

  • در دماهای خیلی بالا یا پایین عملکرد ممکن است نامطلوب باشد.

  • سنسور در محیط‌های مرطوب یا با نویز دیجیتال نزدیک ممکن است دچار خطا شود.

به همین دلیل، استفاده از تأخیر مناسب بین خواندن‌ها و بررسی خطاهای مقدار NaN در کد شما مهم است (که شما در کد نیز کنترل کرده‌اید).

همچنین در پروژه‌های حساس‌تر، ممکن است بخواهید از سنسورهای دقیق‌تر مثل DHT22 یا BME280 استفاده کنید.


توضیح کامل کد ESP32

کد ارسالی شامل دو تسک جداگانه (sensorTask و mqttTask) است و از FreeRTOS روی ESP32 استفاده می‌کند. اجازه دهید بخش به بخش توضیح دهم:

بخش کتابخانه‌ها و پیکربندی

کد شما از کتابخانه‌های زیر استفاده می‌کند:

				
					#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
				
			
  • #define DHTPIN 4
    #define DHTTYPE DHT11
    WiFi.h برای اتصال به شبکه WiFi
  • PubSubClient برای کار با MQTT
  • ArduinoJson برای ساخت رشته JSON
  • Adafruit_Sensor و DHT برای کار با سنسور DHT

سپس پین داده و نوع سنسور تعریف می‌شود:

				
					#define DHTPIN 4
#define DHTTYPE DHT11
				
			
  • و سپس یک شیء DHT_Unified ایجاد می‌شود:
				
					DHT_Unified dht(DHTPIN, DHTTYPE);
				
			
  • و سپس یک شیء DHT_Unified ایجاد می‌شود:
				
					uint32_t delayMS;
float temp;
float humadity;
bool hvac = true;
				
			
  • delayMS برای تأخیر بین خواندن‌ها، temp و humadity برای ذخیره مقدار دما و رطوبت، و hvac یک متغیر کنترلی است.

    همچنین اطلاعات مربوط به سرور MQTT و شیء client:

				
					const char *mqtt_server = MQTT_SERVER;
const uint16_t mqtt_port = MQTT_PORT;

WiFiClient espClient;
PubSubClient client(espClient);
				
			

پارامترهای MQTT_SERVER, MQTT_PORT, MQTT_USER, MQTT_PASSWORD در فایل secrets.h تعریف شده‌اند و نباید در کد عمومی قرار گیرند.

تابع callback

وقتی پیام جدیدی از موضوعی که مشترک شده‌ایم می‌آید، این تابع فراخوانی می‌شود:

				
					void callback(char *topic, byte *payload, unsigned int length) { … }
				
			

در اینجا تنها پیام و موضوع چاپ می‌شود، اما می‌توانید بر اساس موضوع، عملیاتی انجام دهید.

تابع reconnect

اگر ارتباط MQTT قطع شود، این تابع تلاش می‌کند مجدداً به بروکر متصل شود:

				
					while (!client.connected()) {
    if (client.connect("ESP32Client", MQTT_USER, MQTT_PASSWORD)) {
        client.subscribe("thermostat/command");
    }
    …
}

				
			

در اینجا پس از اتصال، در موضوع thermostat/command مشترک می‌شود تا فرمان‌ها از اپلیکیشن بگیرد.

تابع‌های تسک‌ها و setup

در setup()، شما:

  1. ارتباط سریال را شروع می‌کنید

  2. سنسور DHT را آغاز می‌کنید

  3. تأخیر بین خواندن‌ها را محاسبه می‌کنید

  4. به WiFi وصل می‌شوید

  5. سرور MQTT را تنظیم می‌کنید

  6. دو تسک مجزا روی هسته ۱ ایجاد می‌کنید: sensorTask و mqttTask

تسک sensorTask به‌طور مداوم دما و رطوبت را می‌خواند و مقادیر را در متغیرهای جهانی temp و humadity ذخیره می‌کند.
تسک mqttTask نیز وضعیت اتصال MQTT را مدیریت می‌کند و هر ثانیه یک پیام JSON حاوی داده‌های سنسور را روی موضوع thermostat/sensor منتشر می‌کند:

				
					doc["temp"] = temp;
doc["hum"] = humadity;
doc["hvac"] = hvac;
serializeJson(doc, jsonString);
client.publish("thermostat/sensor", jsonString.c_str());
				
			

دقت به این نکته باشد که شما باید JSONDocument یا DynamicJsonDocument را استفاده کنید. (در کد شما صرف JsonDocument doc; نوشته شده؛ لازم است یکی از نسخه‌های مشخص مثل StaticJsonDocument<128> یا DynamicJsonDocument باشد).


گام به گام اجرای پروژه

مرحله ۱: راه‌اندازی محیط

  1. نصب افزونه ESP32 برای Arduino IDE

  2. نصب کتابخانه‌های DHT و Adafruit Sensor

  3. نصب PubSubClient و ArduinoJson

  4. آماده کردن IP یا آدرس بروکر MQTT شما (مثلاً Mosquitto محلی یا سرویس ابری)

مرحله ۲: تعریف secrets.h

در فایلی به نام secrets.h، مقادیر زیر را قرار دهید:

				
					#define WIFI_SSID "نام_WiFi"
#define WIFI_PASSWORD "کلمه_عبور"
#define MQTT_SERVER "آدرس_بروکر"
#define MQTT_PORT 1883
#define MQTT_USER "نام_کاربری"
#define MQTT_PASSWORD "رمز_عبور"

				
			

مرحله ۳: آپلود کد به ESP32

کد کامل را در IDE خود قرار دهید، مطمئن شوید که انتخاب برد صحیح است (ESP32 Dev Module یا مدل شما) و سپس آپلود کنید.
از مانیتور سریال با نرخ 115200 استفاده کنید تا پیام‌ها مانند اتصال WiFi، ارسال JSON و پیام‌های خطا را ببینید.

مرحله ۴: آزمون بر روی MQTT

برای بررسی اینکه داده‌ها به درستی ارسال می‌شوند، می‌توانید از یک کلاینت MQTT استفاده کنید مثل:

  • MQTT Explorer

  • MQTT.fx

  • یا حتی اپلیکیشن موبایل MQTT Dashboard

مشترک شوید به موضوع thermostat/sensor و ببینید پیام‌هایی شبیه زیر دریافت می‌شوند:

				
					{"temp":25.5,"hum":60.0,"hvac":true}

				
			

اگر پیام‌ها دریافت شدند، بخش ESP32 به درستی عمل می‌کند.

مرحله ۵: ساخت اپلیکیشن فلاتر

در ادامه، بخشی از کد فلاتر را ارائه می‌دهم که می‌تواند به بروکر MQTT متصل شود و پیام‌ها را دریافت کند.

ابتدا در فایل pubspec.yaml وابستگی زیر را اضافه کنید:

				
					dependencies:
  mqtt_client: ^10.0.0
  flutter:
    sdk: flutter

				
			

سپس در فایل Dart (مثلاً mqtt_service.dart)، یک کلاس برای مدیریت اتصال MQTT بسازید:

				
					import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';

class MqttService {
  late MqttServerClient client;

  Future<void> connect(String server, String clientId) async {
    client = MqttServerClient(server, clientId);
    client.port = 1883;
    client.logging(on: true);
    client.keepAlivePeriod = 60;
    client.onConnected = onConnected;
    client.onDisconnected = onDisconnected;
    client.onSubscribed = onSubscribed;

    final connMess = MqttConnectMessage()
        .withClientIdentifier(clientId)
        .withWillTopic('willtopic')
        .withWillMessage('My Will message')
        .startClean()
        .withWillQos(MqttQos.atLeastOnce);
    client.connectionMessage = connMess;

    try {
      await client.connect();
    } catch (e) {
      print('MQTT client exception: $e');
      client.disconnect();
    }
  }

  void onConnected() {
    print('Connected to MQTT broker');
    client.subscribe('thermostat/sensor', MqttQos.atLeastOnce);
  }

  void onDisconnected() {
    print('Disconnected from MQTT');
  }

  void onSubscribed(String topic) {
    print('Subscribed to $topic');
  }
}

				
			

سپس در main.dart یا ویجت اصلی خود:

				
					import 'package:flutter/material.dart';
import 'mqtt_service.dart';
import 'package:mqtt_client/mqtt_client.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) =>
      MaterialApp(home: SensorPage());
}

class SensorPage extends StatefulWidget {
  @override
  _SensorPageState createState() => _SensorPageState();
}

class _SensorPageState extends State<SensorPage> {
  late MqttService mqttService;
  String temp = '--';
  String hum = '--';

  @override
  void initState() {
    super.initState();
    mqttService = MqttService();
    mqttService.connect('آدرس_بروکر_MQTT', 'flutter_client').then((_) {
      mqttService.client.updates?.listen((List<MqttReceivedMessage<MqttMessage>> c) {
        final MqttPublishMessage recMess = c[0].payload as MqttPublishMessage;
        final message =
            MqttPublishPayload.bytesToStringAsString(recMess.payload.message);

        print('Received message: $message');
        // پیام JSON را پارس کن
        final map = jsonDecode(message);
        setState(() {
          temp = map['temp'].toString();
          hum = map['hum'].toString();
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('دما و رطوبت')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('دما: $temp °C',
                style: TextStyle(fontSize: 24)),
            SizedBox(height: 16),
            Text('رطوبت: $hum %',
                style: TextStyle(fontSize: 24)),
          ],
        ),
      ),
    );
  }
}

				
			

با این کد، اپلیکیشن فلاتر به بروکر MQTT وصل می‌شود، مشترک thermostat/sensor می‌شود و پیام‌ها را شنود می‌کند. با دریافت پیام، JSON آن را تجزیه کرده و مقادیر دما و رطوبت را در رابط کاربری به‌روزرسانی می‌کند.


نکات پیشرفته و بهبودها

کنترل فرمان از اپلیکیشن

از آنجایی که شما در کد ESP32 مشترک thermostat/command شده‌اید، اپلیکیشن فلاتر می‌تواند پیام‌هایی روی آن موضوع بفرستد تا دستگاه ESP32 فرمان‌ها را دریافت کند (مثلاً روشن/خاموش کردن HVAC). در فلاتر باید متد client.publish('thermostat/command', payload) را استفاده کنید.

نگهداری اتصال

در فلاتر باید مکانیزم reconnect در صورت افت اتصال MQTT پیاده شود. مثلاً اگر اتصال قطع شود، دوباره تلاش کند. در مثال‌های آموزش MQTT در فلاتر این قابلیت درج شده است. Medium

امنیت

در پروژه‌های حقیقی، از TLS/SSL برای MQTT استفاده کنید تا ارتباط شما امن باشد. همچنین احراز هویت (نام کاربری و رمز عبور) را جدی بگیرید.

ذخیره‌سازی داده‌ها

می‌توانید داده‌های دریافتی را در دیتابیس محلی (مثلاً SQLite یا Hive) ذخیره کنید تا تاریخچه مقادیر را نمایش دهید.

حاصل کار با پلتفرم‌های دیگر

اگر هم بخواهید از طریق وب یا داشبورد آنلاین نمایش دهید، می‌توانید ارتباط MQTT را به سمت سرور وب منتقل کنید یا از Node-RED یا Grafana استفاده کنید. در آموزش‌های ESP32 به MQTT، این روش رایج است. Random Nerd Tutorials+1


مشکلات رایج و راه حل‌ها

مشکلعلت احتمالیراه حل
دریافت پیام خالی یا NaNخراب بودن خواندن سنسوردر کد کنترل isnan() را داشته باشید و اگر مقدار نامعتبر است دوباره تلاش کنید
عدم اتصال به WiFiSSID یا رمز عبور اشتباهبررسی مقدارهای WIFI_SSID و WIFI_PASSWORD و چاپ وضعیت WiFi در سریال
قطع شدن ارتباط MQTTنداشتن مکانیزم reconnectتابع reconnect را کامل پیاده کرده و در mqttTask آن را فرا بخوانید
خطا در پارس JSON در فلاترپیام دریافتی ممکن است فرمت JSON نداشته باشدقبل از jsonDecode بررسی کنید که پیام به‌درستی دریافتی است
تداخل تسک‌هامنابع مشترک بین تسک‌هااز متغیرهای اتمی یا قفل (درصورت نیاز) استفاده کنید، البته در پروژه ساده معمولاً مشکلی پیش نمی‌آید
 

جمع‌بندی

در این مقاله راه‌اندازی کامل سنسور DHT11 به همراه ESP32، ارسال داده‌ها از طریق MQTT و ساخت اپلیکیشن فلاتر برای نمایش آن را آموزش دادم. از کد شما به عنوان مبنا استفاده کردم و جزئیات آن را توضیح دادم، سپس بخش فلاتر را طراحی کردم تا ارتباط دوطرفه امکان‌پذیر باشد.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

برای امنیت، استفاده از سرویس کپتچا گوگل مورد نیاز است که تابع گوگل است سیاست حفظ حریم خصوصی و شرایط استفاده.

Iبا این شرایط موافقید.