Главная » Arduino
Призовой фонд
на декабрь 2016 г.
1. Тестер компонентов MG328
Паяльник
2. Осциллограф DSO138
Паяльник
3. 1000 руб.
Radio-Sale
4. 220 руб.
От пользователей

Как СМСнуть обогревателю?

Winter is coming

Winter is coming, господа, а посему нужно начинать готовиться. Как говорится, готовь скетч с обогревателем летом, а скетч с кондиционером – зимой.

Наша задача – сделать умный обогреватель.  Сейчас уже существуют обогреватели с термостатами, но нам важна сама идея. К тому же не каждый может похвастать тем, что может спросить у своего обогревателя температуру или попросить подогреть комнату ко времени прихода с работы, учебы.

Подключаем безлимитный тариф SMS и вперед, к прогрессу.

Детали

Для создания нашего устройства нам потребуются:

  • Собственно, обогреватель, самый простой 

 

 

  • Troyka Shield. Уж больно он мне нравится. Все датчики подключаются легко и непринужденно.

  

  • Соединительные провода. Тут все немного сложнее.  Если хочется собрать готовое устройство, то термостат желательно сделать выносной. Для этого нужно сделать провода достаточно длинными, а можно соорудить беспроводной термостат. В целях обучения беспроводной связи я выбрал второй вариант.

Описание устройства

Наше устройство будет состоять из двух частей – термостата и центрального контроллера. Термостат будет посылать данные о температуре на центральное устройство, которое, в свою очередь, будет управлять реле и общаться со смартфоном посредством GPRS Shield.

Со смартфона можно будет задать температуру, которую нужно поддерживать и режим работы устройства, а также узнать состояние и температуру.

Термостат

Начнем, пожалуй, с создания термостата. Наша задача – считывать показания температуры с DHT11 и передавать их на центральное устройство каждый фиксированный промежуток времени.

Задача поставлена – приступаем к выполнению. Соберем макет термостата.

Для эксперимента, соберем  макет центрального контроллера с единственной функцией – принятие сообщений от термостата. Это вид сверху. Под Troyka Shield находятся GPRS Shield и Arduino.

Может возникнуть вопрос – “А почему у приемника четыре пина, хотя используются только три?” Отвечаю – все просто, пин Data продублирован.

Теперь посмотрим на код передатчика.

//Подключаем библиотеки

#include <TroykaDHT11.h>
#include <VirtualWire.h>

//Определяем пин DHT11

DHT11 dht(11);

void setup() 
{

  Serial.begin(9600); 
  dht.begin();
  //Светодиод для индикации
  pinMode(13,OUTPUT);
  //требуется для DR3100
  vw_set_ptt_inverted(true); 
  //Обозначаем пин, к которому подключили приемник
  vw_set_rx_pin(12);
  //Установим скорость передачи
  vw_setup(4000);  
}

void loop()
{ 
  //Получаем температуру с DHT11
  String temp;
  dht.read();
  temp = dht.getTemperatureC();
  Serial.println(temp);
  //Приводим температуру к нужному для отправки виду
  char msg[10];
  temp.toCharArray(msg, 10);
  Serial.println(msg);
  //Отправляем сообщение
  digitalWrite(13, HIGH);
  vw_send((uint8_t *)msg, strlen(msg));
  vw_wait_tx();
  digitalWrite(13, LOW);
  //Ждем немного
  delay(5000);
 
}

А вот код для приемника.

//Подключаем библиотеку

#include <VirtualWire.h>

//Создаем массив для передачи температуры

char temp[3];

