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

Winter is coming

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

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

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

Детали

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

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

 

 

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

  

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

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

Наше устройство будет состоять из 2-х частей – термостата и центрального контроллера. Термостат будет посылать данные о температуре на центральное устройство, которое, в свою очередь, будет управлять реле и общаться со смартфоном посредством 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 = 1r»);

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 команд. Прочитать и скачать его можно тут.

 

Итог

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

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

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

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

Добавить комментарий

Ваш адрес email не будет опубликован.