Полуумный свет

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Есть желание сделать систему управления светом в доме, причем основанного на принципе «проходного» выключателя, то есть сделать так, чтобы включать и выключать свет можно было как в обычном ручном режиме, так и в автоматическом.

Для тех кто не в курсе поясню: проходной выключатель это система из 2-х или более выключателей, которые при перещелкивании включают или выключают лампочку не зависимо от положения другого выключателя, то есть независимо друг от друга. Получается что и ардуинка может включать и выключать лампочки, и пользователь через обычные выключатели. Очевидно что для реализации данного проекта необходимо тянуть дополнительную проводку, благо желание совпало с ремонтом и проводка кинулась так как нужно. Квартира у меня однокомнатная, в итоге насчиталось 6 лампочек, 2 на кухне, 2 в комнате, коридор и ванная с туалетом. На уну контактов хватает. Датчик тока нужен для того, чтобы ардуина понимала горит ли лампочка или ее выключили рукой. Проект условно разделен на 2 фазы, задачи первой фазы смастерить прототип в котором реализовано выключение всех лампочек при нажатии на кнопки, расположенные у кровати и у входной двери, а на втором сделать пульт (сначала проводной, потом безпроводной) из второй ардуины для настройки правил на первой ( включение /выключение по времени, по сенсорам и по кнопкам, с пульта).

Задачи системы управления освещением (конечная готовая система):

·         Управление освещением (с кнопок, по средством датчиков, с пульта управления, по времени);

·         Работа ручных выключателей независимо от работоспособности системы;

·         Контроль перегорания лампочки;

·         Беспроводной пульт управления с экранном;

Написать скетч решил по средствам создания классов, есть класс «лампочка», «сенсор», «правило», которые имеют свои параметры. В настоящий момент отлаживаю передачу данных между ардуинками (виртуально), пока не знаю, как реализовать беспроводной интерфейс.

Скетчик писался в онлайн эмуляторе так как это единственная возможность делать его на работе.

"Обрезанный" без второй дуньки

https://circuits.io/circuits/2285246-semy-smart-light-cut-edition

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//    Исполнительный элелемнт ПОЛОУМНОГО СВЕТА (обрезанный)   \\
// 				автор Mr.PRIVET	     		                  \\
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#define VER 1.0

#define but_pin_1 7
#define but_pin_2 8

#define lamp_pin_1 9
#define lamp_pin_2 10
#define lamp_pin_3 11
#define lamp_pin_4 12
#define lamp_pin_5 6
#define lamp_pin_6 13

#define cur_pin_1 5
#define cur_pin_2 4
#define cur_pin_3 3
#define cur_pin_4 A3
#define cur_pin_5 A4
#define cur_pin_6 A5

#define lamps 6
#define buttons 2
//==============================================================//
// Класс Лапочка												//
//==============================================================//
class LAMP 
{
  public:														//Хранит
  bool status,p_status;											//состояние,предыдущее состояние для функции Switch
  void update(){status=digitalRead(cur_pin);}					//обновляет состояние
  void save(){p_status=status;}									//сохраняет предыдущее состояние
  void on(){if(!status)digitalWrite(pin,!digitalRead(pin));}	//включает лампочку
  void off(){if(status)digitalWrite(pin,!digitalRead(pin));}	//выключает лампочку
  void setup(byte _pin,byte _cur_pin){pin=_pin;cur_pin=_cur_pin;pinMode(_pin,OUTPUT);pinMode(_cur_pin,INPUT);}
  private:byte pin,cur_pin;};									//пин лампы, датчика тока
//==============================================================
// Класс Кнопка
//==============================================================
class BUTTON {public:static const byte bounce_=50;static const unsigned long timer_=2000;static const unsigned int retention_=1000;
bool click_down,click_up,timer,retention,p,b,t,r;unsigned long m;byte _pb;
void setup(byte pb){_pb=pb;pinMode(_pb,INPUT);digitalWrite(_pb,1);click_down=0;click_up=0;timer=0;retention=0;m=millis();p=digitalRead(_pb);b=0;t=0;r=0;}
void read(){unsigned long nm=millis();boolean np=digitalRead(_pb),nb=0,nt=0,nr=0;click_down=0;click_up=0;timer=0;retention=0;if(np!=p){p=np;m=nm;}
if(nm-m>bounce_)nb=1;if(nb!=b){b=nb;if(p==0&&b==0){click_down=1;}if(p==1&&b==1)click_up=1;}if(nm-m>timer_)nt=1;if(nt!=t){t=nt;if(p==1&&t==1)timer=1;}
if(nm-m>retention_)nr=1;if(nr!=r){r=nr;if(p==0&&r==1)retention=1;}}};
//==============================================================
BUTTON button[buttons];
LAMP lamp[lamps];
const byte button_pins[buttons]={but_pin_1,but_pin_2};												//сдесь добавить если меняется количество кнопок
const byte lamp_pins[lamps]={lamp_pin_1,lamp_pin_2,lamp_pin_3,lamp_pin_4,lamp_pin_5,lamp_pin_6};	//сдесь добавить если меняется количество лампочек
const byte cur_pins[lamps]={cur_pin_1,cur_pin_2,cur_pin_3,cur_pin_4,cur_pin_5,cur_pin_6};	  		//сдесь добавить если меняется количество лампочек
bool all_lamps_off, all_lamps_on;																	//статусы режимов все вкл и все выкл
//==============================================================
// ФУНКЦИИ
//==============================================================
void all(bool op)												//все вкл(1), выкл(0)
{
  for (byte i=0;i<lamps;i++)
  {
    lamp[i].update();
  	lamp[i].save();
    if(op)lamp[i].on();else lamp[i].off();
  }
  all_lamps_off=!op;
  all_lamps_on=op;
}
//==============================================================
void all_switch()												//действие, которое после операции all возвращает все на место
{
  if (all_lamps_off||all_lamps_on)
  {
    for (byte i=0;i<lamps;i++)
      if(lamp[i].p_status)lamp[i].on();
      else lamp[i].off();
  }
  all_lamps_off=false;
  all_lamps_on=false;
}
//==============================================================
void lamp_update()
{
  for (byte i=0;i<lamps;i++)
    lamp[i].update();
}
//==============================================================
void button_update()											//обновляем кнопочки и проверяем кнопочные правила
{
  for (byte i=0;i<buttons;i++)button[i].read();
}
//==============================================================
void setup()
{
  for (byte i=0;i<buttons;i++)button[i].setup(button_pins[i]);	//установка пинов кнопок
  for (byte i=0;i<lamps;i++)lamp[i].setup(lamp_pins[i],cur_pins[i]);//установка пинов ламп и датчиков тока(номер, пин лампы, пин датчика)
}
void loop()
{ 
  delay(50);
  lamp_update();
  button_update();												//выполняем постоянные действия
  if(all_lamps_off&&button[0].retention)all_switch();
  else if(!all_lamps_off&&button[0].click_down)all(0);
  if(all_lamps_off&&button[1].retention)all_switch();
  else if(!all_lamps_off&&button[1].click_down)all(0);
}

