找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3721

积分

0

好友

519

主题
发表于 2026-2-15 20:11:14 | 查看: 28| 回复: 0

近年来,前端工程师不再局限于页面交互与UI实现,越来越多地参与到全栈甚至物联网(IoT)项目的开发中。本文将以一个真实的温湿度监控系统为例,完整还原从前端、后端、数据库到硬件设备的全链路开发流程,涵盖 MQTT 协议通信、EMQX 消息代理部署、硬件数据采集与前端实时可视化等关键技术环节。

系统架构概览

整个系统由五个核心模块构成:

  • 硬件端:Wemos D1 R2 开发板搭载 ESP8266 Wi-Fi 模块,连接 DHT11 温湿度传感器
  • 通信协议:基于发布/订阅模式的 MQTT 协议,实现轻量级双向通信
  • 消息代理:EMQX 作为 MQTT Broker,负责消息路由与客户端管理
  • 后端服务:Egg.js 框架构建的服务端,处理数据存储与接口暴露
  • 前端展示:jQuery + ECharts 实现动态图表,通过 WebSocket 接入实时数据

各组件通过统一的主题(Topic)进行松耦合通信,形成完整的数据闭环。

硬件端开发:从传感器读取数据

选用 Wemos D1 R2 开发板,因其兼容 Arduino 生态且内置 Wi-Fi 功能,适合快速原型开发。DHT11 传感器通过数字引脚接入,供电为 3.3V,接地引脚连接 GND。

在 Arduino IDE 中编写代码前需安装以下依赖:

  • ESP8266 支持包:通过 Boards Manager 添加 arduino.esp8266.com/stable/package_esp8266com_index.json
  • DHT Sensor Library by Adafruit:用于解析 DHT11 数据
  • PubSubClient:MQTT 客户端库,实现与 EMQX 的通信

获取温湿度数据示例代码

#include "DHT.h"
#include "string.h"
#define DHTPIN 14      // DHT11 数据引脚连接到 D5 引脚(PIN=14)
#define DHTTYPE DHT11  // 定义 DHT11 传感器
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  pinMode(BUILTIN_LED, OUTPUT);
  dht.begin();
}

char* getDHT11Data() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  static char data[100];
  if (isnan(h) || isnan(t)) {
    sprintf(data, "Temperature: %.1f, Humidity: %.1f", 0.0, 0.0);
    return data;
  }
  sprintf(data, "Temperature: %.1f, Humidity: %.1f", t, h);
  return data;
}

void loop() {
  char* data = getDHT11Data();
  Serial.println("got: " + String(data));
  delay(1000);
}

设备联网与MQTT通信

在获取传感器数据的基础上,通过 Wi-Fi 和 MQTT 协议将数据上传至云端。

连接Wi-Fi

#include "ESP8266WiFi.h"

char* ssid = "2104";
char* passwd = "13912428897";

void connectWIFI() {
  int isConnect = 0;
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, passwd);
  int timeCount = 0;
  while (WiFi.status() != WL_CONNECTED) {
    for (int i = 200; i <= 255; i++) {
      analogWrite(BUILTIN_LED, i);
      delay(2);
    }
    for (int i = 255; i >= 200; i--) {
      analogWrite(BUILTIN_LED, i);
      delay(2);
    }
    Serial.println("wifi connecting......" + String(timeCount));
    timeCount++;
    isConnect = 1;
    if (timeCount >= 200) {
      isConnect = 0;
      break;
    }
  }
  if (isConnect == 1) {
    Serial.println("Connect to wifi successfully!" + String("SSID is ") + WiFi.SSID());
    analogWrite(BUILTIN_LED, 250);
    settMqttConfig();
  } else {
    analogWrite(BUILTIN_LED, 255);
    delay(60000);
  }
}

连接MQTT Broker

#include "PubSubClient.h"

const char* mqtt_server = "larryblog.top";
const char* TOPIC = "testtopic";
const char* client_id = "mqttx_3b2687d2";
WiFiClient espClient;
PubSubClient client(espClient);

void settMqttConfig() {
  client.setServer(mqtt_server, 1883);
  client.setCallback(onMessage);
  Serial.println("try connect mqtt broker");
  client.connect(client_id, "wemos", "aa995231030");
  client.subscribe(TOPIC);
  Serial.println("mqtt connected");
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  char* payloadStr = (char*)malloc(length + 1);
  memcpy(payloadStr, payload, length);
  payloadStr[length] = '\0';
  if (strcmp(payloadStr, (char*)"getDHTData") == 0) {
    char* data = getDHT11Data();
    client.publish("wemos/dht11", data);
  }
  free(payloadStr);
}

void loop() {
  if (!client.connected() && isConnect == 1) {
    reconnect();
  }
  if (WiFi.status() != WL_CONNECTED) {
    connectWIFI();
  }
  client.loop();
  publishDhtData();
  long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    client.publish("home/status/", "{device:client_id,'status':'on'}");
  }
  delay(1000);
}

设备每两秒向 wemos/dht11 主题发布一次数据,并监听 testtopic 主题以响应外部查询指令。

服务端部署:EMQX消息代理配置

EMQX 是一款大规模分布式物联网 MQTT 消息服务器,具备高并发、低延迟特性。推荐使用 Ubuntu 系统部署。

安装步骤

curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash
sudo apt-get install emqx
sudo systemctl start emqx

防火墙配置

确保以下端口对外开放:

  • 1883:MQTT 默认端口
  • 8083:WebSocket 端口
  • 18083:Dashboard 管理界面端口

使用 UFW 配置规则:

sudo ufw allow 1883
sudo ufw allow 8083
sudo ufw allow 18083
sudo ufw status

