Полуумный свет
- Войдите на сайт для отправки комментариев
Есть желание сделать систему управления светом в доме, причем основанного на принципе «проходного» выключателя, то есть сделать так, чтобы включать и выключать свет можно было как в обычном ручном режиме, так и в автоматическом.
Для тех кто не в курсе поясню: проходной выключатель это система из 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;
}
}
//===============================================================
Здоровая критика приветствуется...
ткните пожалуйста куда нибудь в разборщик сборщик команд по сериал, а то он у меня совсем коленочный и не работает и не дописан к тому же... или хотя бы на пальцах расскажите как лучше сделать. Мне нужно передавать правила от исполнительного элемента на пульт и обратно, а также передавать статус от исполнительного на пульт. там в circuits все наглядно...