ESP32+Mqtt+Node.js+Vue3 做工控界面
文章目录1.主机安装 mosquitto2.EPS32端的代码3.在电脑端查看1.主机安装 mosquitto作为mqtt的服务端转发消息https://mosquitto.org/download/2.EPS32端的代码注意配置WIFI mqtt_server 是安装了mosquitto同局域网下的主机ip#includeWiFi.h#includePubSubClient.h#includeAdafruit_ADS1X15.h#includeWire.h#includeArduinoJson.h// -------------------- 用户配置必改 --------------------constchar*ssidTSK;constchar*passwordtsk_251010;constchar*mqtt_server192.168.234.34;constintmqtt_port1883;// -------------------- MQTT 主题 --------------------constchar*status_topicesp32/status;constchar*control_topicesp32/control;// -------------------- 引脚定义 --------------------// 数字输入 (外部下拉高电平有效)constintDI_PINS[4]{40,39,38,37};// 数字输出constintDO_PINS[4]{7,15,16,17};// PWM 输出constintPWM_PINS[4]{47,21,20,19};constintPWM_FREQ1000;constintPWM_RESOLUTION14;constintPWM_MAX_VALUE(1PWM_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(JsonDocumentdoc);voidsetPWMDuty(intindex,intpercent);// 初始化 voidsetup(){Serial.begin(115200);delay(100);Serial.println(\n ESP32 PLC 4444 启动 );// ----- 配置 GPIO -----Serial.println(初始化数字输入 (外部下拉, 高电平有效));for(inti0;i4;i){pinMode(DI_PINS[i],INPUT);// 外部下拉无需内部上拉diState[i]digitalRead(DI_PINS[i]);lastDIState[i]diState[i];Serial.printf( DI%d (GPIO%d) 初始状态: %d\n,i1,DI_PINS[i],diState[i]);}Serial.println(初始化数字输出 (初始LOW));for(inti0;i4;i){pinMode(DO_PINS[i],OUTPUT);digitalWrite(DO_PINS[i],LOW);doState[i]0;Serial.printf( DO%d (GPIO%d) - LOW\n,i1,DO_PINS[i]);}Serial.println(初始化 PWM 输出);for(inti0;i4;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,i1,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);intretry0;while(WiFi.status()!WL_CONNECTEDretry30){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(unsignedinti0;ilength;i)Serial.print((char)payload[i]);Serial.println();DynamicJsonDocumentdoc(256);DeserializationError errordeserializeJson(doc,payload,length);if(error){Serial.print(❌ JSON 解析失败: );Serial.println(error.c_str());return;}handleControl(doc);}// 控制处理 voidhandleControl(JsonDocumentdoc){boolupdateDOfalse,updatePWMfalse;if(doc.containsKey(do)){JsonArray arrdoc[do].asJsonArray();if(arr.size()4){for(inti0;i4;i){doState[i]arr[i].asbool();digitalWrite(DO_PINS[i],doState[i]?HIGH:LOW);}updateDOtrue;}else{Serial.println(⚠️ do 数组长度必须为 4);}}if(doc.containsKey(pwm)){JsonArray arrdoc[pwm].asJsonArray();if(arr.size()4){for(inti0;i4;i){intparr[i].asint();pconstrain(p,0,100);pwmPercent[i]p;setPWMDuty(i,p);}updatePWMtrue;}else{Serial.println(⚠️ pwm 数组长度必须为 4);}}if(updateDO||updatePWM){publishStatus();// 立即反馈}}// PWM 设置 voidsetPWMDuty(intindex,intpercent){intrawmap(percent,0,100,0,PWM_MAX_VALUE);analogWrite(PWM_PINS[index],raw);}// 读取输入 voidreadInputs(){// 数字输入直接读取高电平为1低电平为0for(inti0;i4;i){diState[i]digitalRead(DI_PINS[i]);}// 模拟量for(inti0;i4;i){int16_trawads.readADC_SingleEnded(i);floatvoltageraw*4.096/32767.0;floatcurrentvoltage/150.0*1000.0;currentconstrain(current,0.0,20.0);aiValue[i]current;}}// 发布状态 voidpublishStatus(){DynamicJsonDocumentdoc(256);JsonArray didoc.createNestedArray(di);JsonArray aidoc.createNestedArray(ai);JsonArray doArrdoc.createNestedArray(do);JsonArray pwmArrdoc.createNestedArray(pwm);for(inti0;i4;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边沿变化booldiChangedfalse;for(inti0;i4;i){if(diState[i]!lastDIState[i]){diChangedtrue;Serial.printf([DI变化] GPIO%d %d - %d\n,DI_PINS[i],lastDIState[i],diState[i]);lastDIState[i]diState[i];}}// 如果DI有变化立即发布if(diChanged){publishStatus();}// 每秒定时发布全量状态确保模拟量定期上报staticunsignedlonglastPublish0;if(millis()-lastPublish1000){lastPublishmillis();publishStatus();}delay(10);// 微小延时减轻CPU负载}表示正在运行的状态3.在电脑端查看在电脑端查看使用MQTTXhttps://mqttx.app/zh/web