智能空调伴侣(美的)

智能空调伴侣(美的)

浮梦 286 2023-08-14

前言

踏上玩硬件的路,是因为我在外地学习的时候,回到家以后开空调,还得等他一会,才能凉快,原本我想自己买一个智能插座远程控制空调的,但是我一看,我滴妈!60多只有一个孔,算了算了,我就想着自己开发一个,去哔哩哔哩上搜索的教程,来源于杰叔叔捣鼓这个UP主。不会的可以找我一起来学习交流,我的QQ:645302680

材料准备

我发现,我要买的东西还挺多,就是烙铁头之类的,成本远远大于智能插座,但仔细一想,只用买这一次,以后直接都是很便宜的开发成本,于是我花了将近170在京东买了一个很全的焊台套装(数显款),然后万用表才14块(能用就行,我们用不到很好的,这种在淘宝上买,能测试个大概电压就OK),下面是我买的东西仅供参考!

材料名称 单价 链接 备注
ESP8266 开发板(CH340)micro口 11.80 淘宝链接 这里一定别买便宜的,那是底座拓展版!我图便宜买错了,买成了拓展板
1W 3W大功率 红外线发射模块 13.00 淘宝链接 他们家发的是源智作的,不是很放心的,直接去官方买源智作的就行,不过这便宜点,买1w的就够了,3w的用不到
1*3p 2.54MM直插单排母黑色(20个) 2.50 淘宝链接 这个买了就行,没啥坑
线仔跳线焊接线 2.80 淘宝链接 这个买了就行,没啥坑

不过啊,我还是推荐新手使用杜邦线,我被烧到手过,350度啊!!!

代码区域

这是我自己写的逻辑,我直接贴代码吧
Arduino IDE中需要烧录的代码

#include <Arduino.h>
#include "IRsendMeidi.h"
#include <IRsend.h>
#include <ESP8266WiFi.h>  
#include <ESP8266WiFiMulti.h>  
#include <ESP8266HTTPClient.h>  
#include <PubSubClient.h>
#include <ArduinoJson.h>
// 在这里的四代表GPIO4,ESP8266的引脚D2代表GPIO4
const uint8_t IR_LED = 4;   //设置发送信号的GPIO引脚号,官方推荐4
IRsendMeidi irsendmeidi(IR_LED);  //声明类对象
//设置两个宏定义用于WiFi名和密码
#define WIFINAME "WiFi名称"  
#define WIFIPW   "WiFi密码" 
const char* mqtt_server = "MQTT服务器";
const int mqtt_port = 1883;
const char* mqtt_username = "MQTT服务器账号";
const char* mqtt_password = "MQTT服务器密码";
const char* mqtt_topic = "订阅的主题";

WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // 定义板载LED灯为输出方式
  Serial.begin(115200);  
  Serial.println("");  
  irsendmeidi.begin_2();   //初始化
  irsendmeidi.setZBPL(40); //设置红外载波频率,单位kHz,不调用此函数则默认38,由于未知原因,我设置为40,示波器测得频率为38左右,当发送信号后没反应时,尝试更改此值。
  irsendmeidi.setCodeTime(500,1600,550,4400,4400,5220); //设置信号的高低电平占比,分别为标记位,1位,0位,前导码低电平,前导码高电平,间隔码高电平
  WiFi.begin(WIFINAME, WIFIPW);  
  Serial.print("Connecting..");  
  while (WiFi.status() != WL_CONNECTED)  
  {  
    delay(500);  
    Serial.print(".");  
  }  
  Serial.println();  
  Serial.print("Connected,IP Address:");  
  Serial.println(WiFi.localIP());
  
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");
    if (client.connect("ESP8266Client", mqtt_username, mqtt_password)) {
      Serial.println("Connected to MQTT");
      client.subscribe(mqtt_topic);
    } else {
      Serial.print("Failed to connect to MQTT, rc=");
      Serial.print(client.state());
      Serial.println(" Retrying in 5 seconds...");
      delay(5000);
    }
  }
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