Полный 

https://circuits.io/circuits/2285239-semy-smart-light

код исполнительного элемента

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//    Исполнительный элелемнт ПОЛОУМНОГО СВЕТА                \\
// 				автор Mr.PRIVET	     		                  \\
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//#include <RTC.h>
#include <EEPROM.h>

#define VER 1.3

#define but_pin_1 7
#define but_pin_2 8

#define sensor_pin_1 A0
#define sensor_pin_2 A1

#define lamp_pin_1 9
#define lamp_pin_2 10
#define lamp_pin_3 11
#define lamp_pin_4 12
#define lamp_pin_5 6
#define lamp_pin_6 13

#define cur_pin_1 5
#define cur_pin_2 4
#define cur_pin_3 3
#define cur_pin_4 A3
#define cur_pin_5 A4
#define cur_pin_6 A5

#define lamps 6
#define rules 9
#define buttons 2
#define sensors 2

//==============================================================//
// Класс Лапочка												//
//==============================================================//
class LAMP 
{
  public:														//Хранит
  bool status;													//состояние
  bool p_status;												//предыдущее состояние для функции Switch
  byte number;													//номер лампы
  byte sensor_number;											//номер сенсора который учавствует в управлении лампой
  byte pin;  													//пин лампы	
  void update(){status=digitalRead(cur_pin);}					//обновляет состояние
  void save(){p_status=status;}									//сохраняет предыдущее состояние
  void on(){if(!status)digitalWrite(pin,!digitalRead(pin));}	//включает лампочку
  void off(){if(status)digitalWrite(pin,!digitalRead(pin));}	//выключает лампочку
  void switch_(){digitalWrite(pin,!digitalRead(pin));}  		//переключает лампочку
  void set_up(byte _number,byte _pin,byte _cur_pin)
  {
    number=_number;
    pin=_pin;
    cur_pin=_cur_pin;
    pinMode(_pin,OUTPUT);
    pinMode(_cur_pin,INPUT);
  }
  private:
  byte cur_pin;													//пин датчика тока	
};
//==============================================================
// Класс сенсор
//==============================================================
class SENSOR
{
  public:
  bool status;
  bool control_lamp;
  byte working_time[4];											//(час начала,минуты начала,час конца,минуты конца)
  byte operation;
  byte number;
  byte active_time;
  byte val;
  long start_time;
  void set_up(byte _number,byte _pin,byte _sensetive=220, byte _active_time=10)
  {
    number=_number;
    pin=_pin;
    sensetive=_sensetive;
    active_time=_active_time;
    pinMode(pin,INPUT);
  }
  void update(byte h,byte m)
  {
    val=analogRead(pin)/4;
    if(analogRead(pin)-sensetive>0)
    status=true;
    else status=false;
    if(status&&h+60*m>working_time[0]+60*working_time[1]&&h+60*m<working_time[2]+60*working_time[3])
    {
      lamp_operation(control_lamp,operation);
    }      
  }
  private:
  byte pin;
  byte sensetive;
};

//==============================================================
// Класс Кнопка
//==============================================================
class BUTTON 
{
  public:
  static const byte bounce_=50, doubleclick_=200;
  static const unsigned long timer_=2000;
  static const unsigned int retention_=800;
  boolean click_down,click_up,doubleclick,timer,retention,p,b,dc,t,r;unsigned long m;byte c,_pb;
  void set_up(byte pb)
  {
    _pb=pb;
    pinMode(_pb,INPUT);
    digitalWrite(_pb,1);
    click_down=0;click_up=0;doubleclick=0;timer=0;retention=0;
    m=millis();p=digitalRead(_pb);b=0;dc=0;c=0;t=0;r=0;
  }
void read()
{
  unsigned long nm=millis();
  boolean np=digitalRead(_pb),nb=0,ndc=0,nt=0,nr=0;           
  click_down=0;
  click_up=0;
  doubleclick=0;
  timer=0;retention=0;
  if(np!=p){p=np;m=nm;}
  if(nm-m>bounce_){nb=1;}
  if(nm-m>doubleclick_){ndc=1;}
  if(ndc!=dc){dc=ndc;if(dc==1){c=0;}}
  if(nb!=b){b=nb;if(p==0&&b==0){click_down=1;++c;if(c==2){c=0;doubleclick=1;}}if(p==1&&b==1){click_up=1;}}
  if(nm-m>timer_){nt=1;}
  if(nt!=t){t=nt;if (p==1&&t==1){timer=1;}}
  if(nm-m>retention_){nr=1;}if(nr!=r){r=nr;if(p==0&&r==1){retention=1;}}}};

BUTTON button[buttons];

