当前位置: 首页 > news >正文

ESP32+Mqtt+Node.js+Vue3 做工控界面

文章目录

      • 1.主机安装 mosquitto
      • 2.EPS32端的代码
      • 3.在电脑端查看

1.主机安装 mosquitto

作为mqtt的服务端,转发消息
https://mosquitto.org/download/

2.EPS32端的代码

注意配置WIFI, mqtt_server 是安装了mosquitto,同局域网下的主机ip

#include<WiFi.h>#include<PubSubClient.h>#include<Adafruit_ADS1X15.h>#include<Wire.h>#include<ArduinoJson.h>// -------------------- 用户配置(必改) --------------------constchar*ssid="TSK";constchar*password="tsk_251010";constchar*mqtt_server="192.168.234.34";constintmqtt_port=1883;// -------------------- MQTT 主题 --------------------constchar*status_topic="esp32/status";constchar*control_topic="esp32/control";// -------------------- 引脚定义 --------------------// 数字输入 (外部下拉,高电平有效)constintDI_PINS[4]={40,39,38,37};// 数字输出constintDO_PINS[4]={7,15,16,17};// PWM 输出constintPWM_PINS[4]={47,21,20,19};constintPWM_FREQ=1000;constintPWM_RESOLUTION=14;constintPWM_MAX_VALUE=(1<<PWM_RESOLUTION)-1;// 16383// I2C (ADS1115)#defineI2C_SDA9#defineI2C_SCL10#defineLED_BUILTIN13// -------------------- 全局对象 --------------------WiFiClient espClient;PubSubClientclient(espClient);Adafruit_ADS1115 ads;// -------------------- 状态变量 --------------------booldiState[4]={0};boollastDIState[4]={0};// 用于边沿检测booldoState[4]={0};floataiValue[4]={0.0};intpwmPercent[4]={0};// -------------------- 前向声明 --------------------voidsetupWiFi();voidreconnectMQTT();voidcallback(char*topic,byte*payload,unsignedintlength);voidreadInputs();voidpublishStatus();voidhandleControl(JsonDocument&doc);voidsetPWMDuty(intindex,intpercent);// ==================== 初始化 ====================voidsetup(){Serial.begin(115200);delay(100);Serial.println("\n=== ESP32 PLC 4444 启动 ===");// ----- 配置 GPIO -----Serial.println("初始化数字输入 (外部下拉, 高电平有效)");for(inti=0;i<4;i++){pinMode(DI_PINS[i],INPUT);// 外部下拉,无需内部上拉diState[i]=digitalRead(DI_PINS[i]);lastDIState[i]=diState[i];Serial.printf(" DI%d (GPIO%d) 初始状态: %d\n",i+1,DI_PINS[i],diState[i]);}Serial.println("初始化数字输出 (初始LOW)");for(inti=0;i<4;i++){pinMode(DO_PINS[i],OUTPUT);digitalWrite(DO_PINS[i],LOW);doState[i]=0;Serial.printf(" DO%d (GPIO%d) -> LOW\n",i+1,DO_PINS[i]);}Serial.println("初始化 PWM 输出");for(inti=0;i<4;i++){pinMode(PWM_PINS[i],OUTPUT);analogWriteResolution(PWM_PINS[i],PWM_RESOLUTION);analogWriteFrequency(PWM_PINS[i],PWM_FREQ);analogWrite(PWM_PINS[i],0);Serial.printf(" PWM%d (GPIO%d) -> 0%%\n",i+1,PWM_PINS[i]);}pinMode(LED_BUILTIN,OUTPUT);digitalWrite(LED_BUILTIN,LOW);// ----- I2C & ADS1115 -----Wire.begin(I2C_SDA,I2C_SCL);if(!ads.begin()){Serial.println("❌ ADS1115 初始化失败,请检查接线");while(1)delay(1000);}ads.setGain(GAIN_ONE);Serial.println("✅ ADS1115 初始化成功");// ----- WiFi & MQTT -----setupWiFi();client.setServer(mqtt_server,mqtt_port);client.setCallback(callback);Serial.println("✅ 系统就绪\n");}// ==================== WiFi 连接 ====================voidsetupWiFi(){WiFi.mode(WIFI_STA);WiFi.begin(ssid,password);Serial.print("📶 连接 WiFi");intretry=0;while(WiFi.status()!=WL_CONNECTED&&retry<30){delay(500);Serial.print(".");retry++;}if(WiFi.status()==WL_CONNECTED){Serial.println("\n✅ WiFi 已连接,IP: "+WiFi.localIP().toString());}else{Serial.println("\n❌ WiFi 连接失败,请检查 SSID/密码");}}// ==================== MQTT 重连 ====================voidreconnectMQTT(){while(!client.connected()){Serial.print("🔄 尝试连接 MQTT...");if(client.connect("ESP32_PLC_4444")){Serial.println("✅ 已连接");client.subscribe(control_topic);digitalWrite(LED_BUILTIN,HIGH);}else{Serial.print("❌ 失败, rc=");Serial.print(client.state());Serial.println(",5秒后重试");digitalWrite(LED_BUILTIN,LOW);delay(5000);}}}// ==================== MQTT 回调 ====================voidcallback(char*topic,byte*payload,unsignedintlength){Serial.print("📨 收到指令 [");Serial.print(topic);Serial.print("] ");for(unsignedinti=0;i<length;i++)Serial.print((char)payload[i]);Serial.println();DynamicJsonDocumentdoc(256);DeserializationError error=deserializeJson(doc,payload,length);if(error){Serial.print("❌ JSON 解析失败: ");Serial.println(error.c_str());return;}handleControl(doc);}// ==================== 控制处理 ====================voidhandleControl(JsonDocument&doc){boolupdateDO=false,updatePWM=false;if(doc.containsKey("do")){JsonArray arr=doc["do"].as<JsonArray>();if(arr.size()==4){for(inti=0;i<4;i++){doState[i]=arr[i].as<bool>();digitalWrite(DO_PINS[i],doState[i]?HIGH:LOW);}updateDO=true;}else{Serial.println("⚠️ do 数组长度必须为 4");}}if(doc.containsKey("pwm")){JsonArray arr=doc["pwm"].as<JsonArray>();if(arr.size()==4){for(inti=0;i<4;i++){intp=arr[i].as<int>();p=constrain(p,0,100);pwmPercent[i]=p;setPWMDuty(i,p);}updatePWM=true;}else{Serial.println("⚠️ pwm 数组长度必须为 4");}}if(updateDO||updatePWM){publishStatus();// 立即反馈}}// ==================== PWM 设置 ====================voidsetPWMDuty(intindex,intpercent){intraw=map(percent,0,100,0,PWM_MAX_VALUE);analogWrite(PWM_PINS[index],raw);}// ==================== 读取输入 ====================voidreadInputs(){// 数字输入:直接读取,高电平为1,低电平为0for(inti=0;i<4;i++){diState[i]=digitalRead(DI_PINS[i]);}// 模拟量for(inti=0;i<4;i++){int16_traw=ads.readADC_SingleEnded(i);floatvoltage=raw*4.096/32767.0;floatcurrent=voltage/150.0*1000.0;current=constrain(current,0.0,20.0);aiValue[i]=current;}}// ==================== 发布状态 ====================voidpublishStatus(){DynamicJsonDocumentdoc(256);JsonArray di=doc.createNestedArray("di");JsonArray ai=doc.createNestedArray("ai");JsonArray doArr=doc.createNestedArray("do");JsonArray pwmArr=doc.createNestedArray("pwm");for(inti=0;i<4;i++){di.add(diState[i]?1:0);ai.add(aiValue[i]);doArr.add(doState[i]?1:0);pwmArr.add(pwmPercent[i]);}String jsonStr;serializeJson(doc,jsonStr);if(client.publish(status_topic,jsonStr.c_str())){Serial.println("📤 发布状态: "+jsonStr);}else{Serial.println("❌ 发布失败");}}// ==================== 主循环 ====================voidloop(){if(!client.connected()){reconnectMQTT();}client.loop();// 读取所有输入readInputs();// 检测DI边沿变化booldiChanged=false;for(inti=0;i<4;i++){if(diState[i]!=lastDIState[i]){diChanged=true;Serial.printf("[DI变化] GPIO%d %d -> %d\n",DI_PINS[i],lastDIState[i],diState[i]);lastDIState[i]=diState[i];}}// 如果DI有变化,立即发布if(diChanged){publishStatus();}// 每秒定时发布全量状态(确保模拟量定期上报)staticunsignedlonglastPublish=0;if(millis()-lastPublish>=1000){lastPublish=millis();publishStatus();}delay(10);// 微小延时,减轻CPU负载}

