В корпусе установлен модуль питания ~220v -> 5V 3A.
Мощности модуля питания достаточно для питания ARDUINO Nano и модема SIM800L.
Поскольку питание каждого из модулей осуществляется от одного источника +5В, а SIM800L требует 4В, то запитка последнего осуществляется через 2 последовательно включенных диода, рассчитанных на ток 2 А.
Параллельно выводу питания SIM800L подключены 4 электролитических конденсатора 1000 мкФ х 6.3 В.
В этом случае обеспечивается стабильная связь SIM800L с базовой станцией.
Все протестировано с помощью АТ команд. Модуль подтвердил исправность и стабильную работу.
Содержимое скетча для тестирования не привожу, поскольку подобное было рассмотрено на этом форуме.
Для надежной связи с базовой станцией антенна модема SIM800L вынесена наружу и закреплена на боковой стенке. Отрицательный вывод модуля питания соединен с металлическим корпусом контроллера.
Признаком отказа системы отопления является падение температуры трубы для вывода топочных газов.
При штатном режиме работы отопления эта температура изменяется в диапазоне +45 - +65 °С.
Температура измеряется с помощью DS 18b20. Проблем кодом не оказалось...
По запросу текущую температуру получаю СМС -кой на мой телефон.
// Все работает !!!
// С мобильного телефона можем отправлять SMS сообщения следующего вида 001 ....... 99999 итого 100000 комбинаций....
// С мобильного телефона можем отправлять SMS сообщения следующего вида *100# и другие
/*
На базе этого скетча попытаемся написать код управления для мониторинга текущей температуры датчика,
для отправки СМС на мой смартфон в случае потухания котла,
для получения баланса СИМ карты МТС Беларусь. СИМ-ка установлена в слоте SIM800L.
*/
#include <SoftwareSerial.h> // Библиотека програмной реализации обмена по UART-протоколу
SoftwareSerial SIM800(8, 9); // RX, TX
// int pins[3] = {5, 6, 7}; // Пины с подключенными светодиодами
String _response = ""; // Переменная для хранения ответа модуля
long lastUpdate = millis(); // Время последнего обновления
long updatePeriod = 60000; // Проверять каждую минуту
String phones = "+37529-------"; // Белый список телефонов - Это мой мобильник A1
void setup()
{
Serial.begin(9600); // Скорость обмена данными с компьютером
SIM800.begin(9600); // Скорость обмена данными с модемом
Serial.println("Start!");
sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными
sendATCommand("AT+CMGDA=\"DEL ALL\"", true); // Удаляем все SMS, чтобы не забивать память
// Команды настройки модема при каждом запуске
_response = sendATCommand("AT+CLIP=1", true); // Включаем АОН
_response = sendATCommand("AT+DDET=1", true); // Включаем DTMF
sendATCommand("AT+CMGF=1;&W", true); // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
lastUpdate = millis(); // Обнуляем таймер
}
String sendATCommand(String cmd, bool waiting) {
String _resp = ""; // Переменная для хранения результата
Serial.println(cmd); // Дублируем команду в монитор порта
SIM800.println(cmd); // Отправляем команду модулю
if (waiting) { // Если необходимо дождаться ответа...
_resp = waitResponse(); // ... ждем, когда будет передан ответ
// Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
if (_resp.startsWith(cmd)) { // Убираем из ответа дублирующуюся команду
_resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
}
Serial.println(_resp); // Дублируем ответ в монитор порта
}
return _resp; // Возвращаем результат. Пусто, если проблема
}
String waitResponse() { // Функция ожидания ответа и возврата полученного результата
String _resp = ""; // Переменная для хранения результата
long _timeout = millis() + 5000; // Переменная для отслеживания таймаута (5 секунд)
while (!SIM800.available() && millis() < _timeout) {}; // Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
if (SIM800.available()) { // Если есть, что считывать...
_resp = SIM800.readString(); // ... считываем и запоминаем
}
else { // Если пришел таймаут, то...
Serial.println("Timeout..."); // ... оповещаем об этом и...
}
return _resp; // ... возвращаем результат. Пусто, если проблема
}
bool hasmsg = false; // Флаг наличия сообщений к удалению
void loop() {
if (lastUpdate + updatePeriod < millis() ) { // Пора проверить наличие новых сообщений
do {
_response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений
if (_response.indexOf("+CMGL: ") > -1) { // Если есть хоть одно, получаем его индекс
int msgIndex = _response.substring(_response.indexOf("+CMGL: ") + 7, _response.indexOf("\"REC UNREAD\"", _response.indexOf("+CMGL: ")) - 1).toInt();
char i = 0; // Объявляем счетчик попыток
do {
i++; // Увеличиваем счетчик
_response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true); // Пробуем получить текст SMS по индексу
_response.trim(); // Убираем пробелы в начале/конце
if (_response.endsWith("OK")) { // Если ответ заканчивается на "ОК"
if (!hasmsg) hasmsg = true; // Ставим флаг наличия сообщений для удаления
sendATCommand("AT+CMGR=" + (String)msgIndex, true); // Делаем сообщение прочитанным
sendATCommand("\n", true); // Перестраховка - вывод новой строки
parseSMS(_response); // Отправляем текст сообщения на обработку
break; // Выход из do{}
}
else { // Если сообщение не заканчивается на OK
Serial.println ("Error answer"); // Какая-то ошибка
sendATCommand("\n", true); // Отправляем новую строку и повторяем попытку
}
} while (i < 10);
break;
}
else {
lastUpdate = millis(); // Обнуляем таймер
if (hasmsg) {
sendATCommand("AT+CMGDA=\"DEL READ\"", true); // Удаляем все прочитанные сообщения
hasmsg = false;
}
break;
}
} while (1);
}
if (SIM800.available()) { // Если модем, что-то отправил...
_response = waitResponse(); // Получаем ответ от модема для анализа
_response.trim(); // Убираем лишние пробелы в начале и конце
Serial.println(_response); // Если нужно выводим в монитор порта
if (_response.indexOf("+CMTI:")>-1) { // Пришло сообщение об отправке SMS
lastUpdate = millis() - updatePeriod; // Теперь нет необходимости обрабатывать SMS здесь, достаточно просто
// сбросить счетчик автопроверки и в следующем цикле все будет обработано
}
}
if (Serial.available()) { // Ожидаем команды по Serial...
SIM800.write(Serial.read()); // ...и отправляем полученную команду модему
};
}
void parseSMS(String msg) { // Парсим SMS
String msgheader = "";
String msgbody = "";
String msgphone = "";
msg = msg.substring(msg.indexOf("+CMGR: "));
msgheader = msg.substring(0, msg.indexOf("\r")); // Извлекаем номер телефона отправившего СМС запрос
msgbody = msg.substring(msgheader.length() + 1); // не менять
msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK")); // Извлекаем текст SMS
msgbody.trim();
//Serial.println();
int firstIndex = msgheader.indexOf("\",\"") + 3; // не менять
int secondIndex = msgheader.indexOf("\",\"", firstIndex);
msgphone = msgheader.substring(firstIndex, secondIndex);
Serial.println("Phone: " + msgphone); // Выводим номер телефона
Serial.println("Message: " + msgbody); // Выводим текст SMS
if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) // Если телефон в белом списке, то...
{
// =====================================================================================================================================
sendSMS(phones, "Полученная СМС - ка:"+msgbody ); //ОТПРАВКА НА БЕЛЫЕ ТЕЛЕФОНЫ РЕЗУЛЬТАТА ВЫПОЛНЕНИЯ КОМАНДЫ !!!!!!!
// =====================================================================================================================================
}
else {
Serial.println("Unknown phonenumber");
}
} // ============================================ End void parseSMS(String msg) ==================================================
void sendSMS(String phone, String message)
{
sendATCommand("AT+CMGF=1", true); // Включаем текстовый режима SMS (Text mode)
sendATCommand("AT+CMGS=\"" + phone + "\"", true); // Переходим в режим ввода текстового сообщения
sendATCommand(message + "\r\n" + (String)((char)26), true); // После текста отправляем перенос строки и Ctrl+Z
}
// ЭТО УЖЕ РАБОТАЕТ !!!
#include <SoftwareSerial.h> // Библиотека програмной реализации обмена по UART-протоколу
SoftwareSerial SIM800(8, 9); // RX, TX
String _response = ""; // Переменная для хранения ответа модуля
String _phone_to_SMS = "+375---------"; // Сюда пишем свой номер телефона в международном формате
void setup() {
Serial.begin(9600); // Скорость обмена данными с компьютером
SIM800.begin(9600); // Скорость обмена данными с модемом
Serial.println("Start!");
sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными
// Команды настройки модема при каждом запуске
_response = sendATCommand("AT+CLIP=1", true); // Включаем АОН
//_response = sendATCommand("AT+DDET=1", true); // Включаем DTMF
_response = sendATCommand("AT+CMGF=1", true); // Включаем текстовый режим SMS (Text mode)
_response = sendATCommand("AT+CUSD=1,\"*100#\"", true); // Здесь необходимо указать свой USSD-запрос
}
String sendATCommand(String cmd, bool waiting) {
String _resp = ""; // Переменная для хранения результата
Serial.println(cmd); // Дублируем команду в монитор порта
SIM800.println(cmd); // Отправляем команду модулю
if (waiting) { // Если необходимо дождаться ответа...
_resp = waitResponse(); // ... ждем, когда будет передан ответ
// Если Echo Mode выключен (ATE0), то эти 3 строки можно закоментировать
if (_resp.startsWith(cmd)) { // Убираем из ответа дублирующуюся команду
_resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
}
Serial.println(_resp); // Дублируем ответ в монитор порта
}
return _resp; // Возвращаем результат. Пусто, если проблема
}
String waitResponse() { // Функция ожидания ответа и возврата полученного результата
String _resp = ""; // Переменная для хранения результата
long _timeout = millis() + 5000; // Переменная для отслеживания таймаута (5 секунд)
while (!SIM800.available() && millis() < _timeout) {}; // Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
if (SIM800.available()) { // Если есть, что считывать...
_resp = SIM800.readString(); // ... считываем и запоминаем
}
else { // Если пришел таймаут, то...
Serial.println("Timeout..."); // ... оповещаем об этом и...
}
return _resp; // ... возвращаем результат. Пусто, если проблема
}
// ================== Цикл void loop ========================
void loop() { //=
if (SIM800.available()) { // Если модем, что-то отправил... =
_response = waitResponse(); // Получаем ответ от модема для анализа =
_response.trim(); // Убираем лишние пробелы в начале и конце =
Serial.println(_response); // Если нужно выводим в монитор порта =
//.... =
if (_response.startsWith("+CUSD:")) { // Пришло уведомление о USSD-ответе =
if (_response.indexOf("\"") > -1) { // Если ответ содержит кавычки, значит есть сообщение =
//(предохранитель от "пустых" USSD-ответов) =
String msgBalance = _response.substring(_response.indexOf("\"") + 2); // Получаем непосредственно текст =
msgBalance = msgBalance.substring(0, msgBalance.indexOf("\"")); //=
Serial.println("USSD: " + msgBalance); // Выводим полученный USSD-ответ =
//=
float balance = getFloatFromString(msgBalance); // Извлекаем информацию о балансе =
//=
Serial.println("\r\nBalance: " + (String)balance ); // Выводим информацию о балансе =
sendSMS(_phone_to_SMS, "\r\nBalance: " + (String)balance); //=
} //=
} //=
} //=
if (Serial.available()) { // Ожидаем команды по Serial... //=
SIM800.write(Serial.read()); // ...и отправляем полученную команду модему //=
}; //=
} //========================================================================
void sendSMS(String phone, String message)
{
String _result = "";
sendATCommand("AT+CMGF=1", true); // Включаем текстовый режима SMS (Text mode)
sendATCommand("AT+CMGS=\"" + phone + "\"", true); // Переходим в режим ввода текстового сообщения
_result = sendATCommand(message + (String)((char)26), true); // После текста отправляем перенос строки и Ctrl+Z
}
float getFloatFromString(String str) { // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
bool flag = false;
String result = "";
str.replace(",", "."); // Если в качестве разделителя десятичных используется запятая - меняем её на точку.
for (int i = 0; i < str.length(); i++) {
if (isDigit(str[i]) || (str[i] == (char)46 && flag)) { // Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания),
if (result == "" && i > 0 && (String)str[i - 1] == "-") { // Нельзя забывать, что баланс может быть отрицательным
result += "-"; // Добавляем знак в начале
}
result += str[i]; // начинаем собирать их вместе
if (!flag) flag = true; // Выставляем флаг, который указывает на то, что сборка числа началась.
}
else { // Если цифры закончились и флаг говорит о том, что сборка уже была,
if (str[i] != (char)32) { // Если порядок числа отделен пробелом - игнорируем его, иначе...
if (flag) break; // ...считаем, что все.
}
}
}
return result.toFloat(); // Возвращаем полученное число.
}
Поскольку домик находится в 150 км от Минска, то возникла необходимость проверка текущего баланса на счету. Приведенный выше скетч с этой задачей справляется.
Должен сказать, что приведенные выше тексты написаны не мною. Эти тексты взяты на Codius.ru и мною адаптированы под решаемую задачу. Должен сказать о хорошем качестве выложенной информации на этом сайте. Все выложенные примеры работоспособны.
Эти скетчи каждый сам по себе работают.
Первый скетч возвращает посланное в контроллер сообщение на телефон.
Второй скетч высылает баланс, актуальный в данный момент времени.
Попытки все объединить в один скетч к успеху не привели.
К тому же нужно прописать реагирование на 2 ситуации - снижение температуры ниже 40 °С и наступление момента отрицательного баланса. Белорусский МТС позволяет иметь небольшой отрицательный баланс.
Прошу сообщество оказать мне помощь в решении проблемы. Нужны советы и работающие примеры.
В принципе с этой задачей могу справиться сам. Но возраст почти 70 лет и не очень хорошее знание С++ не способствуют быстрому решению этой задачи...
Другое дело помочь сделать 3D модель корпуса для электронных поделок, которые можно распечатать на 3D принтере... Или сделать рабочие чертежи, используя разработанную 3D модель...
Этим владею на уровне эксперта и обучаю этому студентов БГУ.
ПРивет, почитал сверху, решил тоже выложить рабочий обрезанный код для получения и отправки смс
Arduino Mega используется, если что
Да, еще на русском смс шлет))
Есть голая ардуина, на нее заливаете скетч, при первом запуске, она сама чистит EPPROM, т.к. не добавлен номер главного телефона(хранится он в EPPROM), далее отсылаете на номер, который вставлен в модуль SIM, "Register", в ответ получаете ответ на русском, далее разберетесь по счетчу сами, если прилепить часики реального времени, можно в определенное время проверять баланс(он и так проверяется, только по вашему запросу) и т.п.
//Библиотеки
#include <SoftwareSerial.h>
#include <EEPROM.h>
#include <Wire.h> // Wire.h
#include <OneWire.h>// библиотека для работы с протоколом 1-Wire
#include <DallasTemperature.h>// библиотека для работы с датчиком DS18B20
#define SIM800_TX_PIN 53
#define SIM800_RX_PIN 52
SoftwareSerial gsm(SIM800_TX_PIN,SIM800_RX_PIN);
#define ONE_WIRE_BUS 2 //Датчики по шине 1-wire
// создаём объект для работы с библиотекой OneWire
OneWire oneWire(ONE_WIRE_BUS);
// создадим объект для работы с библиотекой DallasTemperature
DallasTemperature sensors(&oneWire);
// создаём указатель массив для хранения адресов датчиков
DeviceAddress *sensorsUnique;
// количество датчиков на шине
int countSensors;
unsigned long currentMillis = 0;
//переменные для датчиков ТЕ по шине 1-WIRE
long lastUpdateTime1WIRE = 0; // Переменная для хранения времени последнего считывания с датчика
const int TEMP_UPDATE_TIME1WIRE = 5000; // Определяем периодичность проверок датчиков
String STemperature1 = "";
String STemperature2 = "";
String STemperature3 = "";
int StartGSM = 0;
String NBoss = "";
String NBoss1 = "";
String NBoss2 = "";
String NBoss3 = "";
String NBoss4 = "";
String NBoss5 = "";
String NBossNumber = "";
String Temp = "";
int tempZaprosBalansa = 0; // переменная, хранящая метку о запросе каждый день баланса
int tempForWaitSendSmsTE = 0;
long counter = 0;
long timerForSignalGSM = 1000000;
// Переменные для обработки смс +CSQ
int intNumberLevelFirst = 0;
int intNumberLevelSecond = 0;
int IntSignalLevel = 0;
int FlagSignal = 0;
// Переменные для чтения смс
String currStr = "";
String dataSmsN = "";
int flag1 = 0;
int flag2 = 0;
String currStrN = "";
char currSymb = 0;
String dataSms = "";
String dataBalance = "";
//String dataBalanceNumber = "";
String dataBalanceTemp = "";
String val = "";
int ch = 0;
char data = 0;
// Переменные для циклов
int i = 0;
int k = 0;
byte s1; //
byte s2; //
byte s3; //
byte s4; //
byte s5; //
byte s6; //
byte s7; //
byte s8; //
byte s9; //
byte s10; //
byte s11;
String msgBalance = "";
float balance = 0;
int tempBalans = 0; // переменная, хранящая метку о запросе баланса
String textToSend = "";
int Boss = 0;
int BossTemp = 0;
String BalansSim = "Баланс: ";
String HelloNumberIsBoss = "Ваш номер главный: ";
String temp = "";
String _response = ""; // Переменная для хранения ответа модуля
int IntSignalLevelTemp = 0;
byte Temp2;// чтение телефона хозяина
int intUstavkaTE = 0;
int counterClearAddrDataEEprom = 0;
void setup() {
Serial.begin(9600); // Сериал для PC
Serial.println("Start");
gsm.begin(9600); // Сериал для GSM
delay(1000);
sendATCommand("AT+CMGF=1\r", true);// устанавливает текстовый режим смс-сообщенияОК
sendATCommand("AT+IFC=1, 1\r", true);//устанавливает программный контроль потоком передачи данных
sendATCommand("AT+CPBS=\"SM\"\r", true);//открывает доступ к данным телефонной книги SIM-карты
sendATCommand("AT+CNMI=1,2,2,1,0\r", true);// включает оповещение о новых сообщениях, новые сообщения
sendATCommand("AT+GSMBUSY=1\r\n", true);// запрет всех входящих звонков.
sendATCommand("AT+CMGDA=DEL ALL\r\n", true);// команда удалит все сообщения
sendATCommand("AT+CSQ", true); // Проверяем уровень сигнала
// начинаем работу с датчиком DS по шине
sensors.begin();
// выполняем поиск устройств на шине
countSensors = sensors.getDeviceCount();
// Serial.print("Found sensors: ");
// Serial.println(countSensors);
// выделяем память в динамическом массиве под количество обнаруженных сенсоров
sensorsUnique = new DeviceAddress[countSensors];
// делаем запрос на получение адресов датчиков
for (int i = 0; i < countSensors; i++) {
sensors.getAddress(sensorsUnique[i], i);
}
// выводим полученные адреса
for (int i = 0; i < countSensors; i++) {
Serial.print("Device ");
Serial.print(i);
Serial.print(" Address: ");
printAddress(sensorsUnique[i]);
Serial.println();
}
// устанавливаем разрешение всех датчиков в 12 бит
for (int i = 0; i < countSensors; i++) {
sensors.setResolution(sensorsUnique[i], 12);
}
//Конец поиска по шине DS
}
void loop() {
//######### Начало. Если Главного номера нет в EEPROM и запустили систему в первый раз #################
// Удаляем из EEPROM все данные, записываем, что нет номеров и система не стоит на охране, выключаем сирену и маяк
if (EEPROM.read(20) == 0 && counterClearAddrDataEEprom == 0){
RAll();
}
//######### Конец. Если Главного номера нет в EEPROM и запустили систему в первый раз #################
currentMillis = millis();
// Запускаем GSM
if (StartGSM == 0){
gsm.write("AT+CMGF=1\r"); // устанавливает текстовый режим смс-сообщения
delay(300);
}
if (StartGSM == 1){
gsm.write("AT+IFC=1, 1\r"); //устанавливает программный контроль потоком передачи данных
delay(300);
}
if (StartGSM == 2){
gsm.write("AT+CPBS=\"SM\"\r");//открывает доступ к данным телефонной книги SIM-карты
delay(300);
}
if (StartGSM == 3){
gsm.write("AT+CNMI=1,2,2,1,0\r");// включает оповещение о новых сообщениях, новые сообщения
delay(500);
}
if (StartGSM == 4){
gsm.write("AT+GSMBUSY=1\r\n"); // запрет всех входящих звонков.
delay(300);
}
if (StartGSM == 5){
gsm.write("AT+CMGDA=DEL ALL\r\n"); // команда удалит все сообщения
delay(500);
}
if (FlagSignal == 0 && StartGSM == 6){
gsm.println("AT+CSQ");// Проверяем уровень сигнала
delay(800);
}
if (gsm.available()) { //есть данные от GSM модуля
currStr = ""; //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
currStrN = "";
dataBalanceTemp = "";
dataSms = "";
val = "";
flag1 = 0;
flag2 = 0;
while (gsm.available()) { //сохраняем входную строку в переменную val
c:
ch = gsm.read(); //int
// Serial.println(ch);
val += char(ch); // String
data = ch; // char = int
if ('\r' == data) {
currStr = "";
} else if ('\n' != data) {
currStr += String(data);
dataSms = currStr;
}
//+CMT: "+79819998877","","16/04/18,20:25:08+12"
if (data == '+' && flag1 == 0){flag1 = 1;}
if (data == 'C' && flag1 == 1){flag1 = 2;}
if (data == 'M' && flag1 == 2){flag1 = 3;}
if (data == 'T' && flag1 == 3){flag1 = 4;}
if (data == '+' && flag1 == 4){currStrN = "";flag1 = 5;}
if (data != '"' && flag1 == 5){currStrN += String(data); dataSmsN = currStrN;}
if (data == '"' && flag1 == 5){flag1 = 6;}
//+CUSD: 0, "Balance:117,27r ", 15
if (data == 'U' && flag1 == 2){flag2 = 3;}
if (data == 'S' && flag2 == 3){flag2 = 4;}
if (data == 'D' && flag2 == 4){flag2 = 5;}
if (data == ':' && flag2 == 5){flag2 = 6;}
if (data == '"' && flag2 == 6){dataBalanceTemp = ""; flag2 = 7; goto c;}
if (data != '"' && flag2 == 7){dataBalanceTemp += String(data); dataBalance = dataBalanceTemp;}
if (data == '"' && flag2 == 7){flag2 = 8;}
}
// Смотрим данные полученные //режим кодировки СМС - обычный (для англ.)
if (val.indexOf("+CMGF") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 1;
}
}
// Смотрим данные полученные //устанавливает программный контроль потоком передачи данных
if (val.indexOf("+IFC") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 2;
}
}
// Смотрим данные полученные //открывает доступ к данным телефонной книги SIM-карты
if (val.indexOf("+CPBS") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 3;
}
}
// Смотрим данные полученные //включает оповещение о новых сообщениях, новые сообщения
if (val.indexOf("+CNMI") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 4;
}
}
// Смотрим данные полученные //запрет всех входящих звонков.
if (val.indexOf("+GSMBUSY") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 5;
}
}
// Смотрим данные полученные //команда удалит все сообщения
if (val.indexOf("+CMGDA") > -1){
if (dataSms.indexOf("OK") > -1) {
StartGSM = 6;
}
}
// Смотрим данные полученные от модуля +CSQ: 22,0
if (val.indexOf("+CSQ") > -1) {
for (i=0; i<=20; i++){
if (val[i] == 58) {
intNumberLevelFirst = val[i+2]-48;
if (val[i+3] == 44){ intNumberLevelSecond = 0;}
if (val[i+3] != 44){ intNumberLevelSecond = val[i+3]-48;}
if (val[i+3] == 44){IntSignalLevel = intNumberLevelFirst;}
if (val[i+3] != 44){IntSignalLevel = (intNumberLevelFirst*10) + intNumberLevelSecond;}
}
}
if (IntSignalLevel == 99 || IntSignalLevel == 0){
FlagSignal = 0; StartGSM = 0;
// digitalWrite(ledRed, HIGH);
}
if (IntSignalLevel <=32 && IntSignalLevel !=0){
FlagSignal = 1;
}
}
// Смотрим данные полученные от модуля пришло смс
if (val.indexOf("+CMTI:") > -1) { // +CMTI: "SM",
StartGSM = 0;
}
// Смотрим данные полученные от модуля, Получили смс с балансом, теперь отсылаем
if (val.indexOf("+CUSD:") > -1) { // Пришло уведомление о USSD-ответе
if (val.indexOf("\"") > -1) { // Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
msgBalance = val.substring(val.indexOf("\"") + 2); // Получаем непосредственно текст
msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
balance = getFloatFromString(msgBalance); // Извлекаем информацию о балансе
if (tempBalans == 1) {
Boss = BossTemp;
textToSend = BalansSim;
textToSend += (String)balance;
textToSend += "руб";
smsSendAlarm(textToSend);
tempBalans = 0;
BossTemp = 0;
}
if ((int)balance > 400){
tempForWaitSendSmsTE = 0;
// ничего не делаем
}else if (tempZaprosBalansa == 1){
if ((int)balance == 0){
tempZaprosBalansa = 2;
GoBalans();
}else {
Boss = 75;
textToSend = BalansSim;
textToSend += "меньше 400руб, ваш баланс: ";
textToSend += (String)balance;
smsSendAlarm(textToSend);
tempZaprosBalansa = 0;
tempForWaitSendSmsTE = 1;
}
}
}
}
//----------------------- определение факта приема СМС и сравнение номера(ов) с заданным(и)
if (val.indexOf("+CMT") > -1) {
// Регистрация хозяина
if (dataSms.indexOf("Register") > -1 && EEPROM.read(0) == 3) {
if (EEPROM.read(20) == 0){
k=1;
Temp = "";
for (i=20; i<=30; i++){ // записываем с 20 по 30 ячейку номер телефона главного
EEPROM.write(i,dataSmsN[k]-48);
Temp += dataSmsN[k]-48; // записываем в Temp номер телефона из прешедшей смс
k++;
}
EEPROM.write(0,0);
textToSend = "";
Serial1.print("Register"); Serial1.print(Temp);Serial1.println();
Boss = 1;
textToSend = HelloNumberIsBoss;
textToSend += Temp;
smsSendAlarm(textToSend);
goto Exit;
}
Exit:
ClearDataIn();
delay(1);
}
// Проверяем номер телефона хозяина
if (dataSmsN !=""){
Boss = 0;
for (i=1; i<=11; i++){
Temp += dataSmsN[i]-48; // записываем в Temp номер телефона из прешедшей смс
}
ReadNumber(1);// читаем номер хозяина из EEPROM
if (Temp == NBoss){// Сравниваем номер прешедшей смс с номером из памяти
Boss = 1;
NBoss = "";
goto exitWriteNumber;
}
ReadNumber(2);// читаем номер хозяина из EEPROM
if (Temp == NBoss1){// Сравниваем номер прешедшей смс с номером из памяти
Boss = 2;
NBoss1 = "";
goto exitWriteNumber;
}
ReadNumber(3);// читаем номер хозяина из EEPROM
if (Temp == NBoss2){// Сравниваем номер прешедшей смс с номером из памяти
Boss = 3;
NBoss2 = "";
goto exitWriteNumber;
}
ReadNumber(4);// читаем номер хозяина из EEPROM
if (Temp == NBoss3){// Сравниваем номер прешедшей смс с номером из памяти
Boss = 4;
NBoss3 = "";
goto exitWriteNumber;
}
ReadNumber(5);// читаем номер хозяина из EEPROM
if (Temp == NBoss4){// Сравниваем номер прешедшей смс с номером из памяти
Boss = 5;
NBoss4 = "";
goto exitWriteNumber;
}
ReadNumber(6);// читаем номер хозяина из EEPROM
if (Temp == NBoss5){// Сравниваем номер прешедшей смс с номером из памяти
Boss = 6;
NBoss5 = "";
goto exitWriteNumber;
}
exitWriteNumber:
delay(1);
}
// Помощь, вывод меню в смс
if (dataSms.indexOf("Help") > -1){
if (Boss == 1 || Boss == 2 || Boss == 3 || Boss == 4 || Boss == 5 || Boss == 6){
temp = "Hi";//25
temp += "\r\n";//29
temp += "Balans";
smsSendAlarm(temp);
temp = ""; // очищаем переменную
}
}
// Информация
if (dataSms.indexOf("Info") > -1){
if (Boss == 1 || Boss == 2 || Boss == 3 || Boss == 4 || Boss == 5 || Boss == 6){
Boss = 77;
textToSend = "Инфа";
textToSend += "\r\n";
textToSend += "Сигнал:";
IntSignalLevelTemp = map(IntSignalLevel, 0, 32, 0, 100);
textToSend += String(IntSignalLevelTemp);
textToSend += "%";
textToSend += "\r\n";
textToSend += "Темп:";
textToSend += STemperature1;
textToSend += "'С";
smsSendAlarm(textToSend);textToSend = "";
}
}
// Запрос баланса, после получения ответа - отправка обратно на номер
if (dataSms.indexOf("Balans") > -1) { // Запрос баланса
if (Boss == 1 || Boss == 2 || Boss == 3 || Boss == 6){
BossTemp = Boss;
tempBalans = 1;
GoBalans();
}
}
}//+cmt
ClearDataIn();
}
//Начало чтения для датчиков по шине 1-Wire
if (currentMillis - lastUpdateTime1WIRE > TEMP_UPDATE_TIME1WIRE)
{
// goto ENDWire;
lastUpdateTime1WIRE = currentMillis;
if (countSensors >= 1) {
// переменная для хранения температуры
float temperature[10];
// отправляем запрос на измерение температуры всех сенсоров
sensors.requestTemperatures();
// считываем данные из регистра каждого датчика по очереди
for (i = 0; i < countSensors; i++) {
temperature[i] = sensors.getTempCByIndex(i);
if (i == 0) {
Serial.print("TE 1: ");
Serial.println(temperature[0]);
STemperature1 = temperature[0];
}
// if (i == 1) {
// Serial.print("TE 2: ");
// Serial.println(temperature[1]);
// STemperature2 = temperature[1];
// }
// if (i == 2) {
// Serial.print("TE 3: ");
// Serial.println(temperature[2]);
// STemperature3 = temperature[2];
// }
}
}
}//Конец для датчиков 1-Wire
}
String sendATCommand(String cmd, bool waiting) {
String _resp = ""; // Переменная для хранения результата
// Serial.print("CMD: "); // Дублируем команду в монитор порта
// Serial.println(cmd); // Дублируем команду в монитор порта
gsm.println(cmd); // Отправляем команду модулю
if (waiting) { // Если необходимо дождаться ответа...
_resp = waitResponse(); // ... ждем, когда будет передан ответ
// Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
if (_resp.startsWith(cmd)) { // Убираем из ответа дублирующуюся команду
_resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
}
// Serial.println(_resp); // Дублируем ответ в монитор порта
}
return _resp; // Возвращаем результат. Пусто, если проблема
}
// Функция ожидания ответа и возврата полученного результата
String waitResponse() { // Функция ожидания ответа и возврата полученного результата
String _resp = ""; // Переменная для хранения результата
long _timeout = millis() + 10000; // Переменная для отслеживания таймаута (10 секунд)
while (!gsm.available() && millis() < _timeout) {}; // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
if (gsm.available()) { // Если есть, что считывать...
_resp = gsm.readString(); // ... считываем и запоминаем
}
else { // Если пришел таймаут, то...
// Serial.println("Timeout..."); // ... оповещаем об этом и...
}
return _resp; // ... возвращаем результат. Пусто, если проблема
}
// Обработка смс цифр из сообщения - для парсинга баланса из USSD-запроса
float getFloatFromString(String str) { // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
bool flag = false;
String result = "";
str.replace(",", "."); // Если в качестве разделителя десятичных используется запятая - меняем её на точку.
for (int i = 0; i < str.length(); i++) {
if (isDigit(str[i]) || (str[i] == (char)46 && flag)) { // Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания),
if (result == "" && i > 0 && (String)str[i - 1] == "-") { // Нельзя забывать, что баланс может быть отрицательным
result += "-"; // Добавляем знак в начале
}
result += str[i]; // начинаем собирать их вместе
if (!flag) flag = true; // Выставляем флаг, который указывает на то, что сборка числа началась.
}
else { // Если цифры закончились и флаг говорит о том, что сборка уже была,
if (str[i] != (char)32) { // Если порядок числа отделен пробелом - игнорируем его, иначе...
if (flag) break; // ...считаем, что все.
}
}
}
return result.toFloat(); // Возвращаем полученное число.
}
//процедура отправки СМС
void smsSendAlarm(String text) {
textToSend = "";
//Главный номер
if (EEPROM.read(20) == 7 && Boss == 1 || EEPROM.read(20) == 7 && Boss == 75 || EEPROM.read(20) == 7 && Boss == 74 || EEPROM.read(20) == 7 && Boss == 77 || EEPROM.read(20) == 7 && Boss == 80 || EEPROM.read(20) == 7 && Boss == 82 || EEPROM.read(20) == 7 && Boss == 83){
ReadNumber(1);
sendSms(text, NBoss);
}
//User1 31-41,
if (EEPROM.read(31) == 7 && Boss == 2 || EEPROM.read(31) == 7 && Boss == 75 || EEPROM.read(31) == 7 && Boss == 83 || EEPROM.read(31) == 7 && Boss == 74){
ReadNumber(2);
sendSms(text, NBoss1);
}
//User2 42-52,
if (EEPROM.read(42) == 7 && Boss == 3 || EEPROM.read(42) == 7 && Boss == 75 || EEPROM.read(42) == 7 && Boss == 83 || EEPROM.read(42) == 7 && Boss == 74){
ReadNumber(3);
sendSms(text, NBoss2);
}
//User3 53-63
if (EEPROM.read(53) == 7 && Boss == 4 || EEPROM.read(53) == 7 && Boss == 82 || EEPROM.read(53) == 7 && Boss == 83){
ReadNumber(4);
sendSms(text, NBoss3);
}
//User4 64-74
if (EEPROM.read(64) == 7 && Boss == 5 || EEPROM.read(64) == 7 && Boss == 82 || EEPROM.read(64) == 7 && Boss == 83){
ReadNumber(5);
sendSms(text, NBoss4);
}
//User5 75-85
if (EEPROM.read(75) == 7 && Boss == 6 || EEPROM.read(75) == 7 && Boss == 75 || EEPROM.read(75) == 7 && Boss == 77 || EEPROM.read(75) == 7 && Boss == 80 || EEPROM.read(75) == 7 && Boss == 82 || EEPROM.read(75) == 7 && Boss == 83){
ReadNumber(6);
sendSms(text, NBoss5);
}
text = "";
NBoss = "";
NBoss1 = "";
NBoss2 = "";
NBoss3 = "";
NBoss4 = "";
NBoss5 = "";
sendATCommand("AT+CMGDA=DEL ALL\r\n", true);
sendATCommand("AT+CMGD=4", true);
sendATCommand("AT+CMGF=1", true); // устанавливает текстовый режим смс-сообщения
Boss = 0;
}
//Отправка смс о балансе
void GoBalans(){
sendATCommand("AT+CUSD=1,\"#100#\"", true);
}
//Начинаем поиск номера
void ReadNumber(int numberN){
if (numberN == 1){
NBoss = "";
SearchN(20, 30);
NBoss = NBoss;
return NBoss;
}
if (numberN == 2){
NBoss = "";
SearchN(31, 41);
NBoss1 = NBoss;
NBoss = "";
return NBoss1;
}
if (numberN == 3){
NBoss = "";
SearchN(42, 52);
NBoss2 = NBoss;
NBoss = "";
return NBoss2;
}
if (numberN == 4){
NBoss = "";
SearchN(53, 63);
NBoss3 = NBoss;
NBoss = "";
return NBoss3;
}
if (numberN == 5){
NBoss = "";
SearchN(64, 74);
NBoss4 = NBoss;
NBoss = "";
return NBoss4;
}
if (numberN == 6){
NBoss = "";
SearchN(75, 85);
NBoss5 = NBoss;
NBoss = "";
return NBoss5;
}
}
//ищем номер в EEPROM
void SearchN(int firstI, int secondI){
for (i=firstI;i<=secondI;i++){
Temp2 = EEPROM.read(i);
if (Temp2 == 0){NBoss += "0";}
if (Temp2 == 1){NBoss += "1";}
if (Temp2 == 2){NBoss += "2";}
if (Temp2 == 3){NBoss += "3";}
if (Temp2 == 4){NBoss += "4";}
if (Temp2 == 5){NBoss += "5";}
if (Temp2 == 6){NBoss += "6";}
if (Temp2 == 7){NBoss += "7";}
if (Temp2 == 8){NBoss += "8";}
if (Temp2 == 9){NBoss += "9";}
}
return NBoss;
Temp2 = 0;
}
// Удаление всех настроек и номера из памяти EEPROM
void RAll(){
ClearAddresDataEEPROM();
WriteEEPROM(); // Записываем значения по умолчанию
Info(); // Вывод в Serial Инфу
counterClearAddrDataEEprom = 1;
}
// Очистка EEPROM
void ClearAddresDataEEPROM(){
for (i=0; i<=100; i++){
EEPROM.write(i,0);
}
}
void WriteEEPROM(){
//0=48-48
//1=49-48
//2=50-48
//3=51-48
//4=52-48
//5=53-48
//6=54-48
//7=55-48
//8=56-48
//9=57-48
EEPROM.write(0,3); //состоянии системы = 3(в режиме регистации)
// EEPROM.write(75,3);//Уставка температуры, первая цифра
// EEPROM.write(76,0);//Уставка температуры, вторая цифра
// intUstavkaTE = EEPROM.read(75) * 10;
// intUstavkaTE = intUstavkaTE + EEPROM.read(76);
}
void Info(){
Serial.println("Info");
delay(1);
// Состояние регистрации системы
Serial.print("State system register or not: ");
Serial.println(EEPROM.read(0));
// 20-30 - Храним номер №1 Хозяина
Serial.print("Number phone 1: ");
for (i=20; i<=30; i++){
Serial.print(EEPROM.read(i));
}
Serial.println("");
// 31-41 - Храним номер №2
Serial.print("Number phone 2: ");
for (i=31; i<=41; i++){
Serial.print(EEPROM.read(i));
}
Serial.println("");
// 42-52 - Храним номер №3
Serial.print("Number phone 3: ");
for (i=42; i<=52; i++){
Serial.print(EEPROM.read(i));
}
Serial.println("");
// 53-63 - Храним номер №4
Serial.print("Number phone 4: ");
for (i=53; i<=63; i++){
Serial.print(EEPROM.read(i));
}
Serial.println("");
// 64-74 - Храним номер №5
Serial.print("Number phone 5: ");
for (i=64; i<=74; i++){
Serial.print(EEPROM.read(i));
}
Serial.println("");
// 75-85 - Храним номер №6
Serial.print("Number phone 6: ");
for (i=75; i<=85; i++){
Serial.print(EEPROM.read(i));
}
Serial.println("");
}
// Очистка временных переменных
void ClearDataIn(){
Temp = "";
// Boss = 0;
currStr = "";
currStrN = "";
dataBalanceTemp = "";
dataSms = "";
dataSmsN = "";
// dataBalance = "";
val = "";
flag1 = 0;
flag2 = 0;
}
// Отправка смс
void sendSms(String textForSend, String Number){
sendSMSinPDU(Number, textForSend);
do {
_response = sendATCommand("AT+CLIP=1", true); // Включаем АОН
_response.trim(); // Убираем пробельные символы в начале и конце
} while (_response != "OK"); // Не пускать дальше, пока модем не вернет ОК
}
void sendSMSinPDU(String phone, String message)
{
// Serial.println("Отправляем сообщение: " + message);
// ============ Подготовка PDU-пакета =============================================================================================
// В целях экономии памяти будем использовать указатели и ссылки
String *ptrphone = ☎ // Указатель на переменную с телефонным номером
String *ptrmessage = &message; // Указатель на переменную с сообщением
String PDUPack; // Переменная для хранения PDU-пакета
String *ptrPDUPack = &PDUPack; // Создаем указатель на переменную с PDU-пакетом
int PDUlen = 0; // Переменная для хранения длины PDU-пакета без SCA
int *ptrPDUlen = &PDUlen; // Указатель на переменную для хранения длины PDU-пакета без SCA
getPDUPack(ptrphone, ptrmessage, ptrPDUPack, ptrPDUlen); // Функция формирующая PDU-пакет, и вычисляющая длину пакета без SCA
// Serial.println("PDU-pack: " + PDUPack);
// Serial.println("PDU length without SCA:" + (String)PDUlen);
// ============ Отправка PDU-сообщения ============================================================================================
sendATCommand("AT+CMGF=0", true); // Включаем PDU-режим
sendATCommand("AT+CMGS=" + (String)PDUlen, true); // Отправляем длину PDU-пакета
sendATCommand(PDUPack + (String)((char)26), true); // После PDU-пакета отправляем Ctrl+Z
PDUPack = "";
message = "";
*ptrphone = "";
*ptrmessage = "";
*ptrPDUlen = "";
}
void getPDUPack(String *phone, String *message, String *result, int *PDUlen)
{
// Поле SCA добавим в самом конце, после расчета длины PDU-пакета
*result += "01"; // Поле PDU-type - байт 00000001b
*result += "00"; // Поле MR (Message Reference)
*result += getDAfield(phone, true); // Поле DA
*result += "00"; // Поле PID (Protocol Identifier)
*result += "08"; // Поле DCS (Data Coding Scheme)
//*result += ""; // Поле VP (Validity Period) - не используется
String msg = StringToUCS2(*message); // Конвертируем строку в UCS2-формат
*result += byteToHexString(msg.length() / 2); // Поле UDL (User Data Length). Делим на 2, так как в UCS2-строке каждый закодированный символ представлен 2 байтами.
*result += msg;
*PDUlen = (*result).length() / 2; // Получаем длину PDU-пакета без поля SCA
*result = "00" + *result; // Добавляем поле SCA
}
String getDAfield(String *phone, bool fullnum) {
String result = "";
for (int i = 0; i <= (*phone).length(); i++) { // Оставляем только цифры
if (isDigit((*phone)[i])) {
result += (*phone)[i];
}
}
int phonelen = result.length(); // Количество цифр в телефоне
if (phonelen % 2 != 0) result += "F"; // Если количество цифр нечетное, добавляем F
for (int i = 0; i < result.length(); i += 2) { // Попарно переставляем символы в номере
char symbol = result[i + 1];
result = result.substring(0, i + 1) + result.substring(i + 2);
result = result.substring(0, i) + (String)symbol + result.substring(i);
}
result = fullnum ? "91" + result : "81" + result; // Добавляем формат номера получателя, поле PR
result = byteToHexString(phonelen) + result; // Добавляем длину номера, поле PL
return result;
}
// =================================== Блок кодирования строки в представление UCS2 =================================
String StringToUCS2(String s)
{
String output = ""; // Переменная для хранения результата
for (int k = 0; k < s.length(); k++) { // Начинаем перебирать все байты во входной строке
byte actualChar = (byte)s[k]; // Получаем первый байт
unsigned int charSize = getCharSize(actualChar); // Получаем длину символа - кличество байт.
// Максимальная длина символа в UTF-8 - 6 байт плюс завершающий ноль, итого 7
char symbolBytes[charSize + 1]; // Объявляем массив в соответствии с полученным размером
for (int i = 0; i < charSize; i++) symbolBytes[i] = s[k + i]; // Записываем в массив все байты, которыми кодируется символ
symbolBytes[charSize] = '\0'; // Добавляем завершающий 0
unsigned int charCode = symbolToUInt(symbolBytes); // Получаем DEC-представление символа из набора байтов
if (charCode > 0) { // Если все корректно преобразовываем его в HEX-строку
// Остается каждый из 2 байт перевести в HEX формат, преобразовать в строку и собрать в кучу
output += byteToHexString((charCode & 0xFF00) >> 8) +
byteToHexString(charCode & 0xFF);
}
k += charSize - 1; // Передвигаем указатель на начало нового символа
if (output.length() >= 280) break; // Строка превышает 70 (4 знака на символ * 70 = 280) символов, выходим
}
return output; // Возвращаем результат
}
String byteToHexString(byte i) { // Функция преобразования числового значения байта в шестнадцатиричное (HEX)
String hex = String(i, HEX);
if (hex.length() == 1) hex = "0" + hex;
hex.toUpperCase();
return hex;
}
unsigned int getCharSize(unsigned char b) { // Функция получения количества байт, которыми кодируется символ
// По правилам кодирования UTF-8, по старшим битам первого октета вычисляется общий размер символа
// 1 0xxxxxxx - старший бит ноль (ASCII код совпадает с UTF-8) - символ из системы ASCII, кодируется одним байтом
// 2 110xxxxx - два старших бита единицы - символ кодируется двумя байтами
// 3 1110xxxx - 3 байта и т.д.
// 4 11110xxx
// 5 111110xx
// 6 1111110x
if (b < 128) return 1; // Если первый байт из системы ASCII, то он кодируется одним байтом
// Дальше нужно посчитать сколько единиц в старших битах до первого нуля - таково будет количество байтов на символ.
// При помощи маски, поочереди исключаем старшие биты, до тех пор пока не дойдет до нуля.
for (int i = 1; i <= 7; i++) {
if (((b << i) & 0xFF) >> 7 == 0) {
return i;
}
}
return 1;
}
unsigned int symbolToUInt(const String& bytes) { // Функция для получения DEC-представления символа
unsigned int charSize = bytes.length(); // Количество байт, которыми закодирован символ
unsigned int result = 0;
if (charSize == 1) {
return bytes[0]; // Если символ кодируется одним байтом, сразу отправляем его
}
else {
unsigned char actualByte = bytes[0];
// У первого байта оставляем только значимую часть 1110XXXX - убираем в начале 1110, оставляем XXXX
// Количество единиц в начале совпадает с количеством байт, которыми кодируется символ - убираем их
// Например (для размера 2 байта), берем маску 0xFF (11111111) - сдвигаем её (>>) на количество ненужных бит (3 - 110) - 00011111
result = actualByte & (0xFF >> (charSize + 1)); // Было 11010001, далее 11010001&(11111111>>(2+1))=10001
// Каждый следующий байт начинается с 10XXXXXX - нам нужны только по 6 бит с каждого последующего байта
// А поскольку остался только 1 байт, резервируем под него место:
result = result << (6 * (charSize - 1)); // Было 10001, далее 10001<<(6*(2-1))=10001000000
// Теперь у каждого следующего бита, убираем ненужные биты 10XXXXXX, а оставшиеся добавляем к result в соответствии с расположением
for (int i = 1; i < charSize; i++) {
actualByte = bytes[i];
if ((actualByte >> 6) != 2) return 0; // Если байт не начинается с 10, значит ошибка - выходим
// В продолжение примера, берется существенная часть следующего байта
// Например, у 10011111 убираем маской 10 (биты в начале), остается - 11111
// Теперь сдвигаем их на 2-1-1=0 сдвигать не нужно, просто добавляем на свое место
result |= ((actualByte & 0x3F) << (6 * (charSize - 1 - i)));
// Было result=10001000000, actualByte=10011111. Маской actualByte & 0x3F (10011111&111111=11111), сдвигать не нужно
// Теперь "пристыковываем" к result: result|11111 (10001000000|11111=10001011111)
}
return result;
}
}
// функция вывода адреса датчика
void printAddress(DeviceAddress deviceAddress){
for (uint8_t i = 0; i < 8; i++){
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
Строка 618 и далее - это еще повезло, что цифр в арифметике всего 10. Страшно представить, сколько понадобилось бы условий, чтобы отыскать в тексте каждую букву кириллицы и латиницы обоих регистров.
Стамбулов, вы про массивы и циклы не слыхали?
ГРАНДИОЗНО!!!!!!!!! Я только в руки взял SIM800L - пробую разобраться, ранее так же с нуля освоил NRF24 (делал на нем радиоуправление строительного крана - самоделка в помощь на моей стройке)
По SIM800L - пока тренируюсь с терминала, чтоб в дальнейшем проект отработат в Atmel Studio 7
возник вопрос по передаче смс - в начале настройка:
AT+CMGF=1\r\n - установка текстового режима.
AT+CSMP=17,167,0,0\r\n - установка параметров текстового режима.
AT+CMGS="+7XXXXXXXXXX"\r\n - номер получателя SMS.
>\r\n - ответ модуля (модуль готов принять текст SMS). -----------А ВОТ ТУТ Я ЗАВИС - отправляю текст ( латиница) - результат - ноль,
к примеру нужно послать "HELLO" - как это должно выглядель ? почти все варианты уже испробовал - не могу верно понять рекомендацию :
{ TEXT - ввод и отправка текста в модуль. Как только в тексте встретится символ <0x1A>, сообщение будет отправлено. Если в тексте встретится символ <0x1B>, сообщение не будет отправлено.
Примечание:
- В текстовом режиме можно добавлять в текст SMS сообщения символы переноса строки \r\n., в т.ч. перед символом подтверждающим/запрещающим отправку SMS.} - это
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 12
SoftwareSerial SIM800(8, 9);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
const String MAIN_PHONE = "+71234567890"; // Основной номер
const String WHITE_LIST = "+71234567890; +79999999999; +79888888888"; // Включить основной и дополнительный/е телефоны в белый список
const String TEXT_USSD_BALANCE_QUERY = "AT+CUSD=1,\"*100#\""; // Отправляет ТЕКСТОВЫЙ ответ, а не PDU-пакет, альтернативный запрос - "#100#"
const String BALANCE_TEXT_QUERY = "Balance"; // Содержание СМС для получения текстового ответа на запрос о балансе
const String TEMPERATURE_QUERY = "Temperature"; // Содержание СМС для получения ответа на запрос о температуре
const String CURRENCY = " BYN"; // Текстовое представление валюты
const float BALANCE_TRESHOLD = 15.0; // Нижнее пороговое значение температуры
const float TEMPERATURE_TRESHOLD = 24.0; // Нижнее пороговое значение баланса
String sendATCommand(const String& cmd, bool waiting) {
String response = "";
Serial.println(cmd);
SIM800.println(cmd);
if (waiting) {
response = waitAndReturnResponse();
if (response.startsWith(cmd)) {
response = response.substring(response.indexOf("\r", cmd.length()) + 2);
}
Serial.println(response);
}
return response;
}
String waitAndReturnResponse() {
String response = "";
int64_t timeout = millis() + 10000;
while (!SIM800.available() && millis() < timeout) {};
if (SIM800.available()) {
response = SIM800.readString();
}
else {
Serial.println("Timeout...");
}
return response;
}
void sendSMS(const String& phone, const String& message) {
sendATCommand("AT+CMGS=\"" + phone + "\"", true);
sendATCommand(message + (String)((char)26), true);
}
void checkBalance(const String& number) {
sendATCommand(TEXT_USSD_BALANCE_QUERY, true);
String answer = waitAndReturnResponse();
answer.trim();
Serial.println("\r\nBalans SIM karty: " + (String)extractBalanceFromString(answer));
sendSMS(number, "\r\nBalans SIM karty: " + (String)extractBalanceFromString(answer) + CURRENCY + ".");
}
float getFloatFromString(String str) { // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
bool flag = false;
String result = "";
str.replace(",", "."); // Если в качестве разделителя десятичных используется запятая - меняем её на точку.
for (size_t i = 0; i < str.length(); ++i) {
if (isDigit(str[i]) || (str[i] == (char)46 && flag)) { // Если начинается группа цифр (при этом на точку без цифр не обращаем внимания),
if (i != 0 && result == "" && (String)str[i - 1] == "-") { // Нельзя забывать, что баланс может быть отрицательным
result += "-"; // Добавляем знак в начале
}
result += str[i]; // Начинаем собирать их вместе
if (!flag) {
flag = true; // Выставляем флаг, который указывает на то, что сборка числа началась.
}
}
else if (str[i] != (char)32 && flag) {
break;
}
}
return result.toFloat(); // Возвращаем полученное число
}
void parseSMS(String msg) { // Парсим SMS
String msgheader = ""; // Переменная под звонивший телефона для анализа
String msgbody = ""; // Переменная под SMS
String msgphone = ""; // Переменная под номер телефона
msg = msg.substring(msg.indexOf("+CMGR: "));
msgheader = msg.substring(0, msg.indexOf("\r")); // Получаем звонивший телефон
msgbody = msg.substring(msgheader.length() + 2);
msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK")); // Получаем текст полученной SMS
msgbody.trim(); // Обрезаем начальные или концевые символы
int firstIndex = msgheader.indexOf("\",\"") + 3;
int secondIndex = msgheader.indexOf("\",\"", firstIndex);
msgphone = msgheader.substring(firstIndex, secondIndex);
if (WHITE_LIST.indexOf(msgphone) != -1) { // Если телефон в белом списке, то...
if (msgbody == BALANCE_TEXT_QUERY) {
checkBalance(msgphone);
}
else if (msgbody == TEMPERATURE_QUERY) {
sendSMS(msgphone, "Sensor temperature: " +
String(obtainTemperature()) + " C.");
}
Serial.println("Phone: " + msgphone); // Выводим номер телефона
Serial.println("Message: " + msgbody); // Выводим текст SMS
}
else if (msgphone.length()) {
Serial.println("Unknown phone number: " + msgphone);
Serial.println("Message: " + msgbody);
}
}
void checkNewMessages() {
static bool hasmsg = false;
String response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true); // Отправляем запрос чтения непрочитанных сообщений
if (response.indexOf("+CMGL: ") >= 0) { // Если есть хоть одно, получаем его индекс
int msgIndex = response.substring(response.indexOf("+CMGL: ") + 7,
response.indexOf("\"REC UNREAD\"",
response.indexOf("+CMGL: ")) - 1).toInt();
response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true); // Пробуем получить текст SMS по индексу
response.trim(); // Убираем пробелы в начале/конце
if (response.endsWith("OK")) { // Если ответ заканчивается на "ОК"
if (!hasmsg) {
hasmsg = true; // Ставим флаг наличия сообщений для удаления
}
sendATCommand("AT+CMGR=" + (String)msgIndex, true); // Делаем сообщение прочитанным
sendATCommand("\n", true); // Перестраховка - вывод новой строки
parseSMS(response); // Отправляем текст сообщения на обработку
}
}
else {
if (hasmsg == true) {
sendATCommand("AT+CMGDA=\"DEL READ\"", true); // Удаляем все прочитанные сообщения
hasmsg = false;
}
}
}
void modemQueryAndResponse() {
if (SIM800.available()) { // Если модем что-то получил...
String data = waitAndReturnResponse(); // Получаем ответ для модема для анализа
data.trim(); // Убираем лишние пробелы в начале и конце
parseSMS(data);
Serial.println(data); // Если нужно, выводим в монитор порта
if (data.startsWith("+CUSD:")) { // Пришло уведомление об USSD-ответе
if (data.indexOf("\"") > -1) { // Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
float balance = extractBalanceFromString(data);
Serial.println("\r\nBalans SIM karty: " + (String)balance + CURRENCY + ".");
}
}
}
else if (Serial.available()) { // Ожидаем команды по Serial...
SIM800.write(Serial.read()); // ... и отправляем полученную команду модему
}
}
float obtainTemperature() {
sensors.requestTemperatures();
return sensors.getTempCByIndex(0);
}
void tresholdTemperature(float current_temperature) {
static bool flag = 1;
if (current_temperature < TEMPERATURE_TRESHOLD && flag) {
sendSMS(MAIN_PHONE, "Temperature is currently below " + String(TEMPERATURE_TRESHOLD) +
" C and equal to " + String(current_temperature) + " C.");
flag = 0;
}
else if (current_temperature >= TEMPERATURE_TRESHOLD && !flag) {
flag = 1;
}
}
float extractBalanceFromString(const String& response) {
String msgBalance = response.substring(response.indexOf("\"") + 2);
msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
return getFloatFromString(msgBalance);
}
void balanceChecking() {
static bool flag = 1;
sendATCommand(TEXT_USSD_BALANCE_QUERY, true);
String answer = waitAndReturnResponse();
answer.trim();
float balance = extractBalanceFromString(answer);
Serial.println("Balance is " + String(balance));
if (balance < BALANCE_TRESHOLD && flag) {
sendSMS(MAIN_PHONE, "Balance is below " + String(BALANCE_TRESHOLD) +
CURRENCY + " and equal to " + String(balance) + CURRENCY + ".");
flag = 0;
}
else if (balance >= BALANCE_TRESHOLD && !flag) {
flag = 1;
}
}
void setup() {
Serial.begin(9600);
SIM800.begin(9600);
sensors.begin();
sensors.requestTemperatures();
Serial.println("Start!");
sendATCommand("AT", true);
sendATCommand("AT+CMGDA=\"DEL ALL\"", true);
sendATCommand("AT+CLIP=1", true);
sendATCommand("AT+CMGF=1;&W", true);
}
void loop() {
static int64_t balance_check_timer = 0;
static int64_t temperature_check_timer = 0;
static int64_t new_message_check_timer = 0;
modemQueryAndResponse();
if (abs(millis() - new_message_check_timer) >= 5000) {
checkNewMessages();
new_message_check_timer = millis();
}
if (abs(millis() - temperature_check_timer) >= 10000) {
tresholdTemperature(obtainTemperature());
temperature_check_timer = millis();
}
if (abs(millis() - balance_check_timer) >= 300000) {
balanceChecking();
balance_check_timer = millis();
}
}
Вот версия скетча для температурного датчика, отправляет СМС при снижении баланса, температуры ниже определенного уровня, также можно по запросу получить эти параметры в ответном СМС.
Приношу свои извинения andyparker!
Это и его код тоже.
Он вложил в него очень большой труд.
Его полезные советы помогли оживить устройство.
Теперь оно стабильно работает!!!
Общий вид контроллера со снятой крышкой.
В корпусе установлен модуль питания ~220v -> 5V 3A.
Мощности модуля питания достаточно для питания ARDUINO Nano и модема SIM800L.
Поскольку питание каждого из модулей осуществляется от одного источника +5В, а SIM800L требует 4В, то запитка последнего осуществляется через 2 последовательно включенных диода, рассчитанных на ток 2 А.
Параллельно выводу питания SIM800L подключены 4 электролитических конденсатора 1000 мкФ х 6.3 В.
В этом случае обеспечивается стабильная связь SIM800L с базовой станцией.
Все протестировано с помощью АТ команд. Модуль подтвердил исправность и стабильную работу.
Содержимое скетча для тестирования не привожу, поскольку подобное было рассмотрено на этом форуме.
-
Вот тут начались танцы с бубном...
Признаком отказа системы отопления является падение температуры трубы для вывода топочных газов.
При штатном режиме работы отопления эта температура изменяется в диапазоне +45 - +65 °С.
Температура измеряется с помощью DS 18b20. Проблем кодом не оказалось...
По запросу текущую температуру получаю СМС -кой на мой телефон.
Поскольку домик находится в 150 км от Минска, то возникла необходимость проверка текущего баланса на счету. Приведенный выше скетч с этой задачей справляется.
Должен сказать, что приведенные выше тексты написаны не мною. Эти тексты взяты на Codius.ru и мною адаптированы под решаемую задачу. Должен сказать о хорошем качестве выложенной информации на этом сайте. Все выложенные примеры работоспособны.
Эти скетчи каждый сам по себе работают.
Первый скетч возвращает посланное в контроллер сообщение на телефон.
Второй скетч высылает баланс, актуальный в данный момент времени.
Попытки все объединить в один скетч к успеху не привели.
К тому же нужно прописать реагирование на 2 ситуации - снижение температуры ниже 40 °С и наступление момента отрицательного баланса. Белорусский МТС позволяет иметь небольшой отрицательный баланс.
Прошу сообщество оказать мне помощь в решении проблемы. Нужны советы и работающие примеры.
В принципе с этой задачей могу справиться сам. Но возраст почти 70 лет и не очень хорошее знание С++ не способствуют быстрому решению этой задачи...
Другое дело помочь сделать 3D модель корпуса для электронных поделок, которые можно распечатать на 3D принтере... Или сделать рабочие чертежи, используя разработанную 3D модель...
Этим владею на уровне эксперта и обучаю этому студентов БГУ.
Вот работающее решение. Вывод DQ датчика DS18b20 подключен к выводу D12 Arduino nano
Нужно изменить строку номер +100500 !
Что Вы имеете в виду?
ПРивет, почитал сверху, решил тоже выложить рабочий обрезанный код для получения и отправки смс
Arduino Mega используется, если что
Да, еще на русском смс шлет))
Есть голая ардуина, на нее заливаете скетч, при первом запуске, она сама чистит EPPROM, т.к. не добавлен номер главного телефона(хранится он в EPPROM), далее отсылаете на номер, который вставлен в модуль SIM, "Register", в ответ получаете ответ на русском, далее разберетесь по счетчу сами, если прилепить часики реального времени, можно в определенное время проверять баланс(он и так проверяется, только по вашему запросу) и т.п.
Приветствую.
А схему устройства увидеть можно?
Пипец, 900 строк чтоб отправить температуру по Смс?
Строка 618 и далее - это еще повезло, что цифр в арифметике всего 10. Страшно представить, сколько понадобилось бы условий, чтобы отыскать в тексте каждую букву кириллицы и латиницы обоих регистров.
Стамбулов, вы про массивы и циклы не слыхали?
ГРАНДИОЗНО!!!!!!!!! Я только в руки взял SIM800L - пробую разобраться, ранее так же с нуля освоил NRF24 (делал на нем радиоуправление строительного крана - самоделка в помощь на моей стройке)
По SIM800L - пока тренируюсь с терминала, чтоб в дальнейшем проект отработат в Atmel Studio 7
возник вопрос по передаче смс - в начале настройка:
/
Если Вы впервые держите в руках SIM800L - то советую сюда - http://codius.ru/articles?page=1
Вот версия скетча для температурного датчика, отправляет СМС при снижении баланса, температуры ниже определенного уровня, также можно по запросу получить эти параметры в ответном СМС.
andyparker с каких пор вы постите чужое?
Приношу свои извинения andyparker!
Это и его код тоже.
Он вложил в него очень большой труд.
Его полезные советы помогли оживить устройство.
Теперь оно стабильно работает!!!
andyparker с каких пор вы постите чужое?
Приношу свои извинения andyparker!
что это было?
В понедельник узнаем)))
Уже разобрались.
Все в порядке!