class RULE
{
  public:														//Хранит
  byte number;													//номер
  byte active_type;
  byte start_day;
  byte start_hour;
  byte start_min;
  byte stop_day;
  byte stop_hour;
  byte stop_min;
  byte operation;													//операцию 0-ничего, 1-выкл,2-вкл,3-переключить,4-все выкл,5-все вкл,6-вернуть после всего.
  byte lamp;															//номер лампы(не учитывается для операций 4-6
  byte button_number;
  byte button_type;
  byte sensor_number;
  byte sensor_time;
  byte sensor_sensetive;
  bool status;													//текущий статус операции
  friend BUTTON;
void update_rule (byte _day_w,byte _hour, byte _minute)				//проверка правила на начало
  {
    switch (active_type)
    {
      case 1:
      //проверка на наступления правила по времени
      if (start_day==_day_w||start_day==0||start_day==8&&_day_w<=5||start_day==9&&_day_w>=6)
        if (start_hour==_hour)
        if (start_min==_minute)
      {
        if (!status)
        {
          status=true;
        }
      }
      else status=false;
      break;
      case 2://проверка на наступления правила по кнопке
      switch (button_type)
      {
        case 0:
        status=false;
        break;
        case 1:
        if(button[button_number].click_down)status=true;
        break;
        case 2:
        if(button[button_number].click_up)status=true;
        break;
        case 3:
        if(button[button_number].doubleclick)status=true;
        break;
        case 4:
        if(button[button_number].retention)status=true;
        break;
      }
      break;
      case 3:
      //проверка на наступления правила по сенсору
      if (start_day>=_day_w||start_day==0||start_day==8&&_day_w<=5||start_day==9&&_day_w>=6)
      {
        if (stop_day<=_day_w||stop_day==0||stop_day==8&&_day_w<=5||stop_day==9&&_day_w>=6)
          if (start_hour>=_hour&&stop_hour<=_hour)
          if (start_min>=_minute&&stop_min<=_minute)
          if (!status)status=true;
        }
      else status=false;
      break;
    }
  }
char sprint()
{
  char  * s;
  sprintf (s,"%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i",number,active_type,start_day,start_hour,start_min,
           stop_day,stop_hour,stop_min,operation,lamp,button_number,button_type,sensor_number,sensor_time,sensor_sensetive);
  return * s;
}
void parse (String a)
{
  number			=	a.substring(0,2).toInt();
  active_type		=	a.substring(3,5).toInt();
  start_day			=	a.substring(6,8).toInt();
  start_hour		=	a.substring(9,11).toInt();
  start_min			=	a.substring(12,14).toInt();
  stop_day			=	a.substring(15,17).toInt();
  stop_hour			=	a.substring(18,20).toInt();
  stop_min			=	a.substring(21,23).toInt();
  operation			=	a.substring(24,26).toInt();
  lamp				=	a.substring(27,29).toInt();													
  button_number		=	a.substring(30,32).toInt();
  button_type		=	a.substring(33,35).toInt();
  sensor_number		=	a.substring(36,38).toInt();
  sensor_time		=	a.substring(39,41).toInt();
  sensor_sensetive	=	a.substring(42,44).toInt();
}  
void setup(byte n,byte at,byte std,byte sth,byte stm,byte spd,byte sph,byte spm,byte o,byte l,byte bn,byte bt,byte sn, int st, byte ss)
  {  
    number=n;
    active_type=at;
    start_day=std;
    start_hour=sth;
    start_min=stm;
    stop_day=spd;
    stop_hour=sph;
    stop_min=spm;
    operation=o;
    lamp=l;													
    button_number=bn;
    button_type=bt;
    sensor_number=sn;
    sensor_time=st;
    sensor_sensetive=ss;
  } 
};
//==============================================================
//==============================================================
//RTC    time;
LAMP lamp[lamps];
RULE rule[rules];
SENSOR sensor[sensors];
const byte sensor_pins[sensors]={sensor_pin_1,sensor_pin_2};										//сдесь добавить если меняется количество сенсоров
const byte button_pins[buttons]={but_pin_1,but_pin_2};												//сдесь добавить если меняется количество кнопок
const byte lamp_pins[lamps]={lamp_pin_1,lamp_pin_2,lamp_pin_3,lamp_pin_4,lamp_pin_5,lamp_pin_6};	//сдесь добавить если меняется количество лампочек
const byte cur_pins[lamps]={cur_pin_1,cur_pin_2,cur_pin_3,cur_pin_4,cur_pin_5,cur_pin_6};	  		//сдесь добавить если меняется количество лампочек

// ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ

unsigned long last_min_update,last_time_update,period_time_update,time;								//переменные для времени (нужно почистить)
byte day_w=1,hour=12,minute=0;																		// брать из часов 
volatile unsigned long wait_time;	
bool all_lamps_off, all_lamps_on;																	//статусы режимов все вкл и все выкл
byte button_operation[buttons]={4,6};																//3 массива для кнопок, операция, лампочка и вид нажатия
byte button_lamp[buttons]={0,1};																	//(можно запихнуть в класс)(настраиваются с пульта)
byte button_status[buttons]={3,4};																	//значения загружаются из еепром

// НАСТРАИВАЕМЫЕ ПАРАМЕНТЫ
static int minute_time = 1000;																		//длительность минуты по встроенному таймеру
String input_string;
String output_string;
//==============================================================
// ФУНКЦИИ
//==============================================================
void all(bool op)												//все вкл(1), выкл(0)
{
  for (byte i=0;i<lamps;i++)
  {
    lamp[i].update();
  	lamp[i].save();
    if(op)lamp[i].on();else lamp[i].off(); 
  }
  all_lamps_off=!op;
  all_lamps_on=op;
}
//==============================================================
void all_switch()												//действие, которое после операции all возвращает все на место
{
  if (all_lamps_off)
  {
    for (byte i=0;i<lamps;i++)
      if(lamp[i].p_status)digitalWrite(lamp[i].pin,!digitalRead(lamp[i].pin));
  }
  if (all_lamps_on)
  {
    for (byte i=0;i<lamps;i++)
      if(!lamp[i].p_status)digitalWrite(lamp[i].pin,!digitalRead(lamp[i].pin));
  }
  all_lamps_off=false;
  all_lamps_on=false;
}
//==============================================================
/*
void write_byte_eeprom(byte val,int addr)						//запись байта в еепром с проверкой
{
  if (val!=EEPROM.read(addr))EEPROM.write(val,addr);
}
//==============================================================  
byte read_byte_eeprom(int addr)									//чтение байта из еепром
{
  byte val=EEPROM.read(addr);
  return val;
}
//==============================================================

void save_eeprom()												//сохраняем все в еепром (правила и кнопки)
{
  for (byte i=0;i<rules;i++)
  {
    write_byte_eeprom(rule[i].number,6*i);
    write_byte_eeprom(rule[i].day_w,6*i+1);
    write_byte_eeprom(rule[i].hour,6*i+2);
    write_byte_eeprom(rule[i].minute,6*i+3);
    write_byte_eeprom(rule[i].operation,6*i+4);
    write_byte_eeprom(rule[i].lamp,6*i+5);
  }
  for (byte i=0;i<buttons;i++)
  {
    write_byte_eeprom(button_operation[i],rules*6+3*i);
    write_byte_eeprom(button_lamp[i],rules*6+3*i+1);
    write_byte_eeprom(button_status[i],rules*6+3*i+2);
  }
}
//==============================================================
void load_eeprom()												//читаем все из еепром (правила и кнопки)
{
  for (byte i=0;i<rules;i++)
  {
  rule[i].number=read_byte_eeprom(6*i);
    rule[i].day_w=read_byte_eeprom(6*i+1);
    rule[i].hour=read_byte_eeprom(6*i+2);
    rule[i].minute=read_byte_eeprom(6*i+3);
    rule[i].operation=read_byte_eeprom(6*i+4);
    rule[i].lamp=read_byte_eeprom(6*i+5);
  }
  for (byte i=0;i<buttons;i++)
  {
    button_operation[i]=read_byte_eeprom(rules*6+3*i);
    button_lamp[i]=read_byte_eeprom(rules*6+3*i+1);
    button_status[i]=read_byte_eeprom(rules*6+3*i+2);
  }
}
*/
//==============================================================