void setup()
{
    Serial.begin(9600);

    //требуется для DR3100
    vw_set_ptt_inverted(true); 
    //Обозначаем пин, к которому подключили приемник
    vw_set_rx_pin(12);
    //Установим скорость передачи
    vw_setup(4000);  
    //Светодиод для индикации
    pinMode(13, OUTPUT);
    //Стартуем
    vw_rx_start();    
    Serial.println("Setup");
}
    void loop()
{
  uint8_t buf[VW_MAX_MESSAGE_LEN]; // Буфер для сообщения
  uint8_t buflen = VW_MAX_MESSAGE_LEN; // Длина буфера

  if (vw_get_message(buf, &buflen)) // Если принято сообщение
  {
  Serial.println("Received:"); 
  digitalWrite(13, HIGH);
  //По символу записываем принятое сообщение 
  for(int i = 0; i < buflen; i++)
  {
     temp[i] = buf[i];
  }
  //Выводим сообщение
  Serial.print("Temperature is ");
  Serial.print(temp);
  Serial.println(" C");
  digitalWrite(13, LOW);
 }
}

Как это работает?

Начнем с передатчика. Arduino Pro MINI запрашивает значение температуры с DHT11. Получив температуру, MINI готовит пакет для передачи. Для передатчика важна разрядность, поэтому в коде присутствует странная запись - uint8_t *

Не нужно пугаться -  это другой и более правильный вид записи типа данных byte или unsigned char.

Вот небольшая таблица такой записи типов данных.

 int8_t    |  char    |  от -128 до 127
 uint8_t   |  byte, unsigned char |  от 0 до 255
 int16_t   |  int    |  от -32768 до 32767
 uint16_t  |  unsigned int, word  |  от 0 до 65535 
 int32_t   |  long    |  от  -2147483648 до 2147483647 
 uint32_t  |  unsigned long    |  от 0 до 4294967295

Приведенное к требуемому типу данных, значение температуры начинает передаваться на передатчик, который, в свою очередь, отсылает сообщение в эфир.

Приемник отслеживает эфир на наличие сообщений и, если сообщение пришло, выводит пришедшее значение температуры в Serial Monitor .

Умный обогреватель

Пришло время заняться центральным устройством. Корпус устройства и конечное выполнение зависит только от ваших возможностей и фантазии, поэтому я лишь приведу схему, по которой можно собрать устройство. Под Troyka Shield также находятся GPRS Shield и Arduino.

Если кто не знает, как подключать нагрузку к реле – вот схема. Ну и для общего образования:

  • Коричневый провод – это фаза, синий – ноль.
  • По-хорошему, нужно всегда размыкать фазу, а не ноль. Если выключатель будет размыкать ноль, то может ударить током, если притронутся к фазе, а если это сеть с большим напряжением, то исход может быть летальным. Вы там осторожнее.

 

Запрограммируем устройство. Есть готовая библиотека для работы с GPRS Shield, поэтому передача сообщений становится достаточно тривиальной. Скачать библиотеку можно тут. Один минус – функция отправки SMS не принимает SMS в String, поэтому нам нужно переводить String в char array с помощью функции string.toCharArray(char, number);

//Подключаем необходимые библиотеки
//Для GPRG Shield

#include <GPRS_Shield_Arduino.h>
#include <SoftwareSerial.h>

//Для радиоприемника

#include <VirtualWire.h>

//Определяем пин, к которому подключено реле

#define RELAY 8

//Текущее состояние реле
 
bool stateRelay = false;

//Переменная для определения режима работы

int mode = 0;

//Переменная для ручного управления обогревателем

int m_temp = 0;

//Переменные для температуры
//Температура в данный момент

int curr_temp = 0;

//Температура срабатывания 

int trig_temp = 0;

//Нежелательная температура

int danger_temp = 36;

// создаём объект класса GPRS

GPRS gprs;

//Определяем номер, на который будем посылать сообщения
//Нужно ввести свой номер

#define PHONE_NUMBER "+XXXXXXXXXXX"

//Описываем сообщения для отправки

#define HELLO_MESSAGE "Hello from GPRS Shield! Please, set trigger temperature."
#define MODE_MESSAGE "Send mode's name."
#define READY_MESSAGE "I'm ready!"
#define INC_TRIG "Incorrect trigger value! You only can set - 20, 25 and 28."
#define INC_MODE "Incorrect mode value! You can only set - Auto and Manual"
#define DANGER_MESSAGE "Current temperature is bigger than 38C. Relay is off."
#define ERROR_SMS "Incorrect command. You can only ask for state, set trigger temperature or set mode"
#define HEATERON "OK, heater is on."
#define HEATEROFF "OK, heater is off."
#define AUTOMODE "OK, auto mode."
#define MANUALMODE "OK, manual mode."
#define OKTEMP "OK, trigger temperature changed"