表示正在运行的状态

3.在电脑端查看

在电脑端查看:使用MQTTX
https://mqttx.app/zh/web

http://www.jsqmd.com/news/1133613/

相关文章:

  • 如何快速入门openEuler yocto-poky:10步搭建你的第一个嵌入式系统
  • openstack-sig-tool批量创建软件仓:从CSV文件到PR提交的完整指南
  • 如何通过UOS Libvirt Exporter实现Grafana可视化监控面板:终极指南
  • openeuler/sig-OSCourse完全指南:从入门到精通openEuler操作系统课程
  • 放弃OpenClaw,拥抱Hermes:我的API网关迁移实战
  • 当 ATS 遇上开源:我的简历评分过山车与算法招聘的真相
  • MetaBMC安全机制详解:保护服务器管理控制器的5层防护体系
  • 线上慢SQL优化实战:摄影大赛统计功能性能提升记录
  • 互联网大厂 Java 求职面试:在电商场景下的技术挑战
  • ORB突破策略 Python 回测实战:沪深300期货年化89.8%背后的3个关键参数优化
  • 太丝滑了!本地AI实时语音对话,免费开源、低延迟,支持中文(附完整部署教程)
  • 开源AI Agent框架实战:从选型到生产部署的完整指南
  • GEO系统实战:如何用格子GEO系统解决网站流量下降问题
  • OpenDesign miniprogram社区贡献指南:如何参与openEuler小程序项目开发与维护
  • 蓝队(Blue Team)防护技能详解
  • TensorFlow 2.x 实战:3种模型构建方式对比与Fashion MNIST 95%+准确率实现
  • Hey应用场景解析:从文件处理到网络检索的实用案例
  • 逆向解码Wallpaper Engine:RePKG技术重构PKG提取与TEX格式转换
  • 易信easyMarkets综合评析:服务响应如何影响用户体验
  • mpv:一个纯粹的命令行播放器
  • 一人公司必备AI工具:5分钟把详情页变30条获客笔记
  • OpenMPI子项目kucg:探索可扩展通信框架的终极指南
  • OpenDesign资源库社区协作指南:多人协作的设计资源管理策略
  • 如何拿到你在股市“预存”的百万财富?
  • 高效编制检测计划表 (Inspection Plan Sheet) 的标准化流程与技术要点
  • 【LeetCode: 1301. 最大得分的路径数目 + DP】
  • Google Chrome 偷偷装了4GB AI模型?你的电脑正在被“征用“
  • 当我在 Prompt 里写 if-else:自然语言正在成为新的“胶水语言”
  • 青岛MBR膜清洗测评:沧州晶源亮点多但有短板,适合这类企业
  • SQLite数据库在 chaosArsenal 中的应用:故障记录与状态管理的核心技术