revert 90b84b79569fbe40f67f86c0c61fcefdb4bcb83e
revert 上传文件至 红外2
This commit is contained in:
parent
90b84b7956
commit
bdaa3682b2
Binary file not shown.
@ -1,229 +0,0 @@
|
|||||||
{
|
|
||||||
"metadata": {
|
|
||||||
"create_time": "2025-05-14T16:29:46.405745",
|
|
||||||
"total_commands": 24
|
|
||||||
},
|
|
||||||
"raw_data": {
|
|
||||||
"power_on": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1807,
|
|
||||||
"timestamp": "2025-05-14 16:26:50"
|
|
||||||
},
|
|
||||||
"power_off": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1805,
|
|
||||||
"timestamp": "2025-05-14 16:26:54"
|
|
||||||
},
|
|
||||||
"cool_16": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1803,
|
|
||||||
"timestamp": "2025-05-14 16:26:58"
|
|
||||||
},
|
|
||||||
"cool_17": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1805,
|
|
||||||
"timestamp": "2025-05-14 16:27:02"
|
|
||||||
},
|
|
||||||
"cool_18": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1805,
|
|
||||||
"timestamp": "2025-05-14 16:27:16"
|
|
||||||
},
|
|
||||||
"cool_19": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1809,
|
|
||||||
"timestamp": "2025-05-14 16:27:23"
|
|
||||||
},
|
|
||||||
"cool_20": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1802,
|
|
||||||
"timestamp": "2025-05-14 16:27:26"
|
|
||||||
},
|
|
||||||
"heat_16": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1801,
|
|
||||||
"timestamp": "2025-05-14 16:27:31"
|
|
||||||
},
|
|
||||||
"heat_17": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1801,
|
|
||||||
"timestamp": "2025-05-14 16:27:35"
|
|
||||||
},
|
|
||||||
"heat_18": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1803,
|
|
||||||
"timestamp": "2025-05-14 16:27:40"
|
|
||||||
},
|
|
||||||
"heat_19": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1805,
|
|
||||||
"timestamp": "2025-05-14 16:27:47"
|
|
||||||
},
|
|
||||||
"heat_20": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1801,
|
|
||||||
"timestamp": "2025-05-14 16:27:51"
|
|
||||||
},
|
|
||||||
"mode_cool": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1804,
|
|
||||||
"timestamp": "2025-05-14 16:28:09"
|
|
||||||
},
|
|
||||||
"mode_dry": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1811,
|
|
||||||
"timestamp": "2025-05-14 16:28:13"
|
|
||||||
},
|
|
||||||
"mode_fan": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1809,
|
|
||||||
"timestamp": "2025-05-14 16:28:18"
|
|
||||||
},
|
|
||||||
"up_down": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1811,
|
|
||||||
"timestamp": "2025-05-14 16:28:29"
|
|
||||||
},
|
|
||||||
"left_right": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1807,
|
|
||||||
"timestamp": "2025-05-14 16:28:37"
|
|
||||||
},
|
|
||||||
"fan_low": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1807,
|
|
||||||
"timestamp": "2025-05-14 16:28:42"
|
|
||||||
},
|
|
||||||
"fan_mid": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1811,
|
|
||||||
"timestamp": "2025-05-14 16:28:50"
|
|
||||||
},
|
|
||||||
"fan_high": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1809,
|
|
||||||
"timestamp": "2025-05-14 16:28:56"
|
|
||||||
},
|
|
||||||
"turbo_on": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1808,
|
|
||||||
"timestamp": "2025-05-14 16:29:01"
|
|
||||||
},
|
|
||||||
"turbo_off": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1809,
|
|
||||||
"timestamp": "2025-05-14 16:29:25"
|
|
||||||
},
|
|
||||||
"sleep_on": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1804,
|
|
||||||
"timestamp": "2025-05-14 16:29:30"
|
|
||||||
},
|
|
||||||
"sleep_off": {
|
|
||||||
"raw": "PULSEDISTANCE",
|
|
||||||
"protocol": 184,
|
|
||||||
"bits": 1804,
|
|
||||||
"timestamp": "2025-05-14 16:29:46"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"protocols": {
|
|
||||||
"184": {
|
|
||||||
"sample_count": 24,
|
|
||||||
"fixed_bits": [
|
|
||||||
{
|
|
||||||
"position": 0,
|
|
||||||
"value": "P"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 1,
|
|
||||||
"value": "U"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 2,
|
|
||||||
"value": "L"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 3,
|
|
||||||
"value": "S"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 4,
|
|
||||||
"value": "E"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 5,
|
|
||||||
"value": "D"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 6,
|
|
||||||
"value": "I"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 7,
|
|
||||||
"value": "S"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 8,
|
|
||||||
"value": "T"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 9,
|
|
||||||
"value": "A"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 10,
|
|
||||||
"value": "N"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 11,
|
|
||||||
"value": "C"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"position": 12,
|
|
||||||
"value": "E"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"variable_bits": [],
|
|
||||||
"template": [
|
|
||||||
"P",
|
|
||||||
"U",
|
|
||||||
"L",
|
|
||||||
"S",
|
|
||||||
"E",
|
|
||||||
"D",
|
|
||||||
"I",
|
|
||||||
"S",
|
|
||||||
"T",
|
|
||||||
"A",
|
|
||||||
"N",
|
|
||||||
"C",
|
|
||||||
"E"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
#include "irre.h"
|
|
||||||
#include<Arduino.h>
|
|
||||||
|
|
||||||
#define CS_PIN 5
|
|
||||||
#define IR_PIN 4
|
|
||||||
|
|
||||||
BinHeader configHeader;
|
|
||||||
uint16_t rawData[200];
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
while (!Serial);
|
|
||||||
|
|
||||||
if (!IRController::initializeSD(CS_PIN)) {
|
|
||||||
Serial.println("SD卡初始化失败");
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IRController::loadConfig("/ir_config.bin", &configHeader, rawData)) {
|
|
||||||
Serial.println("配置文件加载失败");
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
IRController::sendIRSignal(rawData, configHeader.bits/16, IR_PIN);
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
206
红外2/irre(1).py
206
红外2/irre(1).py
@ -1,206 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
import struct
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
# 常量定义
|
|
||||||
STEPS = [
|
|
||||||
{"desc": "1. [基础] 按电源键开机", "cmd": "power_on"},
|
|
||||||
{"desc": "2. [基础] 按电源键关机", "cmd": "power_off"},
|
|
||||||
*[{"desc": f"3.{i+1} [制冷] 设置{i+16}℃", "cmd": f"cool_{i+16}"} for i in range(5)],#基础温度为16
|
|
||||||
*[{"desc": f"4.{i+1} [制热] 设置{i+16}℃", "cmd": f"heat_{i+16}"} for i in range(5)],
|
|
||||||
{"desc": "5.1 [模式] 制冷模式", "cmd": "mode_cool"},
|
|
||||||
{"desc": "5.2 [模式] 除湿模式", "cmd": "mode_dry"},
|
|
||||||
{"desc": "5.3 [模式] 送风模式", "cmd": "mode_fan"},
|
|
||||||
{"desc": "5.4 [模式] 上下风", "cmd": "up_down"},#上下风
|
|
||||||
{"desc": "6.1 [风速] 左右风", "cmd": "left_right"},#左右风
|
|
||||||
{"desc": "6.2 [风速] 低速", "cmd": "fan_low"},
|
|
||||||
{"desc": "6.3 [风速] 中速", "cmd": "fan_mid"},
|
|
||||||
{"desc": "6.4 [风速] 高速", "cmd": "fan_high"},
|
|
||||||
{"desc": "7.1 [特殊] 超强风速", "cmd": "turbo_on"},#超强风速
|
|
||||||
{"desc": "7.2 [特殊] 静音风速", "cmd": "turbo_off"},#静音风速
|
|
||||||
{"desc": "7.5 [特殊] 睡眠模式开", "cmd": "sleep_on"},
|
|
||||||
{"desc": "7.6 [特殊] 睡眠模式关", "cmd": "sleep_off"},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
def validate_signal(data):
|
|
||||||
"""增强版信号验证"""
|
|
||||||
pattern = r"""
|
|
||||||
uint16_t\s+rawData\[(\d+)\]\s*=\s* # 匹配数组声明
|
|
||||||
{([\d,\s]+)};?[\s\S]*? # 捕获数组内容
|
|
||||||
Protocol\s*=\s*(\w+) # 协议类型
|
|
||||||
(?:.*?(\d+)\s+bits)? # 可选位数匹配
|
|
||||||
"""
|
|
||||||
match = re.search(pattern, data, re.VERBOSE | re.IGNORECASE)
|
|
||||||
|
|
||||||
if not match:
|
|
||||||
return False, None, None, None
|
|
||||||
|
|
||||||
try:
|
|
||||||
arr_length = int(match.group(1))
|
|
||||||
raw_data = list(map(int, match.group(2).split(',')))
|
|
||||||
protocol = match.group(3).upper()
|
|
||||||
bits = int(match.group(4)) if match.group(4) else len(raw_data)*16
|
|
||||||
|
|
||||||
# 数据长度校验
|
|
||||||
if len(raw_data) != arr_length:
|
|
||||||
print(f"数据长度不匹配: 声明{arr_length} 实际{len(raw_data)}")
|
|
||||||
return False, None, None, None
|
|
||||||
|
|
||||||
return raw_data, protocol, bits, len(data)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"解析错误: {str(e)}")
|
|
||||||
return False, None, None, None
|
|
||||||
|
|
||||||
def analyze_signals(collected_data):
|
|
||||||
"""执行控制变量分析"""
|
|
||||||
analysis = {"protocols": {}}
|
|
||||||
|
|
||||||
# 按协议分组
|
|
||||||
protocol_groups = {}
|
|
||||||
for cmd, data in collected_data.items():
|
|
||||||
proto = data['protocol']
|
|
||||||
protocol_groups.setdefault(proto, []).append(data)
|
|
||||||
|
|
||||||
# 分析每个协议
|
|
||||||
for proto, group in protocol_groups.items():
|
|
||||||
proto_analysis = {
|
|
||||||
"sample_count": len(group),
|
|
||||||
"fixed_bits": [],
|
|
||||||
"variable_bits": [],
|
|
||||||
"template": []
|
|
||||||
}
|
|
||||||
|
|
||||||
# 位级分析
|
|
||||||
max_length = max(len(d["raw"]) for d in group)
|
|
||||||
bit_analysis = [[] for _ in range(max_length)]
|
|
||||||
|
|
||||||
for data in group:
|
|
||||||
for i, val in enumerate(data["raw"]):
|
|
||||||
bit_analysis[i].append(val)
|
|
||||||
|
|
||||||
# 识别固定/可变位
|
|
||||||
for idx, values in enumerate(bit_analysis):
|
|
||||||
unique_vals = set(values)
|
|
||||||
if len(unique_vals) == 1:
|
|
||||||
proto_analysis["fixed_bits"].append({
|
|
||||||
"position": idx,
|
|
||||||
"value": values[0]
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
proto_analysis["variable_bits"].append({
|
|
||||||
"position": idx,
|
|
||||||
"values": list(unique_vals)
|
|
||||||
})
|
|
||||||
|
|
||||||
# 生成协议模板
|
|
||||||
proto_analysis["template"] = [
|
|
||||||
"V" if any(idx == b["position"] for b in proto_analysis["variable_bits"])
|
|
||||||
else group[0]["raw"][idx]
|
|
||||||
for idx in range(len(group[0]["raw"]))
|
|
||||||
]
|
|
||||||
|
|
||||||
analysis["protocols"][proto] = proto_analysis
|
|
||||||
|
|
||||||
return analysis
|
|
||||||
|
|
||||||
def collect_signals():
|
|
||||||
"""主采集流程"""
|
|
||||||
collected = {}
|
|
||||||
print("\n空调红外信号采集系统启动")
|
|
||||||
|
|
||||||
for step_num, step in enumerate(STEPS, 1):
|
|
||||||
while True:
|
|
||||||
print(f"\n[{step_num}/{len(STEPS)}] {step['desc']}")
|
|
||||||
print("请输入红外信号数据(输入'exit'退出):")
|
|
||||||
data = input().strip()
|
|
||||||
|
|
||||||
if data.lower() == 'exit':
|
|
||||||
if input("确认退出?(y/n): ").lower() == 'y':
|
|
||||||
save_data(collected)
|
|
||||||
return
|
|
||||||
|
|
||||||
valid, raw, proto, bits = validate_signal(data)
|
|
||||||
if valid:
|
|
||||||
collected[step['cmd']] = {
|
|
||||||
"raw": raw,
|
|
||||||
"protocol": proto,
|
|
||||||
"bits": bits,
|
|
||||||
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
}
|
|
||||||
print(f"√ 已记录:{step['cmd']}")
|
|
||||||
break
|
|
||||||
print("× 格式错误!需包含:\n1.完整C数组 2.协议信息 3.正确数据格式")
|
|
||||||
|
|
||||||
analysis = analyze_signals(collected)
|
|
||||||
save_data(collected, analysis)
|
|
||||||
print(f"\n采集完成!有效数据:{len(collected)}条")
|
|
||||||
|
|
||||||
def convert_to_bin(json_path):
|
|
||||||
"""将JSON配置转换为二进制格式"""
|
|
||||||
with open(json_path, 'r') as f:
|
|
||||||
config = json.load(f)
|
|
||||||
|
|
||||||
bin_data = bytearray()
|
|
||||||
for cmd in config['raw_data'].values():
|
|
||||||
# 协议类型(4字节) + 位数(4字节) + 时间戳(12字节)
|
|
||||||
bin_data.extend(struct.pack('<I', cmd['protocol']))
|
|
||||||
bin_data.extend(struct.pack('<I', cmd['bits']))
|
|
||||||
|
|
||||||
# 时间编码调整(年-2000压缩到1字节,其他字段范围校验)
|
|
||||||
dt = datetime.strptime(cmd['timestamp'], "%Y-%m-%d %H:%M:%S")
|
|
||||||
year_byte = dt.year - 2000
|
|
||||||
if not (0 <= year_byte <= 255):
|
|
||||||
year_byte = max(0, min(year_byte, 255))
|
|
||||||
time_bytes = struct.pack('<6B',
|
|
||||||
year_byte,
|
|
||||||
max(1, min(dt.month, 12)),
|
|
||||||
max(1, min(dt.day, 31)),
|
|
||||||
dt.hour,
|
|
||||||
dt.minute,
|
|
||||||
dt.second
|
|
||||||
)
|
|
||||||
bin_data.extend(time_bytes)
|
|
||||||
|
|
||||||
bin_path = os.path.splitext(json_path)[0] + '.bin'
|
|
||||||
with open(bin_path, 'wb') as f:
|
|
||||||
f.write(bin_data)
|
|
||||||
print(f"二进制配置已生成: {os.path.basename(bin_path)}")
|
|
||||||
|
|
||||||
|
|
||||||
def save_data(data, analysis=None):
|
|
||||||
"""保存数据到文件"""
|
|
||||||
config = {
|
|
||||||
"metadata": {
|
|
||||||
"create_time": datetime.now().isoformat(),
|
|
||||||
"total_commands": len(data)
|
|
||||||
},
|
|
||||||
"raw_data": data,
|
|
||||||
"analysis": analysis if analysis else {}
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "ir_config.json")
|
|
||||||
with open(file_path, "w") as f:
|
|
||||||
json.dump(config, f, indent=2)
|
|
||||||
print("配置已保存至 ir_config.json")
|
|
||||||
convert_to_bin(file_path)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
print("="*40)
|
|
||||||
print("红外信号采集分析系统 v2.0")
|
|
||||||
print("操作说明:")
|
|
||||||
print("1. 保持设备连接")
|
|
||||||
print("2. 按提示操作遥控器")
|
|
||||||
print("3. 从串口监视器复制数据")
|
|
||||||
print("="*40)
|
|
||||||
|
|
||||||
try:
|
|
||||||
collect_signals()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("\n操作中断!正在保存数据...")
|
|
||||||
save_data(collected if 'collected' in locals() else {})
|
|
51
红外2/irre.h
51
红外2/irre.h
@ -1,51 +0,0 @@
|
|||||||
#ifndef IRRE_H
|
|
||||||
#define IRRE_H
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <SD.h>
|
|
||||||
#include <IRremote.h>
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t protocol;
|
|
||||||
uint32_t bits;
|
|
||||||
struct {
|
|
||||||
uint8_t year;
|
|
||||||
uint8_t month;
|
|
||||||
uint8_t day;
|
|
||||||
uint8_t hour;
|
|
||||||
uint8_t minute;
|
|
||||||
uint8_t second;
|
|
||||||
} timestamp;
|
|
||||||
} BinHeader;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
class IRController {
|
|
||||||
public:
|
|
||||||
static bool initializeSD(uint8_t csPin = 5);
|
|
||||||
static bool loadConfig(const char* path, BinHeader* header, uint16_t* rawData);
|
|
||||||
static void sendIRSignal(uint16_t* rawData, size_t length, uint8_t irPin = 4);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool IRController::initializeSD(uint8_t csPin) {
|
|
||||||
if(!SD.begin(csPin)) return false;
|
|
||||||
return SD.exists("/ir_config.bin");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IRController::loadConfig(const char* path, BinHeader* header, uint16_t* rawData) {
|
|
||||||
File file = SD.open(path);
|
|
||||||
if(!file) return false;
|
|
||||||
|
|
||||||
file.read((byte*)header, sizeof(BinHeader));
|
|
||||||
size_t dataSize = (header->bits + 15) / 16 * 2;
|
|
||||||
file.read((byte*)rawData, dataSize);
|
|
||||||
file.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRController::sendIRSignal(uint16_t* rawData, size_t length, uint8_t irPin) {
|
|
||||||
IrSender.sendRaw(rawData, length, 38, false);
|
|
||||||
delay(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
x
Reference in New Issue
Block a user