Очередная Температурная сигнализация с SMS управлением для дома
- Войдите на сайт для отправки комментариев
Чт, 07/09/2017 - 16:07
Приветствую!
Прошлой зимой в деревне два раза вставал автоматический газовый котел,
из-за отключения света на несколько суток, в связи с чем пришлось
делать температурную сигнализацию. В хламе дома нашел древний COM модем,
на нем и собрал.
Итак исходные комплектующие: Arduino UNO + БП, модем IRZ MC52iT + БП,
RS232(COM)-TTL конвертер, датчик температуры DS18B20, четырех разрядный
индикатор TM1637, несколько резисторов, проводов и походящая коробка.
Принцип работы банален: при температуре меньше 12 градусов отсылается SMS.
Раз в сутки принудительно перезагружается модем, в первых двух разрядах
индикатора отображается уровень сигнала (01...30),во вторых температура.
Внешние управляющие команды:
reset - принудительная перезагрузка модема
smson - включение возможности отправки SMS (по умолчанию включено)
smsoff - отключение отправки SMS
balancetele2 - запрос баланса оператора Теле2 - в ответ приходит
баланс оператора, температура и время работы устройства.
balancemegafon - аналогично для Мегафона
delete - удаление из SIM карты последних 8 SMS сообщейний
gettemp - в ответ приходит сообщение с температурой и временем работы устройства
#include <SoftwareSerial.h> SoftwareSerial gsm(7, 8); // RX, TX #include <OneWire.h> #include "TM1637.h" #define CLK 3 #define DIO 4 #define TPN 2 #define CYCLE_RESET_MODEM 85029 // sec. 85029 sec = 23 h 37m 9s #define CYCLE_GET_TEMP 169 #define CRYTICAL_TEMP 12 #define AlarmNumber "+7920xxxxxxx" #define BalanceNumberTele2 "*105#" #define BalanceNumberMegafon "*100#" unsigned long timerSec = 0; unsigned int timerGetTemp = 130; unsigned int timerResetModem = 50000; float curr_temp = 0; int togg_l = 0; boolean SMSoff = false; byte HardStatus = 0; // 0 - OK, 1...30 - Qualyti net, 170 AA - init modem, 255 FF - crytical temp // 225 E1 - error init modem, 226 E2 - error status modem // 227 E3 - error send SMS String val = ""; // get string OneWire ds(TPN); TM1637 tm1637(CLK, DIO); void setup() { // put your setup code here, to run once: Serial.begin(9600); tm1637.init(); tm1637.set(0); tm1637.clearDisplay(); pinMode(LED_BUILTIN, OUTPUT); InitModem(); } void loop() { // put your main code here, to run repeatedly: // read console if (Serial.available()) { while (Serial.available()) { val += char(Serial.read()); delay(50); } MainCommand(); val = ""; } else { delay(50); } if (gsm.available()) { while (gsm.available()) { val += char(gsm.read()); delay(50); } Serial.println(val); MainCommand(); val = ""; } else { delay(50); } // count timers unsigned long ctmr = (long(millis() / 1000)); if ((timerSec > 4294900) && (ctmr < 100)) { timerSec = 0; } if (ctmr > timerSec) { timerSec = ctmr; digitalWrite(LED_BUILTIN, togg_l); togg_l = !togg_l; tm1637.point(togg_l); ++timerGetTemp; ++timerResetModem; if (timerResetModem >= (CYCLE_RESET_MODEM)) { timerResetModem = 0; timerGetTemp = 0; curr_temp = 0; ResetModem(); } if (timerGetTemp >= (CYCLE_GET_TEMP)) { timerGetTemp = 0; curr_temp = GetTemp(); GetModemStatus(); Serial.print(curr_temp); Serial.print("°C"); PrintUptime(); if (curr_temp < CRYTICAL_TEMP) AlarmTemp(); } ShowStatus(); ShowTemp(); } else { delay(50); } } int StrHtoInt(String ins) { ins.trim(); int sl = ins.length(); if (sl < 1) return 0; ins.toUpperCase(); int sum = 0; int pi = 0; for (int ii = (sl - 1); ii >= 0; --ii) { int ti = int(ins[ii]); if (((ti >= 48) && (ti <= 57)) || ((ti >= 65) && (ti <= 70))) { int st = 0; if ((ti >= 48) && (ti <= 57)) { ti -= 48; } else { ti -= 55; } if (pi > 0) { st = 1 + pow(16, pi); } else { st = 1; } sum += (ti * st); ++pi; } } return sum; } void MainCommand() { val.toLowerCase(); String cmd; if ((val.indexOf("+cmgr: ") > -1)) { String vt = val.substring((val.indexOf("+cmgr: ") + 7), val.length()); if ((vt.indexOf("rec unread") > -1)) { if ((vt.indexOf(AlarmNumber) > -1)) { val = vt.substring((vt.indexOf(AlarmNumber) + 15), vt.length()); //case command SMSCommand(); //--- val = ""; } } } else { //--other command if ((val.indexOf("reset") > -1)) { timerResetModem = 0; timerGetTemp = 0; curr_temp = 0; ResetModem(); } if ((val.indexOf("smson") > -1)) { SMSoff = false; } if ((val.indexOf("+cusd: 2,") > -1)) { String vt = val.substring((val.indexOf("+cusd: 2,") + 10), val.length()); vt.toUpperCase(); boolean ft = true; for (int i = 0; i <= 3 ; ++i) { int ti = int(vt[i]); if (!(((ti >= 48) && (ti <= 57)) || ((ti >= 65) && (ti <= 70)))) { ft = false; } } if (ft) { String vo = ""; for (int i = 0; i <= vt.length(); i += 4) { int tf = StrHtoInt(vt.substring(i, (i + 4))); if (tf <= 127) { vo += char(tf); } } SendSMS(vo); } else { if (vt.indexOf('"') > -1) { vt = vt.substring(0, vt.indexOf('"')); } SendSMS(vt); } } if ((val.indexOf("smsoff") > -1)) { SMSoff = true; } if ((val.indexOf("balancetele2") > -1)) { // get balance phone cmd = "ATD"; cmd += BalanceNumberTele2; cmd += ";"; gsm.println(cmd); delay(500); } if ((val.indexOf("balancemegafon") > -1)) { // get balance phone cmd = "ATD"; cmd += BalanceNumberMegafon; cmd += ";"; gsm.println(cmd); delay(500); } if ((val.indexOf("delete") > -1)) { for (int i = 1; i <= 8; ++i) { cmd = "AT+CMGD="; cmd += String(i); gsm.println(cmd); delay(500); } } if ((val.indexOf("gettemp") > -1)) { SendSMS(""); } if ((val.indexOf("+cmti: ") > -1)) { String vt = val.substring((val.indexOf("+cmti: ") + 12), val.length()); cmd = "AT+CMGR="; cmd += vt; gsm.println(cmd); delay(500); } if ((val.indexOf("+csq: ") > -1)) { String vt = val.substring((val.indexOf("+csq: ") + 6), val.length()); if (vt.indexOf(",") > -1) { vt = vt.substring(0, (vt.indexOf(","))); } vt.trim(); int vl = vt.length(); if (vl <= 0) { HardStatus = 226; ShowStatus; return; } if (vl == 1 ) { HardStatus = (int(vt[0])) - 48; } if (vl == 2 ) { int d1 = (int(vt[0])) - 48; d1 *= 16; HardStatus = d1 + (int(vt[1])) - 48; } ShowStatus(); } //-- end other command } } void SMSCommand() { String cmd; if ((val.indexOf("reset") > -1)) { timerResetModem = 0; timerGetTemp = 0; curr_temp = 0; ResetModem(); } if ((val.indexOf("smson") > -1)) { SMSoff = false; } if ((val.indexOf("smsoff") > -1)) { SMSoff = true; } if ((val.indexOf("balancetele2") > -1)) { // get balance phone cmd = "ATD"; cmd += BalanceNumberTele2; cmd += ";"; gsm.println(cmd); delay(500); } if ((val.indexOf("balancemegafon") > -1)) { // get balance phone cmd = "ATD"; cmd += BalanceNumberMegafon; cmd += ";"; gsm.println(cmd); delay(500); } if ((val.indexOf("delete") > -1)) { for (int i = 1; i <= 8; ++i) { cmd = "AT+CMGD="; cmd += String(i); gsm.println(cmd); delay(500); } } if ((val.indexOf("gettemp") > -1)) { SendSMS(""); } } void SendSMS(String text) { text += "t"; text += String(curr_temp); text += "u"; unsigned int days = int(timerSec / 86400); text += days; text += "d"; unsigned int hour = int((timerSec - days * 86400) / 3600); text += hour; text += "h"; // send sms String cmd3 = "AT+CMGF=1"; gsm.println(cmd3); delay(500); cmd3 = "AT+CMGS="; cmd3 += AlarmNumber; gsm.println(cmd3); delay(500); gsm.print(text); delay(500); gsm.print(char(26)); delay(500); } void PrintUptime() { Serial.print(" Uptime: "); unsigned int days = int(timerSec / 86400); Serial.print(days); Serial.print(" day "); unsigned int hour = int((timerSec - days * 86400) / 3600); Serial.print(hour); Serial.print(" hour "); unsigned int min = int((timerSec - days * 86400 - hour * 3600) / 60); Serial.print(min); Serial.print(" min "); unsigned int sec = int(timerSec % 60); Serial.print(sec); Serial.println(" sec "); } void ResetModem() { tm1637.clearDisplay(); //reset modem gsm.println("AT+CFUN=1,1"); delay(10000); //wait ready modem //init modem InitModem(); } void InitModem() { // init modem HardStatus = 170; //AA init modem ShowStatus(); delay(1000); gsm.begin(9600); gsm.println("AT+ILRR=1"); delay(500); gsm.println("AT+IPR=9600"); delay(500); gsm.println("ATE0"); delay(500); gsm.println("AT+CUSD=1"); delay(500); gsm.println("AT+CLIP=1"); delay(500); gsm.println("AT+CMGF=1"); delay(500); gsm.println("AT+CSCS=\"GSM\""); delay(500); gsm.println("AT+CNMI=2,1"); delay(500); HardStatus = 0; ShowStatus(); } void GetModemStatus() { // get modem quality signal and show it gsm.println("AT+CSQ"); delay(500); /*gsm.println("AT+COPS?"); delay(500); gsm.println("AT+CREG?"); delay(500); gsm.println("AT+CCLK?"); delay(500);*/ } void AlarmTemp() { HardStatus = 255; //FF ShowStatus(); delay(1000); if (SMSoff) return; //send sms SendSMS("AlarmTemp "); } void ShowStatus() { int s1; int s2; s1 = int(HardStatus / 16); s2 = int(HardStatus % 16); tm1637.display(0, s1); tm1637.display(1, s2); } void ShowTemp() { int cti; int s1; int s2; cti = abs(curr_temp); if (cti > 0) { s1 = int(cti / 10); s2 = int(cti % 10); tm1637.display(2, s1); tm1637.display(3, s2); } else { tm1637.display(2, 15); tm1637.display(3, 15); } } float GetTemp() { float ct; byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; if ( !ds.search(addr)) { ds.reset_search(); delay(250); return; } switch (addr[0]) { case 0x10: type_s = 1; break; case 0x28: type_s = 0; break; case 0x22: type_s = 0; break; default: return; } ds.reset(); ds.select(addr); ds.write(0x44, 1); // start conversion, with parasite power on at the end delay(1050); // maybe 750ms is enough, maybe not present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); } int16_t raw = (data[1] << 8) | data[0]; if (type_s) { raw = raw < 3; // 9 bit resolution default if (data[7] == 0x10) { // "count remain" gives full 12 bit resolution raw = (raw & 0xFFF0) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); // at lower res, the low bits are undefined, so let's zero them if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms //// default is 12 bit resolution, 750 ms conversion time } ct = (float)raw / 16.0; ct -= 2; return ct; }
А под какой модуль GSM сделано?
используется не GSM модуль, а модем IRZ MC52iT + RS232-TTL конвертор
P.S. Разницы особой не вижу что использовать, при проектировании была только одна сложность -
долго искал документацию по AT командам на этот модем, настройку, что бы при входящей SMS
сразу в COM порт выходило сообщение о приходе новой SMS.
Спасибо за уточнение.
Цена модема 150.00 USD ?
Даже не в курсе про цену - что было то и использовал
В яндекс макете только что нашёл за 2900 модем этот
кстати... а может и нет... я отказался от SNS уведомлений как основного транспорта сообщений... не гарантирован срок доставки... лучше SNS (или e-mail) использовать как дублирующий, а основной информационный о событии - голосовой звонок.
кстати... а может и нет... я отказался от SNS уведомлений как основного транспорта сообщений... не гарантирован срок доставки... лучше SNS (или e-mail) использовать как дублирующий, а основной информационный о событии - голосовой звонок.
во вы тему древнюю подняли .... :)
В идеале, в общем случае нужен как минимум один резервный канал, но проблема в том что место где стоит мой дом в деревне,
практически не имет не то что 3G а просто нормальной связи, заказал и поставил около окна антену 10 dB ( c AliExpress - дороже чем блин сама сигнализация) штыревую здоровую, добился связи на уровне 8...10 (из 30) с трудом. Позвонить аналогично проблема что входящая что исходящая связь. А СМС вполне нормально туда сюда ходят.
так что в моем случае только SMS.
понял. я на даче поставил спутниковую двунаправленную связь и отец в тайге также (взяли по акции) у него кроме спутниковой только голубиная связь. тоже возится с ардуинками....
по поводу антенны я бы на вышку направленную поставил. усиление выше.
штырь ненаправленная антена.
Добрый день!
У меня те же комплектующие, но модем мне, почему-то, не отвечает. Команды от Arduino уходят точно, посылал на COM порт ПК и видел их там. Модем рабочий, изначально был прошит для общения с промышленным контроллером, скорость обмена мне известна. Думаю, вне завиисмости от его прошивки, при правильной скорости порта он должен отвечать хотя бы на "ATI".
Я пробую отсылать библиотекой Serial(), Вы используете MySerial(). Это принципиально?
Можно ли посмотреть Вашу схему подключения, чтобы сравнить с моей?
Поменять rx tx провода местами в кабеле соединяющий arduino и ttl конвертер и в кабеле соединяющий конвертер и модем
Если б это помогало, я бы сюда не писал.
Мне помогло, модем аналогично прекрасно общался с компьютером, а с ардуино не хотел, попробуйте сначала простейший скетч общения с модемом, перебороть скоростей, пинов и т.д. Модем сбросьте до заводских настроек.
И кстати где вы увидели MySerial? Сейчас специально посмотрел - не нашёл в своём скетче
Если вы используете software serial, то у меня объект называется gsm и подключается к 7 и 8 пинам
Нет, конечно, Вы правы, это всё правильно (простые операции по замене RX на Tx и т.д.), я имел ввиду, что все простые проверки я уже перепробовал.
На данном этапе через терминальные программы с ПК я нормально опрашиваю модем. К примеру, одна из простых комманд "ATI" в ПК возвращает нормальный ответ, а вот в Ардуину выдаёт "ERROR". То есть связь нормальная, но что-то пока ещё не так.
Пардон, я имел ввиду software serial.
Нет, конечно, Вы правы, это всё правильно (простые операции по замене RX на Tx и т.д.), я имел ввиду, что все простые проверки я уже перепробовал.
На данном этапе через терминальные программы с ПК я нормально опрашиваю модем. К примеру, одна из простых комманд "ATI" в ПК возвращает нормальный ответ, а вот в Ардуину выдаёт "ERROR". То есть связь нормальная, но что-то пока ещё не так.
Т е связь с МК есть? Тупо сбросьте модем до заводских настроек.
Полностью переписал код, избавился от delay, удаляются все СМС после прихода их чтения, добавил watch dog timer, добавил три исполнительных устройства (реле) и команды для их включения/отключения. Добавил управление через DTMF, но не дописал, т.к. модем не поддерживает :(
Команды для входящих СМС:
А можно вопросы по отдельным кускам программы позадавать? хочу подробнее разобраться.
другим тоже надеюсь будет интересно увидеть более подробные обьяснения.
Эх...я то не против, но это ж сколько времени надо объяснять, где столько времени взять, куча текстовых строк + буфер приёма от модема вот и память забита, progmem используйте, тут целая тема есть - все разжеванно
ну хотя бы снабдили строки скетча пояснениями - что выполняется там..
у вас знаний достаточно, вы то понимаете, а большинство я так догадываюсь что нет..
поэтому и откликов на вашу ветку будет просто минимум.. потратили бы пол-часа и добавили пояснения..
Ну во первых за последние несколько месяцев только вам понадобились комментарии к коду)
Во вторых если есть вопросы конкретные - задавайте
Я не блогер, которым нехрен делать вот они и пишут статьи с кучей комментариев, ардуино для меня как и для многих на форуме это просто хобби, и тратить время на комментарии мне лень и некогда
Алгоритм банален - куча команд модема со списком ответов, если ответы не совпадают - проблема
в теме где вы мне писали - там пример качественного комментария. согаситесь - это очень удобно. просто я первый кто спросил, другие просто шли дальше, не останавливаясь...
в теме где вы мне писали - там пример качественного комментария. согаситесь - это очень удобно. просто я первый кто спросил, другие просто шли дальше, не останавливаясь...
Хватит уже воздух сотрясать, есть конкретные вопросы по коду - задавайте, не забыв указать номера строк.
ЗЫ. Если почаще прочитаете форумы по вопросам работы sim800 то увидите что основные вопросы по классической схеме работы с string и delay, много ссылаются на сайт codius (хорошие кстати статьи), а более сложные варианты людям не интересны, так как уровень использования модуля бытовой - поиграться. А для более надёжной работы надо самим мозг включать что тяжело для современных "жертв ЕГЭ"
ок, соберусь, задам вопрос поблочно, мне нравится разбираться в стороннем коде, понимать логику состевления программы и частей программы, сравнивать при этом загрузку процессора и прочее. Поэтому ваш вараинт мне также очень и очень интересен.
Реинкарнация устройства в новом железе, с резервным питанием и более распространенным модемом SIM800L
Устройство шлет СМС вида
PowerON CSQ:13 temp:25.0 uptime:0d2h
при включении/отключении питания и при получении команды getdata
При получении команды devreset сбрасывается модем, потом само устройство.
- схема
Повышайку DC-DC-STEP-UP до 5 вольт можно использовать любую.
На схеме не указаны, но ябязательно к установке конденсаторы по питанию на МК и модем, электролит+керамика.
- код
проект из 8 файлов, разбито по функциональному назначению, часть запуска инициализации модема взято с более сложного крепного проекта, поэтому какие то части кода могут показаться странными и/или лишними. В последнем файле options.h настройки проекта/пинов/админского телефона/таймеров и т.д.
Код не блокирующий, легко добавить опрос каких либо других датчиков, отправку СМС, получение команд и т.д....
-
В выходные железка поедет на натурные испытания в деревню в зону крайне плохого приема, через пару тройку недель, как засуну в корпус и окончательно оттестирую - напишу.
в собранном устройстве на пин А3 контроля внешнего питания каждые ~44 секунды прилетал непонятный импульс, в итоге часто слались СМС, исправленная функция, типа антидребезга на несколько секунд:
- целиковый код одного файла:
- итоговая железка
Добавлен счетчик принудительных перезагрузок модема, отображается на OLED перед именем оператора.
Добавлено получение баланса раз в 10 суток SIM карты через USSD запрос *100#, на МТС работает корректно, на Мегафоне модем не может выдать такой длинный ответ оператора (там еще куча рекламы в сообщении судя по всему) и поэтому не работает. Баланс присылается в стандартной ответной SMS по запросу getdata или при отключении/включении внешнего питания.
Обновленный скетч:
- добавлен дополнительный контроль питания на пине A0
- увеличено время ожидания получения СМС команды по даташиту до 20 секунд
- пример СМС, питание основное/питание дополнительное/уровень сигнала/ uptime / баланс симки (если удалось получить) / время с последнего получения баланса
-
Успешный тест-драйв железки, uptime millis перевалил unsigned long.
P.S. Тут на форуме давно кто то спорил что GSM устарело, все переходят на сообщения в интернете. На днях после урагана в деревне у всех операторов отрубился интернет на несколько суток, так что SMS - наше фсё :)