控制按钮可点,只证明入口存在
本例把链路分为捕获到码、软件请求发送、实际光学收到、家电执行四层。主工程只从真实完整NEC帧学习两个字段,人工按Replay才发一次;没有预置电视码、自动扫描或开机发命令。另附独立Daikin变体展示完整状态协议,条件不同、二选一刷写。
软件计数或本地灯只确认请求分支走过。即使另一接收器收到相近码,也未证明家电收到了,更未证明空调压缩机或房间响应。本站未执行光路/家电/HA实验,所有对应记录留空。
参考:[3] ESPHome2026.9.1 NEC字段、LSB顺序与重复定义[5] 固定Daikin ARC43XXX完整状态编码[6] climate_ir启动恢复、控制发送和状态发布
GPIO给信号,板载FET承担脉冲电流
固定PID5939接收板,V/H选V并对准竖直头:V+板3V3、Sig到GPIO5/J1-5、GND共地。它是38kHz包络接收器,不测载波/距离;不向它供5V再把输出接S3。发射固定PID5639原有两LED及FET,不加第三颗:V+独立稳压5.0V≥1A、Sig到GPIO6/J1-6、GND共地,外部正端不接板5V/3V3。
厂家5V条件两LED脉冲合计约400mA,经外供/FET而非GPIO;3.3V逻辑高使其发光。33%仅载波占空,不是整机恒定平均电流预算。只作短遥控突发,不能常HIGH作照明;红灯和厂商距离也非本站光学/距离结果。GPIO4经330Ω接WP7113ID只作请求提示,先全断电核V+/GND/Sig和线色标记。
| 模块 | 供电 / 信号 |
|---|---|
| PID5939接收,选V | 板3V3 / Sig GPIO5,inverted接收 |
| PID5639发射,原两LED | 独立5V≥1A / Sig GPIO6,板载FET |
| 两路负端与板GND | 共地;不并两路正电源 |
| GPIO4普通LED | 330Ω串联,非IR执行确认 |
参考:[1] PID5639板载FET、逻辑与脉冲电流[2] PID5939供电、输出与V/H选择[7] 官方S3 v1.1 GPIO4/5/6及桥日志[9] PID5639固定原理图:AO3406、两颗940nm与SIG门极路径
只重放最近真实捕获的完整NEC
ir_session.h与host共用。每次完整解码保留16位address/command,不拿别的工具32位串机械切半;当前codec按LSB顺序处理。200ms内重收忽略、缓存十分钟过期、重启丢弃,人工请求至少间隔1秒,发后500ms忽略可能自收。另一个遥控完整帧可能覆盖缓存,发送前要核日志。
command_repeats=1指该codec同一完整帧的16位命令重复数,不是所有长按短repeat的计数;短repeat不能当新完整学习码。Learned NEC Available是缓存资格,不诊断接收器在线。无收到码可因没人按键、光路或断线,不能自动等同故障或成功。
计时统一取IDF5.5.5的esp_timer_get_time(),以64位保留启动后微秒再除1000转毫秒,不把32位millis扩大后冒充长期时钟。超时比较不会因约49.7天的32位完整周期让旧状态复活;这是同源注入时刻检查,不是已运行49天的实测。
// SPDX-License-Identifier: MIT
#pragma once
#include <cstdint>
#ifdef ESP_PLATFORM
#include "esp_timer.h"
#endif
namespace h06 {
#ifdef ESP_PLATFORM
// IDF monotonic microseconds since boot, widened before conversion; no 32-bit millis cycle.
inline uint64_t now_ms(){return static_cast<uint64_t>(esp_timer_get_time())/1000ULL;}
#endif
class Session {
public:
bool learn(uint64_t now,uint16_t address,uint16_t command){
if(sent_&&now>=tx_at_&&now-tx_at_<500)return false; // ignore possible self-reception
if(seen_&&now>=learned_&&now-learned_<200)return false;
address_=address;command_=command;learned_=now;seen_=true;++captures_;return true;
}
bool available(uint64_t now)const{return seen_&&now>=learned_&&now-learned_<=600000;}
bool request(uint64_t now){
if(!available(now)||(sent_&&(now<tx_at_||now-tx_at_<1000))){++rejected_;return false;}
tx_at_=now;sent_=true;++requests_;return true;
}
uint16_t address()const{return address_;}
uint16_t command()const{return command_;}
uint32_t captures()const{return captures_;}
uint32_t requests()const{return requests_;}
uint32_t rejected()const{return rejected_;}
bool tx_indicator(uint64_t now)const{return sent_&&now>=tx_at_&&now-tx_at_<200;}
const char* phase(uint64_t now)const{return !seen_?"NO_LEARNED_NEC":!available(now)?"LEARNED_EXPIRED":"NEC_AVAILABLE";}
private:
uint16_t address_=0,command_=0;
uint64_t learned_=0,tx_at_=0;
uint32_t captures_=0,requests_=0,rejected_=0;
bool seen_=false,sent_=false;
};
inline Session& session(){static Session value;return value;}
}
参考:[3] ESPHome2026.9.1 NEC字段、LSB顺序与重复定义[10] IDF5.5.5 esp_timer:64位启动后单调微秒
主工程:先日志学习,再人工单次请求
完整YAML保存为esp32-esphome-ir-remote.yaml,与ir_session.h同目录。复用H01固定Python3.12.13/ESPHome2026.9.1/原生IDF5.5.5,填私有secrets,先config、compile,再run --device真实桥口,115200读取NEC/raw;下载README含从venv到热点/USB恢复的完整命令。
用自己可核型号的38kHz NEC遥控器,短按至少间隔0.3秒,保存同键的字段与raw原日志。Replay在缓存或间隔不合时拒绝;Transmit Request Count只计请求,GPIO4仅提示200ms,无设备ACK。接收头避免与自发直射,抑制窗口不证明光路可靠;不增加发射电流来掩盖接线问题。
substitutions:
node_name: hixinwu-h06
esphome:
name: ${node_name}
friendly_name: Hixinwu H06
min_version: 2026.9.1
includes:
- ir_session.h
esp32:
board: esp32-s3-devkitc-1
variant: ESP32S3
flash_size: 8MB
flash_mode: qio
flash_frequency: 80MHz
toolchain: esp-idf
framework:
type: esp-idf
version: 5.5.5
psram:
mode: octal
speed: 80MHz
logger:
baud_rate: 115200
hardware_uart: UART0
level: DEBUG
api:
encryption:
key: !secret api_key
reboot_timeout: 0s
ota:
- platform: esphome
encryption:
key: !secret api_key
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
reboot_timeout: 0s
ap:
ssid: "${node_name} Recovery"
password: !secret fallback_password
ap_timeout: 90s
captive_portal:
remote_receiver:
id: ir_rx
pin:
number: GPIO5
inverted: true
mode: INPUT_PULLUP
dump: [nec, raw]
filter: 50us
idle: 10ms
buffer_size: 4kB
on_nec:
then:
- lambda: |-
if(h06::session().learn(h06::now_ms(),x.address,x.command))
ESP_LOGI("h06","LEARN address=0x%04X command=0x%04X repeats=%u (not appliance feedback)",x.address,x.command,x.command_repeats);
remote_transmitter:
id: ir_tx
pin: GPIO6
carrier_duty_percent: 33%
switch:
- platform: gpio
id: indicator
pin: GPIO4
internal: true
restore_mode: ALWAYS_OFF
button:
- platform: template
name: Replay Learned NEC
on_press:
- if:
condition:
lambda: return h06::session().request(h06::now_ms());
then:
- remote_transmitter.transmit_nec:
transmitter_id: ir_tx
address: !lambda return h06::session().address();
command: !lambda return h06::session().command();
command_repeats: 1
- logger.log: "TX requested once; no appliance acknowledgment"
else:
- logger.log: "TX rejected: no fresh NEC or <1s since previous request"
binary_sensor:
- platform: template
name: Learned NEC Available
lambda: return h06::session().available(h06::now_ms());
text_sensor:
- platform: template
name: IR Session Phase
lambda: return {h06::session().phase(h06::now_ms())};
update_interval: 1s
sensor:
- platform: template
name: NEC Capture Count
lambda: return h06::session().captures();
accuracy_decimals: 0
update_interval: 1s
- platform: template
name: Transmit Request Count
lambda: return h06::session().requests();
accuracy_decimals: 0
update_interval: 1s
- platform: template
name: Rejected Request Count
lambda: return h06::session().rejected();
accuracy_decimals: 0
update_interval: 1s
interval:
- interval: 50ms
then:
- lambda: |-
if(h06::session().tx_indicator(h06::now_ms())) id(indicator).turn_on();
else id(indicator).turn_off();
参考:[1] PID5639板载FET、逻辑与脉冲电流[2] PID5939供电、输出与V/H选择[3] ESPHome2026.9.1 NEC字段、LSB顺序与重复定义[4] 固定receiver RMT范围与transmitter实现
空调先核帧族,再用完整状态编码器
空调常同时编码模式、温度、风速与摆风。变体只对应固定daikin源码标出的ARC43XXX族:38kHz、35字节拆8/8/19三段,末段校验,编码温度10–30℃/1℃步。它不是整个品牌兼容表,本例没有已确认匹配的实体内机型号。品牌相同不能替代协议核对。
保留原遥控/内机型号,录OFF、COOL25℃、COOL27℃及风速/摆风各三遍,逐项核前缀、段长、时序、字段与校验。原遥控有效但格式不符时停止套用,选有匹配依据的组件另验。变体idle=10ms把约32.3ms段间隔分开,以19字节状态段交给上游接收器;初始40ms超过S3当前RMT上限的真实失败与修复已保留,不是所有长帧都该把idle加长。
参考:[4] 固定receiver RMT范围与transmitter实现[5] 固定Daikin ARC43XXX完整状态编码[6] climate_ir启动恢复、控制发送和状态发布
独立变体的HA状态仍是请求状态
本节是可单独构建的daikin-arc43xxx.example.yaml,不能直接叠在主YAML后面。选择该变体前先完成帧族匹配。它没有主工程的NEC缓存,也没有本地自动启动动作。climate_ir setup可能恢复旧设定点,但不在setup发送;用户控制才发码并发布请求状态,收到原遥控也可更新状态。
HA添加ESPHome集成、真实IP/key后核Daikin Requested State。该状态不能证明内机收码、已运行或到温,变体也没有实测室温传感器。先用原遥控恢复已知状态,再人工逐项核本体反馈;不要让未验证实体进入自动化。HA运行与家电结果均待测。
substitutions:
node_name: hixinwu-h06-daikin
esphome:
name: ${node_name}
friendly_name: Hixinwu H06 Daikin Requested
min_version: 2026.9.1
esp32:
board: esp32-s3-devkitc-1
variant: ESP32S3
flash_size: 8MB
flash_mode: qio
flash_frequency: 80MHz
toolchain: esp-idf
framework:
type: esp-idf
version: 5.5.5
psram:
mode: octal
speed: 80MHz
logger:
baud_rate: 115200
hardware_uart: UART0
level: DEBUG
api:
encryption:
key: !secret api_key
reboot_timeout: 0s
ota:
- platform: esphome
encryption:
key: !secret api_key
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
reboot_timeout: 0s
ap:
ssid: "${node_name} Recovery"
password: !secret fallback_password
ap_timeout: 90s
captive_portal:
remote_receiver:
id: ir_rx
pin:
number: GPIO5
inverted: true
mode: INPUT_PULLUP
dump: raw
filter: 50us
idle: 10ms
buffer_size: 8kB
remote_transmitter:
id: ir_tx
pin: GPIO6
carrier_duty_percent: 33%
climate:
- platform: daikin
name: Daikin Requested State
transmitter_id: ir_tx
receiver_id: ir_rx
参考:[5] 固定Daikin ARC43XXX完整状态编码[6] climate_ir启动恢复、控制发送和状态发布[8] Home Assistant官方ESPHome集成入口与加密配置
为请求、光学和家电分别留证据
先录10次间隔足够的短按,长按另录完整帧/短repeat差异。第二轮对自有设备的非关键功能单次重放,分三列记录Request、Optical、Appliance;空调匹配后才测OFF、COOL25/27、风速、摆风,遵守厂商保护延时,不快速反复启停。未做列为空,不把预期照抄observations或capture-log.csv。
无解码先核接收供电、V/H、朝向与38kHz兼容,raw有而NEC无先查协议。发射异常先断电查外供5V、共地、Sig与FET板,不用GPIO供LED。空调不响应先用原遥控恢复,停止自动化,再核协议/朝向/供电。上传或网络失败用桥USB、BOOT/EN和90秒恢复热点;主缓存重启清空,变体旧设定点不当设备同步。
参考:[1] PID5639板载FET、逻辑与脉冲电流[2] PID5939供电、输出与V/H选择[3] ESPHome2026.9.1 NEC字段、LSB顺序与重复定义[5] 固定Daikin ARC43XXX完整状态编码
完整编译和会话检查,各有明确范围
主NEC工程和独立Daikin变体分别执行config/compile,版本、输入、生成CPP、原日志与镜像摘要进入证据。host直接检查同一ir_session.h的无缓存、字段、过期、限速、自收抑制、提示计时、重启和64位跨32位周期,没有复制测试模型。
这些不模拟光学、NEC/Daikin真实解码、RMT时序或家电动作;器件/HA均未运行。下一步可以将已逐项验过的本地命令接到实体按钮,继续保留请求与执行的区别。
2026-10-18已实际执行config与完整固件compile,均Exit0;主NEC OTA 886576字节,Daikin变体884272字节。三组host同源检查均Exit0;这些是软件结果,未执行烧录/HA/实物试验。
clang++ -std=c++17 -Wall -Wextra -Werror host_check.cpp -o /tmp/h06-host
/tmp/h06-host参考:[3] ESPHome2026.9.1 NEC字段、LSB顺序与重复定义[4] 固定receiver RMT范围与transmitter实现[5] 固定Daikin ARC43XXX完整状态编码[6] climate_ir启动恢复、控制发送和状态发布
资料来源与版本说明
固定上游源码和厂家具体章节已阅读,逐字摘要与范围见docs/esp32-evidence/home-devices.md;独立复核/实板结果另记。资料核对日期:。资料核对、程序构建与实板测试分别记录,不互相替代。