В корпусе установлен модуль питания ~220v -> 5V 3A.
Мощности модуля питания достаточно для питания ARDUINO Nano и модема SIM800L.
Поскольку питание каждого из модулей осуществляется от одного источника +5В, а SIM800L требует 4В, то запитка последнего осуществляется через 2 последовательно включенных диода, рассчитанных на ток 2 А.
Параллельно выводу питания SIM800L подключены 4 электролитических конденсатора 1000 мкФ х 6.3 В.
В этом случае обеспечивается стабильная связь SIM800L с базовой станцией.
Все протестировано с помощью АТ команд. Модуль подтвердил исправность и стабильную работу.
Содержимое скетча для тестирования не привожу, поскольку подобное было рассмотрено на этом форуме.
Для надежной связи с базовой станцией антенна модема SIM800L вынесена наружу и закреплена на боковой стенке. Отрицательный вывод модуля питания соединен с металлическим корпусом контроллера.
Признаком отказа системы отопления является падение температуры трубы для вывода топочных газов.
При штатном режиме работы отопления эта температура изменяется в диапазоне +45 - +65 °С.
Температура измеряется с помощью DS 18b20. Проблем кодом не оказалось...
По запросу текущую температуру получаю СМС -кой на мой телефон.
Поскольку домик находится в 150 км от Минска, то возникла необходимость проверка текущего баланса на счету. Приведенный выше скетч с этой задачей справляется.
Должен сказать, что приведенные выше тексты написаны не мною. Эти тексты взяты на Codius.ru и мною адаптированы под решаемую задачу. Должен сказать о хорошем качестве выложенной информации на этом сайте. Все выложенные примеры работоспособны.
Эти скетчи каждый сам по себе работают.
Первый скетч возвращает посланное в контроллер сообщение на телефон.
Второй скетч высылает баланс, актуальный в данный момент времени.
Попытки все объединить в один скетч к успеху не привели.
К тому же нужно прописать реагирование на 2 ситуации - снижение температуры ниже 40 °С и наступление момента отрицательного баланса. Белорусский МТС позволяет иметь небольшой отрицательный баланс.
Прошу сообщество оказать мне помощь в решении проблемы. Нужны советы и работающие примеры.
В принципе с этой задачей могу справиться сам. Но возраст почти 70 лет и не очень хорошее знание С++ не способствуют быстрому решению этой задачи...
Другое дело помочь сделать 3D модель корпуса для электронных поделок, которые можно распечатать на 3D принтере... Или сделать рабочие чертежи, используя разработанную 3D модель...
Этим владею на уровне эксперта и обучаю этому студентов БГУ.
sendSMS(MAIN_PHONE, "Balance is less than "+ String(BALANCE_TRESHOLD) + CURRENCY + " and equal to "+ String(balance) + CURRENCY + ".");
252
flag = 0;
253
}
254
elseif(balance >= BALANCE_TRESHOLD && !flag) {
255
flag = 1;
256
}
257
}
258
259
voidsetup() {
260
Serial.begin(9600);
261
SIM800.begin(9600);
262
263
sensors.begin();
264
sensors.requestTemperatures();
265
266
Serial.println("Start!");
267
268
sendATCommand("AT", true);
269
sendATCommand("AT+CMGDA=\"DEL ALL\"", true);
270
sendATCommand("AT+CLIP=1", true);
271
sendATCommand("AT+CMGF=1;&W", true);
272
273
}
274
275
voidloop() {
276
staticint64_t balance_check_timer = 0;
277
staticint64_t temperature_check_timer = 0;
278
staticint64_t new_message_check_timer = 0;
279
280
modemQueryAndResponse();
281
if(abs(millis() - new_message_check_timer) >= 10000) { // раз в десять секунд проверка входящих СМС
282
checkNewMessages();
283
new_message_check_timer = millis();
284
}
285
if(abs(millis() - temperature_check_timer) >= 60000) { // раз в минуту проверка температуры; если она меньше установленного порога, то 1 раз отправляется СМС с текущей температурой на основной номер, прописанный в скетче
286
tresholdTemperature(obtainTemperature());
287
temperature_check_timer = millis();
288
}
289
if(abs(millis() - balance_check_timer) >= 40000) { // раз в час проверка баланса; если он меньше установленного порога, то 1 раз отправляется СМС с текущим балансом на основной номер, прописанный в скетче
290
balanceChecking(); // уменьшил время срабатывания для того, чтобы не ждать час, значение по умолчанию - 3600000
ПРивет, почитал сверху, решил тоже выложить рабочий обрезанный код для получения и отправки смс
Arduino Mega используется, если что
Да, еще на русском смс шлет))
Есть голая ардуина, на нее заливаете скетч, при первом запуске, она сама чистит EPPROM, т.к. не добавлен номер главного телефона(хранится он в EPPROM), далее отсылаете на номер, который вставлен в модуль SIM, "Register", в ответ получаете ответ на русском, далее разберетесь по счетчу сами, если прилепить часики реального времени, можно в определенное время проверять баланс(он и так проверяется, только по вашему запросу) и т.п.
// Поле SCA добавим в самом конце, после расчета длины PDU-пакета
781
*result += "01"; // Поле PDU-type - байт 00000001b
782
*result += "00"; // Поле MR (Message Reference)
783
*result += getDAfield(phone, true); // Поле DA
784
*result += "00"; // Поле PID (Protocol Identifier)
785
*result += "08"; // Поле DCS (Data Coding Scheme)
786
//*result += ""; // Поле VP (Validity Period) - не используется
787
788
String msg = StringToUCS2(*message); // Конвертируем строку в UCS2-формат
789
790
*result += byteToHexString(msg.length() / 2); // Поле UDL (User Data Length). Делим на 2, так как в UCS2-строке каждый закодированный символ представлен 2 байтами.
791
*result += msg;
792
793
*PDUlen = (*result).length() / 2; // Получаем длину PDU-пакета без поля SCA
794
*result = "00"+ *result; // Добавляем поле SCA
795
}
796
797
String getDAfield(String *phone, boolfullnum) {
798
String result = "";
799
for(inti = 0; i <= (*phone).length(); i++) { // Оставляем только цифры
800
if(isDigit((*phone)[i])) {
801
result += (*phone)[i];
802
}
803
}
804
intphonelen = result.length(); // Количество цифр в телефоне
805
if(phonelen % 2 != 0) result += "F"; // Если количество цифр нечетное, добавляем F
806
807
for(inti = 0; i < result.length(); i += 2) { // Попарно переставляем символы в номере
808
charsymbol = result[i + 1];
809
result = result.substring(0, i + 1) + result.substring(i + 2);
810
result = result.substring(0, i) + (String)symbol + result.substring(i);
811
}
812
813
result = fullnum ? "91"+ result : "81"+ result; // Добавляем формат номера получателя, поле PR
814
result = byteToHexString(phonelen) + result; // Добавляем длину номера, поле PL
815
816
returnresult;
817
}
818
819
// =================================== Блок кодирования строки в представление UCS2 =================================
820
String StringToUCS2(String s)
821
{
822
String output = ""; // Переменная для хранения результата
823
824
for(intk = 0; k < s.length(); k++) { // Начинаем перебирать все байты во входной строке
825
byteactualChar = (byte)s[k]; // Получаем первый байт
Строка 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.} - это
Вот версия скетча для температурного датчика, отправляет СМС при снижении баланса, температуры ниже определенного уровня, также можно по запросу получить эти параметры в ответном СМС.
Приношу свои извинения andyparker!
Это и его код тоже.
Он вложил в него очень большой труд.
Его полезные советы помогли оживить устройство.
Теперь оно стабильно работает!!!
Общий вид контроллера со снятой крышкой.
В корпусе установлен модуль питания ~220v -> 5V 3A.
Мощности модуля питания достаточно для питания ARDUINO Nano и модема SIM800L.
Поскольку питание каждого из модулей осуществляется от одного источника +5В, а SIM800L требует 4В, то запитка последнего осуществляется через 2 последовательно включенных диода, рассчитанных на ток 2 А.
Параллельно выводу питания SIM800L подключены 4 электролитических конденсатора 1000 мкФ х 6.3 В.
В этом случае обеспечивается стабильная связь SIM800L с базовой станцией.
Все протестировано с помощью АТ команд. Модуль подтвердил исправность и стабильную работу.
Содержимое скетча для тестирования не привожу, поскольку подобное было рассмотрено на этом форуме.
-
Вот тут начались танцы с бубном...
Признаком отказа системы отопления является падение температуры трубы для вывода топочных газов.
При штатном режиме работы отопления эта температура изменяется в диапазоне +45 - +65 °С.
Температура измеряется с помощью DS 18b20. Проблем кодом не оказалось...
По запросу текущую температуру получаю СМС -кой на мой телефон.
001
// Все работает !!!
002
// С мобильного телефона можем отправлять SMS сообщения следующего вида 001 ....... 99999 итого 100000 комбинаций....
003
// С мобильного телефона можем отправлять SMS сообщения следующего вида *100# и другие
004
/*
005
На базе этого скетча попытаемся написать код управления для мониторинга текущей температуры датчика,
006
для отправки СМС на мой смартфон в случае потухания котла,
007
для получения баланса СИМ карты МТС Беларусь. СИМ-ка установлена в слоте SIM800L.
008
*/
009
010
#include <SoftwareSerial.h> // Библиотека програмной реализации обмена по UART-протоколу
011
SoftwareSerial SIM800(8, 9);
// RX, TX
012
013
// int pins[3] = {5, 6, 7}; // Пины с подключенными светодиодами
014
015
String _response =
""
;
// Переменная для хранения ответа модуля
016
long
lastUpdate = millis();
// Время последнего обновления
017
long
updatePeriod = 60000;
// Проверять каждую минуту
018
019
String phones =
"+37529-------"
;
// Белый список телефонов - Это мой мобильник A1
020
021
void
setup
()
022
{
023
024
Serial
.begin(9600);
// Скорость обмена данными с компьютером
025
SIM800.begin(9600);
// Скорость обмена данными с модемом
026
Serial
.println(
"Start!"
);
027
028
sendATCommand(
"AT"
,
true
);
// Отправили AT для настройки скорости обмена данными
029
sendATCommand(
"AT+CMGDA=\"DEL ALL\""
,
true
);
// Удаляем все SMS, чтобы не забивать память
030
031
// Команды настройки модема при каждом запуске
032
_response = sendATCommand(
"AT+CLIP=1"
,
true
);
// Включаем АОН
033
_response = sendATCommand(
"AT+DDET=1"
,
true
);
// Включаем DTMF
034
sendATCommand(
"AT+CMGF=1;&W"
,
true
);
// Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
035
lastUpdate = millis();
// Обнуляем таймер
036
}
037
038
String sendATCommand(String cmd,
bool
waiting) {
039
String _resp =
""
;
// Переменная для хранения результата
040
Serial
.println(cmd);
// Дублируем команду в монитор порта
041
SIM800.println(cmd);
// Отправляем команду модулю
042
if
(waiting) {
// Если необходимо дождаться ответа...
043
_resp = waitResponse();
// ... ждем, когда будет передан ответ
044
// Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
045
if
(_resp.startsWith(cmd)) {
// Убираем из ответа дублирующуюся команду
046
_resp = _resp.substring(_resp.indexOf(
"\r"
, cmd.length()) + 2);
047
}
048
Serial
.println(_resp);
// Дублируем ответ в монитор порта
049
}
050
return
_resp;
// Возвращаем результат. Пусто, если проблема
051
}
052
053
String waitResponse() {
// Функция ожидания ответа и возврата полученного результата
054
String _resp =
""
;
// Переменная для хранения результата
055
long
_timeout = millis() + 5000;
// Переменная для отслеживания таймаута (5 секунд)
056
while
(!SIM800.available() && millis() < _timeout) {};
// Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
057
if
(SIM800.available()) {
// Если есть, что считывать...
058
_resp = SIM800.readString();
// ... считываем и запоминаем
059
}
060
else
{
// Если пришел таймаут, то...
061
Serial
.println(
"Timeout..."
);
// ... оповещаем об этом и...
062
}
063
return
_resp;
// ... возвращаем результат. Пусто, если проблема
064
}
065
066
bool
hasmsg =
false
;
// Флаг наличия сообщений к удалению
067
void
loop
() {
068
if
(lastUpdate + updatePeriod < millis() ) {
// Пора проверить наличие новых сообщений
069
do
{
070
_response = sendATCommand(
"AT+CMGL=\"REC UNREAD\",1"
,
true
);
// Отправляем запрос чтения непрочитанных сообщений
071
if
(_response.indexOf(
"+CMGL: "
) > -1) {
// Если есть хоть одно, получаем его индекс
072
int
msgIndex = _response.substring(_response.indexOf(
"+CMGL: "
) + 7, _response.indexOf(
"\"REC UNREAD\""
, _response.indexOf(
"+CMGL: "
)) - 1).toInt();
073
char
i = 0;
// Объявляем счетчик попыток
074
do
{
075
i++;
// Увеличиваем счетчик
076
_response = sendATCommand(
"AT+CMGR="
+ (String)msgIndex +
",1"
,
true
);
// Пробуем получить текст SMS по индексу
077
_response.trim();
// Убираем пробелы в начале/конце
078
if
(_response.endsWith(
"OK"
)) {
// Если ответ заканчивается на "ОК"
079
if
(!hasmsg) hasmsg =
true
;
// Ставим флаг наличия сообщений для удаления
080
sendATCommand(
"AT+CMGR="
+ (String)msgIndex,
true
);
// Делаем сообщение прочитанным
081
sendATCommand(
"\n"
,
true
);
// Перестраховка - вывод новой строки
082
parseSMS(_response);
// Отправляем текст сообщения на обработку
083
break
;
// Выход из do{}
084
}
085
else
{
// Если сообщение не заканчивается на OK
086
Serial
.println (
"Error answer"
);
// Какая-то ошибка
087
sendATCommand(
"\n"
,
true
);
// Отправляем новую строку и повторяем попытку
088
}
089
}
while
(i < 10);
090
break
;
091
}
092
else
{
093
lastUpdate = millis();
// Обнуляем таймер
094
if
(hasmsg) {
095
sendATCommand(
"AT+CMGDA=\"DEL READ\""
,
true
);
// Удаляем все прочитанные сообщения
096
hasmsg =
false
;
097
}
098
break
;
099
}
100
}
while
(1);
101
}
102
103
if
(SIM800.available()) {
// Если модем, что-то отправил...
104
_response = waitResponse();
// Получаем ответ от модема для анализа
105
_response.trim();
// Убираем лишние пробелы в начале и конце
106
Serial
.println(_response);
// Если нужно выводим в монитор порта
107
if
(_response.indexOf(
"+CMTI:"
)>-1) {
// Пришло сообщение об отправке SMS
108
lastUpdate = millis() - updatePeriod;
// Теперь нет необходимости обрабатывать SMS здесь, достаточно просто
109
// сбросить счетчик автопроверки и в следующем цикле все будет обработано
110
}
111
}
112
if
(
Serial
.available()) {
// Ожидаем команды по Serial...
113
SIM800.write(
Serial
.read());
// ...и отправляем полученную команду модему
114
};
115
}
116
117
void
parseSMS(String msg) {
// Парсим SMS
118
String msgheader =
""
;
119
String msgbody =
""
;
120
String msgphone =
""
;
121
122
msg = msg.substring(msg.indexOf(
"+CMGR: "
));
123
msgheader = msg.substring(0, msg.indexOf(
"\r"
));
// Извлекаем номер телефона отправившего СМС запрос
124
125
msgbody = msg.substring(msgheader.length() + 1);
// не менять
126
msgbody = msgbody.substring(0, msgbody.lastIndexOf(
"OK"
));
// Извлекаем текст SMS
127
msgbody.trim();
128
//Serial.println();
129
int
firstIndex = msgheader.indexOf(
"\",\""
) + 3;
// не менять
130
int
secondIndex = msgheader.indexOf(
"\",\""
, firstIndex);
131
msgphone = msgheader.substring(firstIndex, secondIndex);
132
133
Serial
.println(
"Phone: "
+ msgphone);
// Выводим номер телефона
134
Serial
.println(
"Message: "
+ msgbody);
// Выводим текст SMS
135
136
if
(msgphone.length() > 6 && phones.indexOf(msgphone) > -1)
// Если телефон в белом списке, то...
137
{
138
// =====================================================================================================================================
139
sendSMS(phones,
"Полученная СМС - ка:"
+msgbody );
//ОТПРАВКА НА БЕЛЫЕ ТЕЛЕФОНЫ РЕЗУЛЬТАТА ВЫПОЛНЕНИЯ КОМАНДЫ !!!!!!!
140
141
// =====================================================================================================================================
142
}
143
else
{
144
Serial
.println(
"Unknown phonenumber"
);
145
}
146
}
// ============================================ End void parseSMS(String msg) ==================================================
147
148
149
void
sendSMS(String phone, String message)
150
{
151
sendATCommand(
"AT+CMGF=1"
,
true
);
// Включаем текстовый режима SMS (Text mode)
152
sendATCommand(
"AT+CMGS=\""
+ phone +
"\""
,
true
);
// Переходим в режим ввода текстового сообщения
153
sendATCommand(message +
"\r\n"
+ (String)((
char
)26),
true
);
// После текста отправляем перенос строки и Ctrl+Z
154
}
001
// ЭТО УЖЕ РАБОТАЕТ !!!
002
#include <SoftwareSerial.h> // Библиотека програмной реализации обмена по UART-протоколу
003
SoftwareSerial SIM800(8, 9);
// RX, TX
004
String _response =
""
;
// Переменная для хранения ответа модуля
005
String _phone_to_SMS =
"+375---------"
;
// Сюда пишем свой номер телефона в международном формате
006
void
setup
() {
007
Serial
.begin(9600);
// Скорость обмена данными с компьютером
008
SIM800.begin(9600);
// Скорость обмена данными с модемом
009
Serial
.println(
"Start!"
);
010
011
sendATCommand(
"AT"
,
true
);
// Отправили AT для настройки скорости обмена данными
012
013
// Команды настройки модема при каждом запуске
014
_response = sendATCommand(
"AT+CLIP=1"
,
true
);
// Включаем АОН
015
//_response = sendATCommand("AT+DDET=1", true); // Включаем DTMF
016
_response = sendATCommand(
"AT+CMGF=1"
,
true
);
// Включаем текстовый режим SMS (Text mode)
017
_response = sendATCommand(
"AT+CUSD=1,\"*100#\""
,
true
);
// Здесь необходимо указать свой USSD-запрос
018
}
019
020
String sendATCommand(String cmd,
bool
waiting) {
021
String _resp =
""
;
// Переменная для хранения результата
022
Serial
.println(cmd);
// Дублируем команду в монитор порта
023
SIM800.println(cmd);
// Отправляем команду модулю
024
if
(waiting) {
// Если необходимо дождаться ответа...
025
_resp = waitResponse();
// ... ждем, когда будет передан ответ
026
// Если Echo Mode выключен (ATE0), то эти 3 строки можно закоментировать
027
if
(_resp.startsWith(cmd)) {
// Убираем из ответа дублирующуюся команду
028
_resp = _resp.substring(_resp.indexOf(
"\r"
, cmd.length()) + 2);
029
}
030
Serial
.println(_resp);
// Дублируем ответ в монитор порта
031
}
032
return
_resp;
// Возвращаем результат. Пусто, если проблема
033
}
034
035
String waitResponse() {
// Функция ожидания ответа и возврата полученного результата
036
String _resp =
""
;
// Переменная для хранения результата
037
long
_timeout = millis() + 5000;
// Переменная для отслеживания таймаута (5 секунд)
038
while
(!SIM800.available() && millis() < _timeout) {};
// Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
039
if
(SIM800.available()) {
// Если есть, что считывать...
040
_resp = SIM800.readString();
// ... считываем и запоминаем
041
}
042
else
{
// Если пришел таймаут, то...
043
Serial
.println(
"Timeout..."
);
// ... оповещаем об этом и...
044
}
045
return
_resp;
// ... возвращаем результат. Пусто, если проблема
046
}
047
// ================== Цикл void loop ========================
048
void
loop
() {
//=
049
if
(SIM800.available()) {
// Если модем, что-то отправил... =
050
_response = waitResponse();
// Получаем ответ от модема для анализа =
051
_response.trim();
// Убираем лишние пробелы в начале и конце =
052
Serial
.println(_response);
// Если нужно выводим в монитор порта =
053
//.... =
054
if
(_response.startsWith(
"+CUSD:"
)) {
// Пришло уведомление о USSD-ответе =
055
if
(_response.indexOf(
"\""
) > -1) {
// Если ответ содержит кавычки, значит есть сообщение =
056
//(предохранитель от "пустых" USSD-ответов) =
057
String msgBalance = _response.substring(_response.indexOf(
"\""
) + 2);
// Получаем непосредственно текст =
058
msgBalance = msgBalance.substring(0, msgBalance.indexOf(
"\""
));
//=
059
Serial
.println(
"USSD: "
+ msgBalance);
// Выводим полученный USSD-ответ =
060
//=
061
float
balance = getFloatFromString(msgBalance);
// Извлекаем информацию о балансе =
062
//=
063
Serial
.println(
"\r\nBalance: "
+ (String)balance );
// Выводим информацию о балансе =
064
sendSMS(_phone_to_SMS,
"\r\nBalance: "
+ (String)balance);
//=
065
}
//=
066
}
//=
067
}
//=
068
if
(
Serial
.available()) {
// Ожидаем команды по Serial... //=
069
SIM800.write(
Serial
.read());
// ...и отправляем полученную команду модему //=
070
};
//=
071
}
//========================================================================
072
073
void
sendSMS(String phone, String message)
074
{
075
String _result =
""
;
076
sendATCommand(
"AT+CMGF=1"
,
true
);
// Включаем текстовый режима SMS (Text mode)
077
sendATCommand(
"AT+CMGS=\""
+ phone +
"\""
,
true
);
// Переходим в режим ввода текстового сообщения
078
_result = sendATCommand(message + (String)((
char
)26),
true
);
// После текста отправляем перенос строки и Ctrl+Z
079
}
080
081
float
getFloatFromString(String str) {
// Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
082
bool
flag =
false
;
083
String result =
""
;
084
str.replace(
","
,
"."
);
// Если в качестве разделителя десятичных используется запятая - меняем её на точку.
085
for
(
int
i = 0; i < str.length(); i++) {
086
if
(isDigit(str[i]) || (str[i] == (
char
)46 && flag)) {
// Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания),
087
if
(result ==
""
&& i > 0 && (String)str[i - 1] ==
"-"
) {
// Нельзя забывать, что баланс может быть отрицательным
088
result +=
"-"
;
// Добавляем знак в начале
089
}
090
result += str[i];
// начинаем собирать их вместе
091
if
(!flag) flag =
true
;
// Выставляем флаг, который указывает на то, что сборка числа началась.
092
}
093
else
{
// Если цифры закончились и флаг говорит о том, что сборка уже была,
094
if
(str[i] != (
char
)32) {
// Если порядок числа отделен пробелом - игнорируем его, иначе...
095
if
(flag)
break
;
// ...считаем, что все.
096
}
097
}
098
}
099
return
result.toFloat();
// Возвращаем полученное число.
100
}
Поскольку домик находится в 150 км от Минска, то возникла необходимость проверка текущего баланса на счету. Приведенный выше скетч с этой задачей справляется.
Должен сказать, что приведенные выше тексты написаны не мною. Эти тексты взяты на Codius.ru и мною адаптированы под решаемую задачу. Должен сказать о хорошем качестве выложенной информации на этом сайте. Все выложенные примеры работоспособны.
Эти скетчи каждый сам по себе работают.
Первый скетч возвращает посланное в контроллер сообщение на телефон.
Второй скетч высылает баланс, актуальный в данный момент времени.
Попытки все объединить в один скетч к успеху не привели.
К тому же нужно прописать реагирование на 2 ситуации - снижение температуры ниже 40 °С и наступление момента отрицательного баланса. Белорусский МТС позволяет иметь небольшой отрицательный баланс.
Прошу сообщество оказать мне помощь в решении проблемы. Нужны советы и работающие примеры.
В принципе с этой задачей могу справиться сам. Но возраст почти 70 лет и не очень хорошее знание С++ не способствуют быстрому решению этой задачи...
Другое дело помочь сделать 3D модель корпуса для электронных поделок, которые можно распечатать на 3D принтере... Или сделать рабочие чертежи, используя разработанную 3D модель...
Этим владею на уровне эксперта и обучаю этому студентов БГУ.
Вот работающее решение. Вывод DQ датчика DS18b20 подключен к выводу D12 Arduino nano
001
#include <SoftwareSerial.h>
002
#include <OneWire.h>
003
#include <DallasTemperature.h>
004
#define ONE_WIRE_BUS 12
005
006
007
SoftwareSerial SIM800(8, 9);
008
OneWire oneWire(ONE_WIRE_BUS);
009
DallasTemperature sensors(&oneWire);
010
011
012
const
String MAIN_PHONE =
"+************"
;
// напишите сюда свой номер в международном формате
013
const
String PDU_USSD_BALANCE_QUERY =
"AT+CUSD=1,\"*100#\""
;
// пишем код для своего оператора
014
const
String TEXT_USSD_BALANCE_QUERY =
"AT+CUSD=1,\"#100#\""
;
// пишем код для своего оператора
015
const
String BALANCE_TEXT_QUERY =
"Balance"
;
// содержание СМС для получения текстового ответа на запрос о балансе
016
const
String BALANCE_PDU_QUERY =
"Balance ussd"
;
// содержание СМС для получения PDU ответа на запрос о балансе
017
const
String TEMPERATURE_QUERY =
"Temperature"
;
// содержание СМС для получения ответа на запрос о температуре
018
const
String CURRENCY =
" BYN"
;
// текстовое представление валюты
019
const
float
BALANCE_TRESHOLD = 5.0;
// нижнее пороговое значение баланса
020
const
float
TEMPERATURE_TRESHOLD = 35.0;
// нижнее пороговое значение температуры
021
bool
hasmsg =
false
;
022
023
024
String sendATCommand(
const
String& cmd,
bool
waiting) {
025
String response =
""
;
// Переменная для хранения результата
026
Serial
.println(cmd);
// Дублируем команду в монитор порта
027
SIM800.println(cmd);
// Отправляем команду модулю
028
if
(waiting) {
// Если необходимо дождаться ответа...
029
response = waitResponse();
// ... ждем, когда будет передан ответ
030
if
(response.startsWith(cmd)) {
// Убираем из ответа дублирующуюся команду
031
response = response.substring(response.indexOf(
"\r"
, cmd.length()) + 2);
032
}
033
Serial
.println(response );
// Дублируем ответ в монитор порта
034
}
035
return
response;
// Возвращаем результат. Пусто, если проблема
036
}
037
038
String waitResponse() {
// Функция ожидания ответа и возврата полученного результата
039
String response =
""
;
// Переменная для хранения результата
040
int64_t timeout = millis() + 10000;
// Переменная для отслеживания таймаута (5 секунд)
041
while
(!SIM800.available() && millis() < timeout) {};
// Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
042
if
(SIM800.available()) {
// Если есть, что считывать...
043
response = SIM800.readString();
// ... считываем и запоминаем
044
}
045
else
{
// Если пришел таймаут, то...
046
Serial
.println(
"Timeout..."
);
// ... оповещаем об этом и...
047
}
048
return
response;
// ... возвращаем результат. Пусто, если проблема
049
}
050
051
void
sendSMS(
const
String& phone,
const
String& message) {
052
sendATCommand(
"AT+CMGS=\""
+ phone +
"\""
,
true
);
// Переходим в режим ввода текстового сообщения
053
sendATCommand(message + (String)((
char
)26),
true
);
// После текста отправляем перенос строки и Ctrl+Z
054
}
055
056
void
getBalance() {
057
sendATCommand(PDU_USSD_BALANCE_QUERY,
true
);
058
String answer = waitResponse();
059
answer.trim();
060
String msgBalance = answer.substring(answer.indexOf(
"\""
) + 1);
// Получаем непосредственно текст
061
msgBalance = msgBalance.substring(0, msgBalance.indexOf(
"\""
));
062
float
balance = getFloatFromString(UCS2ToString(msgBalance));
// Извлекаем информацию о балансе
063
sendSMS(MAIN_PHONE,
"\r\nBalans SIM karty: "
+ (String)balance + CURRENCY +
"."
);
064
}
065
066
void
alternativeGetBalance() {
067
sendATCommand(TEXT_USSD_BALANCE_QUERY,
true
);
068
String answer = waitResponse();
069
answer.trim();
070
if
(answer.indexOf(
"\""
) > -1) {
071
String msgBalance = answer.substring(answer.indexOf(
"\""
) + 2);
072
msgBalance = msgBalance.substring(0, msgBalance.indexOf(
"\""
));
073
float
balance = getFloatFromString(msgBalance);
074
Serial
.println(
"\r\nBalans SIM karty: "
+ (String)balance);
075
sendSMS(MAIN_PHONE,
"\r\nBalans SIM karty: "
+ (String)balance + CURRENCY +
"."
);
076
}
077
}
078
079
float
getFloatFromString(String str) {
// Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
080
bool
flag =
false
;
081
String result =
""
;
082
str.replace(
","
,
"."
);
// Если в качестве разделителя десятичных используется запятая - меняем её на точку.
083
for
(size_t i = 0; i < str.length(); ++i) {
084
if
(isDigit(str[i]) || (str[i] == (
char
)46 && flag)) {
// Если начинается группа цифр (при этом на точку без цифр не обращаем внимания),
085
if
(i != 0 && result ==
""
&& (String)str[i - 1] ==
"-"
) {
// Нельзя забывать, что баланс может быть отрицательным
086
result +=
"-"
;
// Добавляем знак в начале
087
}
088
result += str[i];
// начинаем собирать их вместе
089
if
(!flag) {
090
flag =
true
;
// Выставляем флаг, который указывает на то, что сборка числа началась.
091
}
092
}
093
else
{
// Если цифры закончились и флаг говорит о том, что сборка уже была,
094
if
(str[i] != (
char
)32) {
095
if
(flag) {
096
break
;
097
}
098
}
099
}
100
}
101
return
result.toFloat();
// Возвращаем полученное число.
102
}
103
104
void
parseSMS(String msg) {
// Парсим SMS
105
String msgheader =
""
;
// Переменная под звонивший телефона для анализа
106
String msgbody =
""
;
// Переменная под SMS
107
String msgphone =
""
;
// Переменная под номер телефона
108
109
msg = msg.substring(msg.indexOf(
"+CMGR: "
));
110
msgheader = msg.substring(0, msg.indexOf(
"\r"
));
// Получаем звонивший телефон
111
112
msgbody = msg.substring(msgheader.length() + 2);
113
msgbody = msgbody.substring(0, msgbody.lastIndexOf(
"OK"
));
// Получаем текст полученной SMS
114
msgbody.trim();
//Обрезаем начальные или концевые символы
115
116
int
firstIndex = msgheader.indexOf(
"\",\""
) + 3;
117
int
secondIndex = msgheader.indexOf(
"\",\""
, firstIndex);
118
msgphone = msgheader.substring(firstIndex, secondIndex);
119
120
if
(msgphone.length() && MAIN_PHONE.indexOf(msgphone) != -1) {
// Если телефон в белом списке, то...
121
if
(msgbody == BALANCE_PDU_QUERY) {
122
getBalance();
123
}
124
else
if
(msgbody == BALANCE_TEXT_QUERY) {
125
alternativeGetBalance();
126
}
127
else
if
(msgbody == TEMPERATURE_QUERY) {
128
sendSMS(MAIN_PHONE,
"SENSOR TEMPERATURE = "
+ String(obtainTemperature()) +
" C."
);
129
}
130
131
Serial
.println(
"Phone: "
+ msgphone);
// Выводим номер телефона
132
Serial
.println(
"Message: "
+ msgbody);
// Выводим текст SMS
133
}
134
else
if
(msgphone.length()) {
135
Serial
.println(
"Unknown phone number: "
+ msgphone);
136
Serial
.println(
"Message: "
+ msgbody);
137
}
138
}
139
140
unsigned
char
HexSymbolToChar(
char
c) {
141
if
((c >= 0x30) && (c <= 0x39))
return
(c - 0x30);
142
else
if
((c >=
'A'
) && (c <=
'F'
))
return
(c -
'A'
+ 10);
143
else
return
(0);
144
}
145
146
String UCS2ToString(String s) {
147
String result =
""
;
148
unsigned
char
c[5] =
""
;
149
for
(size_t i = 0; i < s.length() - 3; i += 4) {
150
unsigned
long
code = (((unsigned
int
)HexSymbolToChar(s[i])) << 12) +
151
(((unsigned
int
)HexSymbolToChar(s[i + 1])) << 8) +
152
(((unsigned
int
)HexSymbolToChar(s[i + 2])) << 4) +
153
((unsigned
int
)HexSymbolToChar(s[i + 3]));
154
if
(code <= 0x7F) {
155
c[0] = (
char
)code;
156
c[1] = 0;
157
}
else
if
(code <= 0x7FF) {
158
c[0] = (
char
)(0xC0 | (code >> 6));
159
c[1] = (
char
)(0x80 | (code & 0x3F));
160
c[2] = 0;
161
}
else
if
(code <= 0xFFFF) {
162
c[0] = (
char
)(0xE0 | (code >> 12));
163
c[1] = (
char
)(0x80 | ((code >> 6) & 0x3F));
164
c[2] = (
char
)(0x80 | (code & 0x3F));
165
c[3] = 0;
166
}
else
if
(code <= 0x1FFFFF) {
167
c[0] = (
char
)(0xE0 | (code >> 18));
168
c[1] = (
char
)(0xE0 | ((code >> 12) & 0x3F));
169
c[2] = (
char
)(0x80 | ((code >> 6) & 0x3F));
170
c[3] = (
char
)(0x80 | (code & 0x3F));
171
c[4] = 0;
172
}
173
result += String((
char
*)c);
174
}
175
return
(result);
176
}
177
178
void
checkNewMessages() {
179
String response = sendATCommand(
"AT+CMGL=\"REC UNREAD\",1"
,
true
);
// Отправляем запрос чтения непрочитанных сообщений
180
if
(response.indexOf(
"+CMGL: "
) >= 0) {
// Если есть хоть одно, получаем его индекс
181
int
msgIndex = response.substring(response.indexOf(
"+CMGL: "
) + 7, response.indexOf(
"\"REC UNREAD\""
, response.indexOf(
"+CMGL: "
)) - 1).toInt();
182
response = sendATCommand(
"AT+CMGR="
+ (String)msgIndex +
",1"
,
true
);
// Пробуем получить текст SMS по индексу
183
response.trim();
// Убираем пробелы в начале/конце
184
if
(response.endsWith(
"OK"
)) {
// Если ответ заканчивается на "ОК"
185
if
(!hasmsg) {
186
hasmsg =
true
;
// Ставим флаг наличия сообщений для удаления
187
}
188
sendATCommand(
"AT+CMGR="
+ (String)msgIndex,
true
);
// Делаем сообщение прочитанным
189
sendATCommand(
"\n"
,
true
);
// Перестраховка - вывод новой строки
190
parseSMS(response);
// Отправляем текст сообщения на обработку
191
}
192
}
193
else
{
194
if
(hasmsg ==
true
) {
195
sendATCommand(
"AT+CMGDA=\"DEL READ\""
,
true
);
// Удаляем все прочитанные сообщения
196
hasmsg =
false
;
197
}
198
}
199
}
200
201
void
modemQueryAndResponse() {
202
if
(SIM800.available()) {
// Если модем что-то получил...
203
String data = waitResponse();
// Получаем ответ для модема для анализа
204
data.trim();
// Убираем лишние пробелы в начале и конце
205
parseSMS(data);
206
Serial
.println(data);
// Если нужно, выводим в монитор порта
207
if
(data.startsWith(
"+CUSD:"
)) {
// Пришло уведомление об USSD-ответе
208
if
(data.indexOf(
"\""
) > -1) {
// Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
209
String msgBalance = data.substring(data.indexOf(
"\""
) + 2);
210
msgBalance = msgBalance.substring(0, msgBalance.indexOf(
"\""
));
211
float
balance = getFloatFromString(msgBalance);
212
Serial
.println(
"\r\nBalans SIM karty: "
+ (String)balance + CURRENCY +
"."
);
213
}
214
}
215
}
216
else
if
(
Serial
.available()) {
// Ожидаем команды по Serial...
217
SIM800.write(
Serial
.read());
// ... и отправляем полученную команду модему
218
}
219
}
220
221
void
sendTemperatureSMS(
const
String& current_temperature) {
222
sendSMS(MAIN_PHONE,
"SENSOR TEMPERATURE = "
+ current_temperature +
" degree "
+
"C"
+
"."
);
223
}
224
225
float
obtainTemperature() {
226
sensors.requestTemperatures();
227
return
sensors.getTempCByIndex(0);
228
}
229
230
void
tresholdTemperature(
float
current_temperature) {
231
static
bool
flag = 1;
232
if
(current_temperature < TEMPERATURE_TRESHOLD && flag) {
233
sendSMS(MAIN_PHONE,
"Temperature is less than "
+ String(TEMPERATURE_TRESHOLD)+
" deg C"
+
" and equal to "
+ String(current_temperature) +
" deg C."
);
234
flag = 0;
235
}
236
else
if
(current_temperature >= TEMPERATURE_TRESHOLD && !flag) {
237
flag = 1;
238
}
239
}
240
241
void
balanceChecking() {
242
static
bool
flag = 1;
243
sendATCommand(TEXT_USSD_BALANCE_QUERY,
true
);
244
String answer = waitResponse();
245
answer.trim();
246
String msgBalance = answer.substring(answer.indexOf(
"\""
) + 2);
247
msgBalance = msgBalance.substring(0, msgBalance.indexOf(
"\""
));
248
float
balance = getFloatFromString(msgBalance);
249
Serial
.println(
"Balance is "
+ String(balance));
250
if
(balance < BALANCE_TRESHOLD && flag) {
251
sendSMS(MAIN_PHONE,
"Balance is less than "
+ String(BALANCE_TRESHOLD) + CURRENCY +
" and equal to "
+ String(balance) + CURRENCY +
"."
);
252
flag = 0;
253
}
254
else
if
(balance >= BALANCE_TRESHOLD && !flag) {
255
flag = 1;
256
}
257
}
258
259
void
setup
() {
260
Serial
.begin(9600);
261
SIM800.begin(9600);
262
263
sensors.begin();
264
sensors.requestTemperatures();
265
266
Serial
.println(
"Start!"
);
267
268
sendATCommand(
"AT"
,
true
);
269
sendATCommand(
"AT+CMGDA=\"DEL ALL\""
,
true
);
270
sendATCommand(
"AT+CLIP=1"
,
true
);
271
sendATCommand(
"AT+CMGF=1;&W"
,
true
);
272
273
}
274
275
void
loop
() {
276
static
int64_t balance_check_timer = 0;
277
static
int64_t temperature_check_timer = 0;
278
static
int64_t new_message_check_timer = 0;
279
280
modemQueryAndResponse();
281
if
(abs(millis() - new_message_check_timer) >= 10000) {
// раз в десять секунд проверка входящих СМС
282
checkNewMessages();
283
new_message_check_timer = millis();
284
}
285
if
(abs(millis() - temperature_check_timer) >= 60000) {
// раз в минуту проверка температуры; если она меньше установленного порога, то 1 раз отправляется СМС с текущей температурой на основной номер, прописанный в скетче
286
tresholdTemperature(obtainTemperature());
287
temperature_check_timer = millis();
288
}
289
if
(abs(millis() - balance_check_timer) >= 40000) {
// раз в час проверка баланса; если он меньше установленного порога, то 1 раз отправляется СМС с текущим балансом на основной номер, прописанный в скетче
290
balanceChecking();
// уменьшил время срабатывания для того, чтобы не ждать час, значение по умолчанию - 3600000
291
balance_check_timer = millis();
292
}
293
}
Нужно изменить строку номер +100500 !
Что Вы имеете в виду?
ПРивет, почитал сверху, решил тоже выложить рабочий обрезанный код для получения и отправки смс
Arduino Mega используется, если что
Да, еще на русском смс шлет))
Есть голая ардуина, на нее заливаете скетч, при первом запуске, она сама чистит EPPROM, т.к. не добавлен номер главного телефона(хранится он в EPPROM), далее отсылаете на номер, который вставлен в модуль SIM, "Register", в ответ получаете ответ на русском, далее разберетесь по счетчу сами, если прилепить часики реального времени, можно в определенное время проверять баланс(он и так проверяется, только по вашему запросу) и т.п.
001
//Библиотеки
002
#include <SoftwareSerial.h>
003
#include <EEPROM.h>
004
#include <Wire.h> // Wire.h
005
#include <OneWire.h>// библиотека для работы с протоколом 1-Wire
006
#include <DallasTemperature.h>// библиотека для работы с датчиком DS18B20
007
008
#define SIM800_TX_PIN 53
009
#define SIM800_RX_PIN 52
010
SoftwareSerial gsm(SIM800_TX_PIN,SIM800_RX_PIN);
011
#define ONE_WIRE_BUS 2 //Датчики по шине 1-wire
012
013
014
// создаём объект для работы с библиотекой OneWire
015
OneWire oneWire(ONE_WIRE_BUS);
016
// создадим объект для работы с библиотекой DallasTemperature
017
DallasTemperature sensors(&oneWire);
018
// создаём указатель массив для хранения адресов датчиков
019
DeviceAddress *sensorsUnique;
020
// количество датчиков на шине
021
int
countSensors;
022
023
unsigned
long
currentMillis = 0;
024
//переменные для датчиков ТЕ по шине 1-WIRE
025
long
lastUpdateTime1WIRE = 0;
// Переменная для хранения времени последнего считывания с датчика
026
const
int
TEMP_UPDATE_TIME1WIRE = 5000;
// Определяем периодичность проверок датчиков
027
String STemperature1 =
""
;
028
String STemperature2 =
""
;
029
String STemperature3 =
""
;
030
int
StartGSM = 0;
031
String NBoss =
""
;
032
String NBoss1 =
""
;
033
String NBoss2 =
""
;
034
String NBoss3 =
""
;
035
String NBoss4 =
""
;
036
String NBoss5 =
""
;
037
String NBossNumber =
""
;
038
String Temp =
""
;
039
int
tempZaprosBalansa = 0;
// переменная, хранящая метку о запросе каждый день баланса
040
int
tempForWaitSendSmsTE = 0;
041
long
counter = 0;
042
long
timerForSignalGSM = 1000000;
043
044
// Переменные для обработки смс +CSQ
045
int
intNumberLevelFirst = 0;
046
int
intNumberLevelSecond = 0;
047
int
IntSignalLevel = 0;
048
int
FlagSignal = 0;
049
// Переменные для чтения смс
050
String currStr =
""
;
051
String dataSmsN =
""
;
052
int
flag1 = 0;
053
int
flag2 = 0;
054
String currStrN =
""
;
055
char
currSymb = 0;
056
String dataSms =
""
;
057
String dataBalance =
""
;
058
//String dataBalanceNumber = "";
059
String dataBalanceTemp =
""
;
060
String val =
""
;
061
int
ch = 0;
062
char
data = 0;
063
// Переменные для циклов
064
int
i = 0;
065
int
k = 0;
066
byte
s1;
//
067
byte
s2;
//
068
byte
s3;
//
069
byte
s4;
//
070
byte
s5;
//
071
byte
s6;
//
072
byte
s7;
//
073
byte
s8;
//
074
byte
s9;
//
075
byte
s10;
//
076
byte
s11;
077
078
String msgBalance =
""
;
079
float
balance = 0;
080
081
int
tempBalans = 0;
// переменная, хранящая метку о запросе баланса
082
String textToSend =
""
;
083
int
Boss = 0;
084
int
BossTemp = 0;
085
086
String BalansSim =
"Баланс: "
;
087
String HelloNumberIsBoss =
"Ваш номер главный: "
;
088
String temp =
""
;
089
String _response =
""
;
// Переменная для хранения ответа модуля
090
int
IntSignalLevelTemp = 0;
091
byte
Temp2;
// чтение телефона хозяина
092
int
intUstavkaTE = 0;
093
int
counterClearAddrDataEEprom = 0;
094
095
void
setup
() {
096
Serial
.begin(9600);
// Сериал для PC
097
Serial
.println(
"Start"
);
098
099
gsm.begin(9600);
// Сериал для GSM
100
delay(1000);
101
sendATCommand(
"AT+CMGF=1\r"
,
true
);
// устанавливает текстовый режим смс-сообщенияОК
102
sendATCommand(
"AT+IFC=1, 1\r"
,
true
);
//устанавливает программный контроль потоком передачи данных
103
sendATCommand(
"AT+CPBS=\"SM\"\r"
,
true
);
//открывает доступ к данным телефонной книги SIM-карты
104
sendATCommand(
"AT+CNMI=1,2,2,1,0\r"
,
true
);
// включает оповещение о новых сообщениях, новые сообщения
105
sendATCommand(
"AT+GSMBUSY=1\r\n"
,
true
);
// запрет всех входящих звонков.
106
sendATCommand(
"AT+CMGDA=DEL ALL\r\n"
,
true
);
// команда удалит все сообщения
107
sendATCommand(
"AT+CSQ"
,
true
);
// Проверяем уровень сигнала
108
109
// начинаем работу с датчиком DS по шине
110
sensors.begin();
111
// выполняем поиск устройств на шине
112
countSensors = sensors.getDeviceCount();
113
// Serial.print("Found sensors: ");
114
// Serial.println(countSensors);
115
// выделяем память в динамическом массиве под количество обнаруженных сенсоров
116
sensorsUnique =
new
DeviceAddress[countSensors];
117
118
// делаем запрос на получение адресов датчиков
119
for
(
int
i = 0; i < countSensors; i++) {
120
sensors.getAddress(sensorsUnique[i], i);
121
}
122
// выводим полученные адреса
123
for
(
int
i = 0; i < countSensors; i++) {
124
Serial
.print(
"Device "
);
125
Serial
.print(i);
126
Serial
.print(
" Address: "
);
127
printAddress(sensorsUnique[i]);
128
Serial
.println();
129
}
130
131
// устанавливаем разрешение всех датчиков в 12 бит
132
for
(
int
i = 0; i < countSensors; i++) {
133
sensors.setResolution(sensorsUnique[i], 12);
134
}
135
//Конец поиска по шине DS
136
}
137
138
void
loop
() {
139
//######### Начало. Если Главного номера нет в EEPROM и запустили систему в первый раз #################
140
// Удаляем из EEPROM все данные, записываем, что нет номеров и система не стоит на охране, выключаем сирену и маяк
141
if
(EEPROM.read(20) == 0 && counterClearAddrDataEEprom == 0){
142
RAll();
143
}
144
//######### Конец. Если Главного номера нет в EEPROM и запустили систему в первый раз #################
145
146
currentMillis = millis();
147
148
// Запускаем GSM
149
if
(StartGSM == 0){
150
gsm.write(
"AT+CMGF=1\r"
);
// устанавливает текстовый режим смс-сообщения
151
delay(300);
152
}
153
if
(StartGSM == 1){
154
gsm.write(
"AT+IFC=1, 1\r"
);
//устанавливает программный контроль потоком передачи данных
155
delay(300);
156
}
157
if
(StartGSM == 2){
158
gsm.write(
"AT+CPBS=\"SM\"\r"
);
//открывает доступ к данным телефонной книги SIM-карты
159
delay(300);
160
}
161
if
(StartGSM == 3){
162
gsm.write(
"AT+CNMI=1,2,2,1,0\r"
);
// включает оповещение о новых сообщениях, новые сообщения
163
delay(500);
164
}
165
if
(StartGSM == 4){
166
gsm.write(
"AT+GSMBUSY=1\r\n"
);
// запрет всех входящих звонков.
167
delay(300);
168
}
169
if
(StartGSM == 5){
170
gsm.write(
"AT+CMGDA=DEL ALL\r\n"
);
// команда удалит все сообщения
171
delay(500);
172
}
173
if
(FlagSignal == 0 && StartGSM == 6){
174
gsm.println(
"AT+CSQ"
);
// Проверяем уровень сигнала
175
delay(800);
176
}
177
178
if
(gsm.available()) {
//есть данные от GSM модуля
179
currStr =
""
;
//выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
180
currStrN =
""
;
181
dataBalanceTemp =
""
;
182
dataSms =
""
;
183
val =
""
;
184
flag1 = 0;
185
flag2 = 0;
186
while
(gsm.available()) {
//сохраняем входную строку в переменную val
187
c:
188
ch = gsm.read();
//int
189
// Serial.println(ch);
190
val +=
char
(ch);
// String
191
data = ch;
// char = int
192
if
(
'\r'
== data) {
193
currStr =
""
;
194
}
else
if
(
'\n'
!= data) {
195
currStr += String(data);
196
dataSms = currStr;
197
}
198
//+CMT: "+79819998877","","16/04/18,20:25:08+12"
199
if
(data ==
'+'
&& flag1 == 0){flag1 = 1;}
200
if
(data ==
'C'
&& flag1 == 1){flag1 = 2;}
201
if
(data ==
'M'
&& flag1 == 2){flag1 = 3;}
202
if
(data ==
'T'
&& flag1 == 3){flag1 = 4;}
203
if
(data ==
'+'
&& flag1 == 4){currStrN =
""
;flag1 = 5;}
204
if
(data !=
'"'
&& flag1 == 5){currStrN += String(data); dataSmsN = currStrN;}
205
if
(data ==
'"'
&& flag1 == 5){flag1 = 6;}
206
//+CUSD: 0, "Balance:117,27r ", 15
207
if
(data ==
'U'
&& flag1 == 2){flag2 = 3;}
208
if
(data ==
'S'
&& flag2 == 3){flag2 = 4;}
209
if
(data ==
'D'
&& flag2 == 4){flag2 = 5;}
210
if
(data ==
':'
&& flag2 == 5){flag2 = 6;}
211
if
(data ==
'"'
&& flag2 == 6){dataBalanceTemp = ""; flag2 = 7;
goto
c;}
212
if
(data !=
'"'
&& flag2 == 7){dataBalanceTemp += String(data); dataBalance = dataBalanceTemp;}
213
if
(data ==
'"'
&& flag2 == 7){flag2 = 8;}
214
215
}
216
// Смотрим данные полученные //режим кодировки СМС - обычный (для англ.)
217
if
(val.indexOf(
"+CMGF"
) > -1){
218
if
(dataSms.indexOf(
"OK"
) > -1) {
219
StartGSM = 1;
220
}
221
}
222
// Смотрим данные полученные //устанавливает программный контроль потоком передачи данных
223
if
(val.indexOf(
"+IFC"
) > -1){
224
if
(dataSms.indexOf(
"OK"
) > -1) {
225
StartGSM = 2;
226
}
227
}
228
// Смотрим данные полученные //открывает доступ к данным телефонной книги SIM-карты
229
if
(val.indexOf(
"+CPBS"
) > -1){
230
if
(dataSms.indexOf(
"OK"
) > -1) {
231
StartGSM = 3;
232
}
233
}
234
// Смотрим данные полученные //включает оповещение о новых сообщениях, новые сообщения
235
if
(val.indexOf(
"+CNMI"
) > -1){
236
if
(dataSms.indexOf(
"OK"
) > -1) {
237
StartGSM = 4;
238
}
239
}
240
// Смотрим данные полученные //запрет всех входящих звонков.
241
if
(val.indexOf(
"+GSMBUSY"
) > -1){
242
if
(dataSms.indexOf(
"OK"
) > -1) {
243
StartGSM = 5;
244
}
245
}
246
// Смотрим данные полученные //команда удалит все сообщения
247
if
(val.indexOf(
"+CMGDA"
) > -1){
248
if
(dataSms.indexOf(
"OK"
) > -1) {
249
StartGSM = 6;
250
}
251
}
252
// Смотрим данные полученные от модуля +CSQ: 22,0
253
if
(val.indexOf(
"+CSQ"
) > -1) {
254
for
(i=0; i<=20; i++){
255
if
(val[i] == 58) {
256
intNumberLevelFirst = val[i+2]-48;
257
if
(val[i+3] == 44){ intNumberLevelSecond = 0;}
258
if
(val[i+3] != 44){ intNumberLevelSecond = val[i+3]-48;}
259
if
(val[i+3] == 44){IntSignalLevel = intNumberLevelFirst;}
260
if
(val[i+3] != 44){IntSignalLevel = (intNumberLevelFirst*10) + intNumberLevelSecond;}
261
}
262
263
}
264
if
(IntSignalLevel == 99 || IntSignalLevel == 0){
265
FlagSignal = 0; StartGSM = 0;
266
// digitalWrite(ledRed, HIGH);
267
}
268
if
(IntSignalLevel <=32 && IntSignalLevel !=0){
269
FlagSignal = 1;
270
}
271
}
272
273
// Смотрим данные полученные от модуля пришло смс
274
if
(val.indexOf(
"+CMTI:"
) > -1) {
// +CMTI: "SM",
275
StartGSM = 0;
276
}
277
278
// Смотрим данные полученные от модуля, Получили смс с балансом, теперь отсылаем
279
if
(val.indexOf(
"+CUSD:"
) > -1) {
// Пришло уведомление о USSD-ответе
280
if
(val.indexOf(
"\""
) > -1) {
// Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
281
msgBalance = val.substring(val.indexOf(
"\""
) + 2);
// Получаем непосредственно текст
282
msgBalance = msgBalance.substring(0, msgBalance.indexOf(
"\""
));
283
balance = getFloatFromString(msgBalance);
// Извлекаем информацию о балансе
284
285
if
(tempBalans == 1) {
286
Boss = BossTemp;
287
textToSend = BalansSim;
288
textToSend += (String)balance;
289
textToSend +=
"руб"
;
290
smsSendAlarm(textToSend);
291
tempBalans = 0;
292
BossTemp = 0;
293
}
294
295
if
((
int
)balance > 400){
296
tempForWaitSendSmsTE = 0;
297
// ничего не делаем
298
}
else
if
(tempZaprosBalansa == 1){
299
if
((
int
)balance == 0){
300
tempZaprosBalansa = 2;
301
GoBalans();
302
}
else
{
303
Boss = 75;
304
textToSend = BalansSim;
305
textToSend +=
"меньше 400руб, ваш баланс: "
;
306
textToSend += (String)balance;
307
smsSendAlarm(textToSend);
308
tempZaprosBalansa = 0;
309
tempForWaitSendSmsTE = 1;
310
}
311
312
}
313
314
}
315
}
316
317
//----------------------- определение факта приема СМС и сравнение номера(ов) с заданным(и)
318
if
(val.indexOf(
"+CMT"
) > -1) {
319
320
// Регистрация хозяина
321
if
(dataSms.indexOf(
"Register"
) > -1 && EEPROM.read(0) == 3) {
322
if
(EEPROM.read(20) == 0){
323
k=1;
324
Temp =
""
;
325
for
(i=20; i<=30; i++){
// записываем с 20 по 30 ячейку номер телефона главного
326
EEPROM.write(i,dataSmsN[k]-48);
327
Temp += dataSmsN[k]-48;
// записываем в Temp номер телефона из прешедшей смс
328
k++;
329
}
330
EEPROM.write(0,0);
331
textToSend =
""
;
332
Serial1.print(
"Register"
); Serial1.print(Temp);Serial1.println();
333
Boss = 1;
334
textToSend = HelloNumberIsBoss;
335
textToSend += Temp;
336
smsSendAlarm(textToSend);
337
goto
Exit;
338
}
339
Exit:
340
ClearDataIn();
341
delay(1);
342
343
}
344
345
346
// Проверяем номер телефона хозяина
347
if
(dataSmsN !=
""
){
348
Boss = 0;
349
for
(i=1; i<=11; i++){
350
Temp += dataSmsN[i]-48;
// записываем в Temp номер телефона из прешедшей смс
351
}
352
ReadNumber(1);
// читаем номер хозяина из EEPROM
353
354
if
(Temp == NBoss){
// Сравниваем номер прешедшей смс с номером из памяти
355
Boss = 1;
356
NBoss =
""
;
357
goto
exitWriteNumber;
358
}
359
ReadNumber(2);
// читаем номер хозяина из EEPROM
360
if
(Temp == NBoss1){
// Сравниваем номер прешедшей смс с номером из памяти
361
Boss = 2;
362
NBoss1 =
""
;
363
goto
exitWriteNumber;
364
}
365
ReadNumber(3);
// читаем номер хозяина из EEPROM
366
if
(Temp == NBoss2){
// Сравниваем номер прешедшей смс с номером из памяти
367
Boss = 3;
368
NBoss2 =
""
;
369
goto
exitWriteNumber;
370
}
371
ReadNumber(4);
// читаем номер хозяина из EEPROM
372
if
(Temp == NBoss3){
// Сравниваем номер прешедшей смс с номером из памяти
373
Boss = 4;
374
NBoss3 =
""
;
375
goto
exitWriteNumber;
376
}
377
ReadNumber(5);
// читаем номер хозяина из EEPROM
378
if
(Temp == NBoss4){
// Сравниваем номер прешедшей смс с номером из памяти
379
Boss = 5;
380
NBoss4 =
""
;
381
goto
exitWriteNumber;
382
}
383
ReadNumber(6);
// читаем номер хозяина из EEPROM
384
if
(Temp == NBoss5){
// Сравниваем номер прешедшей смс с номером из памяти
385
Boss = 6;
386
NBoss5 =
""
;
387
goto
exitWriteNumber;
388
}
389
exitWriteNumber:
390
delay(1);
391
}
392
393
// Помощь, вывод меню в смс
394
if
(dataSms.indexOf(
"Help"
) > -1){
395
if
(Boss == 1 || Boss == 2 || Boss == 3 || Boss == 4 || Boss == 5 || Boss == 6){
396
temp =
"Hi"
;
//25
397
temp +=
"\r\n"
;
//29
398
temp +=
"Balans"
;
399
smsSendAlarm(temp);
400
temp =
""
;
// очищаем переменную
401
}
402
}
403
// Информация
404
if
(dataSms.indexOf(
"Info"
) > -1){
405
if
(Boss == 1 || Boss == 2 || Boss == 3 || Boss == 4 || Boss == 5 || Boss == 6){
406
407
Boss = 77;
408
textToSend =
"Инфа"
;
409
textToSend +=
"\r\n"
;
410
textToSend +=
"Сигнал:"
;
411
IntSignalLevelTemp = map(IntSignalLevel, 0, 32, 0, 100);
412
textToSend += String(IntSignalLevelTemp);
413
textToSend +=
"%"
;
414
textToSend +=
"\r\n"
;
415
textToSend +=
"Темп:"
;
416
textToSend += STemperature1;
417
textToSend +=
"'С"
;
418
smsSendAlarm(textToSend);textToSend =
""
;
419
}
420
}
421
// Запрос баланса, после получения ответа - отправка обратно на номер
422
if
(dataSms.indexOf(
"Balans"
) > -1) {
// Запрос баланса
423
if
(Boss == 1 || Boss == 2 || Boss == 3 || Boss == 6){
424
BossTemp = Boss;
425
tempBalans = 1;
426
GoBalans();
427
}
428
}
429
430
431
}
//+cmt
432
ClearDataIn();
433
434
}
435
436
//Начало чтения для датчиков по шине 1-Wire
437
if
(currentMillis - lastUpdateTime1WIRE > TEMP_UPDATE_TIME1WIRE)
438
{
439
// goto ENDWire;
440
lastUpdateTime1WIRE = currentMillis;
441
if
(countSensors >= 1) {
442
// переменная для хранения температуры
443
float
temperature[10];
444
// отправляем запрос на измерение температуры всех сенсоров
445
sensors.requestTemperatures();
446
// считываем данные из регистра каждого датчика по очереди
447
for
(i = 0; i < countSensors; i++) {
448
temperature[i] = sensors.getTempCByIndex(i);
449
if
(i == 0) {
450
Serial
.print(
"TE 1: "
);
451
Serial
.println(temperature[0]);
452
STemperature1 = temperature[0];
453
}
454
// if (i == 1) {
455
// Serial.print("TE 2: ");
456
// Serial.println(temperature[1]);
457
// STemperature2 = temperature[1];
458
// }
459
// if (i == 2) {
460
// Serial.print("TE 3: ");
461
// Serial.println(temperature[2]);
462
// STemperature3 = temperature[2];
463
// }
464
}
465
}
466
}
//Конец для датчиков 1-Wire
467
}
468
469
String sendATCommand(String cmd,
bool
waiting) {
470
String _resp =
""
;
// Переменная для хранения результата
471
// Serial.print("CMD: "); // Дублируем команду в монитор порта
472
// Serial.println(cmd); // Дублируем команду в монитор порта
473
gsm.println(cmd);
// Отправляем команду модулю
474
if
(waiting) {
// Если необходимо дождаться ответа...
475
_resp = waitResponse();
// ... ждем, когда будет передан ответ
476
// Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
477
if
(_resp.startsWith(cmd)) {
// Убираем из ответа дублирующуюся команду
478
_resp = _resp.substring(_resp.indexOf(
"\r"
, cmd.length()) + 2);
479
}
480
// Serial.println(_resp); // Дублируем ответ в монитор порта
481
}
482
return
_resp;
// Возвращаем результат. Пусто, если проблема
483
}
484
485
// Функция ожидания ответа и возврата полученного результата
486
String waitResponse() {
// Функция ожидания ответа и возврата полученного результата
487
String _resp =
""
;
// Переменная для хранения результата
488
long
_timeout = millis() + 10000;
// Переменная для отслеживания таймаута (10 секунд)
489
while
(!gsm.available() && millis() < _timeout) {};
// Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
490
if
(gsm.available()) {
// Если есть, что считывать...
491
_resp = gsm.readString();
// ... считываем и запоминаем
492
}
493
else
{
// Если пришел таймаут, то...
494
// Serial.println("Timeout..."); // ... оповещаем об этом и...
495
}
496
return
_resp;
// ... возвращаем результат. Пусто, если проблема
497
}
498
499
// Обработка смс цифр из сообщения - для парсинга баланса из USSD-запроса
500
float
getFloatFromString(String str) {
// Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
501
bool
flag =
false
;
502
String result =
""
;
503
str.replace(
","
,
"."
);
// Если в качестве разделителя десятичных используется запятая - меняем её на точку.
504
for
(
int
i = 0; i < str.length(); i++) {
505
if
(isDigit(str[i]) || (str[i] == (
char
)46 && flag)) {
// Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания),
506
if
(result ==
""
&& i > 0 && (String)str[i - 1] ==
"-"
) {
// Нельзя забывать, что баланс может быть отрицательным
507
result +=
"-"
;
// Добавляем знак в начале
508
}
509
result += str[i];
// начинаем собирать их вместе
510
if
(!flag) flag =
true
;
// Выставляем флаг, который указывает на то, что сборка числа началась.
511
}
512
else
{
// Если цифры закончились и флаг говорит о том, что сборка уже была,
513
if
(str[i] != (
char
)32) {
// Если порядок числа отделен пробелом - игнорируем его, иначе...
514
if
(flag)
break
;
// ...считаем, что все.
515
}
516
}
517
}
518
return
result.toFloat();
// Возвращаем полученное число.
519
}
520
521
522
//процедура отправки СМС
523
void
smsSendAlarm(String text) {
524
textToSend =
""
;
525
//Главный номер
526
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){
527
ReadNumber(1);
528
sendSms(text, NBoss);
529
}
530
//User1 31-41,
531
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){
532
ReadNumber(2);
533
sendSms(text, NBoss1);
534
}
535
//User2 42-52,
536
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){
537
ReadNumber(3);
538
sendSms(text, NBoss2);
539
}
540
//User3 53-63
541
if
(EEPROM.read(53) == 7 && Boss == 4 || EEPROM.read(53) == 7 && Boss == 82 || EEPROM.read(53) == 7 && Boss == 83){
542
ReadNumber(4);
543
sendSms(text, NBoss3);
544
}
545
//User4 64-74
546
if
(EEPROM.read(64) == 7 && Boss == 5 || EEPROM.read(64) == 7 && Boss == 82 || EEPROM.read(64) == 7 && Boss == 83){
547
ReadNumber(5);
548
sendSms(text, NBoss4);
549
}
550
//User5 75-85
551
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){
552
ReadNumber(6);
553
sendSms(text, NBoss5);
554
}
555
text =
""
;
556
NBoss =
""
;
557
NBoss1 =
""
;
558
NBoss2 =
""
;
559
NBoss3 =
""
;
560
NBoss4 =
""
;
561
NBoss5 =
""
;
562
sendATCommand(
"AT+CMGDA=DEL ALL\r\n"
,
true
);
563
sendATCommand(
"AT+CMGD=4"
,
true
);
564
sendATCommand(
"AT+CMGF=1"
,
true
);
// устанавливает текстовый режим смс-сообщения
565
Boss = 0;
566
}
567
568
//Отправка смс о балансе
569
void
GoBalans(){
570
sendATCommand(
"AT+CUSD=1,\"#100#\""
,
true
);
571
}
572
573
//Начинаем поиск номера
574
void
ReadNumber(
int
numberN){
575
if
(numberN == 1){
576
NBoss =
""
;
577
SearchN(20, 30);
578
NBoss = NBoss;
579
return
NBoss;
580
}
581
if
(numberN == 2){
582
NBoss =
""
;
583
SearchN(31, 41);
584
NBoss1 = NBoss;
585
NBoss =
""
;
586
return
NBoss1;
587
}
588
if
(numberN == 3){
589
NBoss =
""
;
590
SearchN(42, 52);
591
NBoss2 = NBoss;
592
NBoss =
""
;
593
return
NBoss2;
594
}
595
if
(numberN == 4){
596
NBoss =
""
;
597
SearchN(53, 63);
598
NBoss3 = NBoss;
599
NBoss =
""
;
600
return
NBoss3;
601
}
602
if
(numberN == 5){
603
NBoss =
""
;
604
SearchN(64, 74);
605
NBoss4 = NBoss;
606
NBoss =
""
;
607
return
NBoss4;
608
}
609
if
(numberN == 6){
610
NBoss =
""
;
611
SearchN(75, 85);
612
NBoss5 = NBoss;
613
NBoss =
""
;
614
return
NBoss5;
615
}
616
}
617
618
//ищем номер в EEPROM
619
void
SearchN(
int
firstI,
int
secondI){
620
for
(i=firstI;i<=secondI;i++){
621
Temp2 = EEPROM.read(i);
622
if
(Temp2 == 0){NBoss +=
"0"
;}
623
if
(Temp2 == 1){NBoss +=
"1"
;}
624
if
(Temp2 == 2){NBoss +=
"2"
;}
625
if
(Temp2 == 3){NBoss +=
"3"
;}
626
if
(Temp2 == 4){NBoss +=
"4"
;}
627
if
(Temp2 == 5){NBoss +=
"5"
;}
628
if
(Temp2 == 6){NBoss +=
"6"
;}
629
if
(Temp2 == 7){NBoss +=
"7"
;}
630
if
(Temp2 == 8){NBoss +=
"8"
;}
631
if
(Temp2 == 9){NBoss +=
"9"
;}
632
}
633
return
NBoss;
634
Temp2 = 0;
635
}
636
637
// Удаление всех настроек и номера из памяти EEPROM
638
void
RAll(){
639
ClearAddresDataEEPROM();
640
WriteEEPROM();
// Записываем значения по умолчанию
641
Info();
// Вывод в Serial Инфу
642
counterClearAddrDataEEprom = 1;
643
644
}
645
646
// Очистка EEPROM
647
void
ClearAddresDataEEPROM(){
648
for
(i=0; i<=100; i++){
649
EEPROM.write(i,0);
650
}
651
}
652
653
void
WriteEEPROM(){
654
//0=48-48
655
//1=49-48
656
//2=50-48
657
//3=51-48
658
//4=52-48
659
//5=53-48
660
//6=54-48
661
//7=55-48
662
//8=56-48
663
//9=57-48
664
EEPROM.write(0,3);
//состоянии системы = 3(в режиме регистации)
665
// EEPROM.write(75,3);//Уставка температуры, первая цифра
666
// EEPROM.write(76,0);//Уставка температуры, вторая цифра
667
// intUstavkaTE = EEPROM.read(75) * 10;
668
// intUstavkaTE = intUstavkaTE + EEPROM.read(76);
669
}
670
671
void
Info(){
672
Serial
.println(
"Info"
);
673
delay(1);
674
// Состояние регистрации системы
675
Serial
.print(
"State system register or not: "
);
676
Serial
.println(EEPROM.read(0));
677
678
// 20-30 - Храним номер №1 Хозяина
679
Serial
.print(
"Number phone 1: "
);
680
for
(i=20; i<=30; i++){
681
Serial
.print(EEPROM.read(i));
682
}
683
Serial
.println(
""
);
684
685
// 31-41 - Храним номер №2
686
Serial
.print(
"Number phone 2: "
);
687
for
(i=31; i<=41; i++){
688
Serial
.print(EEPROM.read(i));
689
}
690
Serial
.println(
""
);
691
692
// 42-52 - Храним номер №3
693
Serial
.print(
"Number phone 3: "
);
694
for
(i=42; i<=52; i++){
695
Serial
.print(EEPROM.read(i));
696
}
697
Serial
.println(
""
);
698
699
// 53-63 - Храним номер №4
700
Serial
.print(
"Number phone 4: "
);
701
for
(i=53; i<=63; i++){
702
Serial
.print(EEPROM.read(i));
703
}
704
Serial
.println(
""
);
705
706
// 64-74 - Храним номер №5
707
Serial
.print(
"Number phone 5: "
);
708
for
(i=64; i<=74; i++){
709
Serial
.print(EEPROM.read(i));
710
}
711
Serial
.println(
""
);
712
713
// 75-85 - Храним номер №6
714
Serial
.print(
"Number phone 6: "
);
715
for
(i=75; i<=85; i++){
716
Serial
.print(EEPROM.read(i));
717
}
718
Serial
.println(
""
);
719
}
720
721
// Очистка временных переменных
722
void
ClearDataIn(){
723
Temp =
""
;
724
// Boss = 0;
725
currStr =
""
;
726
currStrN =
""
;
727
dataBalanceTemp =
""
;
728
dataSms =
""
;
729
dataSmsN =
""
;
730
// dataBalance = "";
731
val =
""
;
732
flag1 = 0;
733
flag2 = 0;
734
}
735
736
// Отправка смс
737
void
sendSms(String textForSend, String Number){
738
sendSMSinPDU(Number, textForSend);
739
do
{
740
_response = sendATCommand(
"AT+CLIP=1"
,
true
);
// Включаем АОН
741
_response.trim();
// Убираем пробельные символы в начале и конце
742
}
while
(_response !=
"OK"
);
// Не пускать дальше, пока модем не вернет ОК
743
744
745
}
746
747
void
sendSMSinPDU(String phone, String message)
748
{
749
// Serial.println("Отправляем сообщение: " + message);
750
751
// ============ Подготовка PDU-пакета =============================================================================================
752
// В целях экономии памяти будем использовать указатели и ссылки
753
String *ptrphone = ☎
// Указатель на переменную с телефонным номером
754
String *ptrmessage = &message;
// Указатель на переменную с сообщением
755
756
String PDUPack;
// Переменная для хранения PDU-пакета
757
String *ptrPDUPack = &PDUPack;
// Создаем указатель на переменную с PDU-пакетом
758
759
int
PDUlen = 0;
// Переменная для хранения длины PDU-пакета без SCA
760
int
*ptrPDUlen = &PDUlen;
// Указатель на переменную для хранения длины PDU-пакета без SCA
761
762
getPDUPack(ptrphone, ptrmessage, ptrPDUPack, ptrPDUlen);
// Функция формирующая PDU-пакет, и вычисляющая длину пакета без SCA
763
764
// Serial.println("PDU-pack: " + PDUPack);
765
// Serial.println("PDU length without SCA:" + (String)PDUlen);
766
767
// ============ Отправка PDU-сообщения ============================================================================================
768
sendATCommand(
"AT+CMGF=0"
,
true
);
// Включаем PDU-режим
769
sendATCommand(
"AT+CMGS="
+ (String)PDUlen,
true
);
// Отправляем длину PDU-пакета
770
sendATCommand(PDUPack + (String)((
char
)26),
true
);
// После PDU-пакета отправляем Ctrl+Z
771
PDUPack =
""
;
772
message =
""
;
773
*ptrphone =
""
;
774
*ptrmessage =
""
;
775
*ptrPDUlen =
""
;
776
}
777
778
void
getPDUPack(String *phone, String *message, String *result,
int
*PDUlen)
779
{
780
// Поле SCA добавим в самом конце, после расчета длины PDU-пакета
781
*result +=
"01"
;
// Поле PDU-type - байт 00000001b
782
*result +=
"00"
;
// Поле MR (Message Reference)
783
*result += getDAfield(phone,
true
);
// Поле DA
784
*result +=
"00"
;
// Поле PID (Protocol Identifier)
785
*result +=
"08"
;
// Поле DCS (Data Coding Scheme)
786
//*result += ""; // Поле VP (Validity Period) - не используется
787
788
String msg = StringToUCS2(*message);
// Конвертируем строку в UCS2-формат
789
790
*result += byteToHexString(msg.length() / 2);
// Поле UDL (User Data Length). Делим на 2, так как в UCS2-строке каждый закодированный символ представлен 2 байтами.
791
*result += msg;
792
793
*PDUlen = (*result).length() / 2;
// Получаем длину PDU-пакета без поля SCA
794
*result =
"00"
+ *result;
// Добавляем поле SCA
795
}
796
797
String getDAfield(String *phone,
bool
fullnum) {
798
String result =
""
;
799
for
(
int
i = 0; i <= (*phone).length(); i++) {
// Оставляем только цифры
800
if
(isDigit((*phone)[i])) {
801
result += (*phone)[i];
802
}
803
}
804
int
phonelen = result.length();
// Количество цифр в телефоне
805
if
(phonelen % 2 != 0) result +=
"F"
;
// Если количество цифр нечетное, добавляем F
806
807
for
(
int
i = 0; i < result.length(); i += 2) {
// Попарно переставляем символы в номере
808
char
symbol = result[i + 1];
809
result = result.substring(0, i + 1) + result.substring(i + 2);
810
result = result.substring(0, i) + (String)symbol + result.substring(i);
811
}
812
813
result = fullnum ?
"91"
+ result :
"81"
+ result;
// Добавляем формат номера получателя, поле PR
814
result = byteToHexString(phonelen) + result;
// Добавляем длину номера, поле PL
815
816
return
result;
817
}
818
819
// =================================== Блок кодирования строки в представление UCS2 =================================
820
String StringToUCS2(String s)
821
{
822
String output =
""
;
// Переменная для хранения результата
823
824
for
(
int
k = 0; k < s.length(); k++) {
// Начинаем перебирать все байты во входной строке
825
byte
actualChar = (
byte
)s[k];
// Получаем первый байт
826
unsigned
int
charSize = getCharSize(actualChar);
// Получаем длину символа - кличество байт.
827
828
// Максимальная длина символа в UTF-8 - 6 байт плюс завершающий ноль, итого 7
829
char
symbolBytes[charSize + 1];
// Объявляем массив в соответствии с полученным размером
830
for
(
int
i = 0; i < charSize; i++) symbolBytes[i] = s[k + i];
// Записываем в массив все байты, которыми кодируется символ
831
symbolBytes[charSize] =
'\0'
;
// Добавляем завершающий 0
832
833
unsigned
int
charCode = symbolToUInt(symbolBytes);
// Получаем DEC-представление символа из набора байтов
834
if
(charCode > 0) {
// Если все корректно преобразовываем его в HEX-строку
835
// Остается каждый из 2 байт перевести в HEX формат, преобразовать в строку и собрать в кучу
836
output += byteToHexString((charCode & 0xFF00) >> 8) +
837
byteToHexString(charCode & 0xFF);
838
}
839
k += charSize - 1;
// Передвигаем указатель на начало нового символа
840
if
(output.length() >= 280)
break
;
// Строка превышает 70 (4 знака на символ * 70 = 280) символов, выходим
841
}
842
return
output;
// Возвращаем результат
843
}
844
845
String byteToHexString(
byte
i) {
// Функция преобразования числового значения байта в шестнадцатиричное (HEX)
846
String hex = String(i, HEX);
847
if
(hex.length() == 1) hex =
"0"
+ hex;
848
hex.toUpperCase();
849
return
hex;
850
}
851
852
unsigned
int
getCharSize(unsigned
char
b) {
// Функция получения количества байт, которыми кодируется символ
853
// По правилам кодирования UTF-8, по старшим битам первого октета вычисляется общий размер символа
854
// 1 0xxxxxxx - старший бит ноль (ASCII код совпадает с UTF-8) - символ из системы ASCII, кодируется одним байтом
855
// 2 110xxxxx - два старших бита единицы - символ кодируется двумя байтами
856
// 3 1110xxxx - 3 байта и т.д.
857
// 4 11110xxx
858
// 5 111110xx
859
// 6 1111110x
860
861
if
(b < 128)
return
1;
// Если первый байт из системы ASCII, то он кодируется одним байтом
862
863
// Дальше нужно посчитать сколько единиц в старших битах до первого нуля - таково будет количество байтов на символ.
864
// При помощи маски, поочереди исключаем старшие биты, до тех пор пока не дойдет до нуля.
865
for
(
int
i = 1; i <= 7; i++) {
866
if
(((b << i) & 0xFF) >> 7 == 0) {
867
return
i;
868
}
869
}
870
return
1;
871
}
872
873
unsigned
int
symbolToUInt(
const
String& bytes) {
// Функция для получения DEC-представления символа
874
unsigned
int
charSize = bytes.length();
// Количество байт, которыми закодирован символ
875
unsigned
int
result = 0;
876
if
(charSize == 1) {
877
return
bytes[0];
// Если символ кодируется одним байтом, сразу отправляем его
878
}
879
else
{
880
unsigned
char
actualByte = bytes[0];
881
// У первого байта оставляем только значимую часть 1110XXXX - убираем в начале 1110, оставляем XXXX
882
// Количество единиц в начале совпадает с количеством байт, которыми кодируется символ - убираем их
883
// Например (для размера 2 байта), берем маску 0xFF (11111111) - сдвигаем её (>>) на количество ненужных бит (3 - 110) - 00011111
884
result = actualByte & (0xFF >> (charSize + 1));
// Было 11010001, далее 11010001&(11111111>>(2+1))=10001
885
// Каждый следующий байт начинается с 10XXXXXX - нам нужны только по 6 бит с каждого последующего байта
886
// А поскольку остался только 1 байт, резервируем под него место:
887
result = result << (6 * (charSize - 1));
// Было 10001, далее 10001<<(6*(2-1))=10001000000
888
889
// Теперь у каждого следующего бита, убираем ненужные биты 10XXXXXX, а оставшиеся добавляем к result в соответствии с расположением
890
for
(
int
i = 1; i < charSize; i++) {
891
actualByte = bytes[i];
892
if
((actualByte >> 6) != 2)
return
0;
// Если байт не начинается с 10, значит ошибка - выходим
893
// В продолжение примера, берется существенная часть следующего байта
894
// Например, у 10011111 убираем маской 10 (биты в начале), остается - 11111
895
// Теперь сдвигаем их на 2-1-1=0 сдвигать не нужно, просто добавляем на свое место
896
result |= ((actualByte & 0x3F) << (6 * (charSize - 1 - i)));
897
// Было result=10001000000, actualByte=10011111. Маской actualByte & 0x3F (10011111&111111=11111), сдвигать не нужно
898
// Теперь "пристыковываем" к result: result|11111 (10001000000|11111=10001011111)
899
}
900
return
result;
901
}
902
}
903
904
// функция вывода адреса датчика
905
void
printAddress(DeviceAddress deviceAddress){
906
for
(uint8_t i = 0; i < 8; i++){
907
if
(deviceAddress[i] < 16)
Serial
.print(
"0"
);
908
Serial
.print(deviceAddress[i], HEX);
909
}
910
}
Приветствую.
А схему устройства увидеть можно?
Пипец, 900 строк чтоб отправить температуру по Смс?
Строка 618 и далее - это еще повезло, что цифр в арифметике всего 10. Страшно представить, сколько понадобилось бы условий, чтобы отыскать в тексте каждую букву кириллицы и латиницы обоих регистров.
Стамбулов, вы про массивы и циклы не слыхали?
ГРАНДИОЗНО!!!!!!!!! Я только в руки взял SIM800L - пробую разобраться, ранее так же с нуля освоил NRF24 (делал на нем радиоуправление строительного крана - самоделка в помощь на моей стройке)
По SIM800L - пока тренируюсь с терминала, чтоб в дальнейшем проект отработат в Atmel Studio 7
возник вопрос по передаче смс - в начале настройка:
/
Если Вы впервые держите в руках SIM800L - то советую сюда - http://codius.ru/articles?page=1
001
#include <SoftwareSerial.h>
002
#include <OneWire.h>
003
#include <DallasTemperature.h>
004
#define ONE_WIRE_BUS 12
005
006
007
SoftwareSerial SIM800(8, 9);
008
OneWire oneWire(ONE_WIRE_BUS);
009
DallasTemperature sensors(&oneWire);
010
011
012
const
String MAIN_PHONE =
"+71234567890"
;
// Основной номер
013
const
String WHITE_LIST =
"+71234567890; +79999999999; +79888888888"
;
// Включить основной и дополнительный/е телефоны в белый список
014
const
String TEXT_USSD_BALANCE_QUERY =
"AT+CUSD=1,\"*100#\""
;
// Отправляет ТЕКСТОВЫЙ ответ, а не PDU-пакет, альтернативный запрос - "#100#"
015
const
String BALANCE_TEXT_QUERY =
"Balance"
;
// Содержание СМС для получения текстового ответа на запрос о балансе
016
const
String TEMPERATURE_QUERY =
"Temperature"
;
// Содержание СМС для получения ответа на запрос о температуре
017
const
String CURRENCY =
" BYN"
;
// Текстовое представление валюты
018
const
float
BALANCE_TRESHOLD = 15.0;
// Нижнее пороговое значение температуры
019
const
float
TEMPERATURE_TRESHOLD = 24.0;
// Нижнее пороговое значение баланса
020
021
022
String sendATCommand(
const
String& cmd,
bool
waiting) {
023
String response =
""
;
024
Serial
.println(cmd);
025
SIM800.println(cmd);
026
if
(waiting) {
027
response = waitAndReturnResponse();
028
if
(response.startsWith(cmd)) {
029
response = response.substring(response.indexOf(
"\r"
, cmd.length()) + 2);
030
}
031
Serial
.println(response);
032
}
033
return
response;
034
}
035
036
String waitAndReturnResponse() {
037
String response =
""
;
038
int64_t timeout = millis() + 10000;
039
while
(!SIM800.available() && millis() < timeout) {};
040
if
(SIM800.available()) {
041
response = SIM800.readString();
042
}
043
else
{
044
Serial
.println(
"Timeout..."
);
045
}
046
return
response;
047
}
048
049
void
sendSMS(
const
String& phone,
const
String& message) {
050
sendATCommand(
"AT+CMGS=\""
+ phone +
"\""
,
true
);
051
sendATCommand(message + (String)((
char
)26),
true
);
052
}
053
054
void
checkBalance(
const
String& number) {
055
sendATCommand(TEXT_USSD_BALANCE_QUERY,
true
);
056
String answer = waitAndReturnResponse();
057
answer.trim();
058
Serial
.println(
"\r\nBalans SIM karty: "
+ (String)extractBalanceFromString(answer));
059
sendSMS(number,
"\r\nBalans SIM karty: "
+ (String)extractBalanceFromString(answer) + CURRENCY +
"."
);
060
}
061
062
float
getFloatFromString(String str) {
// Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
063
bool
flag =
false
;
064
String result =
""
;
065
str.replace(
","
,
"."
);
// Если в качестве разделителя десятичных используется запятая - меняем её на точку.
066
for
(size_t i = 0; i < str.length(); ++i) {
067
if
(isDigit(str[i]) || (str[i] == (
char
)46 && flag)) {
// Если начинается группа цифр (при этом на точку без цифр не обращаем внимания),
068
if
(i != 0 && result ==
""
&& (String)str[i - 1] ==
"-"
) {
// Нельзя забывать, что баланс может быть отрицательным
069
result +=
"-"
;
// Добавляем знак в начале
070
}
071
result += str[i];
// Начинаем собирать их вместе
072
if
(!flag) {
073
flag =
true
;
// Выставляем флаг, который указывает на то, что сборка числа началась.
074
}
075
}
076
else
if
(str[i] != (
char
)32 && flag) {
077
break
;
078
}
079
}
080
return
result.toFloat();
// Возвращаем полученное число
081
}
082
083
void
parseSMS(String msg) {
// Парсим SMS
084
String msgheader =
""
;
// Переменная под звонивший телефона для анализа
085
String msgbody =
""
;
// Переменная под SMS
086
String msgphone =
""
;
// Переменная под номер телефона
087
088
msg = msg.substring(msg.indexOf(
"+CMGR: "
));
089
msgheader = msg.substring(0, msg.indexOf(
"\r"
));
// Получаем звонивший телефон
090
091
msgbody = msg.substring(msgheader.length() + 2);
092
msgbody = msgbody.substring(0, msgbody.lastIndexOf(
"OK"
));
// Получаем текст полученной SMS
093
msgbody.trim();
// Обрезаем начальные или концевые символы
094
095
int
firstIndex = msgheader.indexOf(
"\",\""
) + 3;
096
int
secondIndex = msgheader.indexOf(
"\",\""
, firstIndex);
097
msgphone = msgheader.substring(firstIndex, secondIndex);
098
if
(WHITE_LIST.indexOf(msgphone) != -1) {
// Если телефон в белом списке, то...
099
if
(msgbody == BALANCE_TEXT_QUERY) {
100
checkBalance(msgphone);
101
}
102
else
if
(msgbody == TEMPERATURE_QUERY) {
103
sendSMS(msgphone,
"Sensor temperature: "
+
104
String(obtainTemperature()) +
" C."
);
105
}
106
Serial
.println(
"Phone: "
+ msgphone);
// Выводим номер телефона
107
Serial
.println(
"Message: "
+ msgbody);
// Выводим текст SMS
108
}
109
else
if
(msgphone.length()) {
110
Serial
.println(
"Unknown phone number: "
+ msgphone);
111
Serial
.println(
"Message: "
+ msgbody);
112
}
113
}
114
115
void
checkNewMessages() {
116
static
bool
hasmsg =
false
;
117
String response = sendATCommand(
"AT+CMGL=\"REC UNREAD\",1"
,
true
);
// Отправляем запрос чтения непрочитанных сообщений
118
if
(response.indexOf(
"+CMGL: "
) >= 0) {
// Если есть хоть одно, получаем его индекс
119
int
msgIndex = response.substring(response.indexOf(
"+CMGL: "
) + 7,
120
response.indexOf(
"\"REC UNREAD\""
,
121
response.indexOf(
"+CMGL: "
)) - 1).toInt();
122
response = sendATCommand(
"AT+CMGR="
+ (String)msgIndex +
",1"
,
true
);
// Пробуем получить текст SMS по индексу
123
response.trim();
// Убираем пробелы в начале/конце
124
if
(response.endsWith(
"OK"
)) {
// Если ответ заканчивается на "ОК"
125
if
(!hasmsg) {
126
hasmsg =
true
;
// Ставим флаг наличия сообщений для удаления
127
}
128
sendATCommand(
"AT+CMGR="
+ (String)msgIndex,
true
);
// Делаем сообщение прочитанным
129
sendATCommand(
"\n"
,
true
);
// Перестраховка - вывод новой строки
130
parseSMS(response);
// Отправляем текст сообщения на обработку
131
}
132
}
133
else
{
134
if
(hasmsg ==
true
) {
135
sendATCommand(
"AT+CMGDA=\"DEL READ\""
,
true
);
// Удаляем все прочитанные сообщения
136
hasmsg =
false
;
137
}
138
}
139
}
140
141
void
modemQueryAndResponse() {
142
if
(SIM800.available()) {
// Если модем что-то получил...
143
String data = waitAndReturnResponse();
// Получаем ответ для модема для анализа
144
data.trim();
// Убираем лишние пробелы в начале и конце
145
parseSMS(data);
146
Serial
.println(data);
// Если нужно, выводим в монитор порта
147
if
(data.startsWith(
"+CUSD:"
)) {
// Пришло уведомление об USSD-ответе
148
if
(data.indexOf(
"\""
) > -1) {
// Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
149
float
balance = extractBalanceFromString(data);
150
Serial
.println(
"\r\nBalans SIM karty: "
+ (String)balance + CURRENCY +
"."
);
151
}
152
}
153
}
154
else
if
(
Serial
.available()) {
// Ожидаем команды по Serial...
155
SIM800.write(
Serial
.read());
// ... и отправляем полученную команду модему
156
}
157
}
158
159
float
obtainTemperature() {
160
sensors.requestTemperatures();
161
return
sensors.getTempCByIndex(0);
162
}
163
164
void
tresholdTemperature(
float
current_temperature) {
165
static
bool
flag = 1;
166
if
(current_temperature < TEMPERATURE_TRESHOLD && flag) {
167
sendSMS(MAIN_PHONE,
"Temperature is currently below "
+ String(TEMPERATURE_TRESHOLD) +
168
" C and equal to "
+ String(current_temperature) +
" C."
);
169
flag = 0;
170
}
171
else
if
(current_temperature >= TEMPERATURE_TRESHOLD && !flag) {
172
flag = 1;
173
}
174
}
175
176
float
extractBalanceFromString(
const
String& response) {
177
String msgBalance = response.substring(response.indexOf(
"\""
) + 2);
178
msgBalance = msgBalance.substring(0, msgBalance.indexOf(
"\""
));
179
return
getFloatFromString(msgBalance);
180
}
181
182
void
balanceChecking() {
183
static
bool
flag = 1;
184
sendATCommand(TEXT_USSD_BALANCE_QUERY,
true
);
185
String answer = waitAndReturnResponse();
186
answer.trim();
187
float
balance = extractBalanceFromString(answer);
188
Serial
.println(
"Balance is "
+ String(balance));
189
if
(balance < BALANCE_TRESHOLD && flag) {
190
sendSMS(MAIN_PHONE,
"Balance is below "
+ String(BALANCE_TRESHOLD) +
191
CURRENCY +
" and equal to "
+ String(balance) + CURRENCY +
"."
);
192
flag = 0;
193
}
194
else
if
(balance >= BALANCE_TRESHOLD && !flag) {
195
flag = 1;
196
}
197
}
198
199
void
setup
() {
200
Serial
.begin(9600);
201
SIM800.begin(9600);
202
203
sensors.begin();
204
sensors.requestTemperatures();
205
206
Serial
.println(
"Start!"
);
207
208
sendATCommand(
"AT"
,
true
);
209
sendATCommand(
"AT+CMGDA=\"DEL ALL\""
,
true
);
210
sendATCommand(
"AT+CLIP=1"
,
true
);
211
sendATCommand(
"AT+CMGF=1;&W"
,
true
);
212
}
213
214
void
loop
() {
215
static
int64_t balance_check_timer = 0;
216
static
int64_t temperature_check_timer = 0;
217
static
int64_t new_message_check_timer = 0;
218
219
modemQueryAndResponse();
220
if
(abs(millis() - new_message_check_timer) >= 5000) {
221
checkNewMessages();
222
new_message_check_timer = millis();
223
}
224
if
(abs(millis() - temperature_check_timer) >= 10000) {
225
tresholdTemperature(obtainTemperature());
226
temperature_check_timer = millis();
227
}
228
if
(abs(millis() - balance_check_timer) >= 300000) {
229
balanceChecking();
230
balance_check_timer = millis();
231
}
232
}
Вот версия скетча для температурного датчика, отправляет СМС при снижении баланса, температуры ниже определенного уровня, также можно по запросу получить эти параметры в ответном СМС.
andyparker с каких пор вы постите чужое?
Приношу свои извинения andyparker!
Это и его код тоже.
Он вложил в него очень большой труд.
Его полезные советы помогли оживить устройство.
Теперь оно стабильно работает!!!
andyparker с каких пор вы постите чужое?
Приношу свои извинения andyparker!
что это было?
В понедельник узнаем)))
Уже разобрались.
Все в порядке!