void reconnect() {
  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");
    if (client.connect("ESP8266Client", mqtt_username, mqtt_password)) {
      Serial.println("Connected to MQTT");
      client.subscribe(mqtt_topic);
    } else {
      Serial.print("Failed to connect to MQTT, rc=");
      Serial.print(client.state());
      Serial.println(" Retrying in 5 seconds...");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Received message: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, payload, length);
  if (error) {
    Serial.print("Failed to parse JSON: ");
    Serial.println(error.c_str());
    return;
  }
  const char* type = doc["type"];
  String types = type;
  // 开关
  const char* power = doc["power"];
  String powers = power;
  // 模式
  const char* model = doc["model"];
  String models = model;
  int modelf = models.toInt();
  // 温度
  const char* temp = doc["temp"];
  String temps = temp;
  float tempf = temps.toFloat();
  Serial.print(tempf);
  // 风速
  const char* fan = doc["fans"];
  String fans = fans;
  int fanf = fans.toInt();
  // 上下扫风
  const char* sx = doc["sx"];
  String sxs = sx;
  int sxf = sxs.toInt();
  // 模式
  const char* zy = doc["zy"];
  String zys = zy;
  int zyf = zys.toInt();
  // 开关空调
  if(types.indexOf("turn")!=-1) {
    if(powers.indexOf("on")!=-1) {
      // 开空调
      // 这里有个诡异的bug,就是开空调一定要搭配模式使用,这个温度设置我不知道是不是必须的,我没测试,但是我知道,这个温度必须带
      irsendmeidi.setPowers(true);
      irsendmeidi.setModes(modelf);  //设置模式
      irsendmeidi.setTemps(tempf);
    }else{
      // 关空调
      irsendmeidi.setPowers(false); //打开空调
    }
  }
  // 设置温度
  if(types.indexOf("settemp") != -1){
      irsendmeidi.setTemps(tempf);
  }
  // 设置模式
  if(types.indexOf("setmodel") != -1){
      irsendmeidi.setModes(modelf);  //设置模式
      irsendmeidi.setTemps(tempf);
  }
  // 设置风速
  if(types.indexOf("setfans") != -1){
      irsendmeidi.setFanSpeeds(fanf);
  }
  // 设置上下扫风
  if(types.indexOf("setsx") != -1){
      irsendmeidi.setFanSpeeds(sxf);
  }
  // 设置左右扫风
  if(types.indexOf("setzy") != -1){
      irsendmeidi.setFanSpeeds(zyf);
  }
}

然后你还需要别人写的库,有人会问:啊?视频中不是只用ESPIRsend就OK了吗?我跟着视频做的,视频中的红外调用能实现,但是我不能,可能是空调不适配他的红外编码,所以无奈,只能用CSDN一位大佬的了,这是他的GitHub,里面有怎么调用的,你可以根据那个大佬的,自己写逻辑进行调用(代码全靠抄有木有啊)!!!
下面是那位大佬的代码

IRsendMeidi.h文件

#include <Arduino.h>
#ifndef  IRSENDMEIDI_H_
#define  IRSENDMEIDI_H_

class IRsendMeidi{
  public:
  void begin_2(); //初始化,放入void setup()中
  explicit IRsendMeidi(uint8_t ir_led);
  void setCodeTime(int marks,int one_spaces,int zero_spaces, int l_marks, int l_spaces, int s_spaces);
  //设置发送码的高低电平时间
  void setTemps(float Temps1);  //设置温度
  void setModes(int Modes1);    //设置模式
  void setFanSpeeds(int FanSpeeds1);   //设置风速
  void setEco(bool Eco);  //开关ECO
  void setPowers(bool Powers);  //开关空调
  void setZBPL(int khz);   //设置载波频率
  void setSwingUD(bool SwingUD);  //开关上下扫风
  void setSwingLR(bool SwingLR);  //开关左右扫风
  void setFZC(bool FZC);   //开关防直吹
  void setTimers(float Timers);  //设置定时
  void Send_Code(uint8_t A, uint8_t B,uint8_t C);  //ABC码发送
};
#endif

IRsendMeidi.cpp

/*
 * 美的空调遥控器RN02S13红外发射控制库,需配合IRremoteESP8266库使用。
 * 可以控制的参数:温度(精确到0.5),模式,风速,开关机,定时,扫风,ECO,防直吹。
 */
#include <Arduino.h>
#include "IRsendMeidi.h"
#include <IRremoteESP8266.h>
#include <IRsend.h>
int ZBPL = 38;         //设置红外发射载波频率默认值,单位kHz
float Temps = 26;      //设置温度默认值,17-30,分辨率0.5
int Modes = 0;         //设置模式默认值,0自动,1制冷,2制热,3抽湿,4送风
int FanSpeeds = 0;     //设置风速默认值,0自动,1为20%,2为40%,3为60%,4为80%,5为100%
bool Temp01 = 0;       //设置默认发射温度小数位,1为0.5,0为0
int Marks = 500;       //标记位时间单位us
int One_Space = 1600;  //1位高电平时间
int Zero_Space = 550;  //0位高电平时间
int L_Mark = 4400;     //引导位低电平时间
int L_Space = 4400;    //引导位高电平时间
int S_Space = 5220;    //间隔位高电平时间
uint8_t D_1 = 0xAB, D_2 = 0x66, D_3 = 0x00, D_4 = 0x00, D_5 = 0x00, D_6 = 0xDC;
uint8_t A,B,C,B_1 = 0xF, B_2, C_1 = 0x1, C_2 = 0xB;
uint8_t kIrLed = 4;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).

IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.

void Lead_Code();       //定义引导码发送函数
void Stop_Code();       //定义分隔码发送函数
void Send_Byte(uint8_t data1, int nbit1, bool msb);   //定义发送原始数据的函数,data1(数据),nbit1(数据二进制位数),msb(数据发送顺序,1为低位先发,0为高位先发)

void Send_Code_S(uint8_t A, uint8_t B, uint8_t C, uint8_t D_1, uint8_t D_2,  uint8_t D_3, uint8_t D_4, uint8_t D_5, uint8_t D_6);
//定时用的数据发送函数,因为定时发送的数据C码的反码位置为固定的11111111,所以引入该函数,C的反码位置为固定的0xFF

void Send_Code_L(uint8_t A, uint8_t B, uint8_t C, uint8_t D_1, uint8_t D_2,  uint8_t D_3, uint8_t D_4, uint8_t D_5, uint8_t D_6); 
//正常的发送数据的函数,用来发送长码

void if_D6(int fs);  //计算风速数据的函数,因为风速数据的D_6和温度是否有0.5位相关联。

void Send_Meidi(bool Code_State);  //发送长码数据的函数,1为正常发送,0为C反码固定为0xFF的发送。

void IRsendMeidi::begin_2(){   //初始化IRsend.begin的函数,需写入到主程序的void setup()中。
  irsend.begin();
}

void IRsendMeidi::setCodeTime(int  marks,int one_spaces,int zero_spaces, int l_marks, int l_spaces, int s_spaces){
   Marks = marks;
   One_Space = one_spaces;
   Zero_Space = zero_spaces;
   L_Mark = l_marks;
   L_Space = l_spaces;
   S_Space = s_spaces;
}


IRsendMeidi::IRsendMeidi(uint8_t ir_led){  //返回发射信号的引脚

  kIrLed = ir_led;
}

void IRsendMeidi::setZBPL(int khz){ //定义红外发射的载波频率

  ZBPL = khz;
}

void IRsendMeidi::setTemps(float Temps1){  //设置空调温度

  Temps = Temps1;
  int temp2 = floor(Temps);
  float temp_f = Temps - temp2;
  if(temp_f == 0.5){
	  
    Temp01 = 1;
    D_3 = 0x04;
  
  }
  else {
	  
    Temp01 = 0;
    D_3 = 0x00;
  }
  if_D6(FanSpeeds);
  switch(temp2){
    case 17: C_2 = 0x0; break;
    case 18: C_2 = 0x8; break;
    case 19: C_2 = 0xC; break;
    case 20: C_2 = 0x4; break;
    case 21: C_2 = 0x6; break;
    case 22: C_2 = 0xE; break;
    case 23: C_2 = 0xA; break;
    case 24: C_2 = 0x2; break;
    case 25: C_2 = 0x3; break;
    case 26: C_2 = 0xB; break;
    case 27: C_2 = 0x9; break;
    case 28: C_2 = 0x1; break;
    case 29: C_2 = 0x5; break;
    case 30: C_2 = 0xD; break;
  }
  Send_Meidi(1);
}



void IRsendMeidi::setModes(int Modes1){  //设置空调模式。
  Modes = Modes1;
  B_1 = 0xF;
  switch(Modes){
    case 0: C_1 = 0x1; B_2 = 0x8; break; //auto
    case 1: C_1 = 0x0; B_2 = 0xB; break; //cool
    case 2: C_1 = 0x3; B_2 = 0xB; break; //hot
    case 3: C_1 = 0x2; B_2 = 0x8; break; //choushi
    case 4: C_1 = 0x2; B_2 = 0xB; C_2 = 0x7; break; //songfeng
  }
  Send_Meidi(1);
}

void IRsendMeidi::setFanSpeeds(int FanSpeeds1){  //设置空调风速。

  FanSpeeds = FanSpeeds1;
  B_1 = 0xF;
  if_D6(FanSpeeds);
  Send_Meidi(1);
}


