Самодельный GSM контроллер отопления на базе Arduino UNO и модуля SIM800L

Здравствуйте!

Появилась потребность изготовить бюджетный контроллер отопления. Да такой, чтобы можно было управлять им удаленно с помощью SMS команд, и получать данные о температуре влажности и состоянии сети 220 вольт.

Схема самодельный GSM контроллер для отопления

Для проекта понадобятся:

Плата Arduino UNO,

GSM модуль SIM800L, Провода,

Твердотельное реле G3MB-202P,

Модуль зарядки LI-ION батарей от MICROUSB,

LI-ION батарея на 3.7 вольта с емкостью от 1000 миллиампер,

Зарядка от телефона, или блок питания на 5 вольт, и от 500 до 1000 миллиампер,

Датчик температуры и влажности DHT11,

Датчик температуры LM35,

4 сопротивления на 250-500 ом, 2k, 2.4k и 10k

Для индикации любой маломощный светодиод,

Еще понадобится: активная сим карта с положительным балансом на счету.

Вилка, розетка, и коробка в корой все поместится.

Коробку для корпуса лучше использовать из негорючего пластика!

Материалы для самодельный GSM контроллер для отопления

Рассмотрим скетч!

В 16 строке скетча, необходимо вписать номера телефонов, с которых будет разрешено принимать SMS команды.

Также в 245 строке необходимо указать номер, на который будут приходить данные о температуре, влажности, состоянии сети 220 вольт и какую программу выполняет контроллер.

Я прописал в этот скетч 8 SMS команд.

Часть из них служат для переключения на интересующую программу, а остальные для запроса отчета, и настройки климат контроля.

Более подробно я рассказываю на видео, которое закреплено в конце этой статьи


//Начало скетча


  1. #include "SoftwareSerial.h"
  2. #include "SimpleDHT.h"
  3. int p8 = 11, t_1 = 0, pinDHT11 = 15, temperature = 0, humidity=0, msgphone=0;
  4. SimpleDHT11 dht11(pinDHT11);
  5. SoftwareSerial SIM800(2, 3); //программные RX, TX для связи с модулем SIM800L
  6. unsigned long timing1, timing2, timing3, timing4, timing5, timing6, timing7, timing8, timing9;
  7. // Перемен. для хранения точки отсчета для таймеров
  8. int j=0, k=0, a=0, x=9, x2=20, v=0;
  9. String _response = ""; // Переменная для хранения ответа модуля
  10. long lastUpdate = millis(); // Время последнего обновления
  11. long updatePeriod = 60000; // Проверять каждую минуту
  12. String phones = "+xxxxxxxxxxxx, +xxxxxxxxxxxx"; //Список разрешенных номеров
  13. //номера вписываются в международном формате начиная с +
  14. String waitResponse() { // Функция ожидания ответа и возврата полученного результата
  15. String _resp = ""; // Переменная для хранения результата
  16. long _timeout = millis() + 10000; // Переменная для отслеживания тайм аута (10 секунд)
  17. while (!SIM800.available() && millis() < _timeout) {};// Ждем ответа 10 секунд, если пришел ответ или наступил тайм аут, то...
  18. if (SIM800.available()) { // Если есть, что считывать
  19. _resp = SIM800.readString(); //считываем и запоминаем
  20. }else { // Если пришел тайм аут, то
  21. Serial.println("Timeout..."); //оповещаем об этом и
  22. }return _resp; //возвращаем результат. Пусто, если проблема
  23. }
  24. String sendATCommand(String cmd, bool waiting) {
  25. String _resp = ""; // Переменная для хранения результата
  26. Serial.println(cmd); // Дублируем команду в монитор порта
  27. SIM800.println(cmd); // Отправляем команду модулю
  28. if (waiting) { // Если необходимо дождаться ответа
  29. _resp = waitResponse(); // ждем, когда будет передан ответ
  30. // Если Echo Mode выключен (ATE0), то эти 3 строки можно за комментировать
  31. if (_resp.startsWith(cmd)) { // Убираем из ответа дублирующуюся команду
  32. _resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
  33. }
  34. Serial.println(_resp); // Дублируем ответ в Serial
  35. }return _resp; // Возвращаем результат. Пусто, если проблема
  36. }
  37. void parseSMS(String msg) { // Парсим SMS
  38. String msgheader = "";
  39. String msgbody = "";
  40. String msgphone = "";
  41. msg = msg.substring(msg.indexOf("+CMGR: "));
  42. msgheader = msg.substring(0, msg.indexOf("\r")); // Выдергиваем телефон
  43. msgbody = msg.substring(msgheader.length() + 2);
  44. msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK"));// Выдергиваем текст SMS
  45. msgbody.trim();
  46. int firstIndex = msgheader.indexOf("\",\"") + 3;
  47. int secondIndex = msgheader.indexOf("\",\"", firstIndex);
  48. msgphone = msgheader.substring(firstIndex, secondIndex);
  49. Serial.println("Phone: " + msgphone); // Выводим номер телефона
  50. Serial.println("Message: " + msgbody); // Выводим текст SMS
  51. if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) { // Если телефон в белом списке, то
  52. if(msgbody == "Pr0"){j=0;digitalWrite(13, LOW);}
  53. if(msgbody == "Pr1"){j=1;digitalWrite(13, LOW);}
  54. if(msgbody == "Pr2"){j=2;digitalWrite(13, LOW);}
  55. if(msgbody == "Pr3"){j=3;}
  56. if(msgbody == "Pr20"){j=4;digitalWrite(13, LOW);}
  57. if(msgbody == "Ktr"){k=1;}
  58. if(msgbody == "Klx2+"){x2=x2+3;}
  59. if(msgbody == "Klx2-"){x2=x2-3;}
  60. }else {
  61. Serial.println("Unknown phonenumber");
  62. }}
  63. void setup() {
  64. pinMode(13, OUTPUT);
  65. pinMode(p8, OUTPUT);
  66. digitalWrite(13, LOW);
  67. digitalWrite(p8, LOW);
  68. pinMode(7, INPUT);
  69. Serial.begin(9600); // Скорость обмена данными с компьютером
  70. SIM800.begin(9600); // Скорость обмена данными с модемом
  71. Serial.println("Start!");
  72. analogReference(INTERNAL);
  73. sendATCommand("AT", true); // Отправили AT для настройки скорости обмена данными
  74. sendATCommand("AT+CMGDA=\"DEL ALL\"", true); // Удаляем все SMS, чтобы не забивать память
  75. sendATCommand("AT+CMGF=1;&W", true); // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  76. lastUpdate = millis(); // Обнуляем таймер
  77. }
  78. bool hasmsg = false; // Флаг наличия сообщений к удалению
  79. void loop() {
  80. int sensorVal = digitalRead(7);
  81. if (sensorVal == HIGH) {v = 220; } else {v = 0;
  82. }
  83. if (millis() - timing9 > 3000){
  84. timing9 = millis();
  85. byte temperature = 0;
  86. byte humidity = 0;
  87. dht11.read(&temperature, &humidity, NULL);
  88. t_1 = analogRead(A0)/x;
  89. Serial.print("T1 = "); Serial.print(t_1); Serial.print("*C, ");
  90. Serial.print("T2 = "); Serial.print((int)temperature); Serial.print("*C, ");
  91. Serial.print((int)humidity); Serial.println("%");
  92. }
  93. if (lastUpdate + updatePeriod < millis() ) { // Пора проверить наличие новых сообщений
  94. do {
  95. _response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true); // Отправляем запрос чтения непрочитанных сообщений
  96. if (_response.indexOf("+CMGL: ") > -1) { // Если есть хоть одно, получаем его индекс
  97. int msgIndex = _response.substring( _response.indexOf ("+CMGL: ") + 7, _response.indexOf("\"REC UNREAD\"", _response.indexOf("+CMGL: ")) - 1).toInt();
  98. char i = 0; // Объявляем счетчик попыток
  99. do { i++; // Увеличиваем счетчик
  100. _response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true); // Пробуем получить текст SMS по индексу
  101. _response.trim(); // Убираем пробелы в начале/конце
  102. if (_response.endsWith("OK")) { // Если ответ заканчивается на "ОК"
  103. if (!hasmsg) hasmsg = true; // Ставим флаг наличия сообщений для удаления
  104. sendATCommand("AT+CMGR=" + (String)msgIndex, true); // Делаем сообщение прочитанным
  105. sendATCommand("\n", true); // Перестраховка - вывод новой строки
  106. parseSMS(_response); // Отправляем текст сообщения на обработку
  107. break; // Выход из do
  108. }else { // Если сообщение не заканчивается на OK
  109. Serial.println ("Error"); //ошибка
  110. sendATCommand("\n", true); // Отправляем новую строку и повторяем попытку
  111. }}
  112. while (i < 10); break;}else {
  113. lastUpdate = millis(); // Обнуляем таймер
  114. if (hasmsg) {
  115. sendATCommand("AT+CMGDA=\"DEL READ\"", true); // Удаляем все прочитанные сообщения
  116. hasmsg = false;}break;}} while (1);
  117. }
  118. if (SIM800.available()) { // Если модем, что-то отправил
  119. _response = waitResponse(); // Получаем ответ от модема для анализа
  120. _response.trim(); // Убираем лишние пробелы в начале и конце
  121. Serial.println(_response); // Если нужно выводим в монитор порта
  122. if (_response.indexOf("+CMTI:")>-1) { // Пришло сообщение об отправке SMS
  123. lastUpdate = millis() - updatePeriod; // Теперь нет необходимости обрабатывать SMS здесь, достаточно просто сбросить счетчик авто проверки, и в следующем цикле все будет обработано
  124. }}
  125. if (Serial.available()) { // Ожидаем команды по Serial
  126. SIM800.write(Serial.read()); //и отправляем полученную команду модему
  127. };
  128. if (j==0){ //Программа 0
  129. digitalWrite(p8, HIGH);}else{digitalWrite(p8, LOW);}
  130. if (j==1){ //Программа 1
  131. if (millis() - timing1 > 12600000){ //3 часа 30 минут = 12600000 мс
  132. timing1 = millis(); timing2 = millis();
  133. digitalWrite(13, HIGH);
  134. }
  135. if (millis() - timing2 > 1800000){ // 30 минут = 1800000 мс
  136. digitalWrite(13, LOW);
  137. }
  138. if (millis() - timing6 > 3000){
  139. timing6 = millis();
  140. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);
  141. } }
  142. if (j==2){ //Программа 2
  143. if (millis() - timing3 > 23400000){ // 6 часа 30 минут = 23400000 мс
  144. timing3 = millis(); timing4 = millis(); digitalWrite(13, HIGH);
  145. }
  146. if (millis() - timing4 > 1800000){ // 30 минут = 1800000 мс
  147. digitalWrite(13, LOW);
  148. }
  149. if (millis() - timing7 > 3000){
  150. timing7 = millis();
  151. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);delay(300);
  152. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);
  153. } }
  154. if (j==3){digitalWrite(13, HIGH); //Программа 3
  155. if (millis() - timing8 > 3000){ timing8 = millis();
  156. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);delay(300);
  157. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);delay(300);
  158. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);
  159. }}a=j;
  160. if (j==4){ a=20; //Программа 4
  161. if (millis() - timing5 > 3000){ timing5 = millis();
  162. byte temperature = 0;
  163. byte humidity = 0;
  164. dht11.read(&temperature, &humidity, NULL);
  165. if ((int)temperature <= x2) {digitalWrite(13, HIGH);}
  166. if ((int)temperature > x2) {digitalWrite(13, LOW);}}
  167. if (millis() - timing8 > 3000){ timing8 = millis();
  168. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);delay(300);
  169. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);delay(300);
  170. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);delay(300);
  171. digitalWrite(p8, HIGH); delay(100); digitalWrite(p8, LOW);
  172. }}else{a=j;
  173. }
  174. if (k==1){delay(300);
  175. byte temperature = 0;
  176. byte humidity = 0;
  177. dht11.read(&temperature, &humidity, NULL); delay(300);
  178. SIM800.println( "AT+CMGS=\"+xxxxxxxxxx\""); //номер на который будет приходить SMS отчет
  179. delay(3000); //номер вписывается в международном формате начиная с +
  180. SIM800.print("T1=");
  181. delay(300); SIM800.print(t_1);
  182. delay(300); SIM800.print("*C, T2=");
  183. delay(300); SIM800.print((int)temperature);
  184. delay(300); SIM800.print("*C, T2-VL=");
  185. delay(300); SIM800.print((int)humidity);
  186. delay(300); SIM800.print("% Pr="); delay(300);SIM800.print(a);
  187. delay(300); SIM800.print(" t=");
  188. delay(300); SIM800.print(x2);
  189. delay(300); SIM800.print(" Set=");
  190. delay(300); SIM800.print(v);
  191. delay(300); SIM800.print("volt");
  192. delay(300); SIM800.print((char)26);//команда для отправки SMS
  193. delay(300); Serial.println("SMS send finish");} k=0;
  194. }

//Конец скетча


Указав свои номера в скетче, загружаю его на плату.

Затем надо подготовить GSM модуль SIM800L. Припаять антенну, делитель напряжения, и еще 3 провода, как показано на схеме ниже.

Делитель напряжения нужен, для того чтобы не спалить GSM модуль. Сигнал входящего высокого уровня, для модуля SIM800L должен быть в пределах от 2.1 до 2.8 вольта!

Делитель напряжения для SIM800L

Затем собираю все как показано на этой схеме.

GSM контроллер отопления на базе Arduino UNO и модуля SIM800L

Я в схеме применил твердотельное реле G3MB-202P, которое рассчитано на нагрузку до 2 Ампер. Этого вполне достаточно для обычного циркуляционного насоса!

Если вы планируете, управлять мощным обогревателем или теплым полом, то используйте более мощное твердотельное реле, на пример SSR-40DA, которое выдерживает до 40 Ампер, или SSR-80DA до 80 Ампер. И провода соответствующего сечения!

Не используйте слишком тонкие провода для питания GSM модуля, так как при запуске модуля, нагрузка может достигать 2 Ампер. При использовании очень тонких проводов, возникает просадка по напряжению, и модуль не сможет найти сеть GSM.

Подробная видео инструкция о том как пользоваться GSM контроллером.

Самодельный GSM контроллер отопления на базе Arduino UNO и модуля SIM800L