void lamp_update()												//обновляем состояние лампочек
{
  for (byte i=0;i<lamps;i++)
  {
    lamp[i].update();
  }
}

//==============================================================
void time_update()												//здесь сделать чтение из датчика времени
{
  period_time_update=millis()-last_time_update;
  last_time_update=millis();
  minute=minute+period_time_update/minute_time;
  while (minute>59)
  {
    hour++;
  	minute=minute-60;
  }
  while (hour>23)
  {
    day_w++;
  	hour=hour-24;
    if(day_w>7)day_w=1;
  }
  /*
  if (time.weekday==0)day_w=7;else day_w=time.weekday;	//перевод из буржуйских дней в русские)
  hour=time.Hours;
  minute=time.minutes;
//time.seconds  секунды     0-59
//time.minutes  минуты      0-59
//time.hours    часы        1-12
//time.Hours    часы        0-23
//time.midday   полдень     0-1 (0-am, 1-pm)
//time.day      день месяца 1-31
//time.weekday  день недели 0-6 (1-понедельник, 6-суббота, 0-воскресенье)
//time.month    месяц       1-12
//time.year     год         0-99
//time.gettime("строка с параметрами")       функция получает и выводит строку заменяя описанные ниже символы на текущее время
//указанные символы эдентичны символам для функции date() в PHP
//s  секунды                       от      00    до       59  (два знака)
//i  минуты                        от      00    до       59  (два знака)
//h  часы в 12-часовом формате     от      01    до       12  (два знака)
//H  часы в 24-часовом формате     от      00    до       23  (два знака)
//d  день месяца                   от      01    до       31  (два знака)
//w  день недели                   от       0    до        6  (один знак: 0-воскресенье, 6-суббота)
//D  день недели наименование      от     Mon    до      Sun  (три знака: Mon Tue Wed Thu Fri Sat Sun)
//m  месяц                         от      01    до       12  (два знака)
//M  месяц наименование            от     Jan    до      Dec  (три знака: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
//Y  год                           от    2000    до     2099  (четыре знака)
//y  год                           от      00    до       99  (два знака)
//a  полдень                               am   или       pm  (два знака, в нижнем регистре)
//A  полдень                               AM   или       PM  (два знака, в верхнем регистре)
  */
}

//==============================================================
void lamp_operation(byte _lamp,byte operation)
{
  switch(operation)
  {
    case 0:
    break;
    case 1:
    lamp[_lamp].off();
    break;
    case 2:
    lamp[_lamp].on();
    break;
  	case 3:
    lamp[_lamp].switch_();
    break;
  	case 4:
    all(0);
    break;
  	case 5:
    all(1);
    break;
  	case 6:
    all_switch();
    break;
  }
}
void start_rule(byte i, bool but)								// запуск правила
{
  switch((but)? button_operation[i]:rule[i].operation)
  {
  	case 0:
  	break;
    case 1:
    lamp[(but)?button_lamp[i]:rule[i].lamp].off();
    break;
    case 2:
    lamp[(but)?button_lamp[i]:rule[i].lamp].on();
    break;
  	case 3:
    lamp[(but)?button_lamp[i]:rule[i].lamp].switch_();
    break;
  	case 4:
    all(0);
    break;
  	case 5:
    all(1);
    break;
  	case 6:
    all_switch();
    break;
  }
}
//==============================================================
void button_update()											//обновляем кнопочки и проверяем кнопочные правила
{
  for (byte i=0;i<buttons;i++)
  {
    button[i].read();
    switch (button_status[i])
    {
      case 0:
      break;
      case 1:
      if(button[i].click_down)start_rule(i,1);
      break;
      case 2:
      if(button[i].click_up)start_rule(i,1);
      break;
      case 3:
      if(button[i].doubleclick)start_rule(i,1);
      break;
      case 4:
      if(button[i].retention)start_rule(i,1);
      break;
    }
  }
} 
//==============================================================
void rules_update()												// сравинваем текущее время на наступление правил
{
  for (byte i=0;i<rules;i++)
  {
    rule[i].update_rule(day_w,hour,minute);
    if(rule[i].status)start_rule(i,0);
  }
}
//==============================================================
void sensor_update()
{
  for(byte i=0;i<sensors;i++)
  {
    sensor[i].update(hour,minute);
  }
}



//==============================================================
void send_time()												//послать время
{
  
}
//==============================================================
void get_time()													//получить время
{
 
}

