在智能家居快速发展的今天,传统家电的智能化改造成为许多技术爱好者关注的焦点。空调作为家庭能耗主要设备之一,其智能化控制不仅能够提升生活便利性,还能实现能源的有效节约。
目录
(1)项目概述
本项目基于零知ESP8266开发板(ESP-12F模组) 和YS-IR05F红外编解码模块,构建了一套完整的智能空调遥控系统。系统不仅支持通过Web界面远程控制TCL空调的开关和温度调节,还集成了OLED显示屏用于实时状态显示。本项目深入讲解了红外编码的获取方法、ESP8266与红外模块的通信协议、Web服务器搭建以及多外设驱动整合。
(2)项目亮点
>同时提供Web网页控制和OLED本地显示,支持移动端和PC端访问
>详细讲解如何捕获、解析和重发红外编码
>使用串口通信协议与YS-IR05F模块进行数据交互
>采用现代化CSS设计,适配各种屏幕尺寸
(3)项目难点及解决方案
问题分析:不同空调品牌/型号的红外编码需要正确解析才能有效重发
解决方案:使用USB转TTL模块 + STC-ISP软件录制原始红外数据,替换operation.h
中的数组。
一、硬件设计
1.1 硬件清单与选型
组件 | 型号 | 数量 | 选型理由 |
---|---|---|---|
主控制器 | 零知ESP8266(ESP-12F) | 1 | 集成WiFi功能,GPIO丰富,成本低廉 |
红外模块 | YS-IR05F | 1 | 支持学习和发射,兼容多种红外协议 |
OLED显示屏 | SSD1306 0.96寸 | 1 | I2C接口,低功耗,高对比度 |
USB转TTL | CH340G | 1 | 用于红外编码录制和调试 |
杜邦线 | 母对母 | 若干 | 方便连接和调试 |
1.2 接线方案
零知ESP8266(ESP-12F) | SSD1306 OLED显示屏 | YS-IR05F红外模块 |
---|---|---|
3V3 | VCC | 3.3V |
GND | GND | GND |
D4(软串口RX) | / | TXD |
D5(软串口TX) | / | RXD |
SCL | SCL | / |
SDA | SDA | / |
🔌 注意:YS-IR05F的KEY引脚可不接,我们使用串口指令进入学习模式。
1.3 详细接线图
1.4 接线实物图
ESP8266与YS-IR05F通过杜邦线连接,OLED显示屏通过I2C连接。
二、软件设计
2.1 所需库依赖
Adafruit SSD1306:用于OLED显示
Adafruit GFX Library:图形库依赖
ESPAsyncWebServer:异步Web服务器库
SoftwareSerial:软件模拟串口依赖
2.2 初始化框架
#include "operation.h"
#include "ESP8266WiFi.h"
#include "SoftwareSerial.h"
#include <ESPAsyncWebServer.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// 创建软件串口对象,假设使用GPIO4(RX)和GPIO5(TX)
SoftwareSerial mySerial(D4, D5); // RX, TX
WiFiServer wifi_server(80);
String status = "空调关闭"; //默认状态
String statu = "Pausing"; //默认状态
int temperature = 20;
String header;
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
//配置自己的WIFI名称和密码
const char* ssid = "";
const char* password = "";
//读取JSON
String val = "";
void setup() {
Serial.begin(115200);
mySerial.begin(9600); // 初始化软件串口,波特率9600
Wire.begin(); // SDA, SCL
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(WHITE);
oled.setCursor(0, 0);
oled.println("Starting...");
oled.display();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
oled.print(".");
oled.display();
}
Serial.println(WiFi.localIP());
oled.clearDisplay();
oled.setCursor(0, 0);
oled.println("IP: " + WiFi.localIP().toString());
oled.display();
wifi_server.begin();
Serial.println("红外控制就绪,使用软件串口通信");
}
库文件引用、变量参数及设备初始化
2.3 温度设置及展示
void set_TCL(int temperature) {
switch (temperature) {
case 16: mySerial.write(cold_16, 236); break;
case 17: mySerial.write(cold_17, 236); break;
case 18: mySerial.write(cold_18, 236); break;
case 19: mySerial.write(cold_19, 236); break;
case 20: mySerial.write(cold_20, 236); break;
case 21: mySerial.write(cold_21, 236); break;
case 22: mySerial.write(cold_22, 236); break;
case 23: mySerial.write(cold_23, 236); break;
case 24: mySerial.write(cold_24, 236); break;
case 25: mySerial.write(cold_25, 236); break;
case 26: mySerial.write(cold_26, 236); break;
case 27: mySerial.write(cold_27, 236); break;
case 28: mySerial.write(cold_28, 236); break;
case 29: mySerial.write(cold_29, 236); break;
case 30: mySerial.write(cold_30, 236); break;
default:;
}
// 更新OLED显示
oled.clearDisplay();
oled.setCursor(0, 3);
oled.println("TCL AC Control");
oled.println(" ");
oled.println("Status: " + statu);
oled.println("Temp : " + String(temperature) + " C");
oled.display();
}
2.4 Web服务器实现
void loop() {
WiFiClient client = wifi_server.available();
if (client) {
String currentLine = "";
while (client.connected()) {
if (client.available()) {
char c = client.read();
header += c;
if (c == '\n') {
if (currentLine.length() == 0) {
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
if (header.indexOf("GET /TCL/on") >= 0) {
Serial.println("空调开启");
mySerial.write(on, 238);
status = "空调开启";
statu = "Running";
delay(1000);
temperature = 20;
mySerial.write(cold_20, 236);
// 更新OLED显示
oled.clearDisplay();
oled.setCursor(0, 3);
oled.println("TCL AC Control");
oled.println(" ");
oled.println("Status: " + statu);
oled.println("Temp : " + String(temperature) + " C");
oled.display();
}
if (header.indexOf("GET /TCL/off") >= 0) {
Serial.println("空调关闭");
mySerial.write(off, 236);
status = "空调关闭";
statu = "Pausing";
oled.clearDisplay();
}
if (header.indexOf("GET /TCL/descend") >= 0) {
if (temperature > 16) temperature -= 1;
Serial.print("设置空调温度为:");
Serial.println(temperature);
set_TCL(temperature);
}
if (header.indexOf("GET /TCL/ascend") >= 0) {
if (temperature < 30) temperature += 1;
Serial.print("设置空调温度为:");
Serial.println(temperature);
set_TCL(temperature);
}
// 网页界面代码保持不变
client.println("<!DOCTYPE html><html lang='zh-CN'>");
client.println("<head>");
client.println("<meta charset='UTF-8'>");
client.println("<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>");
client.println("<title>TCL空调控制</title>");
client.println("<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css'>");
client.println("<style>");
client.println("* { margin: 0; padding: 0; box-sizing: border-box; }");
client.println("body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d); height: 100vh; display: flex; justify-content: center; align-items: center; color: #fff; }");
client.println(".container { background: rgba(0, 0, 0, 0.7); border-radius: 20px; padding: 30px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); max-width: 400px; width: 90%; text-align: center; }");
client.println(".header { margin-bottom: 20px; }");
client.println(".header h1 { font-size: 28px; margin-bottom: 5px; }");
client.println(".status { font-size: 18px; margin: 10px 0; }");
client.println(".status span { color: #4ECDC4; font-weight: bold; }");
client.println(".temp-display { background: rgba(255, 255, 255, 0.1); border-radius: 50%; width: 180px; height: 180px; margin: 20px auto; display: flex; flex-direction: column; justify-content: center; align-items: center; border: 5px solid #4ECDC4; }");
client.println(".temperature { font-size: 48px; font-weight: bold; }");
client.println(".unit { font-size: 24px; margin-top: 5px; }");
client.println(".controls { display: flex; justify-content: space-between; margin: 20px 0; }");
client.println(".btn { background: #4ECDC4; border: none; border-radius: 50%; width: 60px; height: 60px; color: white; font-size: 24px; cursor: pointer; transition: all 0.3s; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); display: flex; justify-content: center; align-items: center; }");
client.println(".btn:hover { background: #2a8c85; transform: translateY(-3px); }");
client.println(".btn:active { transform: translateY(1px); }");
client.println(".power-btns { display: flex; justify-content: space-around; margin-top: 20px; }");
client.println(".power-btn { padding: 12px 25px; border: none; border-radius: 30px; font-size: 16px; font-weight: bold; cursor: pointer; transition: all 0.3s; }");
client.println(".power-on { background: linear-gradient(to right, #00b09b, #96c93d); color: white; }");
client.println(".power-off { background: linear-gradient(to right, #ff416c, #ff4b2b); color: white; }");
client.println(".power-btn:hover { opacity: 0.9; transform: translateY(-2px); }");
client.println("@media (max-width: 480px) { .container { padding: 20px; } .temp-display { width: 150px; height: 150px; } .temperature { font-size: 40px; } }");
client.println("</style>");
client.println("</head>");
client.println("<body>");
client.println("<div class='container'>");
client.println("<div class='header'>");
client.println("<h1><i class='fas fa-wind'></i> TCL空调控制</h1>");
client.println("<div class='status'>状态: <span>" + status + "</span></div>");
client.println("</div>");
client.println("<div class='temp-display'>");
client.println("<div class='temperature'>" + String(temperature) + "</div>");
client.println("<div class='unit'>°C</div>");
client.println("</div>");
client.println("<div class='controls'>");
client.println("<a href='/TCL/descend' class='btn'><i class='fas fa-minus'></i></a>");
client.println("<a href='/TCL/ascend' class='btn'><i class='fas fa-plus'></i></a>");
client.println("</div>");
client.println("<div class='power-btns'>");
client.println("<a href='/TCL/on' class='power-btn power-on'><i class='fas fa-power-off'></i> 开启</a>");
client.println("<a href='/TCL/off' class='power-btn power-off'><i class='fas fa-power-off'></i> 关闭</a>");
client.println("</div>");
client.println("</div>");
client.println("</body>");
client.println("</html>");
client.println();
break;
} else {
currentLine = "";
}
} else if (c != '\r') {
currentLine += c;
}
}
}
header = "";
client.stop();
// Serial.println("");
}
}
发送ESP8266红外控制空调的静态网页页面
2.5 编码库详解
#ifndef OPERATION_H
#define OPERATION_H
#include <Arduino.h>
// TCL空调红外编码数据
// 注意:这些编码需要根据您的具体空调型号进行录制和替换
const uint8_t on[] = { 0xFD, 0xFD, 0x30, 0x03, 0x79, 0xE3, 0x00, 0x34, 0x5F, 0x00, 0xC1, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x0B, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x12, 0x22, 0x12, 0x21, 0x12, 0x12, 0x21, 0x12, 0x11, 0x22, 0x12, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x12, 0x21, 0x12, 0x22, 0x22, 0x21, 0x11, 0x12, 0x22, 0x21, 0x12, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x12, 0x12, 0x21, 0x23, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x76, 0x3E, 0x15, 0xDF, 0xDF};
const uint8_t off[] = { 0xFD, 0xFD, 0x30, 0x03, 0x79, 0xE3, ... , 0xDF, 0xDF};
//制冷模式温度设置(16-30度)
const uint8_t cold_16[] = { 0xFD, 0xFD, 0x30, 0x03, 0x79, 0xE3, ... , 0xDF, 0xDF};
//其他设置编码省略
#endif
🔧 如何获取这些数据?
使用USB转TTL连接YS-IR05F,按下KEY键进入学习模式,用遥控器对准发射头按下按键,STC-ISP串口助手会显示236字节的16进制数据,复制并替换相应数组即可。
数据格式转换示例
(1)原始串口数据:
FD FD 30 03 79 E3 ... DF DF
(2)转换为C数组:
const uint8_t cool_24[] PROGMEM = {
0xFD, 0xFD, 0x30, 0x03, 0x79, 0xE3, ... , 0xDF, 0xDF };
三、操作过程及展示
3.1 红外编码录制与处理
(1)硬件连接
使用USB转TTL模块连接YS-IR05F
VCC接3.3V,GND接GND,TXD接RXD,RXD接TXD
连接红外接收头到YS-IR05F的IR_IN接口
(2)软件配置
>打开STC-ISP软件或其他串口调试工具
>选择正确的COM口,设置波特率为9600,数据位8,停止位1,无校验位
>选择"十六进制显示"模式
接收缓冲区接收236个字节红外编码,将原始串口数据转换为C数组格式后,替换operation.h库文件中相关操作的对应数组
3.2 系统搭建与调试
(1)软件烧录
修改代码中的WiFi配置,选择正确的开发板和端口,编译并上传代码
(2)系统测试
观察OLED显示的系统状态,打开浏览器访问ESP8266的IP地址,测试各项控制功能
3.3 效果展示
(1) Web控制界面
网页控制空调开启后设置初始温度为20℃的页面
(2) OLED显示效果
TCL AC Control
Status: Running
Temp : 20℃
3.4 视频操作展示
ESP8266驱动YS-IR05F红外控制空调
网页控制ESP8266红外发送开启空调、调节温度和关闭空调等操作指令
四、YS-IR05F红外模块通信协议
4.1 数据包格式
模块使用固定的串口通信协议:
波特率:9600bps、数据位:8位、停止位:1位、校验位:无
数据包格式:
[起始码] [起始码] [命令码] [数据段] [结束码][结束码]
0xFD 0xFD 0x30 228字节 0xDF 0xDF
4.2 指令集说明
>学习指令:0xFD 0xFD 0x30 0x03 + 228字节任意数据 + 0xDF 0xDF
>发射指令:直接发送236字节红外数据
4.3 工作原理
YS-IR05F采用高性能红外处理芯片,能够接收、解析和发射红外信号。其工作流程如下:
(1)接收模式:红外接收头将38KHz的调制信号转换为电信号,经过放大、滤波和解调后,得到原始数字信号
(2)学习模式:模块记录原始波形的时序信息,转换为236字节的数据包
(3)发射模式:将数据包还原为红外波形,通过发射管发出
五、常见问题解答
Q1:红外编码录制不成功怎么办?
A:可能原因及解决方案:
距离太近或太远,保持50cm左右距离
环境光干扰,避免在强光环境下录制
遥控器电池电量不足,更换电池
串口设置错误,确认波特率为9600,十六进制显示
Q2:网页控制无响应?
A:排查步骤:
重启ESP8266,检查OLED显示的IP地址是否正确
确认设备与手机/电脑在同一局域网
检查防火墙设置,是否阻止了局域网访问
Q3:红外控制距离短?
A:增强方法:
使用多个红外发射管并联,增加发射功率
调整发射管角度,对准空调接收器
检查电源供电能力,确保工作电压稳定
项目资源:
YS-IR05F使用手册、串口助手、源码下载链接: ESP8266红外控制
本项目成功实现了一套基于ESP8266和YS-IR05F的智能空调控制系统。如有疑问或建议,欢迎在评论区留言讨论!
✔零知IDE 是一个真正属于国人自己的开源软件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!
✔访问零知实验室,获取更多实战项目和教程资源吧!