Питание моего SIM900 - внешнее 5В 2А, скорость установил 9600, использую на Меге Serial1 - пины 18 и 19. Никаких библиотек не подключаю. Порт живой, т.к. после выключения - включения питания работает нормально. Подозреваю, что он в какой-то режим переходит непонятный после посылки смс. Об ограничении по TX и RX не слышал для SIM900, как его сделать?
Питание моего SIM900 - внешнее 5В 2А, скорость установил 9600, использую на Меге Serial1 - пины 18 и 19. Никаких библиотек не подключаю. Порт живой, т.к. после выключения - включения питания работает нормально. Подозреваю, что он в какой-то режим переходит непонятный после посылки смс. Об ограничении по TX и RX не слышал для SIM900, как его сделать?
Рабочий код для получения баланса
// Дата написания: 04.06.2016
// Создатель: Стамбулов Дмитрий
// E-mail: stambylov@ya.ru
#include <SoftwareSerial.h>
SoftwareSerial gsm(2, 3); // 2-txd, 3-rxo , Arduino mini или Arduino nano
void setup()
{
gsm.begin(9600);
// Запускаем GSM
gsm.write("AT+CMGF=1\r"); // устанавливает текстовый режим смс-сообщения
delay(300);
gsm.write("AT+IFC=1, 1\r"); //устанавливает программный контроль потоком передачи данных
delay(300);
gsm.write("AT+CPBS=\"SM\"\r");//открывает доступ к данным телефонной книги SIM-карты
delay(300);
gsm.write("AT+CNMI=1,2,2,1,0\r");// включает оповещение о новых сообщениях, новые сообщения
delay(500);
gsm.write("AT+GSMBUSY=1\r\n"); // запрет всех входящих звонков.
delay(300);
gsm.write("AT+CMGDA=DEL ALL\r\n"); // команда удалит все сообщения
delay(500);
gsm.println("AT+CSQ");// Проверяем уровень сигнала
delay(800);
}
void loop()
{
//*******************************************************************
if (gsm.available()) { //есть данные от GSM модуля
String currStr = ""; //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
String currStrN = "";
String dataBalanceTemp = "";
String dataBalance = "";
String dataSms = "";
String val = "";
int flag1 = 0;
int flag2 = 0;
while (gsm.available()) { //сохраняем входную строку в переменную val
c:
int ch = gsm.read(); //int
val += char(ch); // String
char data = ch; // char = int
if ('\r' == data) {
currStr = "";
} else if ('\n' != data) {
currStr += String(data);
dataSms = currStr;
}
// Начинаем разбор полученного смс, Работает 100% с оператором МТС
//Полученный текст: +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 (val.indexOf("+CUSD:") > -1) {
// +CUSD: 0, "Balance:117,27r ", 15
if (dataBalance != "") {
smsSendAlarm("Hi, " + dataBalance);
dataBalance = "";
}
}
// Читаем смс полученные с мобильного
if (val.indexOf("+CMT") > -1) {
if (dataSms.indexOf("Balans") > -1) { // Запрос баланса
GoBalans();
}
}
}
}
//процедура отправки СМС
void smsSendAlarm(String text) {
String NBoss = "79115557744";
gsm.println("AT+CMGS=\"" + NBoss + "\""); //Отправляем на GSM комманду отправка смс-номер
NBoss = ""; //Очищаем перемунную
delay(300); //Делаем задержку на передачу комманды
gsm.print(text); //Отправляем на GSM комманду отправка смс-текст
text = ""; //Очищаем перемунную
delay(500); //Делаем задержку на передачу комманды
gsm.print((char)26); //Отправляем на GSM комманду отправка смс!
delay(5000); //Делаем задержку отправку смс
}
//Отправка смс о балансе
void GoBalans(){
gsm.print("AT+CUSD=1,");
gsm.print('"');
gsm.print("#100#");
gsm.println('"');
}
Тоже занимаюсь темой умного дома, правда не столь продвинут. Автору спасибо за труд, и что поделился. Делаю на Меге 2560.
Вопрос у меня касается SIM900 (подключен на Serial1): после посылки смс шилд встаёт в ступор и перестаёт реагировать на АТ команды. В мониторе появляются ">". Привести шилд в чувство можно, передёрнув питание: выключить и включить (программно, конечно) после каждой посланной смс. Предполагаю, что есть более красивое решение, кто имел такую же проблему?
и все таки попробуйте софт сериал. Тоже сначала не работал сим900 на харде. Потом на софтсериале попробовал - заработало как надо. Правда сейчас и на харде работает, хз почему раньше глючило.
Всё получилось после установки задержек:
Serial1.print("AT+CNMI?\r"); delay(300);
// Устанавливаем адресата: телефонный номер в международном формате
Serial1.println("AT + CMGS = \"+79227100381\"");
delay(300);
Serial1.println((char)26);
delay(5000);
Коллеги, кто что думает/ имел опыт по монтажу ардуино + Sim900 с источниками питания в один корпус? У меня корпус небольших размеров, в нём монтирую ардуино, Sim900, твёрдотельное реле и вытащенные из корпусов блоки питания на 9В и 5В. Так вот, в этих БП используются малогабаритные импульсные трансформаторы - они могут наводить помехи на антенну Sim900?
в этом примере ( от OnWire) тоже идет задержка 750 мс. Далласовскую библиотеку по этому поводу и гнобили. Поэтому я и пытался код от Димакса прикрутить-не получилось. Потом разглядел, что в авторской программе опрос датчиков происходит раз в 2 минуты и успокоился.
Продолжаю править программу под свои нужды:
У меня в нежилом доме котел электрический 3-х ступенчатый. 3-6-9 КВт., и счетчик 2х тарифный. Соответственно задумка по максимуму греть теплоноситель ночью, а днем только по необходимости ( чтоб температура была положительная). При этом хочу задействовать ступенчатый нагрев (3-6-9 КВт) в зависимости от (чего??)- темп. за бортом\темп. в доме\ дельта температур дом-улица...
Так я его и убирал, за исключением цикла измерения с датчиков DHT11.
Заменил датчики DHT11 на DHT22. Поставил 2 шт. На улицу и в доме. Все температуры( с DHT и с DS18) выводятся целочисленные.
Хотя указано разрешение 10 бит для Далласа. Не совсем понятно, где происходит округление? INT ?
дак у вас всё же заработали dallasы через прерывание? Не понятно зачем такая точность, но вроде чтобы десятые градуса показывало, нужно там где делится на 16, вместо /16 поставить /16,0
Дорогие форумчане, подскажите по опторазвязкам и модулю времени.
Нашел на ali вот такие PC817, можно ли использовать их в качестве аналога?
Заметил, что модули времени многие начали использовать другие, я нашел DS1302. Все таки есть смысл использовать именно его?
заказывал 100 штук pc817 с али - работают хорошо. Чето в 100 рубей вышло, дешево однако. часы лушче 1307, они по шине i2c подключаются, и вроде как не спешат. 1302 за полгода на полчаса убегают, если не раньше.
Может кому будет интересно. Тестировал тут gsm модуль SIM800L, т.к. он совсем дешевый стал - около 250 руб. Но с ним возникли проблемы. Обязательно нужно хорошее питание через DC-DC преобразователь, 4,0В. Я подключал всё на бредборде естественно китайскими проводочками пин-пин. Так вот модуль по сериал соединению на АТ команды отвечал хорошо, но не находил сеть. Что я только не пробовал, кучу времени убил. Не верил в то, что многие говорили - типа припаяй провода и всё заработает (типа подключение через бредборд не вариант, плохой контакт и т.д.) Каково же было моё удивление, когда действительно модуль стал находить сеть (после надёжного соединения пайкой). Ещё нужно делать согласование уровней Rx и Tx чтобы от ардуино к GSM приходило по 2,7В на этих сигнальных проводах. (делается при помощи резистивных делителей напряжения). Ну и в конце ещё меня ожидали косяки в скетче. Скетч автора темы, который работает на Sim900, не работает на sim800L. В частности вот ошибки.
void startMaxSMS() //__________________Цикл подготовки модуля к отправке СМС-сообщений по первому номеру
{
mySerial.print("AT+CMGF=1\r");
delay(100);
mySerial.println("AT + CMGS = \"+79000000000\""); // (+79000000000 сдесь должен быть ваш номер №1)
delay(100);
}
Здесь косяк кроется в пробелах в команде АТ+CMGS - пробелов быть не должно, иначе команда не выполняется и смс не отправляется, хотя SIM900 на это не обращает внимания
И ещё косяки в скетче автора, которые и для SIM900 нужно тоже исправить
void NastroykaGSM () {
mySerial.print("AT+CMGF=1\r"); //устанавливает текстовый режим смс-сообщения
delay(100);
mySerial.print("AT+IFC=1, 1\r"); //устанавливает программный контроль потоком передачи данных
delay(100);
mySerial.print("AT+CPBS=\"SM\"\r"); //открывает доступ к данным телефонной книги SIM-карты
delay(100);
mySerial.print("AT+GSMBUSY=1, 1\r"); //запрет всех входящих звонков
delay(100);
mySerial.print("AT+CNMI=1,2,2,1,0\r"); //включает оповещение о новых сообщениях
delay(300);
mySerial.print("AT+CMGDA=«DEL ALL»\r"); // удаляем все смс, ки
delay(2000); }
Команда AT+GSMBUSY=1, 1\r непонятно зачем ещё единица после запятной (команда не выполняется, проверял), нужная команда выглядит так AT+GSMBUSY=1\r
Команда AT+CMGDA=«DEL ALL»\r не выполняется, т.к. нужно вот так AT+CMGDA=\"DEL ALL\"\r
Итоговый вариант
void NastroykaGSM () {
mySerial.print("AT+CMGF=1\r"); //устанавливает текстовый режим смс-сообщения
delay(200);
mySerial.print("AT+IFC=1, 1\r"); //устанавливает программный контроль потоком передачи данных
delay(200);
mySerial.print("AT+CPBS=\"SM\"\r"); //открывает доступ к данным телефонной книги SIM-карты
delay(200);
mySerial.print("AT+GSMBUSY=1\r"); //запрет всех входящих звонков
delay(300);
mySerial.print("AT+CNMI=1,2,2,1,0\r"); //включает оповещение о новых сообщениях
delay(300);
mySerial.print("AT+CMGDA=\"DEL ALL\"\r"); // удаляем все смс, ки
delay(2000);
}
////
vlaga = sens.readHumidity(6); // чтение датчика на пине 6 //dht.humidity; // Уровень влажности % с DHT11
Tempout = sens.readTemperature(6); // чтение датчика на пине 6 //dht22.temperature; // Температура в подполе с DHT11
delay(1500);
//vlaga2 = sens.readHumidity(3); // чтение датчика на пине 3 //dht.humidity; // Уровень влажности % с DHT11
// Tempin = sens.readTemperature(3); // чтение датчика на пине 3 //dht22.temperature;
TEMPin = sens.readTemperature(3); // чтение датчика на пине 3
HUMin = sens.readHumidity(3); // чтение датчика на пине 3
#include <SPI.h>
#include <SD.h>
//cs -> 53
//mosi -> 51
//sck -> 52
//miso -> 50
//50---39 было- гараж
//51---48 было- дренаж насос
//52--41 было-баня
//
const int chipSelect = 53;
#include <OneWire.h> // библиотека для DS18B20
#include <DallasTemperature.h> // библиотека для DS18B20
#define ONE_WIRE_BUS 7 // датчики DS18B20 на 7 пин
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds(&oneWire); // Везде где встречается ds - это работа с датчиками Dallas DS18B20
DeviceAddress BoilerC = { 0x28, 0xA3, 0xA4, 0x03, 0x00, 0x00, 0x80, 0x33 }; // Сетевой адрес датчика DS18B20 --в доме ГВС закрашена верхушка
DeviceAddress SlivC = { 0x28, 0xBB, 0x8A, 0x03, 0x00, 0x00, 0x80, 0x93 }; // Сетевой адрес датчика DS18B20 на улице-- В канализации без меток
DeviceAddress OtoplenieC = { 0x28, 0xBB, 0x73, 0x03, 0x00, 0x00, 0x80, 0xC6 }; // Сетевой адрес датчика DS18-- в СО одна точка
int tempC; // для работы с DS18B20
int TempBoilerC = 60; // Переменная. Измеренная температура в зале -ГВС (По умолчанию 20гр.*С)
int TempSlivC = 10; // Переменная. Измеренная температура в сливе (По умолчанию 20гр.*С)
int TempOtoplenieC = 30; // Переменная. Измеренная температура на батарее (По умолчанию 20гр.*С)
int UlicaS = 15; // Переменная. Измеренная освещенность на улице (По умолчанию 15%)
int TEMPMINB = 40; // Переменная. Уставка сигнализации минимальной температуры в зале -- ГВС
int TEMPMINS = -2; // Переменная. Уставка сигнализации минимальной температуры на улице -- (Слив)
int TEMPMINO = 30; // Переменная. Уставка сигнализации минимальной температуры ----в радиаторе
int TEMPMINP = 1; // Переменная. Уставка сигнализации минимальной температуры на улице (По умолчанию 1гр.*С)
int TEMPMAXB = 70; // Переменная. Уставка сигнализации максимальной температуры в зале --ГВС
int TEMPMAXS = 50; // Переменная. Уставка сигнализации максимальной температуры на улице (Слив)
int TEMPMAXO = 70; // Переменная. Уставка сигнализации максимальной температуры ---в радиаторе
int TEMPMAXP = 25; // Переменная. Уставка сигнализации максимальной температуры в подполе (По умолчанию 25гр.*С)
//_______Все для циклов SavePar(),PrintPar(),ReadPar()____________________________________________________
#include <EEPROM.h> // библиотека для записи в память микроконтроллера
int Epause_K; // Переменная печати времени выдержки спец из памяти
int Epause_V; // Переменная печати времени выдержки спец из памяти
int Epause_Z; // Переменная печати времени выдержки спец из памяти
int Epause_S; // Переменная печати времени выдержки спец из памяти
//_______Все для цикла void irremote()____________________________________________________________________
#include <IRremote.h>// удалил 2 фаила из библиотеки ремоте туул
//как исправить косяк с конфликтом таймеров при работе библиотеки IRremote и функции Tone
// <a data-cke-saved-href="http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchenie-tsop#comment-22223" href="http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchenie-tsop#comment-22223" rel="nofollow">http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchenie-tsop#comment-22223</a>
IRrecv irrecv(8);
decode_results results;
//_______Все для цикла void otoplenie()____________________________________________________________________
int tempDust = 22; // Уставка желаемой температуры в доме (По умолчанию 22гр.С)
int tempDECOust = 05; // Уставка температуры в доме в режиме "Экономия"(По умолчанию 15гр.С)
// <a data-cke-saved-href="http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html" href="http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html" rel="nofollow">http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html</a> кодовый замок
#include <stDHT.h>
DHT sens(DHT22);
#include <DS1307.h> //Подключение модуля DS1307
DS1307 rtc(20,21);//(sda 20,scl 21)
Time t;
int RTCSekunda; // Переменная "секунда" для суточного таймера цикл RTCtimer()
int RTCChas; // Переменная "час" для суточного таймера цикл RTCtimer()
int RTCMinuta; // Переменная "минута" для суточного таймера
boolean statusKur=false; // Флаг "работа курантов"
boolean statusDay=false; // Флаг "Режим работы true - дневной, false - ночной"
boolean SMSDvigenieK=false; // Флаг "Отправлена СМС о движении на кухне" --оставляем
boolean SMSDvigenieV=false; // Флаг "Отправлена СМС о движении в ванной"--будет лестница
boolean SMSDvigenieZ=false; // Флаг "Отправлена СМС о движении в зале"-- будет веранда
boolean SMSDvigenieS=false; // Флаг "Отправлена СМС о входе" -- будет в сенях
boolean SMSopenKal=false; // Флаг "Отправлена СМС открыта калитка"
boolean SMSopenBan=false; // Флаг "Отправлена СМС открыта баня"- ----ворота
boolean SMSVoltOFF=false; // Флаг "Отправлена СМС об отключении питания 220в"
boolean SMSVoltON=false; // Флаг "Отправлена СМС о восстановлении питания 220в"
boolean SMSPodpol=false; // Флаг "Отправлена СМС об затоплении подпола"
boolean SMSFireSensor=false; // Флаг "Отправлена СМС о сработке дымового датчика"
boolean SMSFireAlarm=false; // Флаг "Отправлена СМС о сработке пожарной сигнализации"
boolean SMSDelete=false; // Флаг "Удалены все СМС на SIM900"
boolean TimeSMSzapros=false; // Флаг "Отправлена СМС о состоянии дома по таймеру"
boolean SMSAlarmTemp=false; // Флаг "Отправлена СМС о критической температуре"
boolean SMSVoltIBP=false; // Флаг "Отправлена СМС о низком заряде аккумулятора"
//boolean EcoTempDust=false; // Флаг "Экономия отопления"
int SMSschet=0; // Подсчет кол-ва отправленных смс
int Fireschet=0; // Подсчет кол-ва срабатываний пож.шлейфа
int dsshet=0; // Подсчет кол-ва ошибок DS18B20
int Dayschet=0; // Подсчет кол-ва дней бесперебойной работы после последней прошивки
int HUMin; // влажность в доме DTH22
int TEMPin; // температура в доме DTH22
int vlaga; // Значение влажности в цикле ventilyaciya()--На улице DTH22
int Tempout; // Переменная. Измеренная температура на улице ДТН22
int pambilang; // переменная для цикла sirena()
//_______Все для цикла void voltmetr()
float vout = 0.0; // Напряжение на входе аналового входа
float Vpit = 0.0; // Измеряемое напряжение на выходе ИБП
int volt = 0; // Напряжение на входе АЦП
int statushome=0; // переменная статуса включения умного дома 1 - включен, 0 -выключен
int statusotp=0; // статус отопления дома 0 - откл , 1- вкл , 2- экономия
//int statusrzd=0; // статус питания розеток дома 0 - откл , 1- вкл
//int statusgaraj=0; // статус питания гаража 0 - откл , 1- вкл
//int statusbania=0; // статус питания бани 0 - откл , 1- вкл
int statusPump=0; // статус питания станции водоснабжения 0 - откл , 1- вкл
int perimetr=0; // статус включения охраны периметра 0 - откл , 1- вкл
int statusperimetr=0; // статус периметра 1 - все двери закрыты , 0 - дверь не закрыта
int statuspoliv=0; // статус полива 0 - откл , 1- вкл , 2- Таймер
int statusAlarm=0; // Переменная "Наличие тревоги"
int AlarmTemp=0; // Переменная "Наличие тревоги по критической температуре"
int statusFireAlarm=1; // Переменная "Режим работы пож.сигнализации" - 0 - откл , 1- вкл , 2- проверка, 3-в тревоге
int signaliz=0; // Переменная "Режим работы охр.сигнализации" - 0 - откл , 1- вкл , 2- постановка на охрану, 3-в тревоге
int statusPIK=0; // статус работы тональной пищалки - 0 - откл , 1- вкл
int ULsvet=2; // Режим работы уличного освещения - 0 - откл , 1- вкл , 2- АВТОРЕЖИМ
boolean statusBlock=false; // статус блокировки освещения зала пользователем
int intervalPIK = 1000;// интервал для цикла Pik()
int TonPIK = 2500; // частота тона пищалки
//_________ Уставки для работы по расписанию________________________
int TimeOFFpump = 0; // Время выключения насосной станции (По умолчанию 0:00)
int TimeONperimetr = 23; // Время включения охраны периметра (По умолчанию 23:00)
int TimeOFFperimetr = 6; // Время выключения охраны периметра (По умолчанию 6:00)
int TimeONdren = 20; // Время включения дренажного насоса (По умолчанию 20:00)
int TimeOFFdren = 21; // Время выключения дренажного насоса (По умолчанию 21:00)
int TimeONnagr = 4; // Время включения нагревателя воды (По умолчанию 06:00)
int TimeOFFnagr = 22; // Время выключения нагревателя воды (По умолчанию 22:00)
//_________ флаги для таймеров______________________________________
boolean Timer1On = false; //Флаг таймера РЕЗЕРВ
boolean Timer2On = false; //Флаг таймера постановки на охрану
//_________ переменные времени для таймеров_________________________
unsigned long EndPikMillis = 0; // храним время последнего тона для цикла Pik()
unsigned long NowTime1 = 0; // переменная хранения времени таймера №1
unsigned long StartTime1 = 0; // переменная хранения времени запуска таймера №1
unsigned long NowTime2 = 0; // переменная хранения времени таймера №2
unsigned long StartTime2 = 0; // переменная хранения времени запуска таймера №2
//_________ флаги для цикла Kvitirovanie()(сброс звука сирены)______________________________________
boolean KvitDI30 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 30
boolean KvitDI29 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 29
boolean KvitDI31 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 31
boolean KvitBoilerC = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура зал-- Бойлер
boolean KvitSlivC = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура улицы -- СЛИВ
boolean KvitOtoplenieC = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура кухни-СО
boolean KvitPodpolC=false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура на улице
//boolean KvitAI14 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход A14
long previousMillis = 0; // храним время последнего замера влажности для цикла izmereniya()
long interval = 120000; // интервал между замерами параметров для цикла izmereniya() 2 минуты
//______ Переменные для цикла avtosvet() взято с <a data-cke-saved-href="http://zelectro.com.ua/PIR_sensor" href="http://zelectro.com.ua/PIR_sensor" rel="nofollow">http://zelectro.com.ua/PIR_sensor</a> ___________________________
long unsigned int lowIn_K; // Время, в которое был принят сигнал отсутствия движения на кухне(LOW)
long unsigned int lowIn_V; // Время, в которое был принят сигнал отсутствия движения в ванной(LOW)-Лестница
long unsigned int lowIn_Z; // Время, в которое был принят сигнал отсутствия движения в зале(LOW) --веранда
long unsigned int lowIn_S; // Время, в которое был принят сигнал отсутствия движения в сенях(LOW)
int pause_K = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_V = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_Z = 2; //Пауза, после которой движение считается оконченным (2 мин)
int pause_S = 1; //Пауза, после которой движение считается оконченным (1 мин)
boolean lockLow_K = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_V = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_Z = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_S = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean takeLowTime_K; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_V; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_Z; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_S; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
int pirPin_K = 26; //вывод подключения PIR датчика Кухни--
int pirPin_V = 24; //вывод подключения PIR датчика Ванной --лестница
int pirPin_Z = 22; //вывод подключения PIR датчика Зал ---веранда
int pirPin_S = 28; //вывод подключения PIR датчика Сени--
//_______Для работы терминала по bluetooth___________________________
int inSize=0; // Переменная которая будет содержать размер буфера терминала bluetooth
char str[128]; // Так как типа string тут нет, будем использовать массив символов
//_______Для работы терминала по Sim900______________________________
String currStr = "";
boolean isStringMessage = false; // Переменная принимает значение True, если текущая строка является сообщением
//___________________ Стартовый цикл _________________________________
void setup()
{
ds.begin();
ds.setResolution(BoilerC, 10);
ds.setResolution(SlivC, 10);
ds.setResolution(OtoplenieC, 10);
pinMode(22, INPUT); digitalWrite(22,HIGH); // вход датчик движения зал--веранда
pinMode(24, INPUT); digitalWrite(24,HIGH); // вход датчик движения--лестница
pinMode(26, INPUT); digitalWrite(26,HIGH); // вход датчик движения кухня
pinMode(28, INPUT); digitalWrite(28,HIGH); // вход датчик движения сени
pinMode(30, INPUT); digitalWrite(30,HIGH); // вход сигнализатор "Вода протечка"
pinMode(32, INPUT); digitalWrite(32,HIGH); // Резерв
pinMode(34, INPUT); digitalWrite(34,HIGH); // Резерв
pinMode(36, INPUT); digitalWrite(36,HIGH); // Кнопка звонка домофона
pinMode(23, INPUT); digitalWrite(23,HIGH); // вход концевики ворот
pinMode(25, INPUT); digitalWrite(25,HIGH); // вход концевик входной двери(веранда)
pinMode(27, INPUT); digitalWrite(27,HIGH); // вход концевик калитка
pinMode(29, INPUT); digitalWrite(29,HIGH); // вход термостат "Баня готова"
//pinMode(31, INPUT); digitalWrite(31,HIGH); // вход термостат "Очень высока температура в бане"
pinMode(33, INPUT); digitalWrite(33,HIGH); // Дымовой шлейф №1
pinMode(35, INPUT); digitalWrite(35,HIGH); // Дымовой шлейф №2
pinMode(37, INPUT); digitalWrite(37,HIGH); // Нет напряжения после УЗО
pinMode( 5, OUTPUT); // Пьезо динамик
pinMode(13, OUTPUT); // Лампа УД включен
pinMode(38, OUTPUT); // Свет в Кухня
pinMode(40, OUTPUT); // Свет -лестница
pinMode(42, OUTPUT); // Свет в Зал-- веранда
pinMode(44, OUTPUT); // Свет в Сени
pinMode(46, OUTPUT); // Питание насосной станции...
pinMode(48, OUTPUT); // Питание дренажного насоса.......... ТЕПЕРЬ ОТОПЛЕНИЕЁ!!!
//pinMode(50, OUTPUT); // Питание водонагревателя ТЕПЕРЬ MISO
// pinMode(52, OUTPUT); // Освещение двора ТЕПЕРЬ SCK
digitalWrite(38,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(40,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(42,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(44,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(46,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(48,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
// digitalWrite(50,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
//digitalWrite(52,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
//pinMode(50, OUTPUT); // Питание гаража 39
pinMode(41, OUTPUT); // Питание бани 41 Теперь осв двора
pinMode(43, OUTPUT); // Питание розеток дома
pinMode(45, OUTPUT); // Питание нагревателя слива............................
pinMode(47, OUTPUT); // Клапан полива
pinMode(49, OUTPUT); // Сирена громкая
//pinMode(51, OUTPUT); // MOSI было Управление отоплением!!!!!!!!!!!!!!!!!!!!!!!!!!!
pinMode(53, OUTPUT); // SD card
pinMode(31, OUTPUT); // индикация записи на карту SD
pinMode(6, INPUT); //DHT22
digitalWrite(6, HIGH);
pinMode(3, INPUT); // DHT22
digitalWrite(3, HIGH);
Serial.begin(9600); // Связь по терминалу
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
//return;
}
Serial.println("card initialized.");
Serial1.begin(9600); // HC-05 Bluetooth <a data-cke-saved-href="http://robocraft.ru/blog/electronics/587.html#comment4652" href="http://robocraft.ru/blog/electronics/587.html#comment4652" rel="nofollow">http://robocraft.ru/blog/electronics/587.html#comment4652</a>
Serial2.begin(19200); // GSM SMS-передача
//Serial3.begin(9600); // Плата голосового оповещения на attiny2313 и SD-карте
if(EEPROM.read(0)==10){ReadPar();} // Чтение настроек из памяти, если они туда были сохранены ранее
delay(2000);
SMSVoltON=true;
NastroykaGSM(); // Настройка работы с SIM900
irrecv.enableIRIn(); // Запуск ИК-приемника
tone(5, 2000, 200); // Звук, когда все готово! выключил
delay(4000);
t = rtc.getTime();
RTCSekunda = t.sec; // t.sec - запрос секунд
RTCChas = t.hour; // t.hour - запрос часов
RTCMinuta = t.min; // t.min - запрос минут
SMSschet = EEPROM.read(51); // чтение кол-ва ранее отправленных СМС
// startOneSMS();
// Serial2.print("SmartHome vkluchen - "); vremya2(); EndSMS();// время включения
}
void loop()
{
RTCtimer();
izmereniya();
alarms();
irremote();
bluetooth();
sms_read();
osvechenie(); // Управление освещением во дворе
Slivnagrev(); // управление подогревом сливной канализации
// make a string for assembling the data to log:
String dataString = "";
// read three sensors and append to the string:
///for (int analogPin = 0; analogPin < 3; analogPin++) {
// int sensor = analogRead(analogPin);
dataString += (t.date, DEC);
dataString += ",";
dataString += String(rtc.getDOWStr());
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";
// }
// }/////////////////////////////////////////////////////////////////////////////
if(RTCSekunda==0){ // если секунды равны 00
if(RTCMinuta%2==0){//запись каждые --2 мин
// 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);
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}/////////////////////////////////////////////////////////////////////////////////////
}
if (!statusFireAlarm==0){FireAlarm();} // Работа пожарной сигнализации
if (statushome==1) {avtosvet();} // Автоматическое управление освещением в доме меньше 11%
if (statushome==1){digitalWrite(13,HIGH);} else {digitalWrite(13, LOW);} // Лампа "Умный дом включен"
//if (statushome==1){ventilyaciya();} // Управление вентиляцией в подполе по датчику влажности DHT11
if (statusotp==1) {otoplenie();} else {digitalWrite(48, LOW);} // Управление работой газового котла 1 - вкл., 0 - откл.53-51
if (!signaliz==0){signalizSMS();} // Работа сигнализации сигнализации при режимах 1,2,3
if (statusPIK==1){Pik();} // Работа тональной пищалки
if (perimetr==1){Operimetr();} // Охрана периметра участка
if ((statusPump==1) && (digitalRead(30)==LOW)) {digitalWrite(46,LOW);} else {digitalWrite(46, HIGH);} // Питание станции водоснабжения (Сигнал инвертированный)
// if (statusrzd==1){digitalWrite(43,HIGH);} else {digitalWrite(43, LOW);} // Питание розеток дома
// if (statusgaraj==1){digitalWrite(39,HIGH);} else {digitalWrite(39, LOW);} // Питание гаража
// if (statusbania==1){digitalWrite(41,HIGH);} else {digitalWrite(41, LOW);} // Питание бани
if (statuspoliv==0) {digitalWrite(47, LOW);} // Выключение клапана полива
if (statuspoliv==1) {digitalWrite(47, HIGH);} // Включение клапана полива на постоянку
if (statuspoliv==2) {digitalWrite(47, HIGH); timerPoliv();} // Клапан полива включен по таймеру
if ((perimetr==1 && statusperimetr==0) || statusAlarm==1) { sirena();} // Работа малой сирены
//if (analogRead(14)>100) {KvitAI14=false;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(29)==LOW) {KvitDI29=false;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(30)==LOW) {KvitDI30=false;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(31)==LOW) {KvitDI31=false;} // Сброс квитирования при возвращении параметра в норму
}
void izmereniya() // Замер температур с датчиков DS18B20 и влажности с датчика DHT11
{ // <a data-cke-saved-href="http://arduino.ru/tutorials/BlinkWithoutDelay" href="http://arduino.ru/tutorials/BlinkWithoutDelay" rel="nofollow">http://arduino.ru/tutorials/BlinkWithoutDelay</a> на основе
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) { // Замеры в интервале
vlaga = sens.readHumidity(6); // чтение датчика на пине 6 //dht.humidity; // Уровень влажности % с DHT11
Tempout = sens.readTemperature(6); // чтение датчика на пине 6 //dht22.temperature; // Температура в подполе с DHT11
delay(2000);
HUMin = sens.readHumidity(3); // чтение датчика на пине 3
TEMPin = sens.readTemperature(3); // чтение датчика на пине 3
ds.requestTemperatures(); // Замеры температур с DS18B20
delay(350); // Необязательная задержка
TempBoilerC = ds.getTempC(BoilerC); // Считываем температуру в зале---ГВС
delay(100);
TempSlivC = ds.getTempC(SlivC); // Считываем температуру на улице-- Слив
delay(100);
TempOtoplenieC = ds.getTempC(OtoplenieC); // Считываем температуру в кухне--- СО
delay(100);
if(TempBoilerC== -127 || TempSlivC== -127 || TempOtoplenieC== -127) // Перезапрос при ошибке датчика
{
ds.requestTemperatures(); delay(750); dsshet++ ; // +1 к счетчику ошибок DS18B20
TempBoilerC = ds.getTempC(BoilerC); // Считываем температуру в зале--ГВС
delay(100);
TempSlivC = ds.getTempC(SlivC); // Считываем температуру на улице---Слив
delay(100);
TempOtoplenieC = ds.getTempC(OtoplenieC); // Считываем температуру в кухне-- СО
delay(100);
}
UlicaS = analogRead(A15)/10; // Считываем освещенность на улице
voltmetr(); // Считываем напряжения на выходе ИБП (норма 13,5в)
previousMillis = currentMillis;} // Сброс таймера
}
void voltmetr() //____________Цикл "Вольтметр"__измерение напряжения на выходе ИБП
// Взято с <a data-cke-saved-href="http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html" href="http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html" rel="nofollow">http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html</a>
{
volt = analogRead(A0); // А0 аналоговый вход вольтметра
vout = (volt * 5.0) / 1024.0;
Vpit = vout / (10000.0/(100000.0+10000.0)); // По формуле Vpit = vout / (R2/(R1+R2))
if (Vpit<0.09) { Vpit=0.0;} // Округление до нуля
}
void osvechenie() // Работа уличного освещения двора
{
if ( ULsvet==2 ) // Если режим работы автоматический
{
if (UlicaS > 8){digitalWrite(41,HIGH);} // Освещение двора выключить при освещении больше 8% (сигнал инвертированный)52--41
if (UlicaS < 4) {digitalWrite(41,LOW);} // Освещение двора включить при освещении меньше 4% (сигнал инвертированный) 52--41
}
}
void avtosvet() //______Цикл управления автоматическим освещением____________________________________
{
//______Ниже для зала______________________________________
if(digitalRead(pirPin_Z) == HIGH && statusBlock==false && UlicaS < 30) //Если обнаружено движение, нет блокировки, и освещенность улицы меньше 20%
{
if(lockLow_Z) //Если до этого момента еще не включили реле
{ lockLow_Z = false; digitalWrite(42, LOW); delay(50);} //Включаем свет.
takeLowTime_Z = true;
}
if(digitalRead(pirPin_Z) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_Z){lowIn_Z = millis();takeLowTime_Z = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_Z && millis() - lowIn_Z > (pause_Z * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_Z = true; digitalWrite(42, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 35) {digitalWrite(42,HIGH);} // Отключение реле управления освещением больше 35%
//______Ниже для кухни______________________________________
if(digitalRead(pirPin_K) == HIGH && statusDay==false && UlicaS < 30) //Если обнаружено движение с 23 до 8 включаем подсветку
{
if(lockLow_K) //Если до этого момента еще не включили реле
{ lockLow_K = false; digitalWrite(38, LOW); delay(50);} //Включаем свет.
takeLowTime_K = true;}
if(digitalRead(pirPin_K) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_K){lowIn_K = millis();takeLowTime_K = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_K && millis() - lowIn_K > (pause_K * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_K = true; digitalWrite(38, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 35) {digitalWrite(38,HIGH);} // Отключение реле управления освещением больше 20%
//______Ниже для ванной комнаты------лестницы___
if(digitalRead(pirPin_V) == HIGH && UlicaS < 30) //Если обнаружено движение
{
if(lockLow_V) //Если до этого момента еще не включили реле
{ lockLow_V = false; digitalWrite(40, LOW); delay(50);} //Включаем свет.
takeLowTime_V = true;}
if(digitalRead(pirPin_V) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_V){lowIn_V = millis();takeLowTime_V = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_V && millis() - lowIn_V > (pause_V * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_V = true; digitalWrite(40, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 35) {digitalWrite(40,HIGH);} // Отключение реле управления освещением больше 35%
//______Ниже для сеней______________________________________
if(digitalRead(pirPin_S) == HIGH && UlicaS < 16) //Если обнаружено движение
{
if(lockLow_S) //Если до этого момента еще не включили реле
{ lockLow_S = false; digitalWrite(44, LOW); delay(50);} //Включаем свет.
takeLowTime_S = true;}
if(digitalRead(pirPin_S) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_S){lowIn_S = millis();takeLowTime_S = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_S && millis() - lowIn_S > (pause_S * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_S = true; digitalWrite(44, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 20) {digitalWrite(44,HIGH);} // Отключение реле управления освещением больше 20%
}
void Slivnagrev()
{
if (TempSlivC > 5) {digitalWrite(45,LOW );} // Выключение нагревателя при темп более 5 град.
if (TempSlivC < 0) {digitalWrite(45, HIGH);} // Включение нагревателя при темп менее 0
}
void homeON() //____________Цикл включения умного дома____________________________________________________
{
statushome=1; // статус умного дома 0 - откл , 1- вкл
statusotp=1; // статус отопления дома 0 - откл , 1- вкл
// statusrzd=1; // статус питания розеток дома 0 - откл , 1- вкл
// statusgaraj=1; // статус питания гаража 0 - откл , 1- вкл
// statusbania=1; // статус питания бани 0 - откл , 1- вкл
}
void homeOFF() //____________Цикл выключения умного дома________________________
{
statushome=0; // статус питания дома 0 - откл , 1- вкл
//statusrzd=0; // статус питания розеток дома 0 - откл , 1- вкл
// statusgaraj=0; // статус питания гаража 0 - откл , 1- вкл
// statusbania=0; // статус питания бани 0 - откл , 1- вкл
statusPump=0; // статус питания станции водоснабжения 0 - откл , 1- вкл
digitalWrite(38,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(40,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(42,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(44,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(46,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(48,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(39,HIGH); // выключение реле (сигнал инвертированный) 50--39
SMSAlarmTemp=false; // сброс флага отправки СМС о критической темпертуры
// SMSBanyaTemp=false; // сброс флага отправки СМС о критической темпертуры в бане
SMSPodpol=false; // сброс флага отправки СМС о воде в подполе
}
void otoplenie() // Цикл управления газовым котлом (Сигнал инвертированный!
{
if ( statusotp==0) // Отключено
{ digitalWrite(48,HIGH);} // Отключить отопление 51--48
if ( statusotp==1) // Климат-контроль
{ if ( TempOtoplenieC > (tempDust+1)){digitalWrite(48,HIGH);} // Отключить отопление если температура больше желаемой на 1грС 51--48
if ( !TempOtoplenieC== -127 && (TempOtoplenieC < tempDust) ) {digitalWrite(48,LOW);} // Включить отопление если температура меньше желаемой 51--48
}
if ( statusotp==2) // Экономия
{ if ( TempOtoplenieC > (tempDECOust+1)){digitalWrite(48,HIGH);} // Отключить отопление если температура больше желаемой на 1грС 51--48
if ( !TempOtoplenieC== -127 && (TempOtoplenieC < tempDECOust) ) {digitalWrite(48,LOW);} // Включить отопление если температура меньше желаемой 51--48
}
}
void timerPoliv() // Таймер клапана полива огорода 0 - откл , 1- вкл , 2- Таймер
{
NowTime1 = millis();
if(Timer1On == true) { StartTime1 = NowTime1 ; Timer1On = false; statuspoliv=2;}
if( statuspoliv==2 && NowTime1 - StartTime1 > 900000) // выдержка 15 минут
{ statuspoliv=0; } // Сброс таймера
}
В воскресенье перезалил этот код- стал нормально отображать показания с DTH22. Странно, по ним ничего не менял!
Я добавил код записи данных с датчиков температур на SD карту. Пока нет карты закомментировал пару строк кода, чтоб работала остальная программа.
Запись параметров на карту должна происходить каждые 2 мин, когда секунды равны 0.
Обнаружилась особенность- программа в сериал выдает 3-4 раза сообщение об ошибки открытия файла(по идее д.б. один раз в 2 мин.00 секунд) Я так понимаю, что в течении этой нулевой секунды программа успевает 3 раза пытаться открыть файл?
Вывод по блютуф- то параметры выводятся построчно, что есть правильно, но периодически перенос некоторых строк отсутствует. Происходит это случайным образом. Вкладку работы с блютуф кардинально не менял. Только прописал в кавычки параметры по русски.
И ещё косяк- если закрыть терминальную программу, то при последующем открытии терминала происходит частичный или полный сброс ранее установленных параметров( показания датчиков или сброс режима работы).
#include <OneWire.h> // библиотека для DS18B20
OneWire ds(7); // датчики DS18B20 на 7 пин
byte KuhnyaC[8] ={0x28, 0xFF, 0xB1, 0x43, 0x52, 0x15, 0x01, 0xDB};//Сетевой адрес датчика DS18B20 в доме
byte ZalC[8] ={0x28, 0xFF, 0xBA, 0x6C, 0x52, 0x15, 0x01, 0x41};
byte UlicaC[8] ={0x28, 0xFF, 0xE8, 0x3C, 0x03, 0x15, 0x03, 0xE3};
byte FreezeC[8] ={0x28, 0x9D, 0xE5, 0x70, 0x01, 0x00, 0x00, 0xEE};// Сетевой адрес датчика DS18 на батарее
volatile int TempKuhnyaC = 20;
volatile int TempZalC = 20;
volatile int TempFreezeC = 20;
volatile int TempUlicaC = 20;
//bool SMSAlarmTemp = false;
//bool AlarmTemp = false;
//int tempC; // для работы с DS18B20&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//int TempZalC = 20; // Переменная. Измеренная температура в зале (По умолчанию 20гр.*С)
//int TempUlicaC = 20; // Переменная. Измеренная температура на улице (По умолчанию 20гр.*С)
//int TempKuhnyaC = 20; // Переменная. Измеренная температура на батарее (По умолчанию 20гр.*С)
int TempPodpol = 7; // Переменная. Измеренная температура в подполе (По умолчанию 7гр.*С)
int UlicaS = 15; // Переменная. Измеренная освещенность на улице (По умолчанию 15%)
int TEMPMINZ = 15; // Переменная. Уставка сигнализации минимальной температуры в зале (По умолчанию 15гр.*С)
int TEMPMINU = -25; // Переменная. Уставка сигнализации минимальной температуры на улице (По умолчанию -25гр.*С)
int TEMPMINK = 10; // Переменная. Уставка сигнализации минимальной температуры в радиаторе (По умолчанию 10гр.*С)
int TEMPMINP = 1; // Переменная. Уставка сигнализации минимальной температуры в подполе (По умолчанию 1гр.*С)
int TEMPMAXZ = 31; // Переменная. Уставка сигнализации максимальной температуры в зале (По умолчанию 31гр.*С)
int TEMPMAXU = 40; // Переменная. Уставка сигнализации максимальной температуры на улице (По умолчанию 40гр.*С)
int TEMPMAXK = 77; // Переменная. Уставка сигнализации максимальной температуры в радиаторе (По умолчанию 77гр.*С)
int TEMPMAXP = 25; // Переменная. Уставка сигнализации максимальной температуры в подполе (По умолчанию 25гр.*С)
//_______Все для циклов SavePar(),PrintPar(),ReadPar()____________________________________________________
#include <EEPROM.h> // библиотека для записи в память микроконтроллера
int Epause_K; // Переменная печати времени выдержки спец из памяти
int Epause_V; // Переменная печати времени выдержки спец из памяти
int Epause_Z; // Переменная печати времени выдержки спец из памяти
int Epause_S; // Переменная печати времени выдержки спец из памяти
//_______Все для цикла void irremote()____________________________________________________________________
#include <IRremote.h>// удалил 2 фаила из библиотеки ремоте туул
//как исправить косяк с конфликтом таймеров при работе библиотеки IRremote и функции Tone
// http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchen...
IRrecv irrecv(8);
decode_results results;
//_______Все для цикла void otoplenie()____________________________________________________________________
int tempDust = 22; // Уставка желаемой температуры в доме (По умолчанию 22гр.С)
int tempDECOust = 15; // Уставка температуры в доме в режиме "Экономия"(По умолчанию 15гр.С)
// http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html кодовый замок
#include <stDHT.h> //библиотека датчика DTH11
//#define DHT22PIN 6 //Датчик DTH11 на pin6
DHT sens(DHT22);
#include <DS1307.h> //Подключение модуля DS1307
DS1307 rtc(20,21);//(sda 20,scl 21)
Time t;
int RTCSekunda; // Переменная "секунда" для суточного таймера цикл RTCtimer()
int RTCChas; // Переменная "час" для суточного таймера цикл RTCtimer()
int RTCMinuta; // Переменная "минута" для суточного таймера
boolean statusKur=false; // Флаг "работа курантов"
boolean statusDay=false; // Флаг "Режим работы true - дневной, false - ночной"
boolean SMSDvigenieK=false; // Флаг "Отправлена СМС о движении на кухне"
boolean SMSDvigenieV=false; // Флаг "Отправлена СМС о движении в ванной"
boolean SMSDvigenieZ=false; // Флаг "Отправлена СМС о движении в зале"
boolean SMSDvigenieS=false; // Флаг "Отправлена СМС о входе"
boolean SMSopenKal=false; // Флаг "Отправлена СМС открыта калитка"
boolean SMSopenBan=false; // Флаг "Отправлена СМС открыта баня"
boolean SMSdomofon=false; // Флаг "Отправлена СМС Кто там? Кто там?"
boolean SMSVoltOFF=false; // Флаг "Отправлена СМС об отключении питания 220в"
boolean SMSVoltON=false; // Флаг "Отправлена СМС о восстановлении питания 220в"
boolean SMSBanyaTemp=false; // Флаг "Отправлена СМС о предельной температуре в бане"
boolean SMSPodpol=false; // Флаг "Отправлена СМС об затоплении подпола"
boolean SMSFireSensor=false; // Флаг "Отправлена СМС о сработке дымового датчика"
boolean SMSFireAlarm=false; // Флаг "Отправлена СМС о сработке пожарной сигнализации"
boolean SMSDelete=false; // Флаг "Удалены все СМС на SIM900"
boolean TimeSMSzapros=false; // Флаг "Отправлена СМС о состоянии дома по таймеру"
boolean SMSAlarmTemp=false; // Флаг "Отправлена СМС о критической температуре"
boolean SMSVoltIBP=false; // Флаг "Отправлена СМС о низком заряде аккумулятора"
//boolean EcoTempDust=false; // Флаг "Экономия отопления"
int SMSschet=0; // Подсчет кол-ва отправленных смс
int Fireschet=0; // Подсчет кол-ва срабатываний пож.шлейфа
int dsshet=0; // Подсчет кол-ва ошибок DS18B20
int dhtschet=0; // Подсчет кол-ва ошибок DHT11
int dht2schet=0; // Подсчет кол-ва повторных ошибок DHT11
int Dayschet=0; // Подсчет кол-ва дней бесперебойной работы после последней прошивки
int vlaga=0; // Значение влажности в цикле ventilyaciya()
int pambilang; // переменная для цикла sirena()
//_______Все для цикла void voltmetr()
float vout = 0.0; // Напряжение на входе аналового входа
float Vpit = 0.0; // Измеряемое напряжение на выходе ИБП
int volt = 0; // Напряжение на входе АЦП
int statushome=0; // переменная статуса включения умного дома 1 - включен, 0 -выключен
int statusotp=0; // статус отопления дома 0 - откл , 1- вкл , 2- экономия
int statusrzd=0; // статус питания розеток дома 0 - откл , 1- вкл
int statusgaraj=0; // статус питания гаража 0 - откл , 1- вкл
int statusbania=0; // статус питания бани 0 - откл , 1- вкл
int statusPump=0; // статус питания станции водоснабжения 0 - откл , 1- вкл
int perimetr=0; // статус включения охраны периметра 0 - откл , 1- вкл
int statusperimetr=0; // статус периметра 1 - все двери закрыты , 0 - дверь не закрыта
int statuspoliv=0; // статус полива 0 - откл , 1- вкл , 2- Таймер
int statusAlarm=0; // Переменная "Наличие тревоги"
int AlarmTemp=0; // Переменная "Наличие тревоги по критической температуре"
int statusFireAlarm=1; // Переменная "Режим работы пож.сигнализации" - 0 - откл , 1- вкл , 2- проверка, 3-в тревоге
int signaliz=0; // Переменная "Режим работы охр.сигнализации" - 0 - откл , 1- вкл , 2- постановка на охрану, 3-в тревоге
int statusPIK=0; // статус работы тональной пищалки - 0 - откл , 1- вкл
int ULsvet=2; // Режим работы уличного освещения - 0 - откл , 1- вкл , 2- АВТОРЕЖИМ
boolean statusBlock=false; // статус блокировки освещения зала пользователем
int intervalPIK = 1000;// интервал для цикла Pik()
int TonPIK = 2500; // частота тона пищалки
//_________ Уставки для работы по расписанию________________________
int TimeOFFpump = 0; // Время выключения насосной станции (По умолчанию 0:00)
int TimeONperimetr = 23; // Время включения охраны периметра (По умолчанию 23:00)
int TimeOFFperimetr = 6; // Время выключения охраны периметра (По умолчанию 6:00)
int TimeONdren = 20; // Время включения дренажного насоса (По умолчанию 20:00)
int TimeOFFdren = 21; // Время выключения дренажного насоса (По умолчанию 21:00)
int TimeONnagr = 4; // Время включения нагревателя воды (По умолчанию 06:00)
int TimeOFFnagr = 22; // Время выключения нагревателя воды (По умолчанию 23:00)
//_________ флаги для таймеров______________________________________
boolean Timer1On = false; //Флаг таймера РЕЗЕРВ
boolean Timer2On = false; //Флаг таймера постановки на охрану
//_________ переменные времени для таймеров_________________________
unsigned long EndPikMillis = 0; // храним время последнего тона для цикла Pik()
unsigned long NowTime1 = 0; // переменная хранения времени таймера №1
unsigned long StartTime1 = 0; // переменная хранения времени запуска таймера №1
unsigned long NowTime2 = 0; // переменная хранения времени таймера №2
unsigned long StartTime2 = 0; // переменная хранения времени запуска таймера №2
//_________ флаги для цикла Kvitirovanie()(сброс звука сирены)______________________________________
boolean KvitDI30 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 30
boolean KvitDI29 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 29
boolean KvitDI31 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 31
boolean KvitZalC = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура зал
boolean KvitUlicaC = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура улицы
boolean KvitKuhnyaC = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура кухни
boolean KvitPodpolC=false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура в подполе
//boolean KvitAI14 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход A14
long previousMillis = 0; // храним время последнего замера влажности для цикла izmereniya()
long interval = 120000; // интервал между замерами параметров для цикла izmereniya() 2 минуты
//______ Переменные для цикла avtosvet() взято с http://zelectro.com.ua/PIR_sensor ___________________________
long unsigned int lowIn_K; // Время, в которое был принят сигнал отсутствия движения на кухне(LOW)
long unsigned int lowIn_V; // Время, в которое был принят сигнал отсутствия движения в ванной(LOW)
long unsigned int lowIn_Z; // Время, в которое был принят сигнал отсутствия движения в зале(LOW)
long unsigned int lowIn_S; // Время, в которое был принят сигнал отсутствия движения в сенях(LOW)
int pause_K = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_V = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_Z = 4; //Пауза, после которой движение считается оконченным (4 мин)
int pause_S = 1; //Пауза, после которой движение считается оконченным (1 мин)
boolean lockLow_K = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_V = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_Z = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_S = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean takeLowTime_K; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_V; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_Z; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_S; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
int pirPin_K = 26; //вывод подключения PIR датчика Кухни
int pirPin_V = 24; //вывод подключения PIR датчика Ванной
int pirPin_Z = 22; //вывод подключения PIR датчика Зал
int pirPin_S = 28; //вывод подключения PIR датчика Сени
//_______Для работы терминала по bluetooth___________________________
int inSize=0; // Переменная которая будет содержать размер буфера терминала bluetooth
char str[128]; // Так как типа string тут нет, будем использовать массив символов
//_______Для работы терминала по Sim900______________________________
String currStr = "";
boolean isStringMessage = false; // Переменная принимает значение True, если текущая строка является сообщением
//___________________ Стартовый цикл _________________________________
void setup()
{
WDTCSR=(1<<WDCE)|(1<<WDE); //установить биты WDCE WDE (что б разрешить запись в другие биты
WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда
// ds.begin();
// ds.setResolution(ZalC, 10);
// ds.setResolution(UlicaC, 10);
//ds.setResolution(KuhnyaC, 10);
pinMode(22, INPUT); digitalWrite(22,HIGH); // вход датчик движения зал
pinMode(24, INPUT); digitalWrite(24,HIGH); // вход датчик движения ванна
pinMode(26, INPUT); digitalWrite(26,HIGH); // вход датчик движения кухня
pinMode(28, INPUT); digitalWrite(28,HIGH); // вход датчик движения сени
pinMode(30, INPUT); digitalWrite(30,HIGH); // вход сигнализатор "Вода в подполе"
pinMode(32, INPUT); digitalWrite(32,HIGH); // Резерв
pinMode(34, INPUT); digitalWrite(34,HIGH); // Резерв
pinMode(36, INPUT); digitalWrite(36,HIGH); // Кнопка звонка домофона
pinMode(23, INPUT); digitalWrite(23,HIGH); // вход концевики ворот
pinMode(25, INPUT); digitalWrite(25,HIGH); // вход концевик входной двери
pinMode(27, INPUT); digitalWrite(27,HIGH); // вход концевик двери бани
pinMode(29, INPUT); digitalWrite(29,HIGH); // вход термостат "Баня готова"
pinMode(31, INPUT); digitalWrite(31,HIGH); // вход термостат "Очень высока температура в бане"
pinMode(33, INPUT); digitalWrite(33,HIGH); // Дымовой шлейф №1
pinMode(35, INPUT); digitalWrite(35,HIGH); // Дымовой шлейф №2
pinMode(37, INPUT); digitalWrite(37,HIGH); // Нет напряжения после УЗО
pinMode( 5, OUTPUT); // Пьезо динамик
pinMode(13, OUTPUT); // Лампа УД включен
pinMode(38, OUTPUT); // Свет в Кухня
pinMode(40, OUTPUT); // Свет в Ванна
pinMode(42, OUTPUT); // Свет в Зал
pinMode(44, OUTPUT); // Свет в Сени
pinMode(46, OUTPUT); // Питание насосной станции
pinMode(48, OUTPUT); // Питание дренажного насоса
pinMode(50, OUTPUT); // Питание водонагревателя
pinMode(52, OUTPUT); // Освещение двора
digitalWrite(38,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(40,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(42,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(44,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(46,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(48,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(50,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
digitalWrite(52,HIGH); // Подаем единицы на плату реле (сигнал инвентированный)
pinMode(39, OUTPUT); // Питание гаража
pinMode(41, OUTPUT); // Питание бани
pinMode(43, OUTPUT); // Питание розеток дома
pinMode(45, OUTPUT); // Питание вентиляции
pinMode(47, OUTPUT); // Клапан полива
pinMode(49, OUTPUT); // Сирены
pinMode(51, OUTPUT); // Номер дома
pinMode(53, OUTPUT); // Управление отоплением
Serial.begin(9600); // Связь по терминалу
Serial1.begin(9600); // HC-05 Bluetooth http://robocraft.ru/blog/electronics/587.html#comment4652
Serial2.begin(19200); // GSM SMS-передача плата SIM900
//Serial3.begin(9600); // Плата голосового оповещения на attiny2313 и SD-карте
if(EEPROM.read(0)==10){ReadPar();} // Чтение настроек из памяти, если они туда были сохранены ранее
delay(2000);
SMSVoltON=true;
NastroykaGSM(); // Настройка работы с SIM900
irrecv.enableIRIn(); // Запуск ИК-приемника
tone(5, 2000, 200); // Звук, когда все готово! выключил
delay(4000);
t = rtc.getTime();
RTCChas = t.hour; // t.hour - запрос часов
RTCMinuta = t.min; // t.min - запрос минут
SMSschet = EEPROM.read(51); // чтение кол-ва ранее отправленных СМС
startOneSMS();
Serial2.print("SmartHome vkluchen - "); vremya2(); EndSMS();// время включения
}
void loop()
{
RTCtimer();
izmereniya();
alarms();
irremote();
bluetooth();
sms_read();
osvechenie(); // Управление освещением во дворе
if (!statusFireAlarm==0){FireAlarm();} // Работа пожарной сигнализации
if (statushome==1) {avtosvet();} // Автоматическое управление освещением в доме меньше 11%
if (statushome==1){digitalWrite(13,HIGH);} else {digitalWrite(13, LOW);} // Лампа "Умный дом включен"
//if (statushome==1){ventilyaciya();} // Управление вентиляцией в подполе по датчику влажности DHT11
if (statusotp==1) {otoplenie();} else {digitalWrite(53, LOW);} // Управление работой газового котла 1 - вкл., 0 - откл.
if (!signaliz==0){signalizSMS();} // Работа сигнализации сигнализации при режимах 1,2,3
if (statusPIK==1){Pik();} // Работа тональной пищалки
if (perimetr==1){Operimetr();} // Охрана периметра участка
if ((statusPump==1) && (digitalRead(30)==LOW)) {digitalWrite(46,LOW);} else {digitalWrite(46, HIGH);} // Питание станции водоснабжения (Сигнал инвертированный)
if (statusrzd==1){digitalWrite(43,HIGH);} else {digitalWrite(43, LOW);} // Питание розеток дома
if (statusgaraj==1){digitalWrite(39,HIGH);} else {digitalWrite(39, LOW);} // Питание гаража
if (statusbania==1){digitalWrite(41,HIGH);} else {digitalWrite(41, LOW);} // Питание бани
if (statuspoliv==0) {digitalWrite(47, LOW);} // Выключение клапана полива
if (statuspoliv==1) {digitalWrite(47, HIGH);} // Включение клапана полива на постоянку
if (statuspoliv==2) {digitalWrite(47, HIGH); timerPoliv();} // Клапан полива включен по таймеру
if ((perimetr==1 && statusperimetr==0) || statusAlarm==1) { sirena();} // Работа малой сирены
//if (analogRead(14)>100) {KvitAI14=false;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(29)==LOW) {KvitDI29=false;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(30)==LOW) {KvitDI30=false;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(31)==LOW) {KvitDI31=false;} // Сброс квитирования при возвращении параметра в норму
}
void izmereniya() // Замер температур с датчиков DS18B20 и влажности с датчика DHT11
{ // http://arduino.ru/tutorials/BlinkWithoutDelay на основе
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) { // Замеры в интервале
//dht.read(DHT11PIN); // Замеры температур с DHT11
int t = sens.readTemperature(3); // чтение датчика на пине 2
int h = sens.readHumidity(3); // чтение датчика на пине 2
delay(100); // Необязательная задержка
// vlaga = dht.humidity; // Уровень влажности % с DHT11
// TempPodpol = dht.temperature; // Температура в подполе с DHT11
// if (TempPodpol < 3 || TempPodpol > 35){ // Перезапрос. Борьба с помехами.
// dhtschet++; // +1 к счетчику ошибок DHT11
// delay(300); // Необязательная задержка
// dht.read(DHT11PIN); // Замеры температур с DHT11
// vlaga = dht.humidity; // Уровень влажности % с DHT11
// TempPodpol = dht.temperature; // Температура в подполе с DHT11
// if (TempPodpol < 3 || TempPodpol > 35){ // Перезапрос. Борьба с помехами.
// dht2schet++; // +1 к счетчику повторных ошибок DHT11
// }
}
ISR (WDT_vect) { //вектор прерывания W
static boolean n=0; // флаг работы: запрос температуры или её чтение
n=!n;
if (n) {ds.reset(); // сброс шины
ds.write(0xCC);//обращение ко всем датчикам
ds.write(0x44);// начать преобразование (без паразитного питания)
}
else {ds.reset();
ds.select(KuhnyaC);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
TempKuhnyaC = ds.read() | (ds.read()<<8); //прочитаны 2 байта
TempKuhnyaC = TempKuhnyaC / 16;
// получение с 2-го датчика
ds.reset();
ds.select(ZalC);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
TempZalC = ds.read() | (ds.read()<<8); //прочитаны 2 байта
TempZalC = TempZalC/16;
ds.reset();
ds.select(UlicaC);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
TempUlicaC = ds.read() | (ds.read()<<8); //прочитаны 2 байта
TempUlicaC = TempUlicaC / 16;
// получение с 3-го датчика
ds.reset();
ds.select(FreezeC);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
TempFreezeC = ds.read() | (ds.read()<<8); //прочитаны 2 байта
TempFreezeC = TempFreezeC/16 ;
}
}
// ds.requestTemperatures(); // Замеры температур с DS18B20
// delay(750); // Необязательная задержка
// TempZalC = ds.getTempC(ZalC); // Считываем температуру в зале
// delay(100);
// TempUlicaC = ds.getTempC(UlicaC); // Считываем температуру на улице
// delay(100);
// TempKuhnyaC = ds.getTempC(KuhnyaC); // Считываем температуру в кухне
// delay(100);
// if(TempZalC== -127 || TempUlicaC== -127 || TempKuhnyaC== -127) // Перезапрос при ошибке датчика
// {
// ds.requestTemperatures(); delay(750); dsshet++ ; // +1 к счетчику ошибок DS18B20
// TempZalC = ds.getTempC(ZalC); // Считываем температуру в зале
// delay(100);
// TempUlicaC = ds.getTempC(UlicaC); // Считываем температуру на улице
// delay(100);
// TempKuhnyaC = ds.getTempC(KuhnyaC); // Считываем температуру в кухне
// delay(100);
// }
{
UlicaS = analogRead(A15)/10; // Считываем освещенность на улице
voltmetr(); // Считываем напряжения на выходе ИБП (норма 13,5в)
previousMillis = currentMillis;} // Сброс таймера
}
void voltmetr() //____________Цикл "Вольтметр"__измерение напряжения на выходе ИБП
// Взято с http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html
{
volt = analogRead(A0); // А0 аналоговый вход вольтметра
vout = (volt * 5.0) / 1024.0;
Vpit = vout / (10000.0/(100000.0+10000.0)); // По формуле Vpit = vout / (R2/(R1+R2))
if (Vpit<0.09) { Vpit=0.0;} // Округление до нуля
}
void osvechenie() // Работа уличного освещения двора
{
if ( ULsvet==2 ) // Если режим работы автоматический
{
if (UlicaS > 8){digitalWrite(52,HIGH);} // Освещение двора выключить при освещении больше 8% (сигнал инвертированный)
if (UlicaS < 4) {digitalWrite(52,LOW);} // Освещение двора включить при освещении меньше 4% (сигнал инвертированный)
}
}
void avtosvet() //______Цикл управления автоматическим освещением____________________________________
{
//______Ниже для зала______________________________________
if(digitalRead(pirPin_Z) == HIGH && statusBlock==false && UlicaS < 30) //Если обнаружено движение, нет блокировки, и освещенность улицы меньше 20%
{
if(lockLow_Z) //Если до этого момента еще не включили реле
{ lockLow_Z = false; digitalWrite(42, LOW); delay(50);} //Включаем свет.
takeLowTime_Z = true;
}
if(digitalRead(pirPin_Z) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_Z){lowIn_Z = millis();takeLowTime_Z = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_Z && millis() - lowIn_Z > (pause_Z * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_Z = true; digitalWrite(42, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 35) {digitalWrite(42,HIGH);} // Отключение реле управления освещением больше 35%
//______Ниже для кухни______________________________________
if(digitalRead(pirPin_K) == HIGH && statusDay==false && UlicaS < 30) //Если обнаружено движение с 23 до 8 включаем подсветку
{
if(lockLow_K) //Если до этого момента еще не включили реле
{ lockLow_K = false; digitalWrite(38, LOW); delay(50);} //Включаем свет.
takeLowTime_K = true;}
if(digitalRead(pirPin_K) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_K){lowIn_K = millis();takeLowTime_K = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_K && millis() - lowIn_K > (pause_K * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_K = true; digitalWrite(38, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 35) {digitalWrite(38,HIGH);} // Отключение реле управления освещением больше 20%
//______Ниже для ванной комнаты_____________________________
if(digitalRead(pirPin_V) == HIGH && UlicaS < 30) //Если обнаружено движение
{
if(lockLow_V) //Если до этого момента еще не включили реле
{ lockLow_V = false; digitalWrite(40, LOW); delay(50);} //Включаем свет.
takeLowTime_V = true;}
if(digitalRead(pirPin_V) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_V){lowIn_V = millis();takeLowTime_V = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_V && millis() - lowIn_V > (pause_V * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_V = true; digitalWrite(40, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 35) {digitalWrite(40,HIGH);} // Отключение реле управления освещением больше 35%
//______Ниже для сеней______________________________________
if(digitalRead(pirPin_S) == HIGH && UlicaS < 16) //Если обнаружено движение
{
if(lockLow_S) //Если до этого момента еще не включили реле
{ lockLow_S = false; digitalWrite(44, LOW); delay(50);} //Включаем свет.
takeLowTime_S = true;}
if(digitalRead(pirPin_S) == LOW) //Ели движения нет
{ //Если время окончания движения еще не записано
if(takeLowTime_S){lowIn_S = millis();takeLowTime_S = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
if(!lockLow_S && millis() - lowIn_S > (pause_S * 60000)) //Если время без движение превышает паузу => движение окончено
{ lockLow_S = true; digitalWrite(44, HIGH); delay(50);} //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения
}
if (statushome==1 && UlicaS > 20) {digitalWrite(44,HIGH);} // Отключение реле управления освещением больше 20%
}
// void ventilciya()
// {
// if (vlaga > 60) {digitalWrite(45, HIGH);} // Включение вентилятора при влажности более 60%
// if (vlaga < 40) {digitalWrite(45, LOW);} // Выключение вентилятора при влажности менее 40%
// }
void homeON() //____________Цикл включения умного дома____________________________________________________
{
statushome=1; // статус умного дома 0 - откл , 1- вкл
// statusotp=1; // статус отопления дома 0 - откл , 1- вкл
statusrzd=1; // статус питания розеток дома 0 - откл , 1- вкл
// statusgaraj=1; // статус питания гаража 0 - откл , 1- вкл
// statusbania=1; // статус питания бани 0 - откл , 1- вкл
}
void homeOFF() //____________Цикл выключения умного дома________________________
{
statushome=0; // статус питания дома 0 - откл , 1- вкл
statusrzd=0; // статус питания розеток дома 0 - откл , 1- вкл
statusgaraj=0; // статус питания гаража 0 - откл , 1- вкл
statusbania=0; // статус питания бани 0 - откл , 1- вкл
statusPump=0; // статус питания станции водоснабжения 0 - откл , 1- вкл
digitalWrite(38,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(40,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(42,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(44,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(46,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(48,HIGH); // выключение реле (сигнал инвертированный)
digitalWrite(50,HIGH); // выключение реле (сигнал инвертированный)
SMSAlarmTemp=false; // сброс флага отправки СМС о критической темпертуры
SMSBanyaTemp=false; // сброс флага отправки СМС о критической темпертуры в бане
SMSPodpol=false; // сброс флага отправки СМС о воде в подполе
}
void otoplenie() // Цикл управления газовым котлом (Сигнал инвертированный!(Особенность подключения к котлу))
{
if ( statusotp==0) // Отключено
{ digitalWrite(53,HIGH);} // Отключить отопление
if ( statusotp==1) // Климат-контроль
{ if ( TempZalC > (tempDust+1)){digitalWrite(53,HIGH);} // Отключить отопление если температура больше желаемой на 1грС
if ( !TempZalC== -127 && (TempZalC < tempDust) ) {digitalWrite(53,LOW);} // Включить отопление если температура меньше желаемой
}
if ( statusotp==2) // Экономия
{ if ( TempZalC > (tempDECOust+1)){digitalWrite(53,HIGH);} // Отключить отопление если температура больше желаемой на 1грС
if ( !TempZalC== -127 && (TempZalC < tempDECOust) ) {digitalWrite(53,LOW);} // Включить отопление если температура меньше желаемой
}
}
void timerPoliv() // Таймер клапана полива огорода 0 - откл , 1- вкл , 2- Таймер
{
NowTime1 = millis();
if(Timer1On == true) { StartTime1 = NowTime1 ; Timer1On = false; statuspoliv=2;}
if( statuspoliv==2 && NowTime1 - StartTime1 > 900000) // выдержка 15 минут
{ statuspoliv=0; } // Сброс таймера
}
Serg1, вот. Спасибо одному хорошему парню, который выложил основную часть кода. Я туда прикрутил GSM, но надо бы доработать, чтобы можно было значения из текста смс вытащить и куда нужно вставить. Пока с этим не разобрался, если кто поможет, буду очень благодарен. Использовал nano v3, сим900, дисплей 1602, энкодер, плату реле, часы 3231, пищалку.Подключил микрофон от мобилы и динамик, можно с него позвонить и поговорить с хозяином.В качестве питания ББП20 с акб 1,2 А*ч, на 10 часов при отключении хватает. Позже добавлю контроль 220в. Понравился алгоритм измерения температуры с датчика, глюков не заметил.
#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 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
DeviceAddress DS18B20Address;
#define encoderA 2 // энкодер - поворот вправо (об землю)
#define encoderB 3 // энкодер - поворот влево (об землю)
#define encoderK A3 // энкодер - кнопка (об землю)
#define BeepPin 11 // пищалка
#define BeepToneNo 2000 // тон звука "No", герц
#define BeepToneYes 4000 // тон звука "Yes", герц
#define BeepToneNoDuration 200 // длительность звука "No", мс
#define BeepToneYesDuration 200 // длительность звука "Yes", мс
#define Relay 12 // нога, к которой подключено реле
#define RelayOn LOW // полярность сигнала включения реде (HIGH/LOW)
// LCD connection RS, E, D4, D5, D6, D7
// R/W - to ground
LiquidCrystal lcd(10, 9, 8, 7, 6, 5);
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, если текущая строка является сообщением
#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) {
tone(BeepPin,4000,5);
}
}
// обработка поворота энкодера на лету (ручное изменение уставки температуры))
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"
Serial.print("ATD+79206888901;\r");
}
}
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("ZAPROS")) { SMSzapros();}//запрос состояния
// Далее подтверждение параметров по СМС
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");}
if (!currStr.compareTo("ZVONOK")) { Serial.print("AT+CMIC=10;");delay (100);Serial.print("ATD+79206888901;");}
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(" Hyst=");Serial.print(Hysteresis);EndSMS();}
if ((Timer2Enabled)&!(Timer1Activated)) {Serial.print("TIMER 2 ");Serial.print("T2=");Serial.print(Timer2Temp);Serial.print("/TU=");
Serial.print(Temperature);Serial.print(" Hyst=");Serial.print(Hysteresis);EndSMS();EndSMS();}
if ((Timer3Enabled)&!(Timer1Activated)) {Serial.print("TIMER 3 ");Serial.print("T3=");Serial.print(Timer3Temp);Serial.print("/TU=");
Serial.print(Temperature);Serial.print(" Hyst=");Serial.print(Hysteresis);EndSMS();}
else {Serial.print("TIMER OFF ");Serial.print("TSET/TT=");Serial.print(TstatTemp);Serial.print("/");Serial.print(Temperature);Serial.print(" Hyst=");Serial.print(Hysteresis);EndSMS();}
if (digitalRead(12)==HIGH) {Serial.println(" NAGREV-OFF"); } else { Serial.println(" NAGREV-ON");EndSMS();}
EndSMS();
}
void NastroykaGSM()
{
Serial.print("AT+CMGF=1\r"); //устанавливает текстовый режим смс-сообщения
delay(100);
Serial.print("AT+IFC=1,1\r"); //устанавливает программный контроль потоком передачи данных
delay(100);
Serial.print("AT+CPBS=\"SM\"\r"); //открывает доступ к данным телефонной книги SIM-карты
delay(100);
Serial.print("AT+GSMBUSY=1,1\r"); //запрет всех входящих звонков
delay(100);
Serial.print("AT+CMGD=4,\r"); //Очищаем накопившиеся СМС
delay(100);
Serial.print("AT+CNMI=1,2,2,1,0\r"); //включает оповещение о новых сообщениях
delay(100);
}
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);
}
NAZ, у меня все в одном корпусе, импульсные трансы на сим900 не влияют, т.к. он экранирован и частоты не те, а вот на остальное вполне возможно. Иногда при включении нагрузки возникают какие-то наводки, и на дисплей выходит какая-то хрень, но программа в ардуине продолжает работать. Все глюки дисплея пропадают после нажатия на кнопку энкодера. Лучше ставить блоки питания в металлическом корпусе или вообще внешние.
NAZ, у меня все в одном корпусе, импульсные трансы на сим900 не влияют, т.к. он экранирован и частоты не те, а вот на остальное вполне возможно. Иногда при включении нагрузки возникают какие-то наводки, и на дисплей выходит какая-то хрень, но программа в ардуине продолжает работать. Все глюки дисплея пропадают после нажатия на кнопку энкодера. Лучше ставить блоки питания в металлическом корпусе или вообще внешние.
Спасибо за ответ. Вообщем-то собрал я всё в одном корпусе поскорее и отвёз на дачу. Не до экспериментов, у нас в Челябинске температура сейчас до -37, надо греть дом, а без контроллера побаиваюсь калориферы оставлять включёнными. Уже в работе мой контроллер, он получился в виде смс- розетки, дополнительно умеет температуру выслать по запросу. Работает стабильно, не падает уже 3 недели.
Ребят, у кого проблемы с отладкой модулей сим900. Я делаю так: сущеструет переходник usb-rs232, например, такой http://chip69.ru/catalog/1483, или на ch340. Стоит копейки. Подключаю через него сим900, настраиваю с компа через терминал. Либо подключаю на ардуину на нужный порт и смотрю в терминале, что она отсылает в ответ на запрос. Сначала шлем +CMT, следующей строкой запрос и смотрим, что получает и в каком формате сим с дуни. Если что-то не так, правим скетч в нужном месте, и отсылаем снова. Полный список АТ команд есть в инете или в даташите.
Летом 2016 написал прогу для дачнтков, и собрал все
Специально разработанная для дачников!
Состав системы: - 2 датчика температуры-влажности(один устанавливается на улице, второй в доме)
- 2 датчика движения(устанавливаются в доме)
- 1 датчик на открытие входной двери
- сирена с маяком
- Бесперебойный бокс(при отсутствии питание ваша система всегда работает)
Управление производится посредством телефона.
Возможности:
- Постановка и снятие с охраны.
- Запрос баланса
- Запрос состояния системы(Состояние контроля дома, напряжение 220В, напряжение аккумулятора, температура и влажность, сигнал сотовой сети)
- Квитирование тревог(сброс тревоги)
- При пропадании напряжения 220В, придет смс
- При возобновлении напряжения 220В, придет смс
- При разряде аккумулятора, придет смс
- При срабатывании по датчикам, придет смс, включится сирена
- При открывании бокса, придет смс, включится сирена
Друзья, простите, если немного оффтоп. Ищется термоконтроллер для управления батареей отопления наподобие http://www.homematic.ru/Catalog/showDetailscfb4.php?g.. , но ардуино совместимый. Хочется иметь возможность отправить команду на поддержание определенной температуры, либо, как вариант, просто открыть/закрыть клапан. Сейчас проблема именно в поиске подходящего терморегулятора. Вроде в этом проекте такого нет, может кто-то делал такое или знает где взять?
а вот описание http://www.herz-armaturen.ru/upload/normal/7711.pdf . Не сочтите за рекламу. Нужен также БП на 24В. Управлять посредством ПИД регулирования, обычными или твердотельными реле, которые будут коммутировать 24В на привод.
Пусть всё будет freeware типа! А я вот всё жду, кто заделает приложение на андроиде совместимое с моей системой. Вот это была бы тема.
Здравствуйте! Отличный проект, огромная работа! Сам только на старте! Удачи в бесконечном пути к совершенству! Я по поводу андроида - обратите внимение на прграмму Virtuino. Мне очень понравилась, и лучше я ничего не нашёл.
Пусть всё будет freeware типа! А я вот всё жду, кто заделает приложение на андроиде совместимое с моей системой. Вот это была бы тема.
Здравствуйте! Отличный проект, огромная работа! Сам только на старте! Удачи в бесконечном пути к совершенству! Я по поводу андроида - обратите внимение на прграмму Virtuino. Мне очень понравилась, и лучше я ничего не нашёл.
Вот обновил программу. И библиотеки работающие туда же положил. Проблем быть не должно.
В экселевском файле есть таблица подключений к плате мега, и есть таблица команд по серийному порту №1. Теперь они цифровые 4-х значные. Так тратится гораздо меньше оперативы, повышается скорость реакции, ну и голову ломать не придется с придумыванием команды.
Добавлен кухонный 4-х канальный таймер с управление от ИК- пульта телевизора самсунг.
Добавлен определитель номера по примеру MaksaVV. Теперь программа реагирует только на смс от своих номеров. И отсылает ответ, тому кто команду послал.Пример stambylovа я пока не осилил, но применю его точно.
Слава, респект! можно усовершенствовать имхо часть кода, где квитирование, чето намудрено как то. Предлагаю ввести переменную одну Mute вместо всех Kvit...ов, убрать также цикл Kvitirovanie (). Запуск квитирания: вместо Kvitirovanie () набираем просто Mute = 1. Вот пример вкладки Alarm.
int pambilang; // переменная для цикла sirena()
int TEMPMINZ = 15; // Переменная. Уставка сигнализации минимальной температуры в зале (По умолчанию 15гр.*С)
int TEMPMINU = -45; // Переменная. Уставка сигнализации минимальной температуры на улице (По умолчанию -45гр.*С)
int TEMPMINK = 15; // Переменная. Уставка сигнализации минимальной температуры в кухне (По умолчанию 15гр.*С)
int TEMPMINP = 5; // Переменная. Уставка сигнализации минимальной температуры в подполе (По умолчанию 5гр.*С)
int TEMPMAXZ = 35; // Переменная. Уставка сигнализации максимальной температуры в зале (По умолчанию 35гр.*С)
int TEMPMAXU = 50; // Переменная. Уставка сигнализации максимальной температуры на улице (По умолчанию 50гр.*С)
int TEMPMAXK = 35; // Переменная. Уставка сигнализации максимальной температуры в кухне (По умолчанию 35гр.*С)
int TEMPMAXP = 35; // Переменная. Уставка сигнализации максимальной температуры в подполе (По умолчанию 35гр.*С)
void alarms() //______________Цикл "тревожные сигналы"____
{
if (digitalRead(30)==HIGH) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS(); statusPump=0; if } // Сработка датчика затопления подпола
//else if (analogRead(14)<100) {if (!Mute) {sirena(); AlarmTimer++;} alarmsSMS();} // Сработка датчика уровня дренажной емкости
else if (digitalRead(29)==HIGH) {if (!Mute) {sirena(); AlarmTimer++;}} // Сработка датчика готовности бани
else if (digitalRead(31)==HIGH) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS(); statusbania=2;}// Сработка датчика предельной температуры в бане
else if ( !TempZalC==0 && TempZalC <= TEMPMINZ) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();} // Сигнализация низкой температуры в зале
else if ( TempZalC >= TEMPMAXZ) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();} // Сигнализация высокой температуры в зале
else if ( !TempUlicaC==0 && TempUlicaC <= TEMPMINU) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();} // Сигнализация низкой температуры на улице
else if ( TempUlicaC >= TEMPMAXU) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();} // Сигнализация высокой температуры на улице
else if ( !TempKuhnyaC==0 && TempKuhnyaC <= TEMPMINK){if (!Mute) {sirena(); AlarmTimer++;} AlarmTemp=1; alarmsSMS();} // Сигнализация низкой температуры в кухне
else if ( TempKuhnyaC >= TEMPMAXK){if (!Mute) {sirena(); AlarmTimer++;} AlarmTemp=1; alarmsSMS();} // Сигнализация высокой температуры в кухне
// else if ( TempPodpol < TEMPMINP) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();} // Сигнализация низкой температуры в в подполе +3
// else if ( TempPodpol > TEMPMAXP) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();} // Сигнализация высокой температуры в подполе +35
// else if (Vpit<=12.0 && SMSVoltIBP==false) { startOneSMS(); Serial2.println("Alarm! Min zaryad akkumulyatora IBP!"); EndSMS(); SMSVoltIBP=true;} // Низкий заряд аккумулятора
// else if (Vpit>=14.0 && SMSVoltIBP==false) { startOneSMS(); Serial2.println("Alarm! Max zaryad akkumulyatora IBP!"); EndSMS(); SMSVoltIBP=true;} // Перезаряд аккумулятора
else { AlarmTemp=0; AlarmTimer=0;}
if ( AlarmTimer > 300000) {AlarmTimer=0; Mute = true;} // Через 5 минут автоматчекое квитирование тревоги и сброс таймера
if (Mute) {if ( statusperimetr==0){perimetr=0;} AlarmTimer = 0;}
if ( TempZalC > TEMPMINZ+2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if ( TempZalC < TEMPMAXZ-2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if ( TempUlicaC > TEMPMINU+2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if ( TempUlicaC < TEMPMAXU-2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if ( TempKuhnyaC > TEMPMINK+2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if ( TempKuhnyaC < TEMPMAXK-2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if ( TempPodpol > TEMPMINP) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if ( TempPodpol < TEMPMAXP) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
//if (analogRead(14)>100) {KvitAI14=false;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(29)==LOW) {Mute=false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(30)==LOW) {Mute=false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(31)==LOW) {Mute=false; AlarmTimer = 0;} // Сброс квитирования при возвращении параметра в норму
if (digitalRead(37)==HIGH && SMSVoltOFF==false) {
startOneSMS(); Serial2.print("Propalo pitanie 220V!_"); vremya2(); EndSMS();
SMSVoltOFF=true; SMSVoltON=false; homeOFF(); statusotp=2; ULsvet=3; } // Отключение питания 220В потребителей от греха подальше и для экономии аккумулятора(выключаются реле)
if ((digitalRead(37)==LOW && SMSVoltON==false) && (RTCMinuta==0 || RTCMinuta==15|| RTCMinuta==30 || RTCMinuta==45))
{ startOneSMS(); Serial2.print("Pitanie 220V vosstanovleno!_"); vremya2(); EndSMS();
if (ULsvet==3){ ULsvet=2; } // включить освещение двора если оно было выключено автоматически
SMSVoltON=true; SMSVoltOFF=false; } // Восстановление питания 220В
}
void alarmsSMS() //______Цикл отправки алармов по СМС__________________________________________________
{
if (digitalRead(30)==HIGH && SMSPodpol==false) //Отправка СМС о затоплении подпола
{ startOneSMS(); Serial2.println("Alarm!Voda v podpole!"); vremya2(); EndSMS();
startTwoSMS(); Serial2.println("Alarm!Voda v podpole!"); vremya2(); EndSMS(); SMSPodpol=true;}
if (AlarmTemp==1 && SMSAlarmTemp==false) //Отправка СМС о критической температуре
{
//if((TempPodpol < TEMPMINP)||(TempPodpol > TEMPMAXP)) { volume(); mp3_play (1); delay(4000);} // Проигрываем сообщение по оповещению, подпол
if((TempZalC <= TEMPMINZ)||(TempZalC >= TEMPMAXZ)) { volume(); mp3_play (2); delay(4000);} // Проигрываем сообщение по оповещению, зал
if((TempUlicaC <= TEMPMINU)||(TempUlicaC >= TEMPMAXU)) { volume(); mp3_play (5); delay(4000);} // Проигрываем сообщение по оповещению, улица
if((TempKuhnyaC <= TEMPMINK)||(TempKuhnyaC >= TEMPMAXK)) { volume(); mp3_play (4); delay(4000);} // Проигрываем сообщение по оповещению, кухня
startOneSMS();
Serial2.println("Alarm!Temperatura!");
Serial2.print("Podpol:"); Serial2.print(TempPodpol); Serial2.println("*C,");
Serial2.print("Zal:"); Serial2.print(TempZalC); Serial2.println("*C");
Serial2.print("Ylica:"); Serial2.print(TempUlicaC); Serial2.println("*C");
Serial2.print("Kuhnya:"); Serial2.print(TempKuhnyaC); Serial2.println("*C");
EndSMS();
startTwoSMS();
Serial2.println("Alarm!Temperatura!");
Serial2.print("Podpol:"); Serial2.print(TempPodpol); Serial2.println("*C,");
if (dsZshet<4){Serial2.print("Zal:"); Serial2.print(TempZalC); Serial2.println("*C");} else{ Serial2.println("net svyazi");}
if (dsUshet<4){Serial2.print("Ylica:"); Serial2.print(TempUlicaC); Serial2.println("*C");} else{ Serial2.println("net svyazi");}
if (dsKshet<4){Serial2.print("Kuhnya:");Serial2.print(TempKuhnyaC);Serial2.println("*C");} else{ Serial2.println("net svyazi");}
EndSMS(); SMSAlarmTemp=true;
}
if (digitalRead(31)==HIGH && SMSBanyaTemp==false) //Отправка СМС о критической температуре в бане
{
volume(); mp3_play (3); // Проигрываем сообщение по оповещению
startOneSMS(); Serial2.println("Alarm!Predelnaya temperatura v bane!"); vremya2(); EndSMS();
SMSBanyaTemp=true;
}
}
void sirena()
{
pambilang++;
if(pambilang > 500){ tone(5, 1500, 400); pambilang = 0;}
//for (int m = 1600; m<=2200; m++){tone (5, m, 75);} // (пин пищалки,частота,длина тона)
//for (int m = 2200; m>=1600; m--){tone (5, m, 75);}
//if(pambilang==4){noTone(5); pambilang = 0;}
}
Ну и раз уж оптимизация, убирай библиотеку далас, делай по прерыванию, так и памяти меньше используется и delay при измерении температуры отсутсвует. а глядишь и датчики меньше ошибок выдавать будут (наверное). Пример я выше приводил.
модуль BT HC-05 у вас подключены напрямую или уровни сигналов согласованы? ( на плате указаны уровни сигн 3,3 в).
У меня блютус модуль был подключен просто через килоомные резисторы. Но лучше делай по уму через делитель по два резистора.
А сейчас я esp8266 приляпал. Терпит и без резисторов она. Осваиваю HTML. Пытаюсь делать простенькие странички для веба. А тут на днях коллега похвастался вот таким экранчиком Nextion HMI nx3224t024_011, так мне его тоже захотелось поставить.
Кстати, есть на примете HTML редактор какой? чтобы там натащил готовых полей да кнопок и готово?
Serg1 пишет:
Датчики Даллас опрашиваются с какой периодичностью? (можно выставить таймер до 8 сек вроде, а сколько выставлено в обсуждаемом коде).
Ну у меня раз в 2 минуты. Можно и чаще, главное чтобы не один раз в цикл. А вот Макс хитрый ход предложил. Тоже буду его осознавать.
Я вот думаю работу с часами тоже переделать, так как мне секунды нигде не нужны, а опрашиваются они каждый цикл, а это чуть ли не 10мс задержки.
Слава, респект! можно усовершенствовать имхо часть кода, где квитирование, чето намудрено как то. Предлагаю ввести переменную одну Mute вместо всех Kvit...ов, убрать также цикл Kvitirovanie (). Запуск квитирания: вместо Kvitirovanie () набираем просто Mute = 1. Вот пример вкладки Alarm
Неа, у меня же задумка такая, что если параметр какой то вышел за предел, то квитирование "затыкает" только его, пока он не пришел в норму. И если в этот момент другой какой то параметр вышел за пределы, то сирена включается снова. Снова жмешь кнопку МУТЕ и тревога по этому параметру прекращается. Правда не всегда такое получается почему то :)) Но задумка такая. А если ввести одну mute==true то её вообще можно в цикл сирена() запихать и всё, но она будет блокировать работу сирены по всем тревогам. Или я не понял чего то?
MaksVV пишет:
Ну и раз уж оптимизация, убирай библиотеку далас, делай по прерыванию, так и памяти меньше используется и delay при измерении температуры отсутсвует. а глядишь и датчики меньше ошибок выдавать будут (наверное). Пример я выше приводил.
Да! делать однозначно надо! Хитрый код.
Кстати да, когда датчики глючат, то выдают либо 0, или 255. Сделал игнорирование по этим двум числам и всё тишина. А то последнее время раз в две недели ложная тревога была.
Питание моего SIM900 - внешнее 5В 2А, скорость установил 9600, использую на Меге Serial1 - пины 18 и 19. Никаких библиотек не подключаю. Порт живой, т.к. после выключения - включения питания работает нормально. Подозреваю, что он в какой-то режим переходит непонятный после посылки смс. Об ограничении по TX и RX не слышал для SIM900, как его сделать?
Питание моего SIM900 - внешнее 5В 2А, скорость установил 9600, использую на Меге Serial1 - пины 18 и 19. Никаких библиотек не подключаю. Порт живой, т.к. после выключения - включения питания работает нормально. Подозреваю, что он в какой-то режим переходит непонятный после посылки смс. Об ограничении по TX и RX не слышал для SIM900, как его сделать?
Рабочий код для получения баланса
Здравствуйте, форумчане.
Тоже занимаюсь темой умного дома, правда не столь продвинут. Автору спасибо за труд, и что поделился. Делаю на Меге 2560.
Вопрос у меня касается SIM900 (подключен на Serial1): после посылки смс шилд встаёт в ступор и перестаёт реагировать на АТ команды. В мониторе появляются ">". Привести шилд в чувство можно, передёрнув питание: выключить и включить (программно, конечно) после каждой посланной смс. Предполагаю, что есть более красивое решение, кто имел такую же проблему?
Шилд стал адекватен, спасибо ответившим.
MaksVV,
я вставил ваш код #371 для работы с датчиками DS18 по таймеру в программу умного дома. Разложил фрагменты по соответствующим местам программы.
Остался последний рубеж- убрать ошибку:
"In file included from C:\Users\Сергей\Desktop\arduino-1.6.5-r5\hardware\arduino\avr\cores\arduino/Arduino.h:30:0,
from C:\Users\Сергей\Desktop\arduino-1.6.5-r5\скетч\libraries\OneWire/OneWire.h:7, from DS181.ino:2:
Подскажите, если не сложно, где напортачил?
MaksVV,
могли бы вы поделиться вашим вариантом программы?
Не получается у меня внедрить опрос датчиков DS18 по сторожевому таймеру.(Ваш пост #371).
Коллеги, кто что думает/ имел опыт по монтажу ардуино + Sim900 с источниками питания в один корпус? У меня корпус небольших размеров, в нём монтирую ардуино, Sim900, твёрдотельное реле и вытащенные из корпусов блоки питания на 9В и 5В. Так вот, в этих БП используются малогабаритные импульсные трансформаторы - они могут наводить помехи на антенну Sim900?
MaksVV,
могли бы вы поделиться вашим вариантом программы?
Не получается у меня внедрить опрос датчиков DS18 по сторожевому таймеру.(Ваш пост #371).
Я использовал пример для DS18 из библиотеки OnWire- заработал сразу, прочитал адрес и выдал температуру.
NAZ,
в этом примере ( от OnWire) тоже идет задержка 750 мс. Далласовскую библиотеку по этому поводу и гнобили. Поэтому я и пытался код от Димакса прикрутить-не получилось. Потом разглядел, что в авторской программе опрос датчиков происходит раз в 2 минуты и успокоился.
Продолжаю править программу под свои нужды:
У меня в нежилом доме котел электрический 3-х ступенчатый. 3-6-9 КВт., и счетчик 2х тарифный. Соответственно задумка по максимуму греть теплоноситель ночью, а днем только по необходимости ( чтоб температура была положительная). При этом хочу задействовать ступенчатый нагрев (3-6-9 КВт) в зависимости от (чего??)- темп. за бортом\темп. в доме\ дельта температур дом-улица...
Есть ли у кого идеи по такому алгоритму?
Подскажите, если не сложно, где напортачил?
нужно убрать цикл void izmerenia () . вы измеряете температуры здесь ISR (WDT_vect)
Просто пользуетесь переменными температур, они сами обновляются сторожевой собакой.
..
Так я его и убирал, за исключением цикла измерения с датчиков DHT11.
Заменил датчики DHT11 на DHT22. Поставил 2 шт. На улицу и в доме. Все температуры( с DHT и с DS18) выводятся целочисленные.
Хотя указано разрешение 10 бит для Далласа. Не совсем понятно, где происходит округление? INT ?
Мужики вот здесь http://remotexy.com/ru/registration/complate/
Если кому интересно.
Дорогие форумчане, подскажите по опторазвязкам и модулю времени.
Нашел на ali вот такие PC817, можно ли использовать их в качестве аналога?
Заметил, что модули времени многие начали использовать другие, я нашел DS1302. Все таки есть смысл использовать именно его?
Так я его и убирал, за исключением цикла измерения с датчиков DHT11.
Заменил датчики DHT11 на DHT22. Поставил 2 шт. На улицу и в доме. Все температуры( с DHT и с DS18) выводятся целочисленные.
Хотя указано разрешение 10 бит для Далласа. Не совсем понятно, где происходит округление? INT ?
дак у вас всё же заработали dallasы через прерывание? Не понятно зачем такая точность, но вроде чтобы десятые градуса показывало, нужно там где делится на 16, вместо /16 поставить /16,0
Дорогие форумчане, подскажите по опторазвязкам и модулю времени.
Нашел на ali вот такие PC817, можно ли использовать их в качестве аналога?
Заметил, что модули времени многие начали использовать другие, я нашел DS1302. Все таки есть смысл использовать именно его?
заказывал 100 штук pc817 с али - работают хорошо. Чето в 100 рубей вышло, дешево однако. часы лушче 1307, они по шине i2c подключаются, и вроде как не спешат. 1302 за полгода на полчаса убегают, если не раньше.
Часы лучше ds3231, идут очень точно, кварц вствроен в микросхему, есть температурная компенсация и т.д.
Может кому будет интересно. Тестировал тут gsm модуль SIM800L, т.к. он совсем дешевый стал - около 250 руб. Но с ним возникли проблемы. Обязательно нужно хорошее питание через DC-DC преобразователь, 4,0В. Я подключал всё на бредборде естественно китайскими проводочками пин-пин. Так вот модуль по сериал соединению на АТ команды отвечал хорошо, но не находил сеть. Что я только не пробовал, кучу времени убил. Не верил в то, что многие говорили - типа припаяй провода и всё заработает (типа подключение через бредборд не вариант, плохой контакт и т.д.) Каково же было моё удивление, когда действительно модуль стал находить сеть (после надёжного соединения пайкой). Ещё нужно делать согласование уровней Rx и Tx чтобы от ардуино к GSM приходило по 2,7В на этих сигнальных проводах. (делается при помощи резистивных делителей напряжения). Ну и в конце ещё меня ожидали косяки в скетче. Скетч автора темы, который работает на Sim900, не работает на sim800L. В частности вот ошибки.
Здесь косяк кроется в пробелах в команде АТ+CMGS - пробелов быть не должно, иначе команда не выполняется и смс не отправляется, хотя SIM900 на это не обращает внимания
И ещё косяки в скетче автора, которые и для SIM900 нужно тоже исправить
Команда AT+GSMBUSY=1, 1\r непонятно зачем ещё единица после запятной (команда не выполняется, проверял), нужная команда выглядит так AT+GSMBUSY=1\r
Команда AT+CMGDA=«DEL ALL»\r не выполняется, т.к. нужно вот так AT+CMGDA=\"DEL ALL\"\r
Итоговый вариант
Часы лучше ds3231, идут очень точно, кварц вствроен в микросхему, есть температурная компенсация и т.д.
точно, лучше такие заказывать. (я перепутал их с 1307)
MaksVV, нет датчики не заработали.
Оставил как есть.
У меня очередной косяк обнаружился- датчики DHT22. Один на 6 пине, второй на 3 пине(пока не подключен). Данные дублируются.
////
vlaga = sens.readHumidity(6); // чтение датчика на пине 6 //dht.humidity; // Уровень влажности % с DHT11
Tempout = sens.readTemperature(6); // чтение датчика на пине 6 //dht22.temperature; // Температура в подполе с DHT11
delay(1500);
//vlaga2 = sens.readHumidity(3); // чтение датчика на пине 3 //dht.humidity; // Уровень влажности % с DHT11
// Tempin = sens.readTemperature(3); // чтение датчика на пине 3 //dht22.temperature;
TEMPin = sens.readTemperature(3); // чтение датчика на пине 3
HUMin = sens.readHumidity(3); // чтение датчика на пине 3
MaksVV, нет датчики не заработали.
покажи весь скетч, посмотрим что у тебя не так
MaksVV, выкладываю основной код.
В воскресенье перезалил этот код- стал нормально отображать показания с DTH22. Странно, по ним ничего не менял!
Я добавил код записи данных с датчиков температур на SD карту. Пока нет карты закомментировал пару строк кода, чтоб работала остальная программа.
Запись параметров на карту должна происходить каждые 2 мин, когда секунды равны 0.
Обнаружилась особенность- программа в сериал выдает 3-4 раза сообщение об ошибки открытия файла(по идее д.б. один раз в 2 мин.00 секунд) Я так понимаю, что в течении этой нулевой секунды программа успевает 3 раза пытаться открыть файл?
Вывод по блютуф- то параметры выводятся построчно, что есть правильно, но периодически перенос некоторых строк отсутствует. Происходит это случайным образом. Вкладку работы с блютуф кардинально не менял. Только прописал в кавычки параметры по русски.
И ещё косяк- если закрыть терминальную программу, то при последующем открытии терминала происходит частичный или полный сброс ранее установленных параметров( показания датчиков или сброс режима работы).
MaksVV, нет датчики не заработали.
покажи весь скетч, посмотрим что у тебя не так
Я имел ввиду посмотрим только почему не работают датчики даллас по прерыванию. А в предоставленном коде вообще по обычной библе они работают.
у тебя вектор прерывания ISR (WDT_vect) находится в цикле izmereniya (), то есть в loop. Нужно вытащить его за луп. как бы смешно это не звучало.
Serg1 мне кажется, у меня есть, что тебе нужно, завтра выложу в гугл, сброшу тебе ссылку.
MaksVV, спасибо, скомпилировалось без ошибок.
Serg1, вот. Спасибо одному хорошему парню, который выложил основную часть кода. Я туда прикрутил GSM, но надо бы доработать, чтобы можно было значения из текста смс вытащить и куда нужно вставить. Пока с этим не разобрался, если кто поможет, буду очень благодарен. Использовал nano v3, сим900, дисплей 1602, энкодер, плату реле, часы 3231, пищалку.Подключил микрофон от мобилы и динамик, можно с него позвонить и поговорить с хозяином.В качестве питания ББП20 с акб 1,2 А*ч, на 10 часов при отключении хватает. Позже добавлю контроль 220в. Понравился алгоритм измерения температуры с датчика, глюков не заметил.
NAZ, у меня все в одном корпусе, импульсные трансы на сим900 не влияют, т.к. он экранирован и частоты не те, а вот на остальное вполне возможно. Иногда при включении нагрузки возникают какие-то наводки, и на дисплей выходит какая-то хрень, но программа в ардуине продолжает работать. Все глюки дисплея пропадают после нажатия на кнопку энкодера. Лучше ставить блоки питания в металлическом корпусе или вообще внешние.
NAZ, у меня все в одном корпусе, импульсные трансы на сим900 не влияют, т.к. он экранирован и частоты не те, а вот на остальное вполне возможно. Иногда при включении нагрузки возникают какие-то наводки, и на дисплей выходит какая-то хрень, но программа в ардуине продолжает работать. Все глюки дисплея пропадают после нажатия на кнопку энкодера. Лучше ставить блоки питания в металлическом корпусе или вообще внешние.
Спасибо за ответ. Вообщем-то собрал я всё в одном корпусе поскорее и отвёз на дачу. Не до экспериментов, у нас в Челябинске температура сейчас до -37, надо греть дом, а без контроллера побаиваюсь калориферы оставлять включёнными. Уже в работе мой контроллер, он получился в виде смс- розетки, дополнительно умеет температуру выслать по запросу. Работает стабильно, не падает уже 3 недели.
Ребят, у кого проблемы с отладкой модулей сим900. Я делаю так: сущеструет переходник usb-rs232, например, такой http://chip69.ru/catalog/1483, или на ch340. Стоит копейки. Подключаю через него сим900, настраиваю с компа через терминал. Либо подключаю на ардуину на нужный порт и смотрю в терминале, что она отсылает в ответ на запрос. Сначала шлем +CMT, следующей строкой запрос и смотрим, что получает и в каком формате сим с дуни. Если что-то не так, правим скетч в нужном месте, и отсылаем снова. Полный список АТ команд есть в инете или в даташите.
Летом 2016 написал прогу для дачнтков, и собрал все
Специально разработанная для дачников!
Состав системы:
- 2 датчика температуры-влажности(один устанавливается на улице, второй в доме)
- 2 датчика движения(устанавливаются в доме)
- 1 датчик на открытие входной двери
- сирена с маяком
- Бесперебойный бокс(при отсутствии питание ваша система всегда работает)
Управление производится посредством телефона.
Возможности:
- Постановка и снятие с охраны.
- Запрос баланса
- Запрос состояния системы(Состояние контроля дома, напряжение 220В, напряжение аккумулятора, температура и влажность, сигнал сотовой сети)
- Квитирование тревог(сброс тревоги)
- При пропадании напряжения 220В, придет смс
- При возобновлении напряжения 220В, придет смс
- При разряде аккумулятора, придет смс
- При срабатывании по датчикам, придет смс, включится сирена
- При открывании бокса, придет смс, включится сирена
Друзья, простите, если немного оффтоп. Ищется термоконтроллер для управления батареей отопления наподобие http://www.homematic.ru/Catalog/showDetailscfb4.php?g.. , но ардуино совместимый. Хочется иметь возможность отправить команду на поддержание определенной температуры, либо, как вариант, просто открыть/закрыть клапан. Сейчас проблема именно в поиске подходящего терморегулятора. Вроде в этом проекте такого нет, может кто-то делал такое или знает где взять?
мне кажется надёжнее будет по проводам. Регулятор типа этого http://www.herz-armaturen.ru/thermal-actuators/1-7711-13/
а вот описание http://www.herz-armaturen.ru/upload/normal/7711.pdf . Не сочтите за рекламу. Нужен также БП на 24В. Управлять посредством ПИД регулирования, обычными или твердотельными реле, которые будут коммутировать 24В на привод.
Благодарю
Коллеги, спаял плату с опторазвязками для ПИР датчиков и концевиков и призадумался:
А как же решается вопрос защиты от наводок на кабельных линиях идущих к датчикам типа DS18 и DTH22 ??.
в этой теме уже обсуждалось, я ссылки приводил с радиокота - ищите
Пусть всё будет freeware типа! А я вот всё жду, кто заделает приложение на андроиде совместимое с моей системой. Вот это была бы тема.
Здравствуйте! Отличный проект, огромная работа! Сам только на старте! Удачи в бесконечном пути к совершенству! Я по поводу андроида - обратите внимение на прграмму Virtuino. Мне очень понравилась, и лучше я ничего не нашёл.
Пусть всё будет freeware типа! А я вот всё жду, кто заделает приложение на андроиде совместимое с моей системой. Вот это была бы тема.
Здравствуйте! Отличный проект, огромная работа! Сам только на старте! Удачи в бесконечном пути к совершенству! Я по поводу андроида - обратите внимение на прграмму Virtuino. Мне очень понравилась, и лучше я ничего не нашёл.
https://yadi.sk/d/PUVyBzOJ38tTQe
Вот обновил программу. И библиотеки работающие туда же положил. Проблем быть не должно.
В экселевском файле есть таблица подключений к плате мега, и есть таблица команд по серийному порту №1. Теперь они цифровые 4-х значные. Так тратится гораздо меньше оперативы, повышается скорость реакции, ну и голову ломать не придется с придумыванием команды.
Добавлен кухонный 4-х канальный таймер с управление от ИК- пульта телевизора самсунг.
Добавлен определитель номера по примеру MaksaVV. Теперь программа реагирует только на смс от своих номеров. И отсылает ответ, тому кто команду послал.Пример stambylovа я пока не осилил, но применю его точно.
Ну и так порядки навел.
Пользуйтесь, предлагайте, будем совершенствоваться дальше.
Слава, респект! можно усовершенствовать имхо часть кода, где квитирование, чето намудрено как то. Предлагаю ввести переменную одну Mute вместо всех Kvit...ов, убрать также цикл Kvitirovanie (). Запуск квитирания: вместо Kvitirovanie () набираем просто Mute = 1. Вот пример вкладки Alarm.
Ну и раз уж оптимизация, убирай библиотеку далас, делай по прерыванию, так и памяти меньше используется и delay при измерении температуры отсутсвует. а глядишь и датчики меньше ошибок выдавать будут (наверное). Пример я выше приводил.
Слава, Макс, молодцы!
В процессе пайки возникли вопросы и сомнения:
модуль BT HC-05 у вас подключены напрямую или уровни сигналов согласованы? ( на плате указаны уровни сигн 3,3 в).
Датчики Даллас опрашиваются с какой периодичностью? (можно выставить таймер до 8 сек вроде, а сколько выставлено в обсуждаемом коде).
модуль BT HC-05 у вас подключены напрямую или уровни сигналов согласованы? ( на плате указаны уровни сигн 3,3 в).
У меня блютус модуль был подключен просто через килоомные резисторы. Но лучше делай по уму через делитель по два резистора.
А сейчас я esp8266 приляпал. Терпит и без резисторов она. Осваиваю HTML. Пытаюсь делать простенькие странички для веба. А тут на днях коллега похвастался вот таким экранчиком Nextion HMI nx3224t024_011, так мне его тоже захотелось поставить.
Кстати, есть на примете HTML редактор какой? чтобы там натащил готовых полей да кнопок и готово?
Датчики Даллас опрашиваются с какой периодичностью? (можно выставить таймер до 8 сек вроде, а сколько выставлено в обсуждаемом коде).
Ну у меня раз в 2 минуты. Можно и чаще, главное чтобы не один раз в цикл. А вот Макс хитрый ход предложил. Тоже буду его осознавать.
Я вот думаю работу с часами тоже переделать, так как мне секунды нигде не нужны, а опрашиваются они каждый цикл, а это чуть ли не 10мс задержки.
Слава, респект! можно усовершенствовать имхо часть кода, где квитирование, чето намудрено как то. Предлагаю ввести переменную одну Mute вместо всех Kvit...ов, убрать также цикл Kvitirovanie (). Запуск квитирания: вместо Kvitirovanie () набираем просто Mute = 1. Вот пример вкладки Alarm
Неа, у меня же задумка такая, что если параметр какой то вышел за предел, то квитирование "затыкает" только его, пока он не пришел в норму. И если в этот момент другой какой то параметр вышел за пределы, то сирена включается снова. Снова жмешь кнопку МУТЕ и тревога по этому параметру прекращается. Правда не всегда такое получается почему то :)) Но задумка такая. А если ввести одну mute==true то её вообще можно в цикл сирена() запихать и всё, но она будет блокировать работу сирены по всем тревогам. Или я не понял чего то?
Ну и раз уж оптимизация, убирай библиотеку далас, делай по прерыванию, так и памяти меньше используется и delay при измерении температуры отсутсвует. а глядишь и датчики меньше ошибок выдавать будут (наверное). Пример я выше приводил.
Да! делать однозначно надо! Хитрый код.
Кстати да, когда датчики глючат, то выдают либо 0, или 255. Сделал игнорирование по этим двум числам и всё тишина. А то последнее время раз в две недели ложная тревога была.