//==============================================================
void send_rule(byte i)												//послать все правила
{
/*
  for (byte i=0;i<rules;i++)
  {
    send_byte(rule[i].number);
    send_byte(rule[i].active_type);
    send_byte(rule[i].start_day);
    send_byte(rule[i].start_hour);
    send_byte(rule[i].start_min);
    send_byte(rule[i].stop_day);
    send_byte(rule[i].stop_hour);
    send_byte(rule[i].stop_min);
    send_byte(rule[i].operation);
    send_byte(rule[i].lamp);
    send_bool(rule[i].status);
    send_byte(rule[i].button_number);
    send_byte(rule[i].button_type);
    send_byte(rule[i].sensor_number);
    send_byte(rule[i].sensor_time);
    send_byte(rule[i].sensor_sensetive);
  }
*/
}
//==============================================================
void get_rule(byte i)												//получить все правила
{
  char ch[45];
  printf(ch,"%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i",rule[i].number,rule[i].active_type,rule[i].start_day,rule[i].start_hour,rule[i].start_min,rule[i].stop_day,
         rule[i].stop_hour,rule[i].stop_min,rule[i].operation,rule[i].lamp,rule[i].button_number,rule[i].button_type,rule[i].sensor_number,rule[i].sensor_time,rule[i].sensor_sensetive);
  String str(ch);
  output_string=str;
  //save_eeprom();
}
/*
//==============================================================
																//послать все правила для кнопок
void send_buttons()
{
  for(byte i=0;i<buttons;i++)
  {
    send_byte(button_operation[i]);
    send_byte(button_lamp[i]);
    send_byte(button_status[i]);
  }
}

//==============================================================
																//получить все правила для кнопок

void get_buttons()
{
  delay(100);
  for(byte i=0;i<buttons;i++)
  {
    button_operation[i]=get_byte();
    button_lamp[i]=get_byte();
    button_status[i]=get_byte();
  }
  //save_eeprom();
}

//==============================================================
*/																//послать статус всех ламп
void send_status()
{
  output_string="";
  output_string+=String(day_w);
  if(hour>9)output_string+=String(hour);else output_string+="0"+String(hour);
  if(minute>9)output_string+=String(minute);else output_string+="0"+String(minute);    
  for (byte i=0;i<lamps;i++)output_string+=String(lamp[i].status);
  Serial.print(output_string);
/*
    for (byte i=0;i<lamps;i++)
    {
      send_bool(lamp[i].status);
    }
    send_bool(all_lamps_off);
    send_bool(all_lamps_on);
  for(byte i=0;i<sensors;i++)
  {
    send_byte(sensor[i].val);
  }
*/
}
//==============================================================
void send_const()												//послать начальные численные константы для проверки совместимости пульта
{																//(можно сделать подстройку пульта под численные переменные)
  /*
  send_byte(lamps);
  delay(100);
  send_byte(rules);
  delay(100);
  send_byte(buttons);
  delay(100);
  send_byte(sensors);
  delay(100);
  */
}
//==============================================================

void parse(String a)
{
  if(a.indexOf("send_rule_")>0)send_rule(a.substring(a.indexOf("send_rule_")).toInt());
  if(a.indexOf("get_rule_")>0)get_rule(a.substring(a.indexOf("get_rule_")).toInt());
  if(a.equals("send_status"))send_status();
  if(a.equals("get_time"))get_time();
}
//==============================================================
void inter()													//дейтвие при прерывании
{
  detachInterrupt(0);
  interrupts();
  input_string="";
  while(Serial.available()>0)input_string +=(char)(Serial.read());
  parse(input_string);
  attachInterrupt(0, inter, RISING);
}
//==============================================================
void setup()
{
  attachInterrupt(0, inter, RISING);							//настройка прерывания
  Serial.begin(19200);
  //time.begin(RTC_DS1307);										//для модуля часов
  //load_eeprom();												//загрузка данных из еепром
  for (byte i=0;i<buttons;i++)button[i].set_up(button_pins[i]);	//установка пинов кнопок
  for (byte i=0;i<lamps;i++)lamp[i].set_up(i,lamp_pins[i],cur_pins[i]);//установка пинов ламп и датчиков тока(номер, пин лампы, пин датчика)
  for (byte i=0;i<rules;i++)
  {rule[i].number=i;}											//номерация правил
  for (byte i=0;i<sensors;i++)sensor[i].set_up(i,sensor_pins[i]);
  sensor[0].working_time[0]=12;
  sensor[0].working_time[1]=0;
  sensor[0].working_time[2]=13;
  sensor[0].working_time[3]=0;
  sensor[0].operation=4;
  rule[0].setup(0,2,1,12,30,2,13,45,1,1,1,2,2,300,200);
}
void loop()
{ 
  delay(100);													//для ускорения виртуальной 
  button_update();												//выполняем постоянные действия
  lamp_update();
  if (millis()-last_min_update>=minute_time)					//выполняем минутные действия
  {
    time_update();
    rules_update();
    sensor_update();
    last_min_update=millis();
  }
}

код пульта управления

//++++++++++++++++++++++++++++++++++++++++++++++++++\\
//    пульт управления		  ПОЛОУМНОГО СВЕТА      \\
// 				автор Mr.PRIVET	     				\\
//++++++++++++++++++++++++++++++++++++++++++++++++++\\

#define pin_button_left 5
#define pin_button_right 3
#define pin_button_enter 4
#define pin_button_esc 2
#define pin_inter 9
#define pin_led 13
#define lamps 6
#define rules 9
#define buttons 2
#define sensors 2
#include <LiquidCrystal.h>

LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);

//==============================================================
// Велсипед (кнопковый, титановый)

class BUTTON {public:static const byte bounce_=50, doubleclick_=200;static const unsigned long timer_=2000;static const unsigned int retention_=800;
boolean click_down,click_up,doubleclick,timer,retention,p,b,dc,t,r;unsigned long m;byte c,_pb;
BUTTON(byte pb){_pb=pb;pinMode(_pb,INPUT);digitalWrite(_pb,1);click_down=0;click_up=0;doubleclick=0;timer=0;retention=0;m=millis();p=digitalRead(_pb);b=0;dc=0;c=0;t=0;r=0;}
void read(){unsigned long nm=millis();boolean np=digitalRead(_pb),nb=0,ndc=0,nt=0,nr=0;click_down=0;click_up=0;doubleclick=0;timer=0;retention=0;if(np!=p){p=np;m=nm;}
if(nm-m>bounce_){nb=1;}if(nm-m>doubleclick_){ndc=1;}if(ndc!=dc){dc=ndc;if(dc==1){c=0;}}if(nb!=b){b=nb;if(p==0&&b==0){click_down=1;++c;if(c==2){c=0;doubleclick=1;}}
if(p==1&&b==1){click_up=1;}}if(nm-m>timer_){nt=1;}if(nt!=t){t=nt;if(p==1&&t==1){timer=1;}}if(nm-m>retention_){nr=1;}if(nr!=r){r=nr;if(p==0&&r==1){retention=1;}}}};
//==============================================================

