Скетч для управления кондиционером

На основе вчера опубликованной программки IR-decoder для анализа сигналов пульта сегодня сделал для примера скетч, управляющий пультом 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() {

}