String helloText = "Hello from GPRS Shield!";
String tempText = "Tempreature is ";
String termValue = String(curr_temp);
String degree = " C.";
String heaterOn = "Heater is On.";
String heaterOff = "Heater is Off.";
String message_to_send;
char char_message_to_send[60];

// текст сообщения
char message[160];
// номер, с которого пришло сообщение
char phone[16];
// дата отправки сообщения
char datetime[24];

void setup()
{
  //Определяем пины реле, светодиода, приемника
  
  pinMode(RELAY, OUTPUT);
  pinMode(13, OUTPUT);
  digitalWrite(RELAY, LOW);
  vw_set_ptt_inverted(true);
  vw_set_rx_pin(12);

  //Устанавливаем связь

  Serial.begin(9600);
  vw_setup(4000);
  vw_rx_start(); 

  Serial.println("Start");
  gprs.powerUpDown();
  
  while (!gprs.init()) 
   {
    delay(1000);
    Serial.println("Connecting");
   }
   
//Отправляем запрос температуры

 Serial.println("Connected");
 gprs.sendSMS(PHONE_NUMBER, HELLO_MESSAGE);
 Serial.println("Hello message sent");
 
 while(trig_temp == 0)
 {
  Serial.println("Waiting for trigger temperature");
    if (gprs.ifSMSNow()) 
   {
    gprs.readSMS(message, phone, datetime);
    sms_temp(message);
   } 
   delay(1000);
 }
 
 Serial.println("Trigger temperature assigned. Ask for mode name.");

 //Отправляем запрос режима
 
  gprs.sendSMS(PHONE_NUMBER, MODE_MESSAGE);
  
 while(mode == 0)
 {
   Serial.println("Waiting for mode");
   if (gprs.ifSMSNow()) 
   {
    gprs.readSMS(message, phone, datetime);
    sms_mode(message);   
   }
   delay(1000);
 }
  Serial.println("Mode assigned");

  gprs.sendSMS(PHONE_NUMBER, READY_MESSAGE);
}

void loop()
{
    //Ждем сообщения
    
    if (gprs.ifSMSNow()) 
   {
    gprs.readSMS(message, phone, datetime);
    Serial.println("Message");
    inc_sms(message);
   }
   //Получаем текущую температуру с термостата
   
   inc_temp();
   
   //Проверяем надобность включения реле
   
   relay();
}

//Включаем или выключаем реле

void relay()
{
  if(curr_temp < trig_temp && mode == 1)
  {
    digitalWrite(RELAY, HIGH);  
    stateRelay = true;
    delay(3000);
  }
   if(curr_temp >= trig_temp && mode == 1) 
  {
    digitalWrite(RELAY, LOW);
    stateRelay = false;
    delay(3000);
  }
  if(m_temp == 1 &&  mode == 2 && curr_temp < danger_temp)
  {
     digitalWrite(RELAY, HIGH);  
     stateRelay = true;
  }
  if(m_temp == 0 &&  mode == 2 || curr_temp >= danger_temp)
  {
     digitalWrite(RELAY, LOW);  
     stateRelay = false;
     if(curr_temp >= danger_temp)
     {
      Serial.println("DANGER!");
      gprs.sendSMS(PHONE_NUMBER, DANGER_MESSAGE);
      delay(60000);
     }
  }
}

//Проверяем входящее SMS

