У меня в нежилом доме котел электрический 3-х ступенчатый. 3-6-9 КВт., и счетчик 2х тарифный. Соответственно задумка по максимуму греть теплоноситель ночью, а днем только по необходимости ( чтоб температура была положительная). При этом хочу задействовать ступенчатый нагрев (3-6-9 КВт) в зависимости от (чего??)- темп. за бортом\темп. в доме\ дельта температур дом-улица...
Доброй ночи разработчики! Сваял я термостат для управления двумя нагревателями, алгоритм такой, если температура ниже заданной, включаем обогреватель 1, при этом, если разница текущей и установленной температурой больше х градусов, включается нагреватель 2. Если меньше х, нагреватель 2 отключается и температура доводится первым до установленной+гистерезис. Но, если у первого мощи не хватает и разница температур меньше х , температура не растет и второй не включается. Возникла у меня необходимость сделать контроль роста температуры и перевести управление вторым нагревателем на этот контроль. Идею вижу так, если за время Т температура поднялась на Х градусов, включение нагревателя 2 не требуется, если поднялась на Y градусов или не поднялась или опустилась, включаем нагреватель 2. При этом модуля часов у меня там не предусмотрено. Всю голову сломал нах и гугл не помогает. Может кто подскажет? P.S. Сильно не пинайте, это не окончательная версия кода, но уже пытается работать...
#include <EEPROM.h> // EE
#include <LiquidCrystal.h> // LCD 16*2
#include <OneWire.h> // 1wire для DS18B20
#include <DallasTemperature.h> // DS18B20
#define ONE_WIRE_BUS 12 // датчики DS18B20 на 11 пин
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds(&oneWire); // Везде где встречается ds - это работа с датчиками Dallas DS18B20
DeviceAddress ds1 = { 0x28, 0xFF, 0xA6, 0xC0, 0x74, 0x16, 0x04, 0x88 }; // Сетевой адрес датчика 1
DeviceAddress ds2 = { 0x28, 0x8D, 0x76, 0x7C, 0x06, 0x00, 0x00, 0x24 }; // Сетевой адрес датчика 2
int tempC; // для работы с DS18B20
int Temp_1 = 20; // Переменная. Чтение с датчика 1
int Temp_2= 20; // Переменная. Чтение с датчика 2
int Temp1 = 20; // Переменная. Итоговая температура датчик 1 (По умолчанию 20гр.*С)
int Temp2 = 20; // Переменная. Итоговая температура датчик 2 (По умолчанию 20гр.*С)
#define encoderA 2 // энкодер - поворот вправо (об землю)
#define encoderB 3 // энкодер - поворот влево (об землю)
#define encoderK A6 // энкодер - кнопка (об землю)
#define Relay1 10 // нога, к которой подключено реле
#define Relay2 11 // нога, к которой подключено реле
#define Relay1On LOW // полярность сигнала включения реле (HIGH/LOW)
#define Relay2On LOW // полярность сигнала включения реле (HIGH/LOW)
#define Error 13 //ошибка
#define ErrorOn LOW // полярность сигнала включения реле (HIGH/LOW)
#define Ventcont A0 //контроль работы вентилятора (маностат)
#define OpenCam A1 // открыта крышка тэна
#define Stop A2 //кнопка стоп
// LCD connection RS, E, D4, D5, D6, D7
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
byte block1[8] = {
0x06,0x09,0x09,0x06,0x00,0x04,0x0E,0x1F }; // значок градуса с пламенем снизу
byte block2[8] = {
0x06,0x09,0x09,0x06,0x00,0x00,0x00,0x00 }; // значок градуса
int ds1shet=0; // Подсчет кол-ва ошибок DS18B20 1
int ds2shet=0; // Подсчет кол-ва ошибок DS18B20 2
int statusotp=0; // статус нагрева 0 - откл , 1- вкл ,
float TstatTemp = 23; //температура термостатирования, может изменяться настройками
float Hysteresis = 0.1; // гистерезис термостата, может изменяться настройками
float HysteresisOld;
float AlarmTemp = 20;
float AlarmhTemp = 95;
static boolean rotating=false; // debounce management
boolean A_set = false;
boolean B_set = false;
boolean encoderR = false;
boolean encoderL = false;
// EEPROM addresses
#define TstatTempEEaddr 0 // EE - адрес для сохранения температуры термостатирования, 4 байта(float)!
#define HysteresisEEaddr 4 // EE - адрес для сохранения гистерезиса, 4 байта(float)!
#define AlarmTempEEaddr 8 // EE - адрес для сохранения значения недопустимого снижения температуры, 4 байта(float)!
#define AlarmhTempEEaddr 12 // EE - адрес для сохранения значения недопустимого повышения температуры, 4 байта(float)!
long previousMillis = 0; // храним время последнего замера
long interval = 10000;
// ===== SETUP ========================================================================
void setup() {
ds.begin();
ds.setResolution(ds1, 10);
ds.setResolution(ds2, 10);
pinMode(Relay1, OUTPUT);
digitalWrite(Relay1, HIGH);
pinMode(Relay2, OUTPUT);
digitalWrite(Relay2, HIGH);
pinMode(Ventcont, INPUT);
digitalWrite(Ventcont, HIGH);
pinMode(OpenCam, INPUT);
digitalWrite(OpenCam, HIGH);
pinMode(Stop, INPUT);
digitalWrite(Stop, HIGH);
pinMode(Error, OUTPUT);
digitalWrite(Error, HIGH);
lcd.begin(16, 2);
lcd.createChar(1, block1);
lcd.createChar(2, block2);
pinMode(encoderA, INPUT);
digitalWrite(encoderA, HIGH);
pinMode(encoderB, INPUT);
digitalWrite(encoderB, HIGH);
pinMode(encoderK, INPUT);
digitalWrite(encoderK, HIGH);
attachInterrupt(0, doEncoderA, CHANGE); // encoder pin on interrupt 0 (pin 2)
attachInterrupt(1, doEncoderB, CHANGE); // encoder pin on interrupt 1 (pin 3)
if (EEPROM.read(TstatTempEEaddr) > 10) { // если первая запись однокристалки - записать начальные значения в EE
EEPROM_float_write(TstatTempEEaddr, TstatTemp);
EEPROM_float_write(HysteresisEEaddr, Hysteresis);
EEPROM_float_write(AlarmTempEEaddr, AlarmTemp);
EEPROM_float_write(AlarmhTempEEaddr, AlarmhTemp);
}
TstatTemp = EEPROM_float_read(TstatTempEEaddr);
Hysteresis = EEPROM_float_read(HysteresisEEaddr);
AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
AlarmhTemp = EEPROM_float_read(AlarmhTempEEaddr);
}
// ===== MAIN CYCLE ===================================================================
void loop()
{
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("t="));
if (Temp1 < 10) {
lcd.print(F(" "));}
lcd.print(Temp1,1);
lcd.write(0x02); // значок градуса
lcd.setCursor(8, 0); //инфо на LCD
lcd.print(F("t1="));
if (Temp2 < 10) {
lcd.print(F(" "));}
lcd.print(Temp2,1);
lcd.write(0x02); // значок градуса
lcd.setCursor(0, 1); //инфо на LCD
lcd.print(F("set="));
lcd.print(TstatTemp,1);
if ( digitalRead(Relay1) == Relay1On ) {lcd.write(0x01);} // значок градуса с пламенем
else {lcd.write(0x02);} // значок градуса
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) { // Замеры в интервале
ds.requestTemperatures(); // Замеры температур с DS18B20
delay(150); // Необязательная задержка
Temp_1 = ds.getTempC(ds1); // Считываем температуру с датчика 1
if(-55 < Temp_1 && Temp_1 < 120){Temp1 = Temp_1; ds1shet=0;} delay(50);// Если нет ошибки, то обновляем температур
Temp_2 = ds.getTempC(ds2); // Считываем температуру датчика 2
if(-55 < Temp_2 && Temp_2 < 120){Temp2 = Temp_2; ds2shet=0;} delay(50);// Если нет ошибки, то обновляем температуру
if(Temp1 < -55 || Temp1 > 120) {ds1shet++;} // +1 к счетчикам ошибок
if(Temp2 < -55 || Temp2 > 120){ds2shet++;} // +1 к счетчикам ошибок
if (Temp1 < AlarmTemp){digitalWrite(Error, ErrorOn);}
if (Temp1 > AlarmhTemp){statusotp==0;digitalWrite(Error, ErrorOn);}
if (Temp2 < AlarmTemp){digitalWrite(Error, ErrorOn);}
if (Temp2 > AlarmhTemp){statusotp==0;digitalWrite(Error, ErrorOn);}
previousMillis = currentMillis;}
if (statusotp==0){digitalWrite(Relay1, !Relay1On); digitalWrite(Relay2, !Relay2On);} // Отключить нагрев
if (ds1shet >2 && ds2shet >2) {statusotp=0;digitalWrite(Error, ErrorOn);} // Если нет связи с датчиками температуры отключить нагрев
if (statusotp==1) // Климат-контроль по датчику температуры в зале
{ if ( Temp1 >( TstatTemp + Hysteresis )){digitalWrite(Relay1, !Relay1On);} // Отключить нагрев если температура больше желаемой
if ( Temp1 <( TstatTemp - Hysteresis )){digitalWrite(Relay1, Relay1On);} // Включить нагрев если температура меньше желаемой
if ( ds1shet >2){statusotp=2;} // если нет связи с датчиком 1 перейти на датчик 2
}
if (statusotp==2) // Климат-контроль по датчику температуры в кухне
{ if ( Temp2 >( TstatTemp + Hysteresis )){digitalWrite(Relay1, !Relay1On);} // Отключить нагрев если температура больше желаемой
if ( Temp2 <( TstatTemp - Hysteresis )){digitalWrite(Relay1, Relay1On);} // Включить нагрев если температура меньше желаемой
if ( ds2shet >2){statusotp=1;} // если нет связи с датчиком 2 перейти на датчик 1
}
if ((( TstatTemp - Temp1)>10)&&(digitalRead(Relay1) == Relay1On)){digitalWrite(Relay2, Relay2On);}
if (( TstatTemp - Temp1)<10) {digitalWrite(Relay2, !Relay2On);}
if ((( TstatTemp - Temp2)>10)&&(digitalRead(Relay1) == Relay1On)){digitalWrite(Relay2, Relay2On);}
if (( TstatTemp - Temp2)<10) {digitalWrite(Relay2, !Relay2On);}
if (digitalRead(Relay1) == !Relay1On) {digitalWrite(Relay2, !Relay2On);}
if (digitalRead(Ventcont) == LOW) {statusotp==0;digitalWrite(Error, ErrorOn);}
if (digitalRead(OpenCam) == LOW) {statusotp==0;}
if (digitalRead(Stop) == LOW) {statusotp==0;}
// обработка поворота энкодера на лету (ручное изменение уставки температуры))
rotating = true; // reset the debouncer
if ((encoderR)^(encoderL)) {
if (encoderR) {TstatTemp += 1;}
else
{TstatTemp -= 1;}
TstatTemp = constrain(TstatTemp, 10, 90);
encoderR = false;
encoderL = false;
}
// ================ по нажатию кнопки энкодера - меню настроек ====================
if(digitalRead(encoderK) == 0) {
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("< SETUP >"));
delay(200);
int menuitem = 0;
do {
rotating = true; // reset the debouncer
if ((encoderR)^(encoderL)) {
if (encoderR) { menuitem += 1; }
else { menuitem -= 1; }
if ( menuitem > 3 ) { menuitem = 0; } // границы пунктов меню
if ( menuitem < 0 ) { menuitem = 3; }
encoderR = false;
encoderL = false;
}
// индикация пункта меню (номер пункта - в menuitem)
lcd.setCursor(0, 1); //инфо на LCD
switch(menuitem){
case 0:
lcd.print(F("0.BACK "));
break;
case 1:
lcd.print(F("1.HYSTERESIS SET"));
break;
case 2:
lcd.print(F("2.L-ALARM SET "));
break;
case 3:
lcd.print(F("3.H-ALARM SET "));
break;
}
}
while (digitalRead(encoderK)==1); // если нажата кнопка энкодера или таймаут - обработка пункта меню (номер пункта - в menuitem)
switch(menuitem)
{
// ====== пункт 0 - выход
case 0:
break; // case 0 out
// ====== пункт 1 - установка гистерезиса
case 1:
HysteresisOld = Hysteresis;
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SETUP HYSTERESIS"));
delay(200);
do {
lcd.setCursor(0,1);
lcd.print(Hysteresis, 1);
lcd.write(0x02); // значок градуса
rotating = true; // reset the debouncer
if (encoderR) {
Hysteresis += 0.1;
encoderR = false;
}
if (encoderL) {
Hysteresis -= 0.1;
encoderL = false;
}
Hysteresis = constrain(Hysteresis, 0.1, 5); // крайние значения
}
while (digitalRead(encoderK)==1);
if (EEPROM_float_read(HysteresisEEaddr) != Hysteresis) {
EEPROM_float_write(HysteresisEEaddr, Hysteresis);
}
else {
Hysteresis = HysteresisOld;
}
break; // case 1 out
// ====== пункт 2 - установка коррекции L alarm температуры
case 2:
// MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("L ALARM-TEMP SET"));
delay(200);
do {
lcd.setCursor(0,1);
lcd.print(AlarmTemp, 0);
lcd.write(0x02); // значок градуса
rotating = true; // reset the debouncer
if (encoderR) {
AlarmTemp += 1;
encoderR = false;
}
if (encoderL) {
AlarmTemp -= 1;
encoderL = false;
}
AlarmTemp = constrain(AlarmTemp, 5, 50); // крайние значения
}
while (digitalRead(encoderK)==1);
if (EEPROM_float_read(AlarmTempEEaddr) != AlarmTemp) {
EEPROM_float_write(AlarmTempEEaddr, AlarmTemp);
}
else {
AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
}
break; // case 2 out
// ====== пункт 3 - установка коррекции H alarm температуры
case 3:
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("H ALARM-TEMP SET"));
delay(200);
do{
lcd.setCursor(0,1);
lcd.print(AlarmhTemp, 0);
lcd.write(0x02); // значок градуса
rotating = true; // reset the debouncer
if (encoderR) {
AlarmhTemp += 1;
encoderR = false;
}
if (encoderL) {
AlarmhTemp -= 1;
encoderL = false;
}
AlarmhTemp = constrain(AlarmhTemp, 50, 105); // крайние значения
}
while (digitalRead(encoderK)==1);
if (EEPROM_float_read(AlarmhTempEEaddr) != AlarmhTemp) {
EEPROM_float_write(AlarmhTempEEaddr, AlarmhTemp);
}
else {
AlarmhTemp = EEPROM_float_read(AlarmhTempEEaddr);
}
break; // case 3 out
delay(200);
lcd.clear();
}
}
}
// ===== SUBROUTINES ==================================================================
// ========= чтение/запись float в EE =====
void EEPROM_float_write(int addr, float val) // запись в ЕЕПРОМ
{
byte *x = (byte *)&val;
for(byte i = 0; i < 4; i++) EEPROM.write(i+addr, x[i]);
}
float EEPROM_float_read(int addr) // чтение из ЕЕПРОМ
{
byte x[4];
for(byte i = 0; i < 4; i++) x[i] = EEPROM.read(i+addr);
float *y = (float *)&x;
return y[0];
}
// ============================ Encoder interrupts =============================
void doEncoderA(){
if ( rotating ) {
delay (1) ; }
if( digitalRead(encoderA) != A_set ) { // debounce once more
A_set = !A_set;
if ( A_set && !B_set )
{
encoderR = true;
rotating = false; }}}
void doEncoderB(){
if ( rotating ) {
delay (1); }
if( digitalRead(encoderB) != B_set ) {
B_set = !B_set;
if( B_set && !A_set ) {
encoderL = true;
rotating = false;}}}
Макс, я с миллисом не очень разобрался, в моем коде уже есть интервал для замера температур, но он короткий. Можно ли объявить еще интервал и если да, как это делается? И еще, вчера не тот код выложил, вечером выложу правильный.
long previousTime = 0; // храним время последнего начала отсчета таймера (переменные можно называть по-разному, чтобы отличать таймеры)
long intervalTime = 60000; // интервал 1 мин например (60000 мсек)
bool zamer_1 = false; // флаг для замера t1
void setup() {
бла бла
}
void loop() {
if (zamer_1==false) { t1 = бла бла ; zamer_1 = true } //замеряем здесь t1, флаг zamer_1 после замера делаем true, чтобы один раз только замерялось при одном цикле таймера
unsigned long currentTime = millis();
if(currentTime - previousTime > intervalTime) { // Если таймер кончился, замеряем t2
t2 = бла бла
тут сравниваем t2-t1 и делаем что-то в зависимости от величины дельта температур
previousTime = currentTime; zamer_1 = false; } // сбрасываем таймер, флаг zamer_1 тоже сбрасываем
Коллеги, может кому интересно, приладил в программу запись на СД карту. С индикацией процесса записи(светодиод светится пол секунды, когда запись идёт. Запись осуществляется раз в 2 минуты по условию, когда на часах выставляется ..2 мин 0 секунд.
if(RTCSekunda==0){ // если секунды равны 00
if(RTCMinuta%2==0){//запись каждые --2 мин
digitalWrite(31, HIGH); // идет запись на карту
// make a string for assembling the data to log:
String dataString = "";
t = rtc.getTime();
dataString += (t.date, DEC);// день
dataString += " ";
dataString += String(rtc.getMonthStr());//месяц
dataString += " ";
dataString += String(t.hour, DEC);
dataString += ":";
dataString += String(t.min, DEC);
dataString += " ";
dataString += String(HUMin);
dataString += "% in ;";
dataString += String(TEMPin);
dataString += " Cin ;";
dataString += String(vlaga);
dataString += "% out ;";
dataString += String(Tempout);
dataString += " Cout ;";
dataString += String(UlicaS);
dataString += " lux";
delay(500);
// open the file.
File dataFile = SD.open("datalog.txt", FILE_WRITE);
// if the file is available, write to it:
if (dataFile) {
dataFile.println(dataString);
dataFile.close();
// print to the serial port too:
Serial.println(dataString);
digitalWrite(31, LOW); // окончание записи на карту
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
Но есть косячёк- пока длится нулевая секунда, программа успевает сделать запись 2-3 раза. понимаю, что если вставить задержку не 500мс а 900, то будет все хор, но мы же боремся за оптимизацию программы. Ка же сделать красиво и оптимально?
Внедрил код как у MaksVV на опрос Датчиков DS18. Установил таймер на 8 сек. Работает! Только не получается сделать отображение температуры с точностью до десятой доли ,хотя прописывал:
Коллеги, можно мне со своим вопросом встрять? Кто-то решал задачу контроля состояния шилда SIM900?
У меня на даче стоит смс- розетка уже третий месяц. На улице бывало до -30, и я не даю уйти дому в минус с помощью калориферов.
Проблема в том, что иногда шилд выключается (а Мега 2560 продолжает работать) или теряет сеть, и поэтому перестаёт отвечать на смс запросы. Хочется его перезагрузить, а для этого надо спросить его состояние, и если нет сети или он выключен-то сделать нужное действие. У кого-нибудь есть протестированный кусочек кода?
У меня есть, правда проверка состояния идет на момент запуска самой меги, но можно и просто на опрос состояния сделать.
Другой момент, как модуль отваливается по питанию, а сама мега работает?
Я использую библиотеку SIM900, соответственно, у меня не АТ команды.
При перезагрузке Меги или в момент включения подаётся 3-х секундный импульс на 9 ножку шилда, который и включает шилд. Каким образом шилд выключается- не знаю. У нас, бывает, пропадает питание по всему саду, но при восстановлении по идее и Мега, и шилд должны включиться. Просто он перестаёт отвечать, я еду на дачу и руками перезагружаю. Да, собственно, мне и не важна причина, главное - повысить надёжнось. Мега должна проверять шилд ну, хотя бы через час, и послать ему импульс на включение (или на выключение/ включение).
Библиотеку не стал использовать, т.к. вроде AT команд хватает.
Slavyanin55, прочитал Вашу тему очень интересно, большое спасибо.
Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?
Спасибо.
Тоже интересует этот вопрос. Думаю не на ИБП тратиться, а поставить старый 12- вольтовый автомобильный аккумулятор, не совсем дохлый. При наличии сети он должен подзаряжаться слабым током, а при обесточивании- послать смс. При восстановлении энегроснабжения- тоже смс. Как-то так, не должно быть сложно.
Slavyanin55, прочитал Вашу тему очень интересно, большое спасибо.
Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?
Спасибо.
Тоже интересует этот вопрос. Думаю не на ИБП тратиться, а поставить старый 12- вольтовый автомобильный аккумулятор, не совсем дохлый. При наличии сети он должен подзаряжаться слабым током, а при обесточивании- послать смс. При восстановлении энегроснабжения- тоже смс. Как-то так, не должно быть сложно.
Naz, не совсем понимаю, как у Вас реализовано общение gsm модуля. По идее скрипт, чтобы прочитать полученную смс, должен регулярно обращатся к gsm. Тут и должно проверятся условие, есть смс, нет смс, модуль не отвечает. Если не отвечает - ресет на пин. Вот и все.
Все очень просто. Посмотрите void nastroyka gsm. В начале работы мы настраиваем gsm модуль посредством АТ команд, чтобы он при получении смс сразу сливал его в мегу. А мега просто ждет, что упадет в сериал и реагирует соответственно. Почитайте в google АТ команды gsm модемов и все станет ясно.
Попробуйте проверять состояние модема командой AT+CPAS к примеру раз в час, если не ответил, или ответил не так, даем ему с любого пина ардуины ресет, если я не ошибаюсь, на сим 900 это пин16, далее ждем загрузки и снова даем настройку.
Коллеги, можно мне со своим вопросом встрять? Кто-то решал задачу контроля состояния шилда SIM900?
У меня на даче стоит смс- розетка уже третий месяц. На улице бывало до -30, и я не даю уйти дому в минус с помощью калориферов.
Проблема в том, что иногда шилд выключается (а Мега 2560 продолжает работать) или теряет сеть, и поэтому перестаёт отвечать на смс запросы. Хочется его перезагрузить, а для этого надо спросить его состояние, и если нет сети или он выключен-то сделать нужное действие. У кого-нибудь есть протестированный кусочек кода?
Рабочий урезаный код моей проги, работает у меня уже более года)
Код для проверки работоспособности системы без каких либо часов реального времени, ну и чуть-чуть кода для отправки смс на номер( номер указан в начале кода).
Я люблю работать с памятью ардуины, т.к. хочу управлять сам своим ус-вом
В данном примере нет работы с памятью.
#include <SoftwareSerial.h>
SoftwareSerial gsm(2, 3); // 2-txd, 3-rxo
#define led 13 // светодиод
String NBoss = "79817425566";
int i = 0;
int Automatic = 0;
int StartGSM = 0;
// Переменные для чтения смс
String currStr = "";
String dataSmsN = "";
int flag1 = 0;
int flag2 = 0;
String currStrN = "";
char currSymb = 0;
String dataSms = "";
String dataBalance = "";
//String dataBalanceNumber = "";
String dataBalanceTemp = "";
String val = "";
int ch = 0;
char data = 0;
// Переменные для обработки смс +CSQ
int intNumberLevelFirst = 0;
int intNumberLevelSecond = 0;
int IntSignalLevel = 0;
int FlagSignal = 0;
int countLed = 0;
long counter = 0;
long timerForSignalGSM = 1000000;
int timerSearchGSM = 20;// таймер для регистрации сети GSm 20*2000=40 сек
int tempBalans = 0; // переменная, хранящая метку о запросе баланса
int tempZaprosBalansa = 0; // переменная, хранящая метку о запросе каждый день баланса
int SendSmsDeviceOn = 0;
void setup() {
// Мигание светодиода на плате, говорит о работоспособности системы
pinMode(led, OUTPUT); digitalWrite(led, LOW);
// Читаем из памяти данные о состоянии системы
Automatic = 1;//EEPROM.read(0); // Убрал для примера
// делаем задержку на поиск сотовой сети
for (i=0; i<=timerSearchGSM; i++){
if (Automatic == 1){digitalWrite(led, HIGH);delay(250);}
if (Automatic == 1){digitalWrite(led, LOW);delay(250);}
}
}
void loop() {
// Запускаем GSM
if (StartGSM == 0){
gsm.begin(9600);
gsm.write("AT+CMGF=1\r"); // устанавливает текстовый режим смс-сообщения
delay(300);
}
if (StartGSM == 1){
gsm.write("AT+IFC=1, 1\r"); //устанавливает программный контроль потоком передачи данных
delay(300);
}
if (StartGSM == 2){
gsm.write("AT+CPBS=\"SM\"\r");//открывает доступ к данным телефонной книги SIM-карты
delay(300);
}
if (StartGSM == 3){
gsm.write("AT+CNMI=1,2,2,1,0\r");// включает оповещение о новых сообщениях, новые сообщения
delay(500);
}
if (StartGSM == 4){
gsm.write("AT+GSMBUSY=1\r\n"); // запрет всех входящих звонков.
delay(300);
}
if (StartGSM == 5){
gsm.write("AT+CMGDA=DEL ALL\r\n"); // команда удалит все сообщения
delay(500);
}
if (FlagSignal == 0 && StartGSM == 6){
gsm.println("AT+CSQ");// Проверяем уровень сигнала
delay(800);
}
// Работоспособность системы
countLed++;
if (countLed >= 500){
digitalWrite(led, HIGH);
}
if (countLed >= 1000){
digitalWrite(led, LOW);
countLed = 0;
}
// Проверяем включено ли было устройство, если система на охране или снята с охраны и сеть есть
if (Automatic <=1 && SendSmsDeviceOn == 1 && FlagSignal == 1 && StartGSM == 6){
smsSendAlarm("Hi, Device on!");
SendSmsDeviceOn = 0;
}
// Проверка уровня сигнала во время работы системы каждые 20сек(400000)
// Смысл этой процедуры: проверка по таймеру и если уровень сигнала нормальный и вроде бы сиситема работает нормально,
// делаем проверку уровня сигнала для проверки работоспособности системы, если сигнала нет, смотрим код, где все начинается заново
counter++;
if (counter >= timerForSignalGSM && FlagSignal == 1 && StartGSM == 6){
gsm.println("AT+CSQ");
delay(300);
// Обнуляем счетчик
counter = 0;
}
//*********************
if (gsm.available()) { //есть данные от GSM модуля
currStr = ""; //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
currStrN = "";
dataBalanceTemp = "";
dataSms = "";
val = "";
flag1 = 0;
flag2 = 0;
while (gsm.available()) { //сохраняем входную строку в переменную val
ch = gsm.read(); //int
val += char(ch); // String
data = ch; // char = int
if ('\r' == data) {
currStr = "";
} else if ('\n' != data) {
currStr += String(data);
dataSms = currStr;
}
//+CMT: "+79819998877","","16/04/18,20:25:08+12"
if (data == '+' && flag1 == 0){flag1 = 1;}
if (data == 'C' && flag1 == 1){flag1 = 2;}
if (data == 'M' && flag1 == 2){flag1 = 3;}
if (data == 'T' && flag1 == 3){flag1 = 4;}
if (data == '+' && flag1 == 4){currStrN = "";flag1 = 5;}
if (data != '"' && flag1 == 5){currStrN += String(data); dataSmsN = currStrN;}
if (data == '"' && flag1 == 5){flag1 = 6;}
//+CUSD: 0, "Balance:117,27r ", 15
if (data == 'U' && flag1 == 2){flag2 = 3;}
if (data == 'S' && flag2 == 3){flag2 = 4;}
if (data == 'D' && flag2 == 4){flag2 = 5;}
if (data == ':' && flag2 == 5){flag2 = 6;}
if (data == '"' && flag2 == 6){dataBalanceTemp = ""; flag2 = 7; goto c;}
if (data != '"' && flag2 == 7){dataBalanceTemp += String(data); dataBalance = dataBalanceTemp;}
if (data == '"' && flag2 == 7){flag2 = 8;}
// if (data == ':' && flag2 == 7){dataBalanceTemp = ""; flag2 = 8; goto c;}
// if (data != ':' && flag2 == 8){dataBalanceTemp += String(data); dataBalanceNumber = dataBalanceTemp; flag2 = 9;}
}
// Смотрим данные полученные //режим кодировки СМС - обычный (для англ.)
if (val.indexOf("+CMGF") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 1;
}
}
// Смотрим данные полученные //устанавливает программный контроль потоком передачи данных
if (val.indexOf("+IFC") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 2;
}
}
// Смотрим данные полученные //открывает доступ к данным телефонной книги SIM-карты
if (val.indexOf("+CPBS") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 3;
}
}
// Смотрим данные полученные //включает оповещение о новых сообщениях, новые сообщения
if (val.indexOf("+CNMI") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 4;
}
}
// Смотрим данные полученные //запрет всех входящих звонков.
if (val.indexOf("+GSMBUSY") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 5;
}
}
// Смотрим данные полученные //команда удалит все сообщения
if (val.indexOf("+CMGDA") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 6;
}
}
// Смотрим данные полученные от модуля +CSQ: 22,0
if (val.indexOf("+CSQ") > -1) {
for (i=0; i<=20; i++){
if (val[i] == 58) {
intNumberLevelFirst = val[i+2]-48;
if (val[i+3] == 44){ intNumberLevelSecond = 0;}
if (val[i+3] != 44){ intNumberLevelSecond = val[i+3]-48;}
if (val[i+3] == 44){IntSignalLevel = intNumberLevelFirst;}
if (val[i+3] != 44){IntSignalLevel = (intNumberLevelFirst*10) + intNumberLevelSecond;}
}
}
if (IntSignalLevel == 99 || IntSignalLevel == 0){
for (i=0; i<=timerSearchGSM; i++){
if (Automatic == 0){// можно что-то включить, например светодиод}
delay(1000);
if (Automatic == 0){// можно что-то выключить, например светодиод}
delay(1000);
}
FlagSignal = 0; StartGSM = 0;
}
if (IntSignalLevel <=32 && IntSignalLevel !=0){
FlagSignal = 1;
}
}
// Смотрим данные полученные от модуля пришло смс
if (val.indexOf("+CMTI:") > -1) { // +CMTI: "SM",
StartGSM = 0;
}
// Смотрим данные полученные от модуля, Получили смс с балансом, теперь отсылаем
if (val.indexOf("+CUSD:") > -1) {
if (dataBalance != "" && tempBalans == 1) {
smsSendAlarm("Hi, " + dataBalance);
tempBalans = 0;
dataBalance = "";
}
if (dataBalance[8]-48 >= 1 && dataBalance[9]-48 >= 0 && dataBalance[10]-48 >= 0){
// ничего не делаем
}else if (tempZaprosBalansa == 1){
smsSendAlarm("Hi, balance < 100r, vash balance = " + dataBalance);
tempZaprosBalansa = 0;
dataBalance = "";
}
}
//----------------------- определение факта приема СМС и сравнение номера(ов) с заданным(и)
if (val.indexOf("+CMT") > -1) {
// Здесь обрабатываем смс
}//+cmt
}
}// коней if gsm
}
}
//процедура отправки СМС
void smsSendAlarm(String text) {
// ReadNBoss(); //Читаем номер из памяти
gsm.println("AT+CMGS=\"" + NBoss + "\""); //Отправляем на GSM комманду отправка смс-номер
// NBoss = ""; //Очищаем перемунную
delay(300); //Делаем задержку на передачу комманды
gsm.print(text); //Отправляем на GSM комманду отправка смс-текст
text = ""; //Очищаем перемунную
delay(500); //Делаем задержку на передачу комманды
gsm.print((char)26); //Отправляем на GSM комманду отправка смс!
delay(5000); //Делаем задержку отправку смс
}
Naz, не совсем понимаю, как у Вас реализовано общение gsm модуля. По идее скрипт, чтобы прочитать полученную смс, должен регулярно обращатся к gsm. Тут и должно проверятся условие, есть смс, нет смс, модуль не отвечает. Если не отвечает - ресет на пин. Вот и все.
Сделано так: регулярно опрашивается буфер UART, соединённый с gsm. И если буфер пуст- непонятно, то ли нет входящего смс, то ли шилд сеть потерял/ вырубился.
Добрый день. Сегодня наткнулся на данную тему, очень заинтересовала. Есть желание сделать умную квартиру, на дом ещё не заработал. Работаю на производстве, у нас стоят контроллеры BECKHOFF, очень интересная штука, почитал на них собирают умные дома, на самой старой серии bc9000. Хотел купить б/у но продают только в Штатах и в Германии, а стоимость за пересылку кусается. А тут увидел на Меге такой проект и загорелся попробовать. До этого на меге собрал только 3d принтер, так что опыта не много. Я так понимаю у Вас проект существует уже с 14 года. Хотел спросить, много у вас элементов сгорало и ломалось за это время? Пробежался по форуму и не увидел спецификации, думаю она есть, но не нашел. Хотел посмотреть какие шильды датчики и релюшки нужно купить для базовой конфигурации.
Доброго всем дня, доехал конструктор до наших краев. Подскажите несведующему, последнюю прошивку не могу залить на mega2560 выходит ошибка при компиляции. В какую сторону смотреть? Бибилиотеки вроде перекинул в папку с Arduino.
Я заказал уже на пробу мегу и кней температурные датчики, релюшку импульсную, платку с обычными реле. вайфайный модуль и плату изернет. несколько объемников и всякой мелочёвки ещё. Хотел сделать базу какую то к которой можно было бы подключать разные датчики. Думал тут какую то статистику и спецификацию почерпнуть, но все молчат.
Какая статистика тебя интересует? Тут все пилят проект под свои нужды, добавляя что-то от себя и заимствуя у других. Сформулируй вопрос понятно, что не получается, что пытаешься сделать, что недопонял и тебе подскажут. Для того форум и существует. Если что, моя почта s-tver@mail.ru, чем смогу.
Мега, gsm sim800L+ антенна выносная + модуль питания к нему, часы ds3231, дисплей 4 строчный i2с, гора термодатчиков ds18b20, гора PIR датчиков, гора оптопар pc817, платы реле, mp3 модуль, датчик инфракрасный для приема сигналов от пульта, пищалка от материнской платы компьютера, wi-fi модуль, bluetooth модуль, ethernet модуль, блок питания 12в и 5В, ИБП для блока питания с АКБ, 4g wi-fi роутер, бухта провода в экране 4 жилы или 8 жил.
ООО половину уже купил, оптопары не взял пожалу и gsm модуль, дисплей ещё от принтера остался без применения. спасибо. Хотел спросить, делаю пока всю подготовку, квартира ещё строится, сдаваться будет на нулевой стадии отделки, так что поле для прокладки обширное. Хотел по проводам спросить. Думаю к каждой розетке и выключателю проложить витую пару экранированную и легко достать и запас по проводам будет, там всётаки 8 жил. сечения будет достаточно?
Доброй ночи, товарищи! Вот сваял окончательную версию термостата для управления конвекторами, поставил, все работает, все устраивает. Месяц работы, полет нормальный. Ежедневный отчет по GSM приходит исправно.Управляется по GSM тоже ок. Можно даже позвонить туда и оттуда и полноценно поговорить.Но вот сижу и думаю... Хата моя стоит за 300 км от меня, там мать живет, программистов нет.
ВООБЩЕ. НИКАКИХ.
А если датчик температуры накрылся? Он же адресный, придется тогда брать ноут и новыйдатчик и ехать менять, т.к. без скетча никто ничего не сможет сделать. Далее, возниклаидея прикрутить еще датчик на улицу. Тут уже адрес нужен и ремонтопригодностьсводится к 1 человеку, который это сделал. Вот сижу и думаю, ведь можно и без адресовопросить все датчики на шине, но как контроллер узнает, какой из них какой, если адресане прописаны? Но если это реализовать, то обслуживание и ремонт наших систем упростится в разы.
Может, у кого есть идеи по этому поводу?
#include <Wire.h> // i2c (для RTC)
#include <RealTimeClockDS1307.h> // RTC
#include <EEPROM.h> // EE
#include <LiquidCrystal.h> // LCD 16*2
#include <TimerOne.h> // прерывания по таймеру1
#include <OneWire.h> // 1wire для DS18B20
#include <DallasTemperature.h> // DS18B20
#define ONE_WIRE_BUS 11
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
DeviceAddress DS18B20Address;
#define encoderA 12 // энкодер - поворот вправо (об землю)
#define encoderB 13 // энкодер - поворот влево (об землю)
#define encoderK A3 // энкодер - кнопка (об землю)
#define BeepPin 9 // пищалка
#define BeepToneNo 2000 // тон звука "No", герц
#define BeepToneYes 4000 // тон звука "Yes", герц
#define BeepToneNoDuration 200 // длительность звука "No", мс
#define BeepToneYesDuration 200 // длительность звука "Yes", мс
#define Relay 10 // нога, к которой подключено реле
#define RelayOn LOW // полярность сигнала включения реде (HIGH/LOW)
// LCD connection RS, E, D4, D5, D6, D7
// R/W - to ground
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
byte block1[8] = {
0x06,0x09,0x09,0x06,0x00,0x04,0x0E,0x1F }; // значок градуса с пламенем снизу
byte block2[8] = {
0x06,0x09,0x09,0x06,0x00,0x00,0x00,0x00 }; // значок градуса
String currStr = "";
boolean isStringMessage = false; // Переменная принимает значение True, если текущая строка является сообщением
boolean SMSsent = false;
boolean SMSsenti = false;
boolean SMSDelete=false;
boolean TimeSMSzapros=false;
#define TstatTimerMax 120 //минимальная пауза между включениями горелки, сек
unsigned int TstatTimer = 20; //таймер паузы между включениями/выключениями, начальная установка 20 сек для устаканивания системы после сброса
float DS18B20Temperature = 0; //сырая температура от датчика
float Temperature = 0; //вычисленная температура с коррекцией
float DS18B20TempTmp; //времянка
byte DS18B20iteration = 0; //счётчик измерений температуры для усреднения
float TstatTemp = 23; //температура термостатирования, может изменяться настройками
float TemperatureCorr = 0; //коррекция температуры, может изменяться настройками
float Hysteresis = 0.1; // гистерезис термостата, может изменяться настройками
float HysteresisOld;
int Hours = 0; // времянка часов RTC для отображения и установки
int Minutes = 0; // времянка минут RTC для отображения и установки
int Seconds;
boolean PrintYesNo = false; // показывать ли после времени Yes/No (косвенно - указание на режим установка/отображение)
boolean SetH = false; // выделение часов при отображении
boolean SetM = false; // выделение минут при отображении
boolean SetYesNo = false; // выделение Yes/No при установке часов
boolean blink500ms = false; // мигающий бит, инвертируется каждые 500мс
boolean plus1sec = false; // ежесекундно взводится
boolean Zvonok = true;
boolean BeepEnabled = true;
byte MenuTimeoutTimer;
byte Timer1Hours = 0;
byte Timer1Minutes = 0;
boolean Timer1Enabled = false;
boolean Timer1Activated = false;
float Timer1Temp = 23; //температура термостатирования по таймеру1, может изменяться настройками
byte Timer2Hours = 0;
byte Timer2Minutes = 0;
boolean Timer2Enabled = false;
boolean Timer2Activated = false;
float Timer2Temp = 23; //температура термостатирования по таймеру2, может изменяться настройками
byte Timer3Hours = 0;
byte Timer3Minutes = 0;
boolean Timer3Enabled = false;
boolean Timer3Activated = false;
float Timer3Temp = 23; //температура термостатирования по таймеру3, может изменяться настройками
float AlarmTemp = 20; // температура для замерзательного орала
// encoder vars
static boolean rotating=false; // debounce management
boolean A_set = false;
boolean B_set = false;
boolean encoderR = false;
boolean encoderL = false;
// EEPROM addresses
#define TstatTempEEaddr 0 // EE - адрес для сохранения температуры термостатирования, 4 байта(float)!
#define TemperatureCorrEEaddr 4 // EE - адрес для сохранения коррекции температуры, 4 байта(float)!
#define HysteresisEEaddr 8 // EE - адрес для сохранения гистерезиса, 4 байта(float)!
#define Timer1HoursEEaddr 12 // EE - адрес для сохранения часов таймера 1 (byte)
#define Timer1MinutesEEaddr 13 // EE - адрес для сохранения минут таймера 1 (byte)
#define Timer1EnabledEEaddr 14 // EE - адрес для сохранения статуса таймера 1 (boolean)
#define Timer1TempEEaddr 15 // EE - адрес для сохранения температуры таймера 1, 4 байта(float)!
#define Timer2HoursEEaddr 19 // EE - адрес для сохранения часов таймера 2 (byte)
#define Timer2MinutesEEaddr 20 // EE - адрес для сохранения минут таймера 2 (byte)
#define Timer2EnabledEEaddr 21 // EE - адрес для сохранения статуса таймера 2 (boolean)
#define Timer2TempEEaddr 22 // EE - адрес для сохранения температуры таймера 2, 4 байта(float)!
#define Timer3HoursEEaddr 26 // EE - адрес для сохранения часов таймера 3 (byte)
#define Timer3MinutesEEaddr 27 // EE - адрес для сохранения минут таймера 3 (byte)
#define Timer3EnabledEEaddr 28 // EE - адрес для сохранения статуса таймера 3 (boolean)
#define Timer3TempEEaddr 29 // EE - адрес для сохранения температуры таймера 3, 4 байта(float)!
#define BeepEnabledEEaddr 33 // EE - адрес для сохранения признака разрешения звука (boolean)
#define AlarmTempEEaddr 34 // EE - адрес для сохранения значения недопустимого снижения температуры, 4 байта(float)!
// ===== SETUP ========================================================================
void setup() {
Serial.begin(19200);
pinMode(Relay, OUTPUT);
digitalWrite(Relay, HIGH);
lcd.begin(16, 2);
lcd.createChar(1, block1);
lcd.createChar(2, block2);
pinMode(encoderA, INPUT);
digitalWrite(encoderA, HIGH);
pinMode(encoderB, INPUT);
digitalWrite(encoderB, HIGH);
pinMode(encoderK, INPUT);
digitalWrite(encoderK, HIGH);
attachInterrupt(0, doEncoderA, CHANGE); // encoder pin on interrupt 0 (pin 2)
attachInterrupt(1, doEncoderB, CHANGE); // encoder pin on interrupt 1 (pin 3)
Timer1.initialize(500000); // Timer0 interrupt - set a timer of length 500000 microseconds
Timer1.attachInterrupt( timerIsr ); // attach the service routine here
if (EEPROM.read(Timer1HoursEEaddr) > 23) { // если первая запись однокристалки - записать начальные значения в EE
EEPROM.write(BeepEnabledEEaddr, BeepEnabled);
EEPROM_float_write(TstatTempEEaddr, TstatTemp);
EEPROM_float_write(TemperatureCorrEEaddr, TemperatureCorr);
EEPROM_float_write(HysteresisEEaddr, Hysteresis);
EEPROM.write(Timer1HoursEEaddr, Timer1Hours);
EEPROM.write(Timer1MinutesEEaddr, Timer1Minutes);
EEPROM.write(Timer1EnabledEEaddr, Timer1Enabled);
EEPROM_float_write(Timer1TempEEaddr, Timer1Temp);
EEPROM.write(Timer2HoursEEaddr, Timer2Hours);
EEPROM.write(Timer2MinutesEEaddr, Timer2Minutes);
EEPROM.write(Timer2EnabledEEaddr, Timer2Enabled);
EEPROM_float_write(Timer2TempEEaddr, Timer2Temp);
EEPROM.write(Timer3HoursEEaddr, Timer3Hours);
EEPROM.write(Timer3MinutesEEaddr, Timer3Minutes);
EEPROM.write(Timer3EnabledEEaddr, Timer3Enabled);
EEPROM_float_write(Timer3TempEEaddr, Timer3Temp);
EEPROM_float_write(AlarmTempEEaddr, AlarmTemp);
}
BeepEnabled = EEPROM.read(BeepEnabledEEaddr);
TstatTemp = EEPROM_float_read(TstatTempEEaddr);
TemperatureCorr = EEPROM_float_read(TemperatureCorrEEaddr);
Hysteresis = EEPROM_float_read(HysteresisEEaddr);
Timer1Hours = EEPROM.read(Timer1HoursEEaddr);
Timer1Minutes = EEPROM.read(Timer1MinutesEEaddr);
Timer1Enabled = EEPROM.read(Timer1EnabledEEaddr);
Timer1Temp = EEPROM_float_read(Timer1TempEEaddr);
Timer2Hours = EEPROM.read(Timer2HoursEEaddr);
Timer2Minutes = EEPROM.read(Timer2MinutesEEaddr);
Timer2Enabled = EEPROM.read(Timer2EnabledEEaddr);
Timer2Temp = EEPROM_float_read(Timer2TempEEaddr);
Timer3Hours = EEPROM.read(Timer3HoursEEaddr);
Timer3Minutes = EEPROM.read(Timer3MinutesEEaddr);
Timer3Enabled = EEPROM.read(Timer3EnabledEEaddr);
Timer3Temp = EEPROM_float_read(Timer3TempEEaddr);
AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
DS18B20.begin();
DS18B20.getAddress(DS18B20Address, 0);
DS18B20.setResolution(DS18B20Address, 12);
DS18B20.setWaitForConversion(false);
DS18B20.requestTemperatures();
NastroykaGSM();
delay(5000);
tone(BeepPin,2000,50);
delay(50);
tone(BeepPin,3000,50);
delay(50);
tone(BeepPin,4000,50);
delay(50);
startOneSMS(); Serial.print("TERMOSTAT-ON"); EndSMS();
}
// ===== MAIN CYCLE ===================================================================
void loop()
{
sms_read();
lcd.setCursor(8, 0); //инфо на LCD
if ((Temperature < AlarmTemp)&(blink500ms)) {
lcd.print(F("*"));
} else {
lcd.print(F(" "));
}
lcd.print(F("t="));
if (Temperature < 10) {
lcd.print(F(" "));
}
lcd.print(Temperature,1);
lcd.write(0x02); // значок градуса
// если таймер 1 включен - надпись светится, если сработал - мигает
lcd.setCursor(0, 1); //инфо на LCD
if ((Timer1Enabled)&!((Timer1Activated)&(blink500ms))) {
lcd.print(F("T1"));
}
else {
lcd.print(F(" "));
}
// если таймер 2 включен - надпись светится, если сработал - мигает
lcd.setCursor(3, 1); //инфо на LCD
if ((Timer2Enabled)&!((Timer2Activated)&(blink500ms))) {
lcd.print(F("T2"));
}
else {
lcd.print(F(" "));
}
// если таймер 3 включен - надпись светится, если сработал - мигает
lcd.setCursor(6, 1); //инфо на LCD
if ((Timer3Enabled)&!((Timer3Activated)&(blink500ms))) {
lcd.print(F("T3"));
}
else {
lcd.print(F(" "));
}
lcd.setCursor(9, 1); //инфо на LCD
lcd.print(F("s="));
lcd.print(TstatTemp,1);
if ( digitalRead(Relay) == RelayOn ) {
lcd.write(0x01); // значок градуса с пламенем
}
else {
lcd.write(0x02); // значок градуса
}
// печатаем текущее время
PrintYesNo = false;
PrintRTC(0,0);
// термостатирование
if ( TstatTimer == 0 )
{
if ( Temperature > ( TstatTemp + Hysteresis ) ) // гистерезис
{
if ( digitalRead(Relay) == RelayOn ) // если горелка включена -
{
digitalWrite(Relay, !RelayOn); // выключить горелку
TstatTimer = TstatTimerMax; // горелку держать выключённой не менее заданного в TstatTimerMax времени
}
}
if (Temperature < TstatTemp)
{
if ( digitalRead(Relay) == !RelayOn ) // если горелка выключена -
{
digitalWrite(Relay, RelayOn); // включить горелку
TstatTimer = TstatTimerMax; // горелку держать включённой не менее заданного в TstatTimerMax времени
}
}
}
// если прошла 1 секунда - делаем ежесекундные дела
if (plus1sec) {
plus1sec = false; // сбрасываем до следующей секунды
// обновляем часы
RTC.readClock();
Hours=RTC.getHours();
Minutes=RTC.getMinutes();
Seconds=RTC.getSeconds();
// измеряем температуру воздуха
DS18B20TempTmp = DS18B20.getTempCByIndex(0); // получить температуру от датчика
DS18B20.requestTemperatures(); // запустить новое измерение
if (DS18B20TempTmp != -127)
{
DS18B20Temperature += DS18B20TempTmp; // суммируем для усреднения
DS18B20iteration ++;
if (DS18B20iteration == 10)
{
DS18B20iteration = 0;
Temperature = (DS18B20Temperature / 10) + TemperatureCorr; //усреднённая + коррекция
DS18B20Temperature = 0;
}
}
// если уставку термостата поменяли вручную - запись её в EE, не чаще 1 раза в минуту
//(экономия ресурса EE)
if ((EEPROM_float_read(TstatTempEEaddr) != TstatTemp)&(Seconds == 0)) {
EEPROM_float_write(TstatTempEEaddr, TstatTemp);
}
// проверка Timer1 и изменение уставки термостата при совпадении
if ((Hours == Timer1Hours)&(Minutes == Timer1Minutes)&(Timer1Enabled)&(Seconds == 0)) { // время T1 совпадает с RTC
Timer1Activated = true;
Timer2Activated = false;
Timer3Activated = false;
TstatTemp = Timer1Temp;
EEPROM_float_write(TstatTempEEaddr, TstatTemp);
if (BeepEnabled) {
tone(BeepPin,4000,5);
}
}
// проверка Timer2 и изменение уставки термостата при совпадении
if ((Hours == Timer2Hours)&(Minutes == Timer2Minutes)&(Timer2Enabled)&(Seconds == 0)) { // время T2 совпадает с RTC
Timer1Activated = false;
Timer2Activated = true;
Timer3Activated = false;
TstatTemp = Timer2Temp;
EEPROM_float_write(TstatTempEEaddr, TstatTemp);
if (BeepEnabled) {
tone(BeepPin,4000,5);
}
}
// проверка Timer3 и изменение уставки термостата при совпадении
if ((Hours == Timer3Hours)&(Minutes == Timer3Minutes)&(Timer3Enabled)&(Seconds == 0)) { // время T3 совпадает с RTC
Timer1Activated = false;
Timer2Activated = false;
Timer3Activated = true;
TstatTemp = Timer3Temp;
EEPROM_float_write(TstatTempEEaddr, TstatTemp);
if (BeepEnabled) {
tone(BeepPin,4000,5);
}
}
if ((Temperature < AlarmTemp)&& (!SMSsent)){
tone(BeepPin,4000,5);startOneSMS();Serial.print("TREVOGA!!! ");Serial.print("TT=");Serial.print(Temperature);EndSMS();
SMSsent = true;SMSsenti = false;}
if ((Temperature > AlarmTemp)&& (!SMSsenti)){
tone(BeepPin,4000,5);startOneSMS();Serial.print("TREVOGA-OFF ");Serial.print("TT=");Serial.print(Temperature);EndSMS();
SMSsenti = true;SMSsent = false;}
if(Hours == 0 && Minutes == 2 && SMSDelete==false){
Serial.print("AT+CMGDA=«DEL ALL»\r"); SMSDelete=true;} // Удаляем в 0:02 все СМС.
if(Minutes != 2){SMSDelete=false;}
if(Hours == 10 && Minutes == 0 && TimeSMSzapros==false){
SMSzapros(); TimeSMSzapros=true;} // в 12:00 отправляем СМС о состоянии.
if(Minutes != 0){TimeSMSzapros=false;} // сброс флага TimeSMSzapros
}
// обработка поворота энкодера на лету (ручное изменение уставки температуры))
rotating = true; // reset the debouncer
if ((encoderR)^(encoderL)) {
if (encoderR) {
TstatTemp += 0.1;
}
else
{
TstatTemp -= 0.1;
}
TstatTemp = constrain(TstatTemp, 10, 35);
encoderR = false;
encoderL = false;
Timer1Activated = false;
Timer2Activated = false;
Timer3Activated = false;
}
// ================ по нажатию кнопки энкодера - меню настроек ====================
if(digitalRead(encoderK) == 0) {
MenuTimeoutTimer = 10; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("< SETUP >"));
if (BeepEnabled) {
tone(BeepPin,4000,50);
}
delay(200);
int menuitem = 0;
do {
rotating = true; // reset the debouncer
if ((encoderR)^(encoderL)) {
MenuTimeoutTimer = 10; //таймер таймаута, секунд
if (encoderR) { menuitem += 1; }
else { menuitem -= 1; }
if ( menuitem > 9 ) { menuitem = 0; } // границы пунктов меню
if ( menuitem < 0 ) { menuitem = 9; }
encoderR = false;
encoderL = false;
}
// индикация пункта меню (номер пункта - в menuitem)
lcd.setCursor(0, 1); //инфо на LCD
switch(menuitem)
{
case 0:
lcd.print(F("0.BACK "));
break;
case 1:
lcd.print(F("1.TIMER1 SET "));
break;
case 2:
lcd.print(F("2.TIMER2 SET "));
break;
case 3:
lcd.print(F("3.TIMER3 SET "));
break;
case 4:
lcd.print(F("4.CLOCK SET "));
break;
case 5:
lcd.print(F("5.HYSTERESIS SET"));
break;
case 6:
lcd.print(F("6.T-CORRECT SET "));
break;
case 7:
lcd.print(F("7.SOUND SET "));
break;
case 8:
lcd.print(F("8.T-ALARM SET "));
break;
case 9:
lcd.print(F("ZVONOK "));
break;
}
if (MenuTimeoutTimer == 0) {
menuitem = 0;
}
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
// если нажата кнопка энкодера или таймаут - обработка пункта меню (номер пункта - в menuitem)
if (BeepEnabled) {
tone(BeepPin,4000,50);
}
switch(menuitem)
{
// ====== пункт 0 - выход
case 0:
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration);
} //звук "NO"
break; // case 0 out
// ====== пункт 1 - установка Timer1
case 1:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SETUP TIMER1"));
delay(200);
Hours=Timer1Hours;
Minutes=Timer1Minutes;
SetYesNo = false;
PrintYesNo = true;
SetTime(0,1); // в позиции 0,1 - запрос ввода времени
if (MenuTimeoutTimer != 0) {
if (SetYesNo) // если при установке времени выбрано "Yes"
{
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
Timer1Hours = Hours;
Timer1Minutes = Minutes;
Timer1Enabled = true;
EEPROM.write(Timer1HoursEEaddr, Timer1Hours);
EEPROM.write(Timer1MinutesEEaddr, Timer1Minutes);
EEPROM.write(Timer1EnabledEEaddr, Timer1Enabled);
MenuTimeoutTimer = 10; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("Timer1 Temp. Set"));
delay(200);
do {
lcd.setCursor(0,1);
if (blink500ms) {
lcd.print(F(" "));
}
else {
lcd.print(Timer1Temp, 1);
lcd.write(0x02); // значок градуса
}
rotating = true; // reset the debouncer
if (encoderR) {
Timer1Temp += 0.1;
encoderR = false;
}
if (encoderL) {
Timer1Temp -= 0.1;
encoderL = false;
}
Timer1Temp = constrain(Timer1Temp, 10, 35); // крайние значения
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) { // если после выбора температуры нажата кнопка энкодера
EEPROM_float_write(Timer1TempEEaddr, Timer1Temp);
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
else { // если не нажата - используем старую температуру
Timer1Temp = EEPROM_float_read(Timer1TempEEaddr);
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
}
else // если при установке времени выбрано "No"
{
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
Timer1Enabled = false;
EEPROM.write(Timer1EnabledEEaddr, Timer1Enabled);
Timer1Hours = EEPROM.read(Timer1HoursEEaddr);
Timer1Minutes = EEPROM.read(Timer1MinutesEEaddr);
}
}
else {
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
break; // case 1 out
// ====== пункт 2 - установка Timer2
case 2:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SETUP TIMER2"));
delay(200);
Hours=Timer2Hours;
Minutes=Timer2Minutes;
SetYesNo = false;
PrintYesNo = true;
SetTime(0,1); // в позиции 0,1 - запрос ввода времени
if (MenuTimeoutTimer != 0) {
if (SetYesNo) // если при установке времени выбрано "Yes"
{
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
Timer2Hours = Hours;
Timer2Minutes = Minutes;
Timer2Enabled = true;
EEPROM.write(Timer2HoursEEaddr, Timer2Hours);
EEPROM.write(Timer2MinutesEEaddr, Timer2Minutes);
EEPROM.write(Timer2EnabledEEaddr, Timer2Enabled);
MenuTimeoutTimer = 10; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("Timer2 Temp. Set"));
delay(200);
do {
lcd.setCursor(0,1);
if (blink500ms) {
lcd.print(F(" "));
}
else {
lcd.print(Timer2Temp, 1);
lcd.write(0x02); // значок градуса
}
rotating = true; // reset the debouncer
if (encoderR) {
Timer2Temp += 0.1;
encoderR = false;
}
if (encoderL) {
Timer2Temp -= 0.1;
encoderL = false;
}
Timer2Temp = constrain(Timer2Temp, 10, 35); // крайние значения
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) { // если после выбора температуры нажата кнопка энкодера
EEPROM_float_write(Timer2TempEEaddr, Timer2Temp);
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
else { // если не нажата - используем старую температуру
Timer2Temp = EEPROM_float_read(Timer2TempEEaddr);
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
}
else // если при установке времени выбрано "No"
{
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
Timer2Enabled = false;
EEPROM.write(Timer2EnabledEEaddr, Timer2Enabled);
Timer2Hours = EEPROM.read(Timer2HoursEEaddr);
Timer2Minutes = EEPROM.read(Timer2MinutesEEaddr);
}
}
else {
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
break; // case 2 out
// ====== пункт 3 - установка Timer3
case 3:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SETUP TIMER3"));
delay(200);
Hours=Timer3Hours;
Minutes=Timer3Minutes;
SetYesNo = false;
PrintYesNo = true;
SetTime(0,1); // в позиции 0,1 - запрос ввода времени
if (MenuTimeoutTimer != 0) {
if (SetYesNo) // если при установке времени выбрано "Yes"
{
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
Timer3Hours = Hours;
Timer3Minutes = Minutes;
Timer3Enabled = true;
EEPROM.write(Timer3HoursEEaddr, Timer3Hours);
EEPROM.write(Timer3MinutesEEaddr, Timer3Minutes);
EEPROM.write(Timer3EnabledEEaddr, Timer3Enabled);
MenuTimeoutTimer = 10; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("Timer3 Temp. Set"));
delay(200);
do {
lcd.setCursor(0,1);
if (blink500ms) {
lcd.print(F(" "));
}
else {
lcd.print(Timer3Temp, 1);
lcd.write(0x02); // значок градуса
}
rotating = true; // reset the debouncer
if (encoderR) {
Timer3Temp += 0.1;
encoderR = false;
}
if (encoderL) {
Timer3Temp -= 0.1;
encoderL = false;
}
Timer3Temp = constrain(Timer3Temp, 10, 35); // крайние значения
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) { // если после выбора температуры нажата кнопка энкодера
EEPROM_float_write(Timer3TempEEaddr, Timer3Temp);
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
else { // если не нажата - используем старую температуру
Timer3Temp = EEPROM_float_read(Timer3TempEEaddr);
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
}
else // если при установке времени выбрано "No"
{
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
Timer3Enabled = false;
EEPROM.write(Timer3EnabledEEaddr, Timer3Enabled);
Timer3Hours = EEPROM.read(Timer3HoursEEaddr);
Timer3Minutes = EEPROM.read(Timer3MinutesEEaddr);
}
}
else {
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
break; // case 3 out
// ====== пункт 4 - установка RTC
case 4:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SETUP CLOCK"));
delay(200);
RTC.readClock();
Hours=RTC.getHours();
Minutes=RTC.getMinutes();
SetYesNo = false;
PrintYesNo = true;
SetTime(0,1); // в позиции 0,1 - запрос ввода времени
if (MenuTimeoutTimer != 0) {
if (SetYesNo)
{
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
RTC.setHours(Hours);
RTC.setMinutes(Minutes);
RTC.setSeconds(0);
RTC.setClock();
}
else
{
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
}
else {
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
break; // case 4 out
// ====== пункт 5 - установка гистерезиса
case 5:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
HysteresisOld = Hysteresis;
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SETUP HYSTERESIS"));
delay(200);
do {
lcd.setCursor(0,1);
if (blink500ms) {
lcd.print(" ");
}
else {
lcd.print(Hysteresis, 1);
lcd.write(0x02); // значок градуса
}
rotating = true; // reset the debouncer
if (encoderR) {
Hysteresis += 0.1;
encoderR = false;
}
if (encoderL) {
Hysteresis -= 0.1;
encoderL = false;
}
Hysteresis = constrain(Hysteresis, 0.1, 1); // крайние значения
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) {
EEPROM_float_write(HysteresisEEaddr, Hysteresis); // запись в ЕЕПРОМ
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
else {
Hysteresis = HysteresisOld;
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
break; // case 5 out
// ====== пункт 6 - установка коррекции температуры
case 6:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SETUP T-CORRECT "));
delay(200);
do {
lcd.setCursor(0,1);
if (blink500ms) {
lcd.print(F(" "));
}
else {
if (TemperatureCorr >= 0) {
lcd.print(F("+"));
}
lcd.print(TemperatureCorr, 1);
lcd.write(0x02); // значок градуса
}
rotating = true; // reset the debouncer
if (encoderR) {
TemperatureCorr += 0.1;
encoderR = false;
}
if (encoderL) {
TemperatureCorr -= 0.1;
encoderL = false;
}
TemperatureCorr = constrain(TemperatureCorr, -10, 10); // крайние значения
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) {
EEPROM_float_write(TemperatureCorrEEaddr, TemperatureCorr); // запись в ЕЕПРОМ
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
else {
TemperatureCorr = EEPROM_float_read(TemperatureCorrEEaddr);
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
break; // case 6 out
// ====== пункт 7 - вкл/выкл звука
case 7:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("SOUND SET "));
delay(200);
do {
lcd.setCursor(0,1);
if (BeepEnabled) {
lcd.print(F("BEEP ON "));
}
else {
lcd.print(F("BEEP OFF "));
}
rotating = true; // reset the debouncer
if ((encoderR)^(encoderL)) {
BeepEnabled = !BeepEnabled;
encoderR = false;
encoderL = false;
}
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) {
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
EEPROM.write(BeepEnabledEEaddr, BeepEnabled);
}
if (MenuTimeoutTimer == 0) {
BeepEnabled = EEPROM.read(BeepEnabledEEaddr);
}
break; // case 7 out
// ====== пункт 8 - установка коррекции температуры
case 8:
MenuTimeoutTimer = 30; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("ALARM-TEMP SET "));
delay(200);
do {
lcd.setCursor(0,1);
if (blink500ms) {
lcd.print(F(" "));
}
else {
if (AlarmTemp >= 0) {
lcd.print(F("+"));
}
lcd.print(AlarmTemp, 0);
lcd.write(0x02); // значок градуса
}
rotating = true; // reset the debouncer
if (encoderR) {
AlarmTemp += 1;
encoderR = false;
}
if (encoderL) {
AlarmTemp -= 1;
encoderL = false;
}
AlarmTemp = constrain(AlarmTemp, 5, 40); // крайние значения
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) {
EEPROM_float_write(AlarmTempEEaddr, AlarmTemp); // запись в ЕЕПРОМ
if (BeepEnabled) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
}
}
else {
AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
if (BeepEnabled) {
tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
}
}
break; // case 8 out
case 9:
MenuTimeoutTimer = 10; //таймер таймаута, секунд
lcd.clear();
lcd.setCursor(0, 0); //инфо на LCD
lcd.print(F("ZVONOK SET "));
delay(200);
do {
lcd.setCursor(0,1);
if (Zvonok) {
lcd.print(F("YES "));
}
else {
lcd.print(F("NO "));
}
rotating = true; // reset the debouncer
if ((encoderR)^(encoderL)) {
Zvonok = !Zvonok;
encoderR = false;
encoderL = false;
}
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (MenuTimeoutTimer != 0) {
if (Zvonok) {
tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
Dozvon();
}
}
break; // case 7 out
}
delay(200);
lcd.clear();
}
}
// ===== SUBROUTINES ==================================================================
// ========================================
void SetTime(char x, char y)
{
// ========= set hours
SetH = true;
do {
PrintRTC(x,y);
rotating = true; // reset the debouncer
if (encoderR) {
Hours += 1;
if(Hours > 23) {
Hours = 0;
};
encoderR = false;
}
if (encoderL) {
Hours -= 1;
if(Hours < 0) {
Hours = 23;
};
encoderL = false;
}
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (BeepEnabled) {
tone(BeepPin,4000,50); //звук "YES"
}
SetH = false;
delay(200);
// ========= set minutes
SetM = true;
do {
PrintRTC(0,1);
rotating = true; // reset the debouncer
if (encoderR) {
Minutes += 1;
if(Minutes > 59) {
Minutes = 0;
};
encoderR = false;
}
if (encoderL) {
Minutes -= 1;
if(Minutes < 0) {
Minutes = 59;
};
encoderL = false;
}
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
if (BeepEnabled) {
tone(BeepPin,4000,50); //звук "YES"
}
if (PrintYesNo) {
SetM = false;
delay(200);
// ========= set yes-no
SetYesNo = false;
do {
PrintRTC(0,1);
rotating = true; // reset the debouncer
if ((encoderR)||(encoderL)) {
SetYesNo = !SetYesNo;
encoderR = false;
encoderL = false;
}
}
while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
delay(200);
}
}
// ========================================
void PrintRTC(char x, char y)
{
lcd.setCursor(x,y);
if (SetH&&blink500ms) {
lcd.print(F(" "));
}
else {
if (Hours < 10) {
lcd.print(F("0"));
}
lcd.print(Hours);
}
// мигающее двоеточие, если не в режиме установки времени
if (!(SetH||SetM||PrintYesNo||blink500ms))
{
lcd.print(F(" "));
}
else {
lcd.print(F(":"));
}
if (SetM&&blink500ms) {
lcd.print(F(" "));
}
else {
if (Minutes < 10) {
lcd.print(F("0"));
}
lcd.print(Minutes);
}
lcd.print(F(" "));
if (PrintYesNo) {
lcd.print(F("["));
if (!(SetH||SetM||blink500ms))
{
lcd.print(F(" "));
}
else {
if (SetYesNo)
{
lcd.print(F("YES"));
}
else {
lcd.print(F("NO "));
}
}
lcd.print(F("]"));
}
}
// ========= чтение/запись float в EE =====
void EEPROM_float_write(int addr, float val) // запись в ЕЕПРОМ
{
byte *x = (byte *)&val;
for(byte i = 0; i < 4; i++) EEPROM.write(i+addr, x[i]);
}
float EEPROM_float_read(int addr) // чтение из ЕЕПРОМ
{
byte x[4];
for(byte i = 0; i < 4; i++) x[i] = EEPROM.read(i+addr);
float *y = (float *)&x;
return y[0];
}
// ========================================
// ============================ Encoder interrupts =============================
// Interrupt on A changing state
void doEncoderA(){
if ( rotating ) {
delay (1) ; // wait a little until the bouncing is done
}
// Test transition, did things really change?
if( digitalRead(encoderA) != A_set ) { // debounce once more
A_set = !A_set;
// adjust counter + if A leads B
if ( A_set && !B_set )
{
MenuTimeoutTimer = 10; //таймер таймаута, секунд
if (BeepEnabled) {
tone(BeepPin,4000,5);
}
encoderR = true;
rotating = false; // no more debouncing until loop() hits again
}
}
}
// Interrupt on B changing state, same as A above
void doEncoderB(){
if ( rotating ) {
delay (1);
}
if( digitalRead(encoderB) != B_set ) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if( B_set && !A_set ) {
MenuTimeoutTimer = 10; //таймер таймаута, секунд
if (BeepEnabled) {
tone(BeepPin,4000,5);
}
encoderL = true;
rotating = false;
}
}
}
// ============================ Timer0 interrupt =============================
// run every 500ms
void timerIsr()
{
blink500ms = !blink500ms; // инверсия мерцающего бита
if(blink500ms) {
plus1sec = true; // ежесекундно взводится
if (TstatTimer != 0) {
TstatTimer --; // ежесекундный декремент этого таймера
}
if (MenuTimeoutTimer != 0) {
MenuTimeoutTimer --; // ежесекундный декремент этого таймера
}
}
}
void sms_read() //_____Цикл чтения входящих СМС-сообщений______________
{
if (!Serial.available()) return;
char currSymb = Serial.read();
if ('\r' == currSymb)
{
if (isStringMessage)
{
if (!currStr.compareTo("ZVONOK")) { Dozvon();}
if (!currStr.compareTo("ZAPROS")) { SMSzapros();}
if (!currStr.compareTo("+30")) { TstatTemp = 30;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+29")) { TstatTemp = 29;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+28")) { TstatTemp = 28;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+27")) { TstatTemp = 27;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+26")) { TstatTemp = 26;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+25")) { TstatTemp = 25;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+24")) { TstatTemp = 24;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");} // Передача параметров по СМС
if (!currStr.compareTo("+23")) { TstatTemp = 23;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+22")) { TstatTemp = 22;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+21")) { TstatTemp = 21;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+20")) { TstatTemp = 20;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+19")) { TstatTemp = 19;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+18")) { TstatTemp = 18;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+17")) { TstatTemp = 17;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+16")) { TstatTemp = 16;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+15")) { TstatTemp = 15;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
if (!currStr.compareTo("+0.1")) { Hysteresis = 0.1;startOneSMS();Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
if (!currStr.compareTo("+0.2")) { Hysteresis = 0.2;startOneSMS();Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
if (!currStr.compareTo("+0.3")) { Hysteresis = 0.3;startOneSMS();Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
if (!currStr.compareTo("+0.4")) { Hysteresis = 0.4;startOneSMS();Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
if (!currStr.compareTo("+0.5")) { Hysteresis = 0.5;startOneSMS();Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
if (!currStr.compareTo("+1")) { Hysteresis = 1;startOneSMS();Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
EndSMS();
isStringMessage = false;
}
else { if (currStr.startsWith("+CMT")) { // если текущая строка начинается с "+CMT",
isStringMessage = true;}} // то следующая строка является сообщением
currStr = "";
}
else if ('\n' != currSymb) { currStr += String(currSymb);}
}
void SMSzapros() // СМС отчет для хозяина
{
startOneSMS();
if ((Timer1Enabled)&!(Timer1Activated)) {Serial.print("TIMER 1 ");Serial.print("T1=");Serial.print(Timer1Temp);Serial.print("/TU=");
Serial.print(Temperature);Serial.print(" HIST=");Serial.print(Hysteresis);}
if ((Timer2Enabled)&!(Timer1Activated)) {Serial.print("TIMER 2 ");Serial.print("T2=");Serial.print(Timer2Temp);Serial.print("/TU=");
Serial.print(Temperature);Serial.print(" HIST=");Serial.print(Hysteresis);}
if ((Timer3Enabled)&!(Timer1Activated)) {Serial.print("TIMER 3 ");Serial.print("T3=");Serial.print(Timer3Temp);Serial.print("/TU=");
Serial.print(Temperature);Serial.print(" HIST=");Serial.print(Hysteresis);}
else {Serial.print("TIMER OFF ");Serial.print("TSET/TT=");Serial.print(TstatTemp);Serial.print("/");Serial.print(Temperature);Serial.print(" HIST=");Serial.print(Hysteresis);}
if (digitalRead(12)==HIGH) {Serial.println(" NAGREV-OFF"); } else { Serial.println(" NAGREV-ON");}
EndSMS();
}
void NastroykaGSM()
{
Serial.print("AT+CMGF=1\r"); //устанавливает текстовый режим смс-сообщения
delay(300);
Serial.print("AT+IFC=1,1\r"); //устанавливает программный контроль потоком передачи данных
delay(300);
Serial.print("AT+CPBS=\"SM\"\r"); //открывает доступ к данным телефонной книги SIM-карты
delay(300);
Serial.print("AT+GSMBUSY=1,1\r"); //запрет всех входящих звонков
delay(300);
Serial.print("AT+CMGD=4,\r"); //Очищаем накопившиеся СМС
delay(300);
Serial.print("AT+CNMI=1,2,2,1,0\r"); //включает оповещение о новых сообщениях
delay(300);
}
void startOneSMS() //__________________Цикл подготовки модуля к отправке СМС-сообщений по первому номеру
{
Serial.print("AT+CMGF=1\r");
delay(100);
Serial.println("AT + CMGS = \"+79206888901\"");
delay(100);
}
void EndSMS() //__________________Цикл окончания и отправки СМС-сообщения_______________________
{
delay(100);
Serial.println((char)26); // Команда отправки СМС
delay(5000);
}
void Dozvon() //__________________Цикл дозвона абоненту (для аудиоконтроля)___________________
{
Serial.println("AT+CMIC=0,12"); // Команда для установки чувствительности микрофона Поэкспериментировать с цифрой.
// 0,- это канал микрофона (1,2,3),15 это уровень см.инструкцию к СИМ900
delay(200);
Serial.println("ATD+79206888901;"); // Набираем номер
}
Hyperline SFTP4-C7A-S22-IN-LSZH-WH-500 (SSTP4-C8-SOLID-INDOOR-LSZH-500)У меня все вот таким проложено, у него двойной экран, нормально работает. Но дорогой, сцуко.
Хотел по проводам спросить. Думаю к каждой розетке и выключателю проложить витую пару экранированную и легко достать и запас по проводам будет, там всётаки 8 жил. сечения будет достаточно?
Если будешь организацию света делать как у меня, например (см. сообщение #374), т.е. низковольтаная слаботочка от выключателей, то да, можно только витуху к выключателям, если как у автора темы - лапшу кидать надо. К розеткам тоже лапшу полюбому. к остальным элементам (датчики, динамики, камеры) - витуха.
Здравствуйте, повторяю Ваш проект немного переделывая под себя. Добавил ключ Ibutton для снятия и постановки на охрану. У меня вопрос по схеме. Зачем в опторазвязке светодиоды? Понятно что удобно посмотреть при настройке, а в дальнейшей работе может от них отказаться ведь даже 20 милиампер умноженых на 15 штук при работе от аккумулятора в мороз очень значительно. Или я неправ специалисты подскажите???
Вот сижу и думаю, ведь можно и без адресовопросить все датчики на шине, но как контроллер узнает, какой из них какой, если адресане прописаны? Но если это реализовать, то обслуживание и ремонт наших систем упростится в разы. Может, у кого есть идеи по этому поводу?
А чего думать то, единственный вариант не морочиться с адресами, это использовать для опроса каждого датчика свой отдельный пин у Дуни(соотв отдельную линию данных)...
И все.. пофигу на адрес, к пину (например 10) подключен датчик на улице...
Вот сижу и думаю, ведь можно и без адресовопросить все датчики на шине, но как контроллер узнает, какой из них какой, если адресане прописаны? Но если это реализовать, то обслуживание и ремонт наших систем упростится в разы. Может, у кого есть идеи по этому поводу?
А чего думать то, единственный вариант не морочиться с адресами, это использовать для опроса каждого датчика свой отдельный пин у Дуни(соотв отдельную линию данных)...
И все.. пофигу на адрес, к пину (например 10) подключен датчик на улице...
И все. с "десятки" получаем уличную температуру..
Сдох датчик, отключили и воткнули новый.. все..
Опять с десятого пина читаем температуру улицы..
Никаких идей более нет..
Вот красивые датчики температуры-влажности, можно даже покрасить в любой цвет
Подключаются на цифровой пин ардуины(каждый на отдельный), внутри имеет разьем 3-х пиновый, менять если что удобно (меняется сама платка внутири пластиковой коробочки)
//Подключаемые Библиотеки
#include <SoftwareSerial.h> //Библиотека для работы с Serial port
#include <DHT.h> //Библиотека для работы с датчиками температуры-влажности
// Объявление датчиков температуры и влажности
#define TempOutSide 3 //Температура и влажность на улице, подкл.на цифровой пин 3
#define DHTTYPE DHT21 // DHT (AM2301)
DHT dht1(TempOutSide, DHTTYPE);
// Переменные
float h = 0;
float t = 0;
float tOut;
float hOut;
int Error = 777; // код ошибки для вывода
void setup() {
Serial.begin(9600);
// Подключаем датчики температуры и влажности
dht1.begin();
}
void loop() {
// Читаем данные с датчика
h = dht1.readHumidity();
t = dht1.readTemperature();
if (isnan(t) || isnan(h)) {
tOut = Error;
hOut = Error;
} else {
tOut = t;
hOut = h;
}
// Выводим данные с датчика
Serial.print("TE: "); // Температура
Serial.println(tOut);
Serial.print("ME: ");
Serial.println(hOut); // Влажность
}
3. Плата реле 8 шт входные цепи. Оптопара +74НС245 (формирователь) всего 12 входов. Интернет шилд ENC28c60 также на этой плате дополнительные элементы питания, цепи подключения и защиты внешних датчиков (DS18b20. DHT11. DHT22. а также в плане датчиков газа) остальные датчики контакные.движения. и пр. также получают питание и подключаются к этой плате
4. Плата Мега. Плата на которой сама Ардуно Мега, через BLS раземы устанавливается (спиной вверх ) Также на ней установлено 3 (панельки) для портов RX-TX (UATR) - RS485 (MAX485). Плата DS1302 (часы) Для подключения внешних блоков. Уже наработана база по модулям и опыт по МОДБАС-у.
В остальном сеть на витой паре. Сервер МаjorDomo Контроллер управления воротами (откатные). калитка (эл. замок. видеокамера (домофон) контроллер ключей. Датчики температуры в комантах и постойках (погреб. баня. мастерская). и пр.
Управлене нагрузками реле. Видеонаблюдение 4 камеры на видеорегистраторе. Сама схема постоянно развивается с 2011 г. в основном на данный момент это преход на микроконтроллеры и датчики на основе NRF24 (MySensors).
Можно Ваш скетч поглядеть. Интресует именно отображение (информативная часть).
У меня вся система (логика) ранее была на сервере (системная плата Атом) но сейчас,после приобретения несколько плат Mega 2560 все решил пренести основные задачи на них. Автоматику. Еще есть небольшой сервер на ESP8266 (AMS http://majordomo.smartliving.ru/forum/viewtopic.php?f=19&t=2890 ) он в основном как информациооное поле. На планшет и пр. выдает информацию.
Если кому интересно, могу приложить ЛУТ плату для Mega (развязка) ее можно доработать под свои задачи.
Коллеги, кто нибудь вводил в программу работу системы отопления по ночному тарифу?
Хочу чтоб электрокотел с 23 ч до 7 утра работал по максимуму( по штатной уставке 22 градуса) а в остальное время на минимуме (в режиме экономии 5 град).
Можно Ваш скетч поглядеть. Интресует именно отображение (информативная часть).
У меня вся система (логика) ранее была на сервере (системная плата Атом) но сейчас,после приобретения несколько плат Mega 2560 все решил пренести основные задачи на них. Автоматику. Еще есть небольшой сервер на ESP8266 (AMS http://majordomo.smartliving.ru/forum/viewtopic.php?f=19&t=2890 ) он в основном как информациооное поле. На планшет и пр. выдает информацию.
Если кому интересно, могу приложить ЛУТ плату для Mega (развязка) ее можно доработать под свои задачи.
Качество USB камер желает лучшего, картинка говно, а у кого денег не хватает и кому пофиг на качество видео и кому не надо записывать на сервер, то делайте....
Я лучше куплю нормальные IP-камеры.
IP камеры 2MP стоят от 2000 до 5000 на AliExpress
Поворотные IP камеры с HD качеством картинки и с 18-и кратным увеличением стоят от 12000 и ого-го, но они ах*енные.
Настраиваются легко, Можно настроить оповещения(фото) по e-mail, постить на сервер (Например: при движении в определенной области, или по внешнему триггеру, или по закрытии камеры чем либо....)
Подскажите библиотеку что бы заменить часы DS 1302 на DS 3231. Все что я находил с часами работают но в данном скетче выдают ошибки, а переделать ума не хватает. Спасибо если кто поможет.
Подскажите библиотеку что бы заменить часы DS 1302 на DS 3231. Все что я находил с часами работают но в данном скетче выдают ошибки, а переделать ума не хватает. Спасибо если кто поможет.
Любая для DS1307. В них нет возможности настройки будильников, но это можно напрямую через Wire (если нужны).
Наконец то (после 2х недель мучений)прицепил GSM модуль М590.
Для отладки добавил пару строк в п\программе SIM900:
void sms_read() //___Цикл чтения входящих СМС-сообщений___
{
if (!Serial2.available()) return;
char currSymb = Serial2.read();
////
<strong>Serial.print(currStr); //печатаем в монитор порта пришедшую строку currStr.</strong> ИЛИ CURRSYMB
/////
if ('\r' == currSymb)
И в п\программе Настройка ГСМ у меня вот такие настройки:
Serial.println("GSM");
Serial2.println("AT+CMGF=1"); //устанавливает текстовый режим смс-сообщения
delay(50);
Serial2.println("AT+CSCS=\"GSM\""); //кодировка смс-сообщения
delay(50);
Serial2.println("AT+CNMI=2,2,0,0,0"); //включает оповещение о новых сообщениях было ("AT+CNMI=1,2,2,1,0\r")
delay(500);
Serial2.println("AT+CLIP=1"); //АОН вкл
delay(50);
// Serial2.println("AT+IFC=1,1"); //устанавливает программный контроль потоком передачи данных
Serial2.println("AT+CPBS=\"SM\""); //открывает доступ к данным телефонной книги SIM-карты
delay(100);
// Serial2.println("AT+CMGD=0,4"); // удаляем все смс, ки "AT+CMGDA=\"DEL ALL\"\r")
// delay(1400);
Serial2.println("AT+CPAS");
delay(100); //AT+CPAS – Возвращает готовность модема. “+CPAS: 0” – готов.
}
В результате программа работает как то странно:
При включении устройства мне на телефон прлетает СМС о протечке. Затем, с задержкой ок 5 сек в сериал выскакивают строки. Строка сначала не полная, затем дублируется полной строкой. И так по каждой команде. НО не все команды пишутся в сериал а только около 2\3.
Если печатать в сериал не строки а символы, то ситуация следующая- символы команд печатаются неспеша-по символу в секунду.
Печатаются правильно. Но тоже не все команды прописывает в сериал, а только первые 2\3.
Так вот. Я не понимаю:
1. Кто (где) ограничивает количество выводимых в сериал символов?
2. Если сначала мне летит смс, а потом идет вывод с сериал команд инициализации модема, то что это за бутафория выводится в сериал?
3. При запросе состояния мне прилетает смс, но в ней только : "HOME=OFFAlarm:ON IBP:+23.74 V" так и должно быть?
4. При включении системы у меня 4 тревоги- ворота, протечка, и что то еще. А прилетает СМС только о протечке. Это правильно?
Благодарю за интересную и полезную информацию. Сам вынашиваю те же идеи. Пока до реализации дело не дошло. Любопытно было посмотреть как у вас это было реализовано на практике.
Продолжаю править программу под свои нужды:
У меня в нежилом доме котел электрический 3-х ступенчатый. 3-6-9 КВт., и счетчик 2х тарифный. Соответственно задумка по максимуму греть теплоноситель ночью, а днем только по необходимости ( чтоб температура была положительная). При этом хочу задействовать ступенчатый нагрев (3-6-9 КВт) в зависимости от (чего??)- темп. за бортом\темп. в доме\ дельта температур дом-улица...
Есть ли у кого идеи по такому алгоритму?
Вот погодозависимый алгоритм, часть1: http://radiokot.ru/circuit/digital/home/112/
часть2: http://radiokot.ru/circuit/digital/home/130/
Там для газового котла, (один контакт управления) но думаю это не проблема. Главное принцип понять погодозависимости...
Обидно что исходник не посмотреть...
Доброй ночи разработчики! Сваял я термостат для управления двумя нагревателями, алгоритм такой, если температура ниже заданной, включаем обогреватель 1, при этом, если разница текущей и установленной температурой больше х градусов, включается нагреватель 2. Если меньше х, нагреватель 2 отключается и температура доводится первым до установленной+гистерезис. Но, если у первого мощи не хватает и разница температур меньше х , температура не растет и второй не включается. Возникла у меня необходимость сделать контроль роста температуры и перевести управление вторым нагревателем на этот контроль. Идею вижу так, если за время Т температура поднялась на Х градусов, включение нагревателя 2 не требуется, если поднялась на Y градусов или не поднялась или опустилась, включаем нагреватель 2. При этом модуля часов у меня там не предусмотрено. Всю голову сломал нах и гугл не помогает. Может кто подскажет? P.S. Сильно не пинайте, это не окончательная версия кода, но уже пытается работать...
Еще хотелось бы организовать ротацию нагревателей, для равномерного износа, но это после подумаю, сейчас бы контроль роста температуры осилить...
При этом модуля часов у меня там не предусмотрено. Всю голову сломал нах и гугл не помогает. Может кто подскажет?
использовать таймер на millis() . измерять температуру в начале и в конце таймера. Их разность и будет дельта за это время.
.
Макс, я с миллисом не очень разобрался, в моем коде уже есть интервал для замера температур, но он короткий. Можно ли объявить еще интервал и если да, как это делается? И еще, вчера не тот код выложил, вечером выложу правильный.
Коллеги, может кому интересно, приладил в программу запись на СД карту. С индикацией процесса записи(светодиод светится пол секунды, когда запись идёт. Запись осуществляется раз в 2 минуты по условию, когда на часах выставляется ..2 мин 0 секунд.
Но есть косячёк- пока длится нулевая секунда, программа успевает сделать запись 2-3 раза. понимаю, что если вставить задержку не 500мс а 900, то будет все хор, но мы же боремся за оптимизацию программы. Ка же сделать красиво и оптимально?
Внедрил код как у MaksVV на опрос Датчиков DS18. Установил таймер на 8 сек. Работает! Только не получается сделать отображение температуры с точностью до десятой доли ,хотя прописывал:
Slavyanin55, прочитал Вашу тему очень интересно, большое спасибо.
Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?
Спасибо.
Коллеги, можно мне со своим вопросом встрять? Кто-то решал задачу контроля состояния шилда SIM900?
У меня на даче стоит смс- розетка уже третий месяц. На улице бывало до -30, и я не даю уйти дому в минус с помощью калориферов.
Проблема в том, что иногда шилд выключается (а Мега 2560 продолжает работать) или теряет сеть, и поэтому перестаёт отвечать на смс запросы. Хочется его перезагрузить, а для этого надо спросить его состояние, и если нет сети или он выключен-то сделать нужное действие. У кого-нибудь есть протестированный кусочек кода?
У меня есть, правда проверка состояния идет на момент запуска самой меги, но можно и просто на опрос состояния сделать.
Другой момент, как модуль отваливается по питанию, а сама мега работает?
Я использую библиотеку SIM900, соответственно, у меня не АТ команды.
При перезагрузке Меги или в момент включения подаётся 3-х секундный импульс на 9 ножку шилда, который и включает шилд. Каким образом шилд выключается- не знаю. У нас, бывает, пропадает питание по всему саду, но при восстановлении по идее и Мега, и шилд должны включиться. Просто он перестаёт отвечать, я еду на дачу и руками перезагружаю. Да, собственно, мне и не важна причина, главное - повысить надёжнось. Мега должна проверять шилд ну, хотя бы через час, и послать ему импульс на включение (или на выключение/ включение).
Библиотеку не стал использовать, т.к. вроде AT команд хватает.
Slavyanin55, прочитал Вашу тему очень интересно, большое спасибо.
Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?
Спасибо.
Тоже интересует этот вопрос. Думаю не на ИБП тратиться, а поставить старый 12- вольтовый автомобильный аккумулятор, не совсем дохлый. При наличии сети он должен подзаряжаться слабым током, а при обесточивании- послать смс. При восстановлении энегроснабжения- тоже смс. Как-то так, не должно быть сложно.
Slavyanin55, прочитал Вашу тему очень интересно, большое спасибо.
Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?
Спасибо.
Тоже интересует этот вопрос. Думаю не на ИБП тратиться, а поставить старый 12- вольтовый автомобильный аккумулятор, не совсем дохлый. При наличии сети он должен подзаряжаться слабым током, а при обесточивании- послать смс. При восстановлении энегроснабжения- тоже смс. Как-то так, не должно быть сложно.
Naz, не совсем понимаю, как у Вас реализовано общение gsm модуля. По идее скрипт, чтобы прочитать полученную смс, должен регулярно обращатся к gsm. Тут и должно проверятся условие, есть смс, нет смс, модуль не отвечает. Если не отвечает - ресет на пин. Вот и все.
Все очень просто. Посмотрите void nastroyka gsm. В начале работы мы настраиваем gsm модуль посредством АТ команд, чтобы он при получении смс сразу сливал его в мегу. А мега просто ждет, что упадет в сериал и реагирует соответственно. Почитайте в google АТ команды gsm модемов и все станет ясно.
Попробуйте проверять состояние модема командой AT+CPAS к примеру раз в час, если не ответил, или ответил не так, даем ему с любого пина ардуины ресет, если я не ошибаюсь, на сим 900 это пин16, далее ждем загрузки и снова даем настройку.
Спасибо, все получилось)
Коллеги, можно мне со своим вопросом встрять? Кто-то решал задачу контроля состояния шилда SIM900?
У меня на даче стоит смс- розетка уже третий месяц. На улице бывало до -30, и я не даю уйти дому в минус с помощью калориферов.
Проблема в том, что иногда шилд выключается (а Мега 2560 продолжает работать) или теряет сеть, и поэтому перестаёт отвечать на смс запросы. Хочется его перезагрузить, а для этого надо спросить его состояние, и если нет сети или он выключен-то сделать нужное действие. У кого-нибудь есть протестированный кусочек кода?
Рабочий урезаный код моей проги, работает у меня уже более года)
Код для проверки работоспособности системы без каких либо часов реального времени, ну и чуть-чуть кода для отправки смс на номер( номер указан в начале кода).
Я люблю работать с памятью ардуины, т.к. хочу управлять сам своим ус-вом
В данном примере нет работы с памятью.
Сделано так: регулярно опрашивается буфер UART, соединённый с gsm. И если буфер пуст- непонятно, то ли нет входящего смс, то ли шилд сеть потерял/ вырубился.
Спасибо, друзья, за ответы, попробую. stambilov, хотелось бы без gsm библиотеки обойтись..
Добрый день. Сегодня наткнулся на данную тему, очень заинтересовала. Есть желание сделать умную квартиру, на дом ещё не заработал. Работаю на производстве, у нас стоят контроллеры BECKHOFF, очень интересная штука, почитал на них собирают умные дома, на самой старой серии bc9000. Хотел купить б/у но продают только в Штатах и в Германии, а стоимость за пересылку кусается. А тут увидел на Меге такой проект и загорелся попробовать. До этого на меге собрал только 3d принтер, так что опыта не много. Я так понимаю у Вас проект существует уже с 14 года. Хотел спросить, много у вас элементов сгорало и ломалось за это время? Пробежался по форуму и не увидел спецификации, думаю она есть, но не нашел. Хотел посмотреть какие шильды датчики и релюшки нужно купить для базовой конфигурации.
Доброго всем дня, доехал конструктор до наших краев. Подскажите несведующему, последнюю прошивку не могу залить на mega2560 выходит ошибка при компиляции. В какую сторону смотреть? Бибилиотеки вроде перекинул в папку с Arduino.
может нужно выбрать нужный МК в настройках а именно мегу 2560. (Инструменты => плата)
Maksim82, при правильном подборе и сборке всех элементов там ломаться и сгорать нечему.
Я заказал уже на пробу мегу и кней температурные датчики, релюшку импульсную, платку с обычными реле. вайфайный модуль и плату изернет. несколько объемников и всякой мелочёвки ещё. Хотел сделать базу какую то к которой можно было бы подключать разные датчики. Думал тут какую то статистику и спецификацию почерпнуть, но все молчат.
Какая статистика тебя интересует? Тут все пилят проект под свои нужды, добавляя что-то от себя и заимствуя у других. Сформулируй вопрос понятно, что не получается, что пытаешься сделать, что недопонял и тебе подскажут. Для того форум и существует. Если что, моя почта s-tver@mail.ru, чем смогу.
спецификацию почерпнуть
так, что на ум быстро пришло
Мега, gsm sim800L+ антенна выносная + модуль питания к нему, часы ds3231, дисплей 4 строчный i2с, гора термодатчиков ds18b20, гора PIR датчиков, гора оптопар pc817, платы реле, mp3 модуль, датчик инфракрасный для приема сигналов от пульта, пищалка от материнской платы компьютера, wi-fi модуль, bluetooth модуль, ethernet модуль, блок питания 12в и 5В, ИБП для блока питания с АКБ, 4g wi-fi роутер, бухта провода в экране 4 жилы или 8 жил.
ООО половину уже купил, оптопары не взял пожалу и gsm модуль, дисплей ещё от принтера остался без применения. спасибо. Хотел спросить, делаю пока всю подготовку, квартира ещё строится, сдаваться будет на нулевой стадии отделки, так что поле для прокладки обширное. Хотел по проводам спросить. Думаю к каждой розетке и выключателю проложить витую пару экранированную и легко достать и запас по проводам будет, там всётаки 8 жил. сечения будет достаточно?
Доброй ночи, товарищи! Вот сваял окончательную версию термостата для управления конвекторами, поставил, все работает, все устраивает. Месяц работы, полет нормальный. Ежедневный отчет по GSM приходит исправно.Управляется по GSM тоже ок. Можно даже позвонить туда и оттуда и полноценно поговорить.Но вот сижу и думаю... Хата моя стоит за 300 км от меня, там мать живет, программистов нет.
ВООБЩЕ. НИКАКИХ.
А если датчик температуры накрылся? Он же адресный, придется тогда брать ноут и новыйдатчик и ехать менять, т.к. без скетча никто ничего не сможет сделать. Далее, возниклаидея прикрутить еще датчик на улицу. Тут уже адрес нужен и ремонтопригодностьсводится к 1 человеку, который это сделал. Вот сижу и думаю, ведь можно и без адресовопросить все датчики на шине, но как контроллер узнает, какой из них какой, если адресане прописаны? Но если это реализовать, то обслуживание и ремонт наших систем упростится в разы.
Может, у кого есть идеи по этому поводу?
Hyperline SFTP4-C7A-S22-IN-LSZH-WH-500 (SSTP4-C8-SOLID-INDOOR-LSZH-500)У меня все вот таким проложено, у него двойной экран, нормально работает. Но дорогой, сцуко.
Хотел по проводам спросить. Думаю к каждой розетке и выключателю проложить витую пару экранированную и легко достать и запас по проводам будет, там всётаки 8 жил. сечения будет достаточно?
Если будешь организацию света делать как у меня, например (см. сообщение #374), т.е. низковольтаная слаботочка от выключателей, то да, можно только витуху к выключателям, если как у автора темы - лапшу кидать надо. К розеткам тоже лапшу полюбому. к остальным элементам (датчики, динамики, камеры) - витуха.
Здравствуйте, повторяю Ваш проект немного переделывая под себя. Добавил ключ Ibutton для снятия и постановки на охрану. У меня вопрос по схеме. Зачем в опторазвязке светодиоды? Понятно что удобно посмотреть при настройке, а в дальнейшей работе может от них отказаться ведь даже 20 милиампер умноженых на 15 штук при работе от аккумулятора в мороз очень значительно. Или я неправ специалисты подскажите???
поставьте синие светодиоды и килоом 10-20 с ними..... будут вообще фигню потреблять, но индицировать достаточно ярко.
А чего думать то, единственный вариант не морочиться с адресами, это использовать для опроса каждого датчика свой отдельный пин у Дуни(соотв отдельную линию данных)...
И все.. пофигу на адрес, к пину (например 10) подключен датчик на улице...
И все. с "десятки" получаем уличную температуру..
Сдох датчик, отключили и воткнули новый.. все..
Опять с десятого пина читаем температуру улицы..
Никаких идей более нет..
А чего думать то, единственный вариант не морочиться с адресами, это использовать для опроса каждого датчика свой отдельный пин у Дуни(соотв отдельную линию данных)...
И все.. пофигу на адрес, к пину (например 10) подключен датчик на улице...
И все. с "десятки" получаем уличную температуру..
Сдох датчик, отключили и воткнули новый.. все..
Опять с десятого пина читаем температуру улицы..
Никаких идей более нет..
Вот красивые датчики температуры-влажности, можно даже покрасить в любой цвет
Подключаются на цифровой пин ардуины(каждый на отдельный), внутри имеет разьем 3-х пиновый, менять если что удобно (меняется сама платка внутири пластиковой коробочки)
Ссылка на Али
Код для датчиков:
Вот наконец то собрал все, протестировал)) скоро поеду ставить, потом фотки выложу, а сейчас вот так выглядит мой бутерброд:
22 реле управления светом
1 реле управление активации датчика освещенности
22 индикации состояния света
1 индикация состояния д.освещенности
6 датчиков температуры-влажности
3 токовых датчика для отображения тока по фазам, также отображение мощности в КВт
1 понижающая плата с 12 на 5В
Всем доброе время суток.
Собираю похожую систему. В основе MEGA2560 R3. Установлена в стеновом боксе. Внутри 4 этажерки платы.
1. Плата питания.
2 Плата индикации LCD 16*2. 7 светодиодов. 7 переключателей (тумблеры).
3. Плата реле 8 шт входные цепи. Оптопара +74НС245 (формирователь) всего 12 входов. Интернет шилд ENC28c60 также на этой плате дополнительные элементы питания, цепи подключения и защиты внешних датчиков (DS18b20. DHT11. DHT22. а также в плане датчиков газа) остальные датчики контакные.движения. и пр. также получают питание и подключаются к этой плате
4. Плата Мега. Плата на которой сама Ардуно Мега, через BLS раземы устанавливается (спиной вверх ) Также на ней установлено 3 (панельки) для портов RX-TX (UATR) - RS485 (MAX485). Плата DS1302 (часы) Для подключения внешних блоков. Уже наработана база по модулям и опыт по МОДБАС-у.
В остальном сеть на витой паре. Сервер МаjorDomo Контроллер управления воротами (откатные). калитка (эл. замок. видеокамера (домофон) контроллер ключей. Датчики температуры в комантах и постойках (погреб. баня. мастерская). и пр.
Управлене нагрузками реле. Видеонаблюдение 4 камеры на видеорегистраторе. Сама схема постоянно развивается с 2011 г. в основном на данный момент это преход на микроконтроллеры и датчики на основе NRF24 (MySensors).
Фотографии чуть позже... пока не дома.
Вот наконец то подключил все компоненты аля умного дома.
Видео обзор сделаю чуть позже.
Вот как получилось:
Вот как получилось:
Хорошо выглядит!!!!
Можно Ваш скетч поглядеть. Интресует именно отображение (информативная часть).
У меня вся система (логика) ранее была на сервере (системная плата Атом) но сейчас,после приобретения несколько плат Mega 2560 все решил пренести основные задачи на них. Автоматику. Еще есть небольшой сервер на ESP8266 (AMS http://majordomo.smartliving.ru/forum/viewtopic.php?f=19&t=2890 ) он в основном как информациооное поле. На планшет и пр. выдает информацию.
Если кому интересно, могу приложить ЛУТ плату для Mega (развязка) ее можно доработать под свои задачи.
Плата https://yadi.sk/d/mvUavlbc3EvUqF
Коллеги, кто нибудь вводил в программу работу системы отопления по ночному тарифу?
Хочу чтоб электрокотел с 23 ч до 7 утра работал по максимуму( по штатной уставке 22 градуса) а в остальное время на минимуме (в режиме экономии 5 град).
Поделитесь, если не жалко кусочком кода.
Вот как получилось:
Хорошо выглядит!!!!
Можно Ваш скетч поглядеть. Интресует именно отображение (информативная часть).
У меня вся система (логика) ранее была на сервере (системная плата Атом) но сейчас,после приобретения несколько плат Mega 2560 все решил пренести основные задачи на них. Автоматику. Еще есть небольшой сервер на ESP8266 (AMS http://majordomo.smartliving.ru/forum/viewtopic.php?f=19&t=2890 ) он в основном как информациооное поле. На планшет и пр. выдает информацию.
Если кому интересно, могу приложить ЛУТ плату для Mega (развязка) ее можно доработать под свои задачи.
Плата https://yadi.sk/d/mvUavlbc3EvUqF
Привет, код страницы смотрите под кодом Arduino
Весь код не скину, урезанный смотрите:
****************************************************************************
**********************************************************************************
КОД СТРАНИЦЫ HTM
Вам еще не хватает камеры наблюдения. Тут есть проект на Raspberry Pi (для расширения ) https://ngin.pro/smart-house/131-kamera-nablyudeniya-dlya-umnogo-doma-na...
Вам еще не хватает камеры наблюдения. Тут есть проект на Raspberry Pi (для расширения ) https://ngin.pro/smart-house/131-kamera-nablyudeniya-dlya-umnogo-doma-na-raspberry-pi-arduino.html
Качество USB камер желает лучшего, картинка говно, а у кого денег не хватает и кому пофиг на качество видео и кому не надо записывать на сервер, то делайте....
Я лучше куплю нормальные IP-камеры.
IP камеры 2MP стоят от 2000 до 5000 на AliExpress
Поворотные IP камеры с HD качеством картинки и с 18-и кратным увеличением стоят от 12000 и ого-го, но они ах*енные.
Настраиваются легко, Можно настроить оповещения(фото) по e-mail, постить на сервер (Например: при движении в определенной области, или по внешнему триггеру, или по закрытии камеры чем либо....)
Подскажите библиотеку что бы заменить часы DS 1302 на DS 3231. Все что я находил с часами работают но в данном скетче выдают ошибки, а переделать ума не хватает. Спасибо если кто поможет.
Подскажите библиотеку что бы заменить часы DS 1302 на DS 3231. Все что я находил с часами работают но в данном скетче выдают ошибки, а переделать ума не хватает. Спасибо если кто поможет.
Любая для DS1307. В них нет возможности настройки будильников, но это можно напрямую через Wire (если нужны).
Тут нужно не просто библиотеку нужную прицепить, но и в программе прописать:
Наконец то (после 2х недель мучений)прицепил GSM модуль М590.
Для отладки добавил пару строк в п\программе SIM900:
При включении устройства мне на телефон прлетает СМС о протечке. Затем, с задержкой ок 5 сек в сериал выскакивают строки. Строка сначала не полная, затем дублируется полной строкой. И так по каждой команде. НО не все команды пишутся в сериал а только около 2\3.
Если печатать в сериал не строки а символы, то ситуация следующая- символы команд печатаются неспеша-по символу в секунду.
Печатаются правильно. Но тоже не все команды прописывает в сериал, а только первые 2\3.
Так вот. Я не понимаю:
1. Кто (где) ограничивает количество выводимых в сериал символов?
2. Если сначала мне летит смс, а потом идет вывод с сериал команд инициализации модема, то что это за бутафория выводится в сериал?
3. При запросе состояния мне прилетает смс, но в ней только : "HOME=OFFAlarm:ON IBP:+23.74 V" так и должно быть?
4. При включении системы у меня 4 тревоги- ворота, протечка, и что то еще. А прилетает СМС только о протечке. Это правильно?
Спасибо за подсказку. Разобрался похоже у меня комфликт библиотек между датчиком освещенности BH1750 и часами. не скажите можно ли их подружить?
Добрый день!
Благодарю за интересную и полезную информацию. Сам вынашиваю те же идеи. Пока до реализации дело не дошло. Любопытно было посмотреть как у вас это было реализовано на практике.
Хочу поделиться информацией касательно улучшения работы GSM модуля на SIM900 на Меге: https://geektimes.ru/post/286150/