void IRsendMeidi::setEco(bool Eco){    //开关ECO模式
  if(Eco == 1){
  Send_Code(0xB9, 0xAF ,0x24);
  }
  if(Eco == 0){
  Send_Code(0xB9, 0xAF ,0xA4);
  }
}

void IRsendMeidi::setPowers(bool Powers){   //开关空调

  if(Powers == 1){
    B_1 = 0xF;
        setTemps(Temps);    
  }
  else{
  Send_Code(0XB2, 0xDE, 0x07); 
  }
}

void IRsendMeidi::setSwingUD(bool SwingUD){  //开关上下扫风

  if(SwingUD == 1){
    Send_Code(0xB9, 0xAF ,0x20);
  }
  if(SwingUD == 0){
    Send_Code(0xB9, 0xAF ,0xA0);
  }
}

void IRsendMeidi::setSwingLR(bool SwingLR){   //开关左右扫风

  if(SwingLR == 1){
    Send_Code(0xB9, 0xAF ,0xE0);
  }
  if(SwingLR == 0){
    Send_Code(0xB9, 0xAF ,0x10);
  }
}



void IRsendMeidi::setFZC(bool FZC){    //开关防直吹

  if(FZC == 1){
    Send_Code(0xB9, 0xAF ,0xDA);
  }
  if(FZC == 0){
    Send_Code(0xB9, 0xAF ,0x3A);
  }
}


void IRsendMeidi::setTimers(float Timers){    //设置定时

  uint8_t C_1_t = C_1;
  int Timers1 = floor(Timers);
  float Timers_f = Timers - Timers1;
  switch(Timers1){
    case 0: B_1 = 0x8; B_2 = 0x5; C_1 = 0x0; break;
    case 1: if(Timers_f == 0){
    B_1 = 0xC; B_2 = 0x5; C_1 = 0x0;}
  else {
    B_1 = 0xA; B_2 = 0x5; C_1 = 0x0;}
  break;
    case 2: if(Timers_f == 0){
    B_1 = 0xE; B_2 = 0x5; C_1 = 0x0;}
  else {
    B_1 = 0x9; B_2 = 0x5; C_1 = 0x0;}
  break;
   case 3: if(Timers_f == 0){
    B_1 = 0xD; B_2 = 0x5; C_1 = 0x0;}
  else {
    B_1 = 0xB; B_2 = 0x5; C_1 = 0x0;}
  break;
   case 4: if(Timers_f == 0){
    B_1 = 0xF; B_2 = 0x5; C_1 = 0x0;}
  else {
    B_1 = 0x8; B_2 = 0xD; C_1 = 0x0;}
  break;
   case 5: if(Timers_f == 0){
    B_1 = 0xC; B_2 = 0xD; C_1 = 0x0;}
  else {
    B_1 = 0xA; B_2 = 0xD; C_1 = 0x0;}
  break;
   case 6: if(Timers_f == 0){
    B_1 = 0xE; B_2 = 0xD; C_1 = 0x0;}
  else {
    B_1 = 0x9; B_2 = 0xD; C_1 = 0x0;}
  break;
   case 7: if(Timers_f == 0){
    B_1 = 0xD; B_2 = 0xD; C_1 = 0x0;}
  else {
    B_1 = 0xB; B_2 = 0xD; C_1 = 0x0;}
  break;
   case 8: if(Timers_f == 0){
    B_1 = 0xF; B_2 = 0xD; C_1 = 0x0;}
  else {
    B_1 = 0x8; B_2 = 0x5; C_1 = 0x8;}
  break;
   case 9: if(Timers_f == 0){
    B_1 = 0xC; B_2 = 0x5; C_1 = 0x8;}
  else {
    B_1 = 0xA; B_2 = 0x5; C_1 = 0x8;}
  break;
   case 10: B_1 = 0xE; B_2 = 0x5; C_1 = 0x8; break;
   case 11: B_1 = 0xD; B_2 = 0x5; C_1 = 0x8; break;
   case 12: B_1 = 0xF; B_2 = 0x5; C_1 = 0x8; break;
   case 13: B_1 = 0xC; B_2 = 0xD; C_1 = 0x8; break;
   case 14: B_1 = 0xE; B_2 = 0xD; C_1 = 0x8; break;
   case 15: B_1 = 0xD; B_2 = 0xD; C_1 = 0x8; break;
   case 16: B_1 = 0xF; B_2 = 0xD; C_1 = 0x8; break;
   case 17: B_1 = 0xC; B_2 = 0x5; C_1 = 0x4; break;
   case 18: B_1 = 0xE; B_2 = 0x5; C_1 = 0x4; break;
   case 19: B_1 = 0xD; B_2 = 0x5; C_1 = 0x4; break;
   case 20: B_1 = 0xF; B_2 = 0x5; C_1 = 0x4; break;
   case 21: B_1 = 0xC; B_2 = 0xD; C_1 = 0x4; break;
   case 22: B_1 = 0xE; B_2 = 0xD; C_1 = 0x4; break;
   case 23: B_1 = 0xD; B_2 = 0xD; C_1 = 0x4; break;
   case 24: B_1 = 0xF; B_2 = 0xD; C_1 = 0x4; break;
  }
  Send_Meidi(0);
  C_1 = C_1_t;

}

