Кондиционер сдался последним. ТВ-пульты, вентилятор, увлажнитель — таблицы были готовы за вечера, а сниффер на сплит-системе печатал UNKNOWN, дамп на полторы сотни строк и кадр, приходящий дважды подряд. Полторы сотни — не фигура речи: интервалы печатаются построчно, и один кадр занимает весь экран монитора. Знакомый путь — записать кадр кнопки «плюс градус» и слать его — работал ровно до вечера, когда я поднял температуру родным пультом с дивана: мой записанный кадр продолжал ставить старые 22 градуса, потому что в нём зашиты именно они.
Причина глубже длины кадра. Пульт кондиционера с экранчиком знает текущее состояние — он его и показывает. Поэтому каждая кнопка отправляет весь паспорт: температуру, режим, скорость вентилятора, положение жалюзи, флажок бипа и служебные байты. Даже жалюзи уезжают в кадре своим байтом: покачали створки — пульт собрал весь паспорт заново. Кнопки «плюс один градус» в эфире не существует: пульт пересобирает кадр целиком и шлёт заново.
Здесь разберём климатический кадр по байтам на примере Midea, включим кондиционер готовыми классами IRac и IRMideaAc и соберём сниффер с воспроизведением для безымянной техники, у которой класса нет.
Климатический кадр: полное состояние вместо кнопки
Сравнение с NEC показывает масштаб. Кадр ТВ-пульта — 32 бита, смысл — «нажали кнопку 43», состояние живёт в телевизоре. Климатический кадр — само состояние: 48 бит у Midea, 18 байт у Mitsubishi, 27 у Daikin, и всё это уезжает заново на каждую кнопку. Длина в интервалах ещё выразительнее: сотня-другая пар импульс-пауза, по два байта RAM на пару. Буфер RAW_BUFFER_LENGTH из RAW-урока здесь встаёт впритык: у Midea с повтором набирается около 200 пар. И время: кадр с дублем тянется в эфире вдвое-втрое дольше любого NEC — по кондиционеру сразу видно, почему спамить кадрами не стоит.
Midea изнутри, чтобы не было магии. Шесть байт: флаги с температурой, режим с вентилятором, жалюзи — плюс два байта-дубля с перевёрнутыми битами, знакомая идея инверсий у NEC. Последний байт — контрольная сумма по остальным. И вишенка: следом за кадром пульт шлёт его инвертированную копию — приёмник сверяет обе и выбрасывает всё, если помеха исказила хоть одну. Дубль не несёт новых данных — он только подтверждение, поэтому в дампе второй блок выглядит похожим, но не идентичным: биты инвертированы, пары 0 и 1 поменялись местами. Одиночная засветка лампы кадр испортит, но не подменит: не сошлась сумма — кондиционер просто молчит.
Это знание работает в двух местах. Сниффер печатает сырые интервалы, и отличить климатический кадр от длинного мусора помогает понимание структуры: шапка, ровный ритм бит, повтор-дубль — вся грамматика из таблицы других протоколов. А когда кондиционер молчит на самодельный кадр, проверка идёт по списку: контрольная сумма, порядок пар, полная ли длина. Половинного прохождения не бывает — кадр либо принят целиком, либо выброшен. У NEC пропуск кадра проходит незаметно, у климата — рассинхрон: поэтому сниффер и строит таблицу состояний, а не событий.
IRac и ir_Midea: готовые классы
В IRremoteESP8266 под климатическую технику лежит отдельный этаж. На каждую марку — свой класс: IRMideaAc, IRGreeAc, IRDaikinESP, IRMitsubishiAC; список в репозитории длинный, нужный подключается заголовком вроде ir_Midea.h. Имена классов иногда забавны: IRDaikinESP получил приставку ESP, потому что этот протокол первым встретили на ESP8266, — к плате приставка отношения не имеет. Внутри класса поля уже разобраны: setTemp(24) ставит градусы, setMode — режим (охлаждение, обогрев, осушение, вентиляция), setFan — скорость вентилятора, setSwingVToggle — вертикальные жалюзи. Контрольная сумма считается внутри send() — руками складывать байты не придётся.
Над марками есть универсальный IRac: описываешь желаемое состояние в структуре — протокол, градусы, режим, вентилятор, жалюзи — и зовёшь sendAc(). Структура называется next: заполнили поля — отправили, состояние можно держать в переменной и менять по одному полю. Сменить кондиционер с Midea на Gree — переписать одну строку протокола, а не скетч. В структуре есть и поле beep: у марок, умеющих писк на включение, он гасится одним присваиванием — скриптовое управление без бипа в два часа ночи.
Имена констант режимов и скоростей меняются от версии к версии — держите открытым ir_Midea.h из установленной библиотеки и сверяйте. Это честнее любой статьи, включая эту: у меня один апдейт библиотеки переименовал пару констант, и скетч напомнил об этом сам, при компиляции. Хорошая привычка после установки — запустить готовый пример из папки examples по своей марке: он печатает разобранное состояние и сразу показывает, какие методы живы в вашей версии.
#include <IRremoteESP8266.h>#include <ir_Midea.h> const uint16_t kIrLed = 4;IRMideaAc ac(kIrLed); void setup() { Serial.begin(115200); ac.begin(); ac.on(); // питание ac.setMode(kMideaCool); // охлаждение ac.setTemp(24); // градусы ac.setFan(kMideaFanAuto); // вентилятор на авто ac.setSwingVToggle(false); // жалюзи на месте ac.send(); // кадр целиком, checksum внутри Serial.println(ac.toString()); // разобранное состояние в монитор} void loop() { // климат не любит спама: один кадр при смене состояния}Сниффер и воспроизведение руками
Путь без классов остаётся полезным — для безымянной техники, которой в списке марок нет. Схема та же, что в RAW-уроке, с одной поправкой: RAW_BUFFER_LENGTH поднимайте до 250-300, иначе кадр с инвертированным дублем не влезет. На ESP32 эта цена незаметна, на Uno — уже больно. Дальше по накатанной: дамп каждого режима в массив uint16_t, воспроизведение IrSender.sendRaw(кадр, длина, 38), проверка с полуметра. Дальность сразу не судите: длинный кадр при слабом токе диода размывается, и тут транзистор на передатчике не роскошь. И держите пульт под рукой: сверять дамп с тем, что показывал экранчик, быстрее, чем гадать по интервалам.
Мой порядок для нового кондиционера: сначала класс — если марка поддержана, он экономит вечер и считает контрольную сумму честно. Класса нет — диктофон: по одному кадру на режим, таблица в PROGMEM (флеш 32 КБ против 2 КБ RAM на Uno), воспроизведение целиком. И никогда не пытайтесь собрать кадр «плюс один градус»: его нет в природе, климатический пульт каждый раз шлёт полный паспорт состояния.
Эксперимент на понимание занимает десять минут: в самодельном кадре измените один байт состояния и отправьте — кондиционер молчит, контрольная сумма не сошлась. Верните байт — включится. Я так убедился, что целостность проверяется по-настоящему, а не на бумаге: заодно стало ясно, почему кадры от помех не превращают климат в генератор случайных команд.
| Признак | NEC-пульт (ТВ) | Климатический пульт (Midea) |
|---|---|---|
| Длина кадра | 32 бита, 50-85 мс | 48 бит плюс инвертированный дубль, около 200 пар импульс-пауза |
| Что несёт | номер кнопки | полное состояние: градусы, режим, вентилятор, жалюзи, бип |
| Где живёт состояние | в телевизоре | в пульте, на его экранчике |
| Стратегия записи | таблица команд по кнопкам | по одному кадру на режим, целиком |
| Пропуск кадра | незаметен: команда без состояния | рассинхрон, лечится полной отправкой |
| Целостность | инверсия байтов | инверсии, контрольная сумма, инвертированный дубль кадра |
- Климатический кадр — полное состояние целиком: кнопки «плюс градус» в эфире нет
- Midea: 48 бит, байты-дубли с инверсией, контрольная сумма, следом инвертированная копия кадра
- Готовые классы: IRMideaAc и десятки марок плюс универсальный IRac; checksum считается внутри send()
- RAW-путь для безымянных: RAW_BUFFER_LENGTH 250-300, дамп, массив uint16_t, sendRaw на 38 кГц
- Состояние живёт в пульте: рассинхрон после чужого нажатия лечится только полной отправкой
- Длинный кадр требует тока: на дальность ставьте транзистор, иначе интервалы размываются
- 1. Записанный кадр кнопки «плюс градус» ставит не плюс один, а конкретные 22. Почему?
- 2. Что едет следом за кадром Midea?
- 3. Кондиционер молчит на самодельный кадр. Первая проверка?
- 4. Кто считает checksum при использовании IRMideaAc?
- 5. Сколько пар импульс-пауза в кадре Midea с инвертированным дублем?
Выдержка из практики: таблицу режимов я держу в PROGMEM и не трогаю годами — состояния кондиционера конечны, как и гардероб. Новые кадры добавляются только при смене техники, а это редкость. И один поведенческий штрих: климат не любит частых кадров — шлёте десять подряд, получаете пик на каждый, и если бип не выключен, домашние в голос: сплит-система отпикивает каждую вашу отправку.
Климатическая техника закрыла самый сложный участок раздела: кадр-состояние, классы по маркам, сниффер с буфером на двести пар. Дальше собранное можно скрещивать: включать охлаждение по будильнику из урока про будильники DS3231 к приходу домой, а управлять всем знакомым пультом из урока про команды и повторы — платформа с транзисторным передатчиком из предыдущего урока умеет и слать кадры, и слушать эфир. Практика на закругление: снимите по кадру на каждый режим своего кондиционера и разложите их по кнопкам шлюза — вечер работы, и техника слушается плату, а не только пульта.
Частые вопросы по теме урока
- Записанный кадр кнопки «плюс градус» ставит не плюс один, а конкретные 22. Почему?
- Пульт с экранчиком знает состояние и отправляет его целиком: в кадре лежат абсолютные градусы, режим и жалюзи, а не шаг изменения. Поэтому и стратегия записи — кадр на режим, а не на кнопку. Климатический пульт шлёт полное состояние, и в кадре зашиты абсолютные значения
- Что едет следом за кадром Midea?
- Пульт шлёт кадр дважды: вторая копия инвертирована. Приёмник сверяет обе и выбрасывает всё, если хоть одна исказилась. Инвертированная копия кадра
- Кондиционер молчит на самодельный кадр. Первая проверка?
- Половинного прохождения не бывает: не сошлась checksum или перепутаны пары — кадр выброшен целиком. Несущая, кстати, почти всегда 38 кГц. И проверьте длину: буфер по умолчанию режет всё длиннее 200 пар. Контрольная сумма, порядок пар, полная ли длина
- Кто считает checksum при использовании IRMideaAc?
- Класс собирает кадр и считает целостность сам — поэтому готовый класс точнее ручного дампа: перепутать пары в нём невозможно. Заодно он соберёт и инвертированный дубль без вашего участия. Скетч вручную, байт за байтом
- Сколько пар импульс-пауза в кадре Midea с инвертированным дублем?
- 48 бит — это 96 пар на кадр, плюс шапки и инвертированный дубль: выходит около 200 пар. Буфер по умолчанию на 200 встаёт впритык. Около 200