class RULE
{
  public:														
  byte number;													
  byte active_type;
  byte start_day;
  byte start_hour;
  byte start_min;
  byte stop_day;
  byte stop_hour;
  byte stop_min;
  byte operation;												
  byte lamp;													
  byte button_number;
  byte button_type;
  byte sensor_number;
  int sensor_time;
  byte sensor_sensetive;
  bool status;
  void setup(byte n,byte at,byte std,byte sth,byte stm,byte spd,byte sph,byte spm,byte o,byte l,byte bn,byte bt,byte sn, int st, byte ss)
  {  
    number=n;
    active_type=at;
    start_day=std;
    start_hour=sth;
    start_min=stm;
    stop_day=spd;
    stop_hour=sph;
    stop_min=spm;
    operation=o;
    lamp=l;													
    button_number=bn;
    button_type=bt;
    sensor_number=sn;
    sensor_time=st;
    sensor_sensetive=ss;
  } 
};

//===============================================================

BUTTON b_left(pin_button_left);
BUTTON b_right(pin_button_right);
BUTTON b_enter(pin_button_enter);
RULE rule[rules];

// ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ

unsigned long time_m=millis();									//переменная для времени по минутам
unsigned long time_s=millis();									//переменная для времени по секундам
int menu=0,level=0,print_rule=0;								//переменная меню
bool screen_update;												//переменная для обновления экрана
bool esc=false;													//переменная для отмены/возврата
bool go_next=false;												//
bool all_lamps_off, all_lamps_on;								//переменные для режимов все выкл и все вкл
byte day_w=1,hour=12,minute=5;									//переменные времени
char string_1[17], string_2[17];

// НАСТРАИВАЕМЫЕ ПАРАМЕНТЫ
static int second_time = 1000;									//длительность секунды по внутреннему таймеру
static int minute_time = 60000;									//длительность минуты по внутреннему таймеру

// ПЕРЕМЕННАЯ ДЛЯ ЛАМП

byte lamp_status[lamps]={0,0,0,0,0,0};							//статус ламп
//char lamp_name[lamps]={"0","1","2","3","4","5",};		//названия ламп
// ПЕРЕМЕННЫЕ ПЕРЕДАЧИ ДАННЫХ
String input_string;
String output_string;


// ПЕРЕМЕННЫЕ ДЛЯ КНОПОК В УПРАВЛЕНИИ

byte 
button_operation[buttons],
button_lamp[buttons],
button_status[buttons],
sensor_val[sensors];	

// СИМВОЛЫ НА ЭКРАНЕ
byte 	   lamp_off[8]={B01110,
                        B10001,
                        B10001,
                        B10001,
                        B10001,
                        B10001,
                        B01110,
                        B01110};
byte 		lamp_on[8]={B01110,
                        B10111,
                        B10111,
                        B10111,
                        B10111,
                        B10111,
                        B01110,
                        B01110};
byte  symbol_button[8]={B00100,
                        B10101,
                        B01110,
                        B00100,
                        B00000,
                        B01110,
                        B01110,
                        B11111};
byte  symbol_sensor[8]={B10101,
                        B00000,
                        B01010,
                        B00000,
                        B00100,
                        B00000,
                        B01110,
                        B11111};
byte   symbol_clock[8]={B00000,
                        B00000,
                        B01110,
                        B10101,
                        B10111,
                        B10001,
                        B01110,
                        B00000};
byte  symbol_number[8]={B00000,
                        B10011,
                        B10010,
                        B10010,
                        B11010,
                        B10110,
                        B10010,
                        B00000};


//===============================================================
//           				ФУНКЦИИ							   //
//===============================================================
void lcd_print(String mes1,String mes2="",bool string_1_senter=0,bool string_2_senter=0,bool without_del=0,int del=1000)
{
  lcd.clear();
  if(string_1_senter)lcd.setCursor(8-mes1.length()/2,0);
  lcd.print(mes1);
  if(string_2_senter)lcd.setCursor(8-mes2.length()/2,1);
  else lcd.setCursor(0,1);
  lcd.print(mes2);
  if(!without_del)delay(del);
  if(!without_del)lcd.clear();
  screen_update=false;
}
//===============================================================
void button_update()											
{
  b_left.read();
  b_right.read();
  b_enter.read();
}
//===============================================================
//проверяет нажата ли кнопка
bool button_press()										
{
  bool press=false;
  if (b_left.click_down||b_left.retention)press=true;
  if (b_right.click_down||b_right.retention)press=true;
  if (b_enter.click_down||b_enter.retention)press=true;
  return press;
}
//===============================================================
//ПЕРЕДАЧА ДАННЫХ ПО СЕРИАЛ
//===============================================================
void send_string(String a)									
{
  Serial.print(a);
  delay(20);
  digitalWrite(pin_inter, HIGH);
  digitalWrite(pin_led, HIGH);
  digitalWrite(pin_inter, LOW);
  digitalWrite(pin_led, LOW);
}
void get_string()
{
  input_string="";
  while(Serial.available())input_string+=(char)(Serial.read());
}

//===============================================================

//===============================================================