Windows 用户可在“高级安全 Windows Defender 防火墙”中添加入站规则,允许 TCP 协议访问 18083 端口。

云服务器安全组配置

若使用阿里云 ECS 或轻量应用服务器,还需在控制台配置安全组规则,放行上述端口,来源 IP 可设为 0.0.0.0/0 或指定范围。

EMQX控制台配置

访问 http://your-server-ip:18083,使用默认账号登录(admin/public)。

进入 访问控制 > 认证,创建基于内置数据库的身份验证机制。随后添加用户:

  • userClient:前端页面使用
  • server:后端服务使用
  • wemos:设备端使用
  • 995231030:超级管理员账户

所有客户端连接时需提供用户名和密码,增强系统安全性。

前端实现:实时数据可视化

前端采用 jQuery + ECharts 构建,通过 wss:// 协议连接 EMQX,利用 WebSocket 实现全双工通信。

引入MQTT.js库

<script src="https://cdn.bootcdn.net/ajax/libs/mqtt/4.1.0/mqtt.min.js"></script>

连接配置

const options = {
  clean: true,
  connectTimeout: 4000,
  clientId: 'userClient_' + generateRandomString(),
  username: 'userClient',
  password: 'aa995231030'
};

function generateRandomString() {
  let result = '';
  let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let charactersLength = characters.length;
  for (let i = 0; i < 6; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

建立连接与订阅主题

const connectUrl = 'wss://larryblog.top/mqtt';
const client = mqtt.connect(connectUrl, options);

client.on('connect', () => {
  console.log('已连接');
  client.subscribe('wemos/dht11');
  client.subscribe('home/status/');
  client.publish('testtopic', 'getDHTData');
});

client.on('message', (topic, message) => {
  switch(topic) {
    case "wemos/dht11":
      const str = message.toString();
      const arr = str.split(", ");
      const obj = Object.fromEntries(arr.map(s => s.split(": ")));

      document.getElementById("Temperature").innerHTML = obj.Temperature + " ℃";
      optionTemperature.series[0].data.push(parseFloat(obj.Temperature));
      optionTemperature.xAxis.data.push(moment().format("MM-DD/HH:mm:ss"));
      ChartTemperature.setOption(optionTemperature, true);

      document.getElementById("Humidity").innerHTML = obj.Humidity + " %RH";
      optionHumidity.series[0].data.push(parseFloat(obj.Humidity));
      optionHumidity.xAxis.data.push(moment().format("MM-DD/HH:mm:ss"));
      ChartHumidity.setOption(optionHumidity, true);
      break;

    case "home/status/":
      $("#statusText").text("device online");
      $(".statusLight").removeClass("off").addClass("on");
      break;
  }
});

页面加载时自动请求最新数据,并持续监听主题更新,实现秒级刷新的动态图表。

后端服务与数据存储

后端使用 Egg.js 框架,配合 egg-emqtt 插件监听 MQTT 消息,将温湿度数据持久化至 MySQL。

数据库设计

创建名为 larry_lot 的数据库,表 wemosd1_dht11 包含以下字段:

字段名 类型 说明
id INT AI PK 自增主键
temperature FLOAT 温度值
humidity FLOAT 湿度值
updateDatetime DATETIME 更新时间

自动清理旧数据

为避免数据膨胀影响性能,设置触发器自动删除超出容量的数据:

DELIMITER $$
CREATE TRIGGER delete_oldest_data
AFTER INSERT ON wemosd1_dht11
FOR EACH ROW
BEGIN
  IF (SELECT COUNT(*) FROM wemosd1_dht11) > 43200 THEN
    CALL delete_oldest();
  END IF;
END$$
DELIMITER ;

CREATE PROCEDURE delete_oldest()
BEGIN
  DELETE FROM wemosd1_dht11 ORDER BY id ASC LIMIT 1;
END$$
DELIMITER ;

该策略保留最近一天的数据(约 43200 条,每两秒一条),保障查询效率。

Nginx反向代理配置(HTTPS支持)

为实现安全的 WebSocket 连接,使用 Nginx 进行 HTTPS 反向代理。

server {
    listen 80;
    server_name larryblog.top;
    rewrite ^(.*)$ https://$host$1 permanent;
}

server {
    listen 443 ssl;
    server_name larryblog.top;

    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    location /mqtt {
        proxy_pass http://localhost:8083;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location / {
        root /var/www/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
}

前端连接地址改为 wss://larryblog.top/mqtt,即可绕过浏览器对非安全上下文的限制。

总结:数据流动全过程

  1. Wemos D1 板载程序定时读取 DHT11 传感器数据
  2. 通过 MQTT 协议将数据发布至 wemos/dht11 主题
  3. EMQX 接收消息并转发给所有订阅该主题的客户端
  4. 前端页面实时接收并渲染图表
  5. 后端服务同步接收数据并写入 MySQL
  6. 页面初始化时从后端拉取历史数据,补全趋势曲线

该方案实现了低成本、高可用的物联网监控系统,适用于家庭环境监测、农业大棚、工业车间等多种场景。前端开发者借此机会深入理解边缘计算与实时通信机制,拓展技术边界。

前端 & 移动 社区中有大量跨平台开发资源,对于希望进一步探索物联网与前端融合的开发者而言,是值得长期关注的技术阵地。

参考资料

[1] 前端程序员搞物联网开发,玩得真6 !, 微信公众号:mp.weixin.qq.com/s/-XWDohjAjjRodSC1qNoYeg

版权声明:本文由 云栈社区 整理发布,版权归原作者所有。




上一篇:快手万人研发组织AI范式跃迁:从工具普及到效能革命的实践之路
下一篇:Traversal AI SRE:破解Claude Hole困局,实现运维自动化根因分析
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-23 11:44 , Processed in 0.768698 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表