void IRsendMeidi::Send_Code(uint8_t AC, uint8_t BC,uint8_t CC){  //发送ABC码的函数

  Lead_Code();
  Send_Byte(AC,8,1);
  Send_Byte(~AC,8,1);
  Send_Byte(BC,8,0);
  Send_Byte(~BC,8,0);
  Send_Byte(CC,8,0);
  Send_Byte(~CC,8,0);
  Stop_Code();
  Lead_Code();
  Send_Byte(AC,8,1);
  Send_Byte(~AC,8,1);
  Send_Byte(BC,8,0);
  Send_Byte(~BC,8,0);
  Send_Byte(CC,8,0);
  Send_Byte(~CC,8,0);
  Stop_Code();
}


void Send_Code_S(uint8_t AC, uint8_t BC,uint8_t CC,uint8_t D1C,uint8_t D2C, uint8_t D3C,uint8_t D4C,uint8_t D5C,uint8_t D6C){

  Lead_Code();
  Send_Byte(AC,8,1);
  Send_Byte(~AC,8,1);
  Send_Byte(BC,8,0);
  Send_Byte(~BC,8,0);
  Send_Byte(CC,8,0);
  Send_Byte(0xFF,8,0);
  Stop_Code();
  Lead_Code();
  Send_Byte(AC,8,1);
  Send_Byte(~AC,8,1);
  Send_Byte(BC,8,0);
  Send_Byte(~BC,8,0);
  Send_Byte(CC,8,0);
  Send_Byte(0xFF,8,0);
  Stop_Code();
  Lead_Code();
  Send_Byte(D1C,8,0);
  Send_Byte(D2C,8,0);
  Send_Byte(D3C,8,0);
  Send_Byte(D4C,8,0);
  Send_Byte(D5C,8,0);
  Send_Byte(D6C,8,0);
  Stop_Code();
}



void Send_Code_L(uint8_t AC, uint8_t BC,uint8_t CC,uint8_t D1C,uint8_t D2C, uint8_t D3C,uint8_t D4C,uint8_t D5C,uint8_t D6C){

  Lead_Code();
  Send_Byte(AC,8,1);
  Send_Byte(~AC,8,1);
  Send_Byte(BC,8,0);
  Send_Byte(~BC,8,0);
  Send_Byte(CC,8,0);
  Send_Byte(~CC,8,0);
  Stop_Code();
  Lead_Code();
  Send_Byte(AC,8,1);
  Send_Byte(~AC,8,1);
  Send_Byte(BC,8,0);
  Send_Byte(~BC,8,0);
  Send_Byte(CC,8,0);
  Send_Byte(~CC,8,0);
  Stop_Code();
  Lead_Code();
  Send_Byte(D1C,8,0);
  Send_Byte(D2C,8,0);
  Send_Byte(D3C,8,0);
  Send_Byte(D4C,8,0);
  Send_Byte(D5C,8,0);
  Send_Byte(D6C,8,0);
  Stop_Code();
}

void Send_Meidi(bool Code_State){   //发送长码数据的函数,1为正常发送,0为C反码固定为0xFF的发送。

  A = 0xB2;
  B = (B_1<<4) + B_2;
  C = (C_1<<4) + C_2;
  
  if(Code_State == 1){
    Send_Code_L( A, B, C, D_1, D_2, D_3, D_4, D_5, D_6);
   
  }
  if(Code_State == 0){
    Send_Code_S(A,  B,  C, D_1, D_2, D_3, D_4, D_5, D_6);
  }
}
void Lead_Code(){  //引导码函数定义

  irsend.enableIROut(ZBPL);
  irsend.sendData(L_Mark,L_Space,450,450,1,1,1);
}

void Stop_Code(){   //间隔码函数定义

  irsend.enableIROut(ZBPL);
  irsend.sendData(450,450,Marks,S_Space,0,1,1);
}