//===============================================================
char * vith0(byte i,byte l)
{
  char  ci[l];
  if(l==2)
  {
    if(i>9)
    {
      ci[0]=i/10;
      ci[1]=i%10;
    }
    else 
    {
      ci[0]=0;
      ci[1]=i;
    }
  }
  if(l==3)
  {
    if(i>99)
    {
      ci[0]=i/100;
      ci[1]=i%100/10;
      ci[2]=i%100%10;
    }
    if(i>9&&i<=99)
    {
      ci[0]=0;
      ci[1]=i/10;
      ci[2]=i%10;
    }
    if(i<=9)
    {
      ci[0]=0;
      ci[1]=0;
      ci[2]=i;
    }
  }
  return ci;
}
//===============================================================
void send_rule(byte i)												//послать правила
{
  output_string=String(with0(i);
}
//===============================================================
void get_status()												//получить состояния ламп
{
  send_string("send_status");
  //delay(50);
  get_string();
  parse("status");
}
//===============================================================
void parse(String a)
{
  if (a="status")
  {
    day_w=input_string.substring(0,1).toInt();
    hour=input_string.substring(1,3).toInt();
    minute=input_string.substring(3,5).toInt();
    for(byte i=0;i<lamps;i++)
    lamp_status[i]=input_string.substring(5+i,6+i).toInt();
  }
}
//===============================================================
void send_time()													//получить время
{
  
}
//===============================================================
void get_rule(byte i)												//получить правила
{
  
}
//===============================================================
void menu_change()												
{
  if(level==0)
  {
  if(b_right.click_down)menu+=1;
  if(b_left.click_down)menu-=1;
  }
  if(menu==1&&level==1)
  {
  if(b_right.click_down)print_rule+=1;
  if(b_left.click_down)print_rule-=1;
  } 
  if(b_enter.click_down)level+=1;
  if(b_enter.retention)level-=2;
  menu=constrain(menu,0,2);
  level=constrain(level,0,2);
  print_rule=constrain(print_rule,0,rules-1);
}													
//===============================================================
char * operation_name(byte operat)								//возвращает текстовое названия операций
{
  char * op_name;
  if (operat==0)op_name="nothing";
  if (operat==1)op_name="off";
  if (operat==2)op_name="on";
  if (operat==3)op_name="switch";
  if (operat==4)op_name="off all";
  if (operat==5)op_name="on all";
  if (operat==6)op_name="switch all";
  return op_name;
}
//===============================================================
char * button_type_name(byte status)									//возвращает текстовое названия типов нажатий
{
  char * st_name;
if(status==1)st_name="down";
if(status==2)st_name="up";
if(status==3)st_name="double";
if(status==4)st_name="ret";
return st_name;
}
//===============================================================
char * day_short_name(byte day) 								//возвращает текстовое сокращенное название дней недели
{
  char * day_name;
  if (day==0)day_name="ever";
  if (day==1)day_name="mon";
  if (day==2)day_name="tue";
  if (day==3)day_name="wed";
  if (day==4)day_name="thu";
  if (day==5)day_name="fri";
  if (day==6)day_name="sat";
  if (day==7)day_name="sun";
  if (day==8)day_name="work";
  if (day==9)day_name="ends";
  return day_name;
}
//===============================================================
char * day_name(byte day) 										//возвращает текстовое полное название дней недели
{
  char * day_name;
  if (day==0)day_name="everyday";
  if (day==1)day_name="monday";
  if (day==2)day_name="tuesday";
  if (day==3)day_name="wednesday";
  if (day==4)day_name="thursday";
  if (day==5)day_name="friday";
  if (day==6)day_name="saturday";
  if (day==7)day_name="sunday";
  if (day==8)day_name="workdays";
  if (day==9)day_name="weekends";
  return day_name;
}
//===============================================================
char * type_name(byte t)
{
  char * type_name;
  if (t==0)type_name="nothing";
  if (t==1)type_name="time";
  if (t==2)type_name="button";
  if (t==3)type_name="sensor";
  return type_name;
}
//===============================================================
void start_screen()												//распечатка начального экрана
{
  /*
  sprintf(string_1,"%c%c%c%c%c%c %iR %i%c %i%c",lamp_status[0]?2:1,lamp_status[1]?2:1,lamp_status[2]?2:1,lamp_status[3]?2:1,lamp_status[4]?2:1,lamp_status[5]?2:1,rules,buttons,3,sensors,4);
  sprintf(string_2,"123456 %02i:%02i-%s",hour,minute,day_short_name(day_w));
  lcd_print(string_1,string_2,0,0,1);
  */
  lcd_print(input_string,output_string,0,0,1);
}

//===============================================================
void show_rule(byte i)											//показвает определенное правило
{
  switch (rule[i].active_type)
  {
    case 0:
    sprintf(string_1,"%i) NOT SET",i+1);
    sprintf(string_2,"");
    lcd_print(string_1,string_2,1,1,1);
    break;
    case 1:
    sprintf(string_1,"%1i) %1c %i:%02i %s",i+1,5,rule[i].start_hour,rule[i].start_min,day_short_name(rule[i].start_day));
    if(rule[i].operation>0&&rule[i].operation<4)sprintf(string_2,"%s lamp %c %1i",operation_name(rule[i].operation),6,rule[i].lamp+1);
    else sprintf(string_2,"%s",operation_name(rule[i].operation));
    lcd_print(string_1,string_2,1,1,1);
    break;
    case 2:
    sprintf(string_1,"%1i) %c %c %1i %s",i+1,3,6,rule[i].button_number,button_type_name(rule[i].button_type));
    if(rule[i].operation>0&&rule[i].operation<4)sprintf(string_2,"%s lamp %c %1i",operation_name(rule[i].operation),6,rule[i].lamp+1);
    else sprintf(string_2,"%s",operation_name(rule[i].operation));
    lcd_print(string_1,string_2,1,1,1);
    break;
    case 3:
    byte s_time;
    char * s_time_name;
    if(rule[i].sensor_time<60){s_time_name = "sec";s_time=rule[i].sensor_time;} else{s_time_name = "min";s_time=rule[i].sensor_time/60;}
    sprintf(string_1,"%1i) %c %c %1i %i %s",i+1,4,6,rule[i].sensor_number,s_time,s_time_name);
    sprintf(string_2,"%i:%02i-%i:%02i %s",rule[i].start_hour,rule[i].start_min,rule[i].stop_hour,rule[i].stop_min,day_short_name(rule[i].start_day));
    lcd_print(string_1,string_2,1,1,1);
    break;
  }
  screen_update=false;
}
//===============================================================
void set_time()													//настройка времени
{
  day_w=setup_val("SET WEEK DAY",13,day_w);
  hour=setup_val("SET HOUR",6,hour);
  minute=setup_val("SET MINUTE",7,minute);
  level--;
}
//===============================================================
  int setup_val(char * s1,byte type,int val)
{ 
  screen_update=true;
  go_next=false;
  int min;
  int max;
  while(!go_next)
  {
    sprintf(string_2,"%2i",val);
    if(screen_update)
    {
      if(type==1){lcd_print(s1,operation_name(val),1,1,1);min=0;max=6;}
      if(type==2){lcd_print(s1,button_type_name(val),1,1,1);min=1;max=4;}
      if(type==3){lcd_print(s1,day_short_name(val),1,1,1);min=0;max=9;}
      if(type==4){lcd_print(s1,day_name(val),1,1,1);min=0;max=9;}
      if(type==5){lcd_print(s1,type_name(val),1,1,1);min=0;max=3;}
      if(type==6){lcd_print(s1,string_2,1,1,1);min=0;max=23;}
      if(type==7){lcd_print(s1,string_2,1,1,1);min=0;max=59;}
      if(type==8){lcd_print(s1,string_2,1,1,1);min=0;max=lamps-1;}
      if(type==9){lcd_print(s1,string_2,1,1,1);min=0;max=buttons-1;}
      if(type==10){lcd_print(s1,string_2,1,1,1);min=0;max=sensors-1;}
      if(type==11){lcd_print(s1,string_2,1,1,1);min=0;max=3600;}
      if(type==12){lcd_print(s1,string_2,1,1,1);min=0;max=256;}
      if(type==13){lcd_print(s1,day_name(val),1,1,1);min=1;max=7;}
    }
    button_update();
    while(!button_press())
    {
      delay(50);
      button_update();
    }
    if(b_right.click_down)val+=1;
    if(b_left.click_down)val-=1;
    if(b_enter.click_down)go_next=true;
    val=constrain(val,min,max);
    screen_update=true;
  }
  return val;
} 
//===============================================================
void set_rule(byte i)											//настройка правила и последующая передача на исполнительное устройство
{
  rule[i].active_type=setup_val("SET ACTIVE TYPE ",5,rule[i].active_type);
  switch (rule[i].active_type)
  {
    case 1:
    rule[i].start_day=setup_val("SET START DAY",4,rule[i].start_day);
    rule[i].start_hour=setup_val("SET START HOUR",6,rule[i].start_hour);
    rule[i].start_min=setup_val("SET START MINUTE",7,rule[i].start_min);
    rule[i].operation=setup_val("SET OPERATION",1,rule[i].operation);
    if(rule[i].operation>=1&&rule[i].operation<=3)rule[i].lamp=setup_val("SET LAMP",8,rule[i].lamp);
    break;
    case 2:
    rule[i].operation=setup_val("SET OPERATION",1,rule[i].operation);
    if(rule[i].operation>=1&&rule[i].operation<=3)rule[i].lamp=setup_val("SET LAMP",8,rule[i].lamp);
    rule[i].button_number=setup_val("SET BUTTON",9,rule[i].button_number);
    rule[i].button_type=setup_val("SET BUTTON TYPE",2,rule[i].button_type);
    break;
    case 3:
    rule[i].start_day=setup_val("SET START DAY",4,rule[i].start_day);
    rule[i].start_hour=setup_val("SET START HOUR",6,rule[i].start_hour);
    rule[i].start_min=setup_val("SET START MINUTE",7,rule[i].start_min);
    rule[i].stop_day=setup_val("SET STOP DAY",4,rule[i].stop_day);
    rule[i].stop_hour=setup_val("SET STOP HOUR",6,rule[i].stop_hour);
    rule[i].stop_min=setup_val("SET STOP MINUTE",7,rule[i].stop_min);
    rule[i].operation=setup_val("SET OPERATION",1,rule[i].operation);
    if(rule[i].operation>=1&&rule[i].operation<=3)rule[i].lamp=setup_val("SET LAMP",8,rule[i].lamp);
    rule[i].sensor_number=setup_val("SET SENSOR",10,rule[i].sensor_number);
    rule[i].sensor_time=setup_val("SET SENSOR TIME",11,rule[i].sensor_time);
    rule[i].sensor_sensetive=setup_val("SET SENSOR SENS",12,rule[i].sensor_sensetive);
    break;
  }
  level--;
  screen_update=true;
}
//===============================================================
void menus()													//навигация по меню
{
  byte y=0;
  switch (menu)
  {
    case 0:
    start_screen();
    break;
    case 1:
    for(byte i=0;i<rules;i++)if(rule[i].operation!=0)y++;
    sprintf(string_1,"(%i of %i)",y,rules);
    if(level==0)lcd_print("RULES",string_1,1,1,1);
    if(level==1)show_rule(print_rule);
    if(level==2)set_rule(print_rule);
    break;
    case 2:
    if(level==0)
    {
      sprintf(string_1,"(%02i:%02i %s)",hour,minute,day_short_name(day_w));
      lcd_print("TIME",string_1,1,1,1);
    }
    if(level==1)set_time();
    break;
  }
}
//===============================================================
void inter()
{
  lcd.clear();
  lcd.print("INTER");
  menu=0;
  level=0;
  screen_update=true;
  esc=true;
}
//===============================================================
void setup()
{
  attachInterrupt(0,inter,RISING);
  lcd.createChar(1, lamp_off);									//настройки символов ламп
  lcd.createChar(2, lamp_on);
  lcd.createChar(3, symbol_button);
  lcd.createChar(4, symbol_sensor);
  lcd.createChar(5, symbol_clock);
  lcd.createChar(6, symbol_number);
  lcd.begin(16,2);
  lcd_print("Half|Smart|Light","start           ",1,1,1);
  lcd.setCursor(5,1);
  for (byte i=0;i<11;i++)
  {lcd.print(".");delay(50);}
  Serial.begin(19200);
  screen_update=true;
  pinMode(pin_button_esc, INPUT);								//пин отправки команды на прерывание
  for (byte i=0;i<rules;i++)rule[i].number=i;					//нумирация правил(не обязательно, щас и так их получим)
  delay(50);
  pinMode(pin_inter,OUTPUT);
  delay(50);
  get_rule(0);													//получение правил
  delay(50);
  get_status();
  //get_const();												//проверка на соответствие
}
//===============================================================
void loop()
{
  delay(100);													//для работы симулятора
  button_update();												//обновление состояния кнопок
  if(button_press())
  {
    menu_change();
    screen_update=true;
  }
  if (screen_update)
  {
    screen_update=false;
    menus(); 
  }
  if (millis()-time_s>second_time)								//секундные действия
  {
    time_s=millis();
    get_status();
    screen_update=true;
  }
  if (millis()-time_m>minute_time)								//минутные действия
  {
    time_m=millis();
    screen_update=true;
  }
}
//===============================================================

 Здоровая критика приветствуется...

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

ткните пожалуйста куда нибудь в разборщик сборщик команд по сериал, а то он у меня совсем коленочный и не работает и не дописан к тому же... или хотя бы на пальцах расскажите как лучше сделать. Мне нужно передавать правила от исполнительного элемента на пульт и обратно, а также передавать статус от исполнительного на пульт. там в circuits все наглядно...