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