void Send_Byte(uint8_t data1, int nbit1, bool msb){  //数据发送函数定义

  irsend.enableIROut(ZBPL);
  irsend.sendData(Marks,One_Space,Marks,Zero_Space,data1,nbit1,msb);  //使用IRsend库里的数据发送函数,具体使用方法可以查看IRsend库里的注释
} 

void if_D6(int fs){  //计算风速数据的函数

  switch(fs){
    case 0: B_2 = 0xD; D_2 = 0x66; if(Temp01 == 0){
      D_6 = 0xDC;}
      else D_6 = 0xDA;
      break;                  //auto
    case 1: B_2 = 0xF; D_2 = 0x28; if(Temp01 == 0){
      D_6 = 0x97;}
      else D_6 = 0x90;
      break; //20
    case 2: B_2 = 0x9; D_2 = 0x14; if(Temp01 == 0){
      D_6 = 0x97;}
      else D_6 = 0xB8;
      break; //40
    case 3: B_2 = 0xA; D_2 = 0x3C; if(Temp01 == 0){
      D_6 = 0x88;}
      else D_6 = 0x8C;
      break; //60
    case 4: B_2 = 0xC; D_2 = 0x0A; if(Temp01 == 0){
      D_6 = 0xA4;}
      else D_6 = 0xA2;
      break; //80
    case 5: B_2 = 0xC; D_2 = 0x26; if(Temp01 == 0){
      D_6 = 0xDC;}
      else D_6 = 0xDA;
      break; //100
  }
}

没错,你得复制粘贴,这两个文件的代码,做成文件,然后进行保存,打包成zip包,再去Arduino IDE软件上面的头部中找到项目(Sketch)->导入库(Include Library)->添加.zip库(Add .zip Library),添加你刚刚打包好的文件,就OK啦,这样子,你的智能空调就完成百分之八十了,还有百分之20是前端页面,废话不多说,我直接贴代码,需要修改的行数是78行还有313行316行,订阅地址改下,这是Vue代码哟!

<template>
  <div id="app">
    <div style="position: fixed;right: 5px;top: 5px;cursor: pointer;" @click="checkRoom">
      <span style="color: red;font-weight: 900;">{{ server }}<br />
        <span>当前房间:{{ nowhome?"其他房间":"我的房间" }}</span>
      </span>
      <span>
      </span>
    </div>
    <!-- 温度显示 -->
    <div class="wdxs">
      <div style="position: relative;" @click="setKuaiTemp">
        <span>{{ temp }}<sup>°C</sup></span>
      </div>
      <div v-if="turn">
        <span v-if="model == 0" style="font-size: 16px">自动模式</span>
        <span v-if="model == 1" style="font-size: 16px">制冷模式</span>
        <span v-if="model == 2" style="font-size: 16px">制热模式</span>
        <span v-if="model == 3" style="font-size: 16px">抽湿模式</span>
        <span v-if="model == 4" style="font-size: 16px">送风模式</span>
      </div>
      <div v-if="!turn">关闭</div>
    </div>
    <!-- 控制开关,空调加减 -->
    <div style="display: flex;justify-content: center;margin-top: 35px;">
      <div class="turnDiv" @click="setTemp('plus')" :class="{isActive: !turn}">
        <img src="./assets/plus.png" alt="" width="45">
      </div>
      <div @click="turnOnOff" class="turnDiv">
        <img src="./assets/off.png" alt="" width="35" v-if="!turn">
        <img src="./assets/on.png" alt="" width="35" v-if="turn">
      </div>
      <div class="turnDiv" @click="setTemp('jian')" :class="{isActive: !turn}">
        <img src="./assets/jian.png" alt="" width="40">
      </div>
    </div>
    <!-- 模式  风速 -->
    <div style="display: flex;justify-content: center;margin-top: 35px;">
      <div class="turnDiv" :class="{isActive: !turn}" style="margin: 0 60px;" @click="setModel">
        <img src="./assets/zidong.png" alt="" width="45" v-if="model == 0">
        <img src="./assets/cold.png" alt="" width="45" v-if="model == 1">
        <img src="./assets/hot.png" alt="" width="45" v-if="model == 2">
        <img src="./assets/choushi.png" alt="" width="45" v-if="model == 3">
        <img src="./assets/feng.png" alt="" width="45" v-if="model == 4">
      </div>
      <div class="turnDiv" :class="{isActive: !turn}" @click="setFans">
        <span v-if="fans == 0" style="font-weight: 900;font-size: 20px;">风速</span>
        <img src="./assets/xinhao1.png" alt="" width="45" v-if="fans == 1">
        <img src="./assets/xinhao2.png" alt="" width="45" v-if="fans == 2">
        <img src="./assets/xinhao3.png" alt="" width="45" v-if="fans == 3">
        <img src="./assets/xinhao4.png" alt="" width="45" v-if="fans == 4">
        <img src="./assets/xinhao5.png" alt="" width="45" v-if="fans == 5">
      </div>
    </div>
    <!-- 上下左右扫风 -->
    <div style="display: flex;justify-content: center;margin-top: 35px;">
      <div class="turnDiv" :class="{isActive: !turn}" style="margin: 0 60px;" @click="setSaofeng('sx')">
        <img src="./assets/sx.png" alt="" width="45" v-if="sx == 0">
        <img src="./assets/sxac.png" alt="" width="45" v-if="sx == 1">
      </div>
      <div class="turnDiv" :class="{isActive: !turn}" @click="setSaofeng('zy')">
        <img src="./assets/zy.png" alt="" width="45" v-if="zy == 0">
        <img src="./assets/zyac.png" alt="" width="45" v-if="zy == 1">
      </div>
    </div>
  </div>
</template>

<script>
import mqtt from "mqtt";
export default {
  data() {
    return {
      client: "",
      message: "",
      nowhome: localStorage.getItem("nowhome")==0 || localStorage.getItem("nowhome") == null ?0:localStorage.getItem("nowhome"),
      logs: [],
      topic: localStorage.getItem("nowhome")==0 || localStorage.getItem("nowhome") == null ?"myhome/me":"myhome/other",
      server: "正在连接服务器...",
      // 温度
      temp: localStorage.getItem("temp")?parseInt(localStorage.getItem("temp")):26,
      // 开关
      turn: localStorage.getItem("turn")==0 || localStorage.getItem("turn")==null?0:localStorage.getItem("turn"),
      // 模式 0自动,1制冷,2制热,3抽湿,4送风
      model: localStorage.getItem("model")==0 || localStorage.getItem("model") == null ?0:localStorage.getItem("model"),
      fans: localStorage.getItem("fans")==0 || localStorage.getItem("fans") == null ?0:localStorage.getItem("fans"),
      sx: localStorage.getItem("sx")==0 || localStorage.getItem("sx") == null ?0:localStorage.getItem("sx"),
      zy: localStorage.getItem("zy")==0 || localStorage.getItem("zy") == null ?0:localStorage.getItem("zy"),
    };
  },
  mounted() {
    this.initMqtt();
    this.mqttPublish();
    this.mqttReceive();
  },
  methods: {
    /**
     * @name:初始化mqtt
     * @msg:
     * @param {*}
     * @return {*}
     */
    initMqtt() {
      let vm = this;
      let commonApi = "http://服务器地址:8083/mqtt";
      var mqtt = require("mqtt");
      var options = {
        //mqtt客户端的id
        clientId: "mqttjs_" + Math.random().toString(16).substr(2, 8),
        username: 'MQTT服务器账号',
        password: 'MQTT服务器密码',
      };
      vm.client = mqtt.connect(commonApi, options);
      let _this = this;
      this.client.on("connect", function () {
        _this.server = "已连接至服务器!"
        console.log("连接成功....");
      });
      //如果连接错误,打印错误
      vm.client.on("error", function (err) {
        console.log("err=>", err);
        vm.client.end();
      });
    },
    /**
     * @name:发布mqtt消息
     * @msg:
     * @param {*}
     * @return {*}
     */
    mqttPublish(msg) {
      this.client.publish(this.topic, msg);
    },
    /**
     * @name:接收mqtt消息
     * @msg:
     * @param {*}
     * @return {*}
     */
    mqttReceive() {
      let topic = "topic/response"; //要接收的主题
      const vm = this;
      vm.client.subscribe(topic, function (err) {
        if (!err) {
          console.log("subscribe success!");
        } else {
          //打印错误
          console.log("err", err);
        }
      });
      vm.client.on("message", function (topic, message) {
        vm.logs.push(message);
        console.log(message)
        console.log(topic)
      });
    },
    // 开关空调
    turnOnOff() {
      let data = {
        "type": "turn",
        "power": "on",
        "model": this.model.toString(),
        "temp": this.temp.toString()
      }
      if(this.turn) {
        this.turn = 0;
        data.power = "off";
        this.mqttPublish(JSON.stringify(data));
      }else {
        this.turn = 1;
        data.power = "on";
        // 设置温度
        data.temp = this.temp.toString();
        // 发布信息
        this.mqttPublish(JSON.stringify(data));
      }
      localStorage.setItem("turn", this.turn);
    },
    // 快捷设置温度
    setKuaiTemp() {
      if(!this.turn) return;
      let temp = prompt("请输入您需要设置的温度");
      if(!temp) return;
      if(temp > 30 || temp < 17) {
        alert("温度最大30度,最低17度哦");
        return;
      }
      this.temp = temp;
      let data = {
        "type": "settemp",
        "power": "on",
        "model": this.model.toString(),
        "temp": temp.toString(),
      }
      localStorage.setItem("temp", temp);
      this.mqttPublish(JSON.stringify(data));
    },
    // 设置温度
    setTemp(type){
      if(!this.turn) return;
      if(type == "plus") {
        if(this.temp == 30) {
            return;
        }
        this.temp = parseInt(this.temp)+1;
      }
      if(type == "jian") {
        if(this.temp == 17) {
            return;
        }
        this.temp = parseInt(this.temp)-1;
      }
      let data = {
        "type": "settemp",
        "power": "on",
        "model": this.model.toString(),
        "temp": this.temp.toString(),
      }
      localStorage.setItem("temp", this.temp);
      this.mqttPublish(JSON.stringify(data));
    },
    // 设置空调模式
    setModel(){
      if(!this.turn) return;
      let flag = 1;
      if(this.model == "0" && flag){
        this.model = 1;
        flag = 0;
      }
      if(this.model == "1" && flag){
        this.model = 2;
        flag = 0;
      }
      if(this.model == "2" && flag){
        this.model = 3;
        flag = 0;
      }
      if(this.model == "3" && flag){
        this.model = 4;
        flag = 0;
      }
      if(this.model == "4" && flag){
        this.model = 0;
        flag = 0;
      }
      let data = {
        "type": "setmodel",
        "power": "on",
        "model": this.model.toString(),
        "temp": this.temp.toString(),
      }
      localStorage.setItem("model", this.model);
      this.mqttPublish(JSON.stringify(data));
    },
    // 设置风速
    setFans() {
      if(!this.turn) return;
      let flag = 1;
      if(this.fans == "0" && flag){
        this.fans = 1;
        flag = 0;
      }
      if(this.fans == "1" && flag){
        this.fans = 2;
        flag = 0;
      }
      if(this.fans == "2" && flag){
        this.fans = 3;
        flag = 0;
      }
      if(this.fans == "3" && flag){
        this.fans = 4;
        flag = 0;
      }
      if(this.fans == "4" && flag){
        this.fans = 5;
        flag = 0;
      }
      if(this.fans == "5" && flag){
        this.fans = 0;
        flag = 0;
      }
      let data = {
        "type": "setfans",
        "power": "on",
        "fans": this.fans.toString()
      }
      localStorage.getItem("fans", this.fans);
      this.mqttPublish(JSON.stringify(data));
    },
    setSaofeng(type) {
      let data = {
        "type": "setzy",
        "power": "on",
        "sx": this.sx == 1?"1":"0",
        "zy": this.zy == 1?"1":"0"
      }
      if(type == "sx") {
        data.type = "setsx";
        this.sx = this.sx == 1?0:1
        localStorage.getItem("sx", this.sx);
      }
      if(type == "zy") {
        data.type = "setzy";
        this.zy = this.zy == 1?0:1
        localStorage.getItem("zy", this.zy);
      }
      this.mqttPublish(JSON.stringify(data));
    },
    checkRoom() {
      if(this.nowhome) {
        this.nowhome = 0;
        this.topic = "myhome/me";
      }else{
        this.nowhome = 1;
        this.topic = "myhome/other";
      }
      localStorage.setItem("nowhome", this.nowhome);
    }
  },
  destroyed() {
    if (this.client.end) this.client.end();
  },
};
</script>

<style>
  * {
    margin: 0;
    padding: 0;
  }
  html, body {
    width: 100%;
    height: 100%;
    background-color: #f9f9f9c4;
  }
  .wdxs {
    width: 100%;
    padding: 45px 0;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;
  }
  .wdxs span {
    font-weight: 900;
    font-size: 70px;
  }
  .wdxs sup {
    position: absolute;
    top: -2px;
    font-size: 20px;
  }
  .turnDiv {
    width: 75px;
    height: 75px;
    background-color: #fff;
    box-shadow: 0 0 4px 1px #a2d2ff8a;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .turnDiv:nth-child(2) {
    margin: 0 65px;
  }
  .isActive {
    background-color: #e5e5e5;
  }
</style>