void inc_sms(char f_message[])
{
  if(strcmp(f_message, "State") == 0)
  {
    Serial.println("Calling for state function");
    state();
  }
  else if(strcmp(f_message, "HeaterOn") == 0)
  {
    m_temp = 1;
    gprs.sendSMS(PHONE_NUMBER, HEATERON);
  }
  else if(strcmp(f_message, "HeaterOff") == 0)
  {
    m_temp = 0;
    gprs.sendSMS(PHONE_NUMBER, HEATEROFF);
  }
  else if(strcmp(f_message, "Auto") == 0)
  {
    mode = 1;
    gprs.sendSMS(PHONE_NUMBER,AUTOMODE);
  }
  else if(strcmp(f_message, "Manual") == 0)
  {
    mode = 2;
    gprs.sendSMS(PHONE_NUMBER, MANUALMODE);
  }
  else if(strcmp(f_message, "20") == 0)
 {
  trig_temp = 20;
  gprs.sendSMS(PHONE_NUMBER, OKTEMP);
 }
 else if(strcmp(f_message, "25") == 0)
 {
  trig_temp = 25;
  gprs.sendSMS(PHONE_NUMBER, OKTEMP);
 }
 else if(strcmp(f_message, "28") == 0)
 {
  trig_temp = 28;
  gprs.sendSMS(PHONE_NUMBER, OKTEMP);
 }
  else 
  {
    Serial.println("Error");
    gprs.sendSMS(PHONE_NUMBER, ERROR_SMS);
    
  }
} 
 
//Устанавливаем режим

void sms_mode(char f_message[])
{
  if(strcmp(f_message, "Auto") == 0)
  {
    mode = 1;
  }
   else if(strcmp(f_message, "Manual") == 0)
  {
    mode = 2;
  }
  else
  {
    gprs.sendSMS(PHONE_NUMBER,INC_MODE);
  }
}
  
  /*
    Температура, которую нужно поддерживать.
    Я не буду делать так, чтобы можно было установить
    любую температуру срабатывания.
    Я выберу три - 20, 25 и 28.
    Вы можете выбирать режим на свое усмотрение.
  */
  void sms_temp(char f_message[])
{
 if(strcmp(f_message, "20") == 0)
 {
  trig_temp = 20;
 }
 else if(strcmp(f_message, "25") == 0)
 {
  trig_temp = 25;
 }
 else if(strcmp(f_message, "28") == 0)
 {
  trig_temp = 28;
 }
 else
 {
  gprs.sendSMS(PHONE_NUMBER,INC_TRIG);
 }
}

//Считываем температуру

void inc_temp()
{
  uint8_t buf[VW_MAX_MESSAGE_LEN]; // Буфер для сообщения
  uint8_t buflen = VW_MAX_MESSAGE_LEN; // Длина буфера
  char temp[3];
  
  if (vw_get_message(buf, &buflen)) // Если принято сообщение
  {
  Serial.println("Received:"); 
  digitalWrite(13, HIGH);
  for(int i = 0; i < buflen; i++)
  {
     temp[i] = buf[i];
  }
  curr_temp = atoi(temp);
  Serial.print("Temperature is ");
  Serial.print(temp);
  Serial.println(" C");
  digitalWrite(13, LOW);
 }
}

//Готовим и отправляем SMS со статусом

void state()
{
  if(stateRelay)
  {
    message_to_send = String(helloText + tempText + termValue + degree + heaterOn);
    message_to_send.toCharArray(char_message_to_send, 100);
    Serial.println("Sending");
    gprs.sendSMS(PHONE_NUMBER, char_message_to_send);
    Serial.println("Sent");
  }
  else if(!stateRelay)
  {
    message_to_send = String(helloText + tempText + termValue + degree + heaterOff);
    message_to_send.toCharArray(char_message_to_send, 100);
    Serial.println("Sending");
    gprs.sendSMS(PHONE_NUMBER, char_message_to_send);
    Serial.println("Sent");
  }
}

А оно как работает?

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

В это же время устройство ждет сообщений от хозяина. Если пришло сообщение о запросе статуса, то устройство отправляет нынешнее значение температуры и состояние реле, если пришло число, то устройство меняет температуру срабатывания, если пришло указание о смене режима – устройство меняет режим работы.

Вот небольшой кусок моего общения с обогревателем.

AT команды

GPRS Shield так же можно управлять с помощью AT команд. Вот небольшой скетч, который показывает, как можно отправить SMS.

