Анализатор пультов (IR сигналов)
- Войдите на сайт для отправки комментариев
Как было сказано на одном сайте «вместо дорогого устройства управления можно купить недорогой контроллер, который будет управлять кондиционером, достаточно знать систему команд…»
Самое простое решение, записать нужные сигналы и транслировать их контроллером. Обычно это работает, но может глючить, так пульт выдает не идеальный сигнал, приемник так же имеет погрешность. В результате «паспортный» сигнал в 560мкс на деле колеблется от 500 до 600, а будучи ретранслирован, погрешность увеличится и не факт что устройство распознает команду.
Это можно решить, записав сигнал раз 10, вычислить по среднему, и полученный «выровненный» отправлять контроллером не один, а три раза подряд.
Однако если требуется полностью эмулировать пульт простейшего кондиционера, то такой подход неприемлем. 4 режима работы, 4 режима мощности вентилятора, три варианта мощности, плюс 16 вариантов температуры, и получаем под тысячу уникальных «команд».
Для работы с пультами сделал декодер. Работает под EPS NodeMCU транслируя результаты в браузер, где их намного удобнее изучать.
Аппаратная часть элементарна, голая EPS с подключенным на цифровой вход IR приемником. Примерно так:
https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e070f971494b-30... 300w" />
Настройка скетча элементарная:
const char *ssid = "CCCP"; const char *password = ""; IPAddress ip(192, 168, 88, 55); IPAddress gateway(192, 168, 88, 1); IPAddress subnet(255, 255, 255, 0); #define IRpin 14 //Номер входа (D5)
Меняете сетевые настройки, указываете пин куда подключен приемник, запускаете, открываете в браузере тот IP который указали в скетче, и ничего не меняя, отправляете пультом сигнал на подключенный к контроллеру ИК приемник.
https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0712997f93a-30... 300w, https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0712997f93a-76... 768w" />
Скрипт сам распознает формат передачи данных, отличая распространенный NECовский от старого RC5, автоматом определяет значения соответствующие единицам, нулям, и пропускам-разделителям, при этом с каждым нажатием на пульт «обучается» выравнивая средний этих показателей.
Переключаете опцию Show: с RAW DATA на BIN CODE, и снова нажав кнопку на пульте, получаете вот такую картинку, при этом если дважды на пульте нажали «+», а данные не изменились, значит пульт «тупой» и никаких настроек внутри себя не хранит.
https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e07140b07950-30... 300w" />
Такой пульт нет смысла анализировать, переключаете Show в режим «C++ array» и можно смело копипастить в свой скетч.
В предисловии я сказал, что пульт можно записать раз 10, высчитать средние значения и транслировать их для избежания глюков — это делается, каждый раз когда Вы нажимаете кнопку в автоматическом режиме, скрипт усредняет значения самого сигнала, а после усредняет их с предыдущими.
https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0714fbe06ab-30... 300w, https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0714fbe06ab-76... 768w" />
Если попался пульт работающий на CR5 то картинка будет немного иная. И все вышеописанные 3 шага будут выглядеть вот так:
https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0716942a476-30... 300w, https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0716942a476-76... 768w" />
Единственный в наличие у меня пульт, работающий по CR5 — это пульт от старого кассетного магнитофона Sony. Сигнал он отправляет повторяя от 4 до 10 раз, поэтому в скетче придется либо в цикл поставить отправку, либо раскопипастить значения массива. Проверить не могу, так как магнитофон давно выброшен.
Если автоматический режим распознавания протокола и сигналов не справился с задачей, можно MODE переключить в режиме MANUAL и вручную выставлять параметры для анализа. С протоколом понятно. DigitalSignal задает где «живут данные» UP в сигналах, DOWN в затуханиях, Separator это время разделителя сигнала, One это время единицы, Zero соответственно нуля. Время понятное дело в микросекундах.
Важный момент: если пробуете анализировать разные пульты, то при каждой смене пульта в автоматическом режиме анализа нужно нажать кнопочку «RESET» чтобы в нули слетели все ранее проанализированные автоматом параметры.
Умные пульты
С умными пультами, вроде пульта от кондиционера, которые хранят параметры в себе и на их основе формируют сигнал, ради который проект и затевался, алгоритм работы следующий.
Нажав 4 раза подряд кнопку «вкл-выкл» в бинарном режиме видим изменения данных:
https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0719a7bfd12-30... 300w, https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e0719a7bfd12-76... 768w" />
То есть в моем случае включение — это единица на 20-ом бите, и её зеркальное значение в виде нуля на 28ом, при выключении, картина обратная, 20-ый зануляется, 28ой единица.
Если присмотреться, то в приведенном примере 48 бит информации на самом деле 3 пакета по 8 бит, после каждого из которых идет инверсия его самого. Это нормальная практика и это менее ресурсоёмко, нежели сначала пульту формировать контрольную сумму, а потом устройству её проверять, хотя теоретически могут попасться пульты с контрольной суммой, и там придется «взламывать» её алгоритм.
С «вкл-выкл» всё просто, переходим к варианту температуры, подняв пультом последовательно температуру с 18 до 30 градусов, получаем следующую картинку:
https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e071ca7d8aab-30... 300w, https://www.kovalenko.su/wp-content/uploads/2019/12/img_5e071ca7d8aab-76... 768w" />
Видно что температура задается 16-19 и 24-27 битами. При этом на 16-19ом очевидно указаны значения от 1 до 13 в двоичной системе.
Чтобы выставить 25С, нужно в десятичном из 25 вычесть базовые 17, и полученные 1000 биты записать в 16-19 как «0001», не забыв их инверсию записать в 24-27ой как «1110».
Надеюсь кому-нибудь будет полезно
Прости, что-то не въеду. Она у тебя каким-то боком у фондовому рынку?
EPS - это ж "Earnings per share" (прибыль на акцию). Или я чего-то не понял?
Спасибо, сохраню ссылку, вдруг пригодится.
"Вовочка", это не про прибыль на акцию, это про инвалидность по "плоскошутию" :)
Ворота, за очепятку спасибо, на код она к счастью не влияет.
Задача проекта - чтобы зацепив 3 провода к контроллеру, залив скетч, можно было посмотреть любой пульт, хоть древний от магнитофона, хоть современный от кондционера. Чтобы в простом варианте можно было быстро получить массив для отправки в rawsend, и в тоже время для сложных, чтобы это был наглядный инструмент для анализа параметров пульта.
Сделал на основе анализатора небольшой код для управления ZH/LW-03, реализовав все режимы и функции пульта, при этом специально несколькими методами записи значений. Единственное чего не делал - это работу с таймером, так как по правде никогда не использовал эту функцию у кондиционера и даже не знаю как там что выставляется :)
Первоначальные данные записываются из анализатора и не важно в каком режиме, при этом гарантируют что начальный, конечный, а так же не измененные скриптом сигналы будут восприняты корректно кондиционером.
#include <IRremote.h> IRsend irsend; //Объявляем массивы глобальными, чтобы иметь к ним доступ из функций, желающие могут загнав в класс //Берем из IR Decoder полученный C++ array, создав константу IRLength #define IRLength 101 unsigned int IRsignal[IRLength] = {6598, 7572, 650, 3400, 650, 3400, 650, 3400, 650, 3400, 650, 1400, 650, 3400, 650, 3400, 650, 3400, 650, 1400, 650, 1400, 650, 1400, 650, 1400, 650, 3400, 650, 1400, 650, 1400, 650, 1400, 650, 3400, 650, 3400, 650, 1400, 650, 1400, 650, 1400, 650, 1400, 545, 1400, 650, 3400, 555, 1400, 556, 1400, 533, 3400, 555, 3400, 650, 3400, 650, 3400, 650, 3400, 555, 1400, 499, 1400, 499, 3400, 555, 1400, 510, 3400, 650, 1400, 476, 3400, 650, 1400, 476, 1400, 499, 3400, 650, 1400, 499, 3400, 650, 1400, 522, 3400, 650, 1400, 556, 3400, 650, 3400, 650, 7307, 650}; //Так же берем строчку BIN MODE и загоняем в массив char, не забывая +1 к размерности boolean bits[47] = {1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1}; #define IRkhz 38 void setup() { Serial.begin(9600); bool ONOFF=true; int MODE=2; //1-охлаждение, 2-обогрев, 3-осушение, 4-вентилятор int TEMP=24; //Температура от 18 до 30, при этом если выставить 17 то датчик отключается и либо охлаждает до Арктики, либо греет до Африки bool ECON=false; //Режим экономии int AIRFLOW=B10; //B10 - нормальный, B00 - пол силы, B01 - сильный int FANSPEED=B00; //B00 - auto, B10 - high, B01 - medium, B11 - low bool HIGHPOWER=false; //Мощный режим MakeSignal(ONOFF,MODE,TEMP,ECON,AIRFLOW,FANSPEED,HIGHPOWER); } void MakeSignal(bool ONOFF,int MODE,int TEMP,int ECON,int AIRFLOW,int FANSPEED, bool HIGHPOWER) { //Если ВКЛ у нас 1 на 20ом и 0 на 28ом, то отправляем функции куда записать и насколько сдвиг инвертированного (обычно он всегда одинаковый) SetBit(ONOFF,20,8); //С режимами работы сложнее, там меняется 16, 17, 19, 21 и 22 бит, и поскольку режимов всего четыре проще сделать через case-ы switch (MODE) { case 1: //Охлаждение SetBit(0,16,8); SetBit(1,17,8); SetBit(0,19,8); SetBit(0,21,8); SetBit(0,22,8); break; case 2: //Отопление SetBit(0,16,8); SetBit(1,17,8); SetBit(0,19,8); SetBit(1,21,8); SetBit(0,22,8); break; case 3: //Осушение SetBit(0,16,8); SetBit(1,17,8); SetBit(0,19,8); SetBit(0,21,8); SetBit(1,22,8); break; case 4: //Вентилятор SetBit(1,16,8); SetBit(0,17,8); SetBit(1,19,8); SetBit(0,21,8); SetBit(0,22,8); break; } //С температурой сложнее, можно как и с режимами сделать 18 условий, поскольку у нас 4 бита которые равны t-17 в двоичной, то проще высчитать //SetBits передается число, сколько битов изменить, начиная с какого бита, ну и сдвиг для инверсии SetBits(TEMP-17,4,16,8); //Экономия в отличие от ВКЛ-ВЫКЛ дублируется единицей (активна) на 32 и 34 бите SetBit(ECON,32,8); SetBit(ECON,34,8); //Воздушный поток меняет 35 и 36 биты, при этом норма 35=1, 36=0, пол силы 0 и 0, сильный поток 0,1 //Чтобы не лепить условий, раз биты подряд, записываем, не забывая что функция записи инвертит порядок битов //B10 - нормальный, B00 - пол силы, B01 - сильный SetBits(AIRFLOW,2,35,8); //По той же схеме записываем скорость вентилятора, живущую в 33 и 34 битах SetBits(FANSPEED,2,33,8); //HIGHPOWER кроме того что живет на 32 бите, в случае включения зануляет 33 и 34, переводя мощность вентилятора в auto SetBit(HIGHPOWER,32,8); if (HIGHPOWER) {SetBits(0,2,33,8);} //Записываем полученные биты, помня, что данные у нас 4го элемента массива с шагом через один записываются как 1400 при нуле и 3400 при единице for (int i = 0; i < sizeof(bits) - 1; i++){ IRsignal[3+i*2]=bits[i] ? 3400 : 1400; } irsend.sendRaw(IRsignal, IRLength, IRkhz); } //Записывает бит в указанный адрес, а так же его инверсию в бит со сдвигом на shift void SetBit(bool Value, unsigned int Adress, unsigned int Shift) { bits[Adress]=Value; bits[Adress+Shift]=!Value; } //Записывает несколько битов void SetBits(unsigned int Value, unsigned int Bits, unsigned int Adress, unsigned int Shift) { for (int x=0; x<Bits; x++) { SetBit(bitRead(Value,Bits-x-1),Adress+x,Shift); //Инвертируя, если нужно без инверсии, то читаем бит x } } void loop() { }