
1. IRGree 库概述面向格力空调的嵌入式红外协议实现IRGree 是一个专为 ESP8266 平台设计的轻量级 Arduino C 库其核心目标是实现对格力GREE品牌家用空调设备的完整红外遥控功能。该库并非通用红外协议解析器而是深度适配格力空调私有红外通信协议的工程化实现——它跳过通用载波检测与脉冲学习环节直接基于逆向分析所得的固定时序结构、地址码、命令帧格式及校验逻辑生成符合格力空调接收端严格时序要求的原始红外信号。在嵌入式系统层面IRGree 的价值在于将复杂的红外物理层编码过程封装为简洁的高层 API使开发者无需接触底层定时器配置、PWM 占空比调节或脉冲宽度微秒级精度控制等硬件细节即可完成空调状态的远程设定与控制。其设计哲学体现典型的“嵌入式务实主义”不追求协议兼容性广度而聚焦于特定设备型号的控制可靠性不依赖昂贵仪器验证而通过大量实机测试收敛出稳定参数不提供抽象中间层而以最小内存开销和确定性执行时间服务于资源受限的 ESP8266典型 Flash 4MB / RAM 80KB。该库的工程定位清晰它是连接 Wi-Fi 智能网关如 ESP8266 运行 Web Server 或 MQTT Client与传统红外家电之间的关键协议桥接模块。当上层应用接收到用户通过手机 App 发送的“制冷 26℃、自动风速、上下扫风”指令后IRGree 负责将该语义化指令精确映射为格力空调红外接收芯片所能识别的 32 位或 36 位二进制数据帧并驱动 GPIO 引脚输出经 38kHz 载波调制的方波序列。整个过程在毫秒级内完成满足实时控制需求。2. 格力红外协议逆向分析与 IRGree 实现原理2.1 协议物理层特征格力空调红外遥控器普遍采用 NEC 兼容协议变种但关键参数存在定制化调整载波频率38 kHz ±1 kHz与标准 NEC 一致IRremoteESP8266 库默认支持逻辑‘0’脉冲560 μs 高电平 1690 μs 低电平总宽 ≈2250 μs逻辑‘1’脉冲560 μs 高电平 560 μs 低电平总宽 ≈1120 μs引导码Leader Code9000 μs 高电平 4500 μs 低电平显著长于标准 NEC 的 9000/4500帧间隔Inter-frame Gap100 ms用于区分重复按键IRGree 库本身不直接操作 PWM 或定时器而是完全复用 IRremoteESP8266 库的底层驱动能力。后者通过 ESP8266 的timer1_write()和PIN_FUNC_SELECT()等 SDK 接口精确控制 GPIO 翻转时序确保载波调制精度。IRGree 的核心工作在于协议帧构造——即根据用户输入的 JSON 参数计算并填充符合格力协议规范的数据字段。2.2 数据帧结构解析格力红外帧通常为 32 位或 36 位IRGree 当前实现基于广泛验证的 32 位格式部分机型可能扩展至 36 位后续版本将支持。其结构分解如下MSB 在前字段位宽含义IRGree 映射方式地址码Address16 位固定设备地址格力通用为0x20DF大端硬编码不可配置命令码Command8 位功能指令如开关、模式、温度等由mode,switch,temp等参数动态计算反转地址~Address16 位地址码按位取反用于校验自动计算~0x20DF 0xDFF0反转命令~Command8 位命令码按位取反自动计算校验位Checksum8 位前 4 字节Address Command ~Address ~Command之和的低 8 位自动计算例如JSON{ mode: 0, switch: 1, temp: 16 }对应的命令码计算逻辑为mode0→ 制冷模式 → 基础命令0x10switch1→ 开机 → 置位0x01temp16→ 温度值需映射为16 - 16 0x00格力以 16℃ 为基准0x00 表示 16℃0x01 表示 17℃…组合命令0x10 | 0x01 | (0x00 4)0x11最终 32 位帧为0x20DF 0x11 0xDFF0 0xEE其中0xEE (0x200xDF0x110xDFF00xEE) 0xFF实际计算需按字节累加。2.3 IRGree 的状态机设计IRGree 采用显式状态管理规避隐式状态导致的发送错误。其核心约束“每发送一次数据就必须重新调用setInfo()”源于以下设计考量无内部缓存库不维护上一次成功设置的 JSON 解析结果。setInfo()执行时才进行 JSON 解析、参数校验、帧计算与内存分配。避免陈旧数据若允许复用旧参数当用户仅修改temp而未重设mode时可能因mode参数未更新导致帧错误。内存效率优先ESP8266 RAM 极其宝贵。setInfo()内部使用栈上StaticJsonDocument256来自 ArduinoJson 库解析完成后立即释放不占用全局静态内存。此设计虽增加调用负担却换来确定性的内存行为与零风险的状态一致性是资源受限环境下的典型权衡。3. API 详解与工程化使用指南3.1bool setInfo(char* json)该函数是 IRGree 的唯一配置入口承担 JSON 解析、参数校验、帧生成三重职责。函数签名bool setInfo(char* json);参数说明参数类型必填说明jsonchar*是指向以\0结尾的 JSON 字符串缓冲区。必须注意字符串转义双引号需写为\反斜杠需写为\\。建议使用String对象的.c_str()方法传入或静态字符数组。返回值trueJSON 解析成功所有参数在有效范围内帧计算完成。false解析失败JSON 格式错误、参数越界如temp 16或temp 30、内存不足JSON 解析器分配失败。关键参数校验逻辑源码级实现// 伪代码示意校验流程 if (!root.containsKey(mode) || !root[mode].isint()) return false; int mode root[mode].asint(); if (mode ! 0 mode ! 1) return false; // 仅接受 0(制冷)/1(制热) if (!root.containsKey(temp) || !root[temp].isint()) return false; int temp root[temp].asint(); if (temp 16 || temp 30) return false; // 严格限制 16~30℃ // 其他参数同理校验...工程实践建议避免动态拼接 JSON不要用sprintf()拼接含用户输入的 JSON易引入注入漏洞。应使用 ArduinoJson 的JsonObject构建StaticJsonDocument256 doc; doc[mode] 0; doc[switch] 1; doc[temp] 26; serializeJson(doc, jsonBuffer); // jsonBuffer 为 char[256] setInfo(jsonBuffer);错误处理必做setInfo()失败后禁止调用sendIR()否则发送未定义数据if (!irgree.setInfo(jsonStr)) { Serial.println(IRGree: Invalid JSON or parameter out of range); return; // 退出控制逻辑 } irgree.sendIR(); // 仅在此处安全调用3.2void sendIR()该函数触发红外信号发射是 IRGree 的执行出口。函数签名void sendIR();内部实现逻辑调用IRsend::sendNEC()来自 IRremoteESP8266传入已预计算的 32 位数据与 32 位地址0x20DF。IRsend库负责将 32 位数据按 NEC 时序规则展开为脉冲序列并通过指定 GPIO默认GPIO3可配置输出。发送完毕后IRsend自动进入空闲状态不占用 CPU。重要约束必须在setInfo()成功后调用sendIR()不检查内部状态直接使用上次setInfo()计算的帧数据。若未调用或调用失败将发送垃圾数据。GPIO 引脚固定IRremoteESP8266 默认使用GPIO3RX pin作为红外发射引脚。若需更改须在IRsend初始化时指定IRsend irsend(4); // 使用 GPIO4 // IRGree 需相应修改其内部持有的 irsend 实例典型调用序列// 1. 准备 JSON 字符串注意转义 const char* cmd { \mode\:0, \switch\:1, \wind_speed\:2, \UD_scavenging\:1, \LR_scavenging\:0, \temp\:26 }; // 2. 设置参数 if (irgree.setInfo(const_castchar*(cmd))) { // 3. 发送红外指令 irgree.sendIR(); Serial.println(IR command sent: Cool, ON, 26°C, Wind Speed 2); } else { Serial.println(IR command setup failed); }4. 硬件集成与开发环境配置4.1 硬件连接IRGree 依赖 IRremoteESP8266 库驱动红外发射管典型电路如下ESP8266 GPIO3 (or configured pin) │ ├─┬─ 100Ω Current Limiting Resistor │ │ │ └─ Anode of IR LED (e.g., TSAL6200) │ └─ Cathode of IR LED │ GND关键设计要点电流驱动能力ESP8266 GPIO 输出电流约 12mA经 100Ω 电阻后驱动 IR LED 电流约3.3V/100Ω 33mA超出 GPIO 安全范围。强烈建议添加 NPN 三极管如 S8050进行电流放大GPIO3 ──┬── Base (via 1kΩ) │ VCC (3.3V) ── Collector of S8050 ── Anode of IR LED ── 100Ω ── GND │ Emitter ─────────────────────────────────────────────── GND载波频率匹配确保 IR LED 响应速度足够快上升/下降时间 1μsTSAL6200 等专用红外发射管完全满足。电源去耦在 ESP8266 VCC 与 GND 间并联 100nF 陶瓷电容抑制红外发射时的瞬态电流噪声。4.2 开发环境搭建Arduino IDEIRGree 依赖两个外部库安装步骤如下安装 ArduinoJsonv6.x打开 Arduino IDE →工具→库管理→ 搜索ArduinoJson选择v6.19.4当前最稳定版本→安装注IRGree README 提到的 “supplement 中的 json 库” 即指此库无需手动下载安装 IRremoteESP8266库管理中搜索IRremoteESP8266选择v3.4.0最新稳定版→安装该库已内置对 ESP8266 的完整支持无需额外 SDK 配置安装 IRGree 库下载 IRGree 项目 ZIP 包Arduino IDE →项目→加载库→添加 .ZIP 库→ 选择下载的 ZIP 文件重启 IDE板级配置工具→板→ESP8266 Boards→NodeMCU 1.0 (ESP-12E Module)工具→Flash Size→4MB (FS:2MB OTA:~1019KB)工具→Upload Speed→1152004.3 最小可行示例MVP以下代码演示如何用 IRGree 控制格力空调开机制冷#include Arduino.h #include IRGree.h #include IRremoteESP8266.h #include IRsend.h // 创建 IRGree 实例内部已创建 IRsend 对象 IRGree irgree; void setup() { Serial.begin(115200); delay(1000); Serial.println(IRGree Demo Start); // 初始化 IR 发射器IRremoteESP8266 内部完成 // IRGree 构造函数已隐式调用 IRsend::begin() } void loop() { // 构建 JSON 字符串制冷、开机、26℃、自动风速、关闭扫风 const char* jsonCmd { \mode\:0, \switch\:1, \wind_speed\:0, \UD_scavenging\:0, \LR_scavenging\:0, \temp\:26 }; Serial.print(Sending command: ); Serial.println(jsonCmd); // 设置参数 if (irgree.setInfo(const_castchar*(jsonCmd))) { // 发送红外 irgree.sendIR(); Serial.println(IR signal sent successfully!); } else { Serial.println(Failed to parse JSON or invalid parameters); } // 空调响应需要时间避免高频发送 delay(5000); }编译与上传确保IRGree.h已被正确包含IDE 会自动索引编译无报错后按住 NodeMCU 的FLASH键再按RESET键进入下载模式点击上传串口监视器将显示发送日志同时用手机摄像头观察 IR LED 是否发出紫光可见光波段泄露5. 功能扩展与高级应用实践5.1 支持模式扩展制热/送风/除湿当前 IRGree 仅支持mode0制冷与mode1制热但格力协议实际支持更多模式。通过逆向分析遥控器红外码可扩展如下mode 值功能命令码基值说明0制冷0x10默认压缩机运行1制热0x11电辅热启动2送风0x12压缩机停仅风扇运行3除湿0x13低风速制冷除湿实现方式修改setInfo()中的命令码映射逻辑增加case 2:和case 3:分支。需同步更新 README 文档。5.2 与 FreeRTOS 集成实现非阻塞控制在复杂网关项目中红外发送不应阻塞其他任务如 Wi-Fi 连接、MQTT 通信。利用 FreeRTOS 可实现异步发送#include freertos/FreeRTOS.h #include freertos/task.h #include queue.h // 创建发送队列 QueueHandle_t irQueue; // IR 发送任务 void irSendTask(void* pvParameters) { char jsonBuf[256]; while (1) { if (xQueueReceive(irQueue, jsonBuf, portMAX_DELAY) pdPASS) { if (irgree.setInfo(jsonBuf)) { irgree.sendIR(); vTaskDelay(100 / portTICK_PERIOD_MS); // 确保发送完成 } } } } // 在 setup() 中创建任务 void setup() { // ... 其他初始化 irQueue xQueueCreate(5, sizeof(char[256])); xTaskCreate(irSendTask, IR_Send, 2048, NULL, 1, NULL); } // 在其他任务中发送如 MQTT callback void onMqttMessage(char* topic, char* payload) { if (strcmp(topic, gree/control) 0) { // payload 为 JSON 字符串 xQueueSend(irQueue, payload, 0); } }5.3 红外学习与协议自适应未来方向尽管当前 README 声明“无示波器故不支持定时”但利用 ESP8266 的高精度micros()和digitalRead()可实现简易学习功能学习引脚配置 GPIO14 为输入连接红外接收头如 VS1838B输出脉冲捕获在loop()中循环读取电平变化记录每个脉冲的起始与结束micros()模式识别对捕获的脉冲序列进行聚类识别引导码、逻辑0/1的典型宽度动态生成帧将学习到的时序参数注入 IRGree替代硬编码的 NEC 参数此方案无需示波器仅需一个廉价红外接收头是 IRGree 后续版本的重要演进路径。6. 常见问题排查与稳定性优化6.1 典型故障现象与根因现象可能原因解决方案空调无反应1. IR LED 未点亮电路故障2. GPIO 引脚配置错误非 GPIO33. 电池电量不足遥控器对比用手机摄像头检查 IR LED万用表测 GPIO3 电压更换新电池测试原装遥控器空调响应不稳定1. 供电纹波大LED 驱动电流冲击2. IR LED 距离过远或角度偏差增加电源滤波电容缩短距离至 3 米内正对空调接收窗setInfo()总是返回false1. JSON 字符串未以\0结尾2. 使用了中文引号“”而非英文3.temp值超出 16~30 范围检查字符串定义复制粘贴时注意引号类型打印temp值调试6.2 生产环境稳定性加固看门狗启用在setup()中启用 ESP8266 硬件看门狗防止单次红外发送卡死#include esp8266_peri.h void setup() { // ... 其他初始化 ESP.wdtEnable(2000); // 2 秒超时 } void loop() { // ... 控制逻辑 ESP.wdtFeed(); // 每次循环喂狗 }红外发送重试机制网络指令可能丢失增加最多 3 次重试for (int i 0; i 3; i) { if (irgree.setInfo(json) (i 0 || i 0)) { // 第一次不重试 irgree.sendIR(); break; } delay(200); }温度单位统一IRGree 输入为摄氏度整数但部分 App 可能传入华氏度。在setInfo()前增加转换int celsius (fahrenheit - 32) * 5 / 9; celsius constrain(celsius, 16, 30);IRGree 库的价值在于它将格力空调红外协议这一“黑盒”转化为可编程、可测试、可集成的嵌入式组件。当工程师在凌晨三点调试完最后一行代码看着空调风扇缓缓启动那不是魔法而是对时序、对协议、对硬件边界的深刻理解所凝结的确定性结果。