void setup()
{

//Включаем GPRS Shield
  
gprs_On();

//Открываем Serial port для индикации...

Serial.begin(9600);

//...и Serila1 для общения с шилдом

Serial1.begin(9600);

while(!Serial)
{
}

    Serial.println("I'm ready");

    //Устанавливаем текстовый режим сообщений
    
    Serial1.print("AT+CMGF = 1\r");

    delay(3000);

    //Указываем номер, на который будем отправлять SMS
    //Не забудьте указать свой номер

    Serial1.println("AT + CMGS = \"+XXXXXXXXXXX\"");
    delay(300);
    
    // Пишем текст сообщения
    
    Serial1.println("AT Test");
    delay(300);
    
    // Отправляем Ctrl+Z, обозначая, что сообщение готово
    
    Serial1.println((char)26);
    Serial.println("SMS send!");

}

void loop() 
{
}

//Функция включения GPRS Shield

void gprs_On()
{
  // настраиваем пин №2 в режим выхода
  pinMode(2, OUTPUT);
  // проверяем состояние 3 пина
  if (digitalRead(3) != HIGH) {
    // если на нём «низкий уровень»
    // подаём на пин 2 «высокий уровень»
    digitalWrite(2, HIGH);
    // ждём 3 секунды
    delay(3000);
  }
  // подаём на пин 2 «низкий уровень»
  digitalWrite(2, LOW);
}

AT команды используются, если вам не хватает функционала готовых библиотек. С помощью AT команд, например, можно использовать часы реального времени, встроенные в GPRS Shield.

Если хочется общаться с GPRS Shield в режиме реального времени, то можно запустить пример из библиотеки под названием  GPRS_AT_Commands.

Чтобы узнать время у модуля, нужно отправить команду AT+CCLK?. Если вы включили Shield в первый раз или вынули из него батарейку, а потом включили, то ответом будет время, прошедшее после запуска GPRS Shileld.У меня ответом было это.

Для того чтобы установить время, нужно использовать команду AT+CCLK="YY/MM/DD,HH:MM:SS+ZZ"

Где YY – это год, MM – месяц, DD – день, HH – час, MM – минута, SS – секунда, ZZ – часовой пояс, причем, если сейчас сентябрь, то я должен вписывать 09, а не просто 9.Вот пример.

Не забываем, что если Shield отключить от питания и не установить батарейку, то время сбрасывается.

Для тех, кто хочет залезть глубже, есть справочник AT команд. Прочитать и скачать его можно тут.

 

Итог

Теперь, на “А у нас в квартире газ” можно с гордостью ответить – “А у меня обогреватель доцент кафедры обогревательных наук!”

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

Ну а я с вами прощаюсь – до скорого!

Прикрепленные файлы:

Теги:

Опубликована: 0 1
Я собрал 0 2
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 5 Проголосовало: 2 чел.

Комментарии (4) | Я собрал (0) | Подписаться

0
Публикатор #
На форуме автоматически создана тема для обсуждения статьи.
Ответить
0
r9o-11 #
Надо же, сейчас как раз проверяю управление обогревом гаража, сделанном на таком же принципе, только всё заморочено на старом телефоне и без ардуины. Бывают же совпадения... Автору спасибо, и хоть в программировании не разбираюсь, но всё равно поставил по всем пунктам "пятёрочки".
Ответить
0
Аристократ #
Автор где достать эту плату Troyka Shield? Нигде не могу таких найти на алиэкспрессе, ебей, Герберст нет их. Или можно чем нибудь заменить?!
Ответить
0

[Автор]
Симилячник #
Не принципиально использовать Тройку. Ее плюс в том, что земля и питание выведеный на каждый трех-штырьевой контакт. Можно взять макетную плату и развести питание землю и управляющий пин на ней.
Кстати, первый ответ по запросу "Troyka shield" является ссылкой на сайт, где можно приобрести Тройку.
Аналогом на AliExpress будет являться Sensor Shield.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическое сопротивление?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Модуль измерения тока на ACS712 (30А)
Модуль измерения тока на ACS712 (30А)
Arduino UNO Радиореле 220В
вверх