Ethernet термометр на основе Arduino

Arduino

О цифровых термометрах на основе Arduino было сказано немало. Все они либо подключались к компьютеру, либо выводили температуры сразу на дисплей.
Но мне был нужен уличный термометр, который автономно и отправляет данные на сайт. Итак, приступим.

Что нам понадобится:
  • Arduino Duemilanove (Freeduino 2009)
  • Ethernet Shield v2
  • цифровой датчик температуры — DS18B20
  • вентилятор для корпуса (120 мм)
  • банка от водоэмульсионки или клея ПВА (2 литра)
  • светодиод
  • витая пара
Задачи

Опрашивать датчик температуры по шине 1-Wire и каждые 3 секунды самостоятельно отправлять результаты на Web-сервер, на котором они будут храниться.

Алгоритм работы устройства:
  1. присваиваем нашему Ethernet Shield`у MAC адрес и ip-адрес
  2. инициализируем соединение с сервером на 80 порт
  3. получаем данные с цифрового датчика температуры, по 1-Wire шине
  4. формируем GET запрос
  5. отправляем GET запрос
  6. разрываем соединение
Исходный код скетча:

Комментарии по ходу кода должны внести ясность.

include Ethernet.h>
// Библиотеки ниже нет в стандартной поставке среды разработки Arduino.
// придётся её скопировать.
include DallasTemperature.h>

// MAC-адрес нашего устройства
byte mac[] = < 0x00, 0x3A, 0xF1, 0x19, 0x69, 0xFC >;
// ip-адрес устройства
byte ip[] = < 192, 168, 1, 156 >;
// ip-адрес удалённого сервера
byte server[] = < 79, 140, 28, 20 >; // измените на свой
char temp[6];
byte isdata=0;

Client client(server, 80); // 80-порт.
DallasTemperature tempSensor;

void setup()
<
Ethernet.begin(mac, ip); // Инициализируем Ethernet Shield
tempSensor.begin(7); // Датчик температуры на 7-й пин
Serial.begin(9600); // Скорость консольного порта 9600 (пригодится для отладки)
>

void loop()
<
delay(3000); // задержка в 3 сек.
// Соединяемся
if (client.connect()) <
Serial.println( "connecting. " ); // Serial.println для отладки. Лучше его оставить, на всякий случай, потом будет легче понять, в чём проблема.
// Обработчик ошибок датчика
switch (tempSensor.isValid())
<
case 1:
Serial.println( "Invalid CRC" ); // ошибка контрольной суммы
tempSensor.reset(); // сбросить девайс
return ;
case 2:
Serial.println( "Invalid device" ); // какой-то "левый" датчик 🙂
tempSensor.reset(); // сбросить девайс
return ;
>

Serial.println( "connected" );
char buf[80];
float f=tempSensor.getTemperature(); // получаем температуру

// Ниже извращения с отделением дробной части и целой. Почему-то Arduino не хочет работать с float.
// Вместо числа вставляет вопросик. Наверное, виной тому отсутствие аппаратной поддержки работы с
// числами с плавающей запятой в Arduino. Буду рад увидеть более красивое решение в комментариях.
int temp1 = (f — ( int )f) * 100; // выделяем дробную часть
// Составляем GET запрос. Переменная code нужна для того, чтобы вражеский термометр не слал какие попало значения.
// проверяется на стороне Web-сервера.
sprintf(buf, "GET /class/backend/meteo.php?temp=%0d.%dcode=123456 HTTP/1.0" , ( int )f, abs(temp1));

Serial.println(buf);
client.println(buf); // Отправляем GET запрос
client.println( "Host: opck.info" ); // Указываем, какой конкретно host на данном ip нас интересует.
client.println();

> else <
Serial.println( "connection failed" );
>

while (client.available()) <
isdata=1;
char c = client.read(); // Читаем, что нам ответил Web-сервер
Serial.print(c);

if (!client.connected()) <
isdata=0;
Serial.println();
Serial.println( "disconnecting." );
client.stop(); // Завершаем соединение
>
>

Сборка устройства:
  1. первую «ногу» датчика цепляем на «минус» GND
  2. вторую «ногу» (DQ) на 7-й пин
  3. третью на «плюс»
  4. вторую и третью нужно соединить резистором на

По идее, вот и всё. Должно работать.
Работает, но боевые условия показали, что когда падает солнечный свет на датчик, тот может нагреваться и показывать температуру гораздо выше реальной. Всё правильно — он покажет температуру на солнце. А нам нужна температура воздуха.

В первый раз для этого был собран корпус из-под банки от кофе, обёрнутый в фольгу. Но это ничем не помогло.

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

Делаем корпус для датчика

Подходящей по размеру оказалась банка от водоэмульсионной краски (такие же бывают из-под клея ПВА, объёмом 2-3 литра). В нижней части банки делаем отверстие под вентилятор. И прикрепляем его к банке. В центре банки размещаем площадку под датчики, диаметром немного меньшим самой банки, чтобы воздух мог циркулировать.
Несколько фото:

Банка от водоэмульсионки

Банка от водоэмульсионки
Детали и банка с проделанным отвестием
Детали и банка с проделанным отвестием

Установка датчика в корпус
Установка датчика в корпус

Датчик в корпусе, вид сверху
Датчик в корпусе, вид сверху

Как вы помните, резистор я заменил светодиодом, поэтому делаем и для него отверстие, чтобы всегда было видно работу устройства.

Корпус, вид сбоку
Корпус, вид сбоку

Крышка от банки нам не нужна, вместо неё нужен навес, такой, чтобы и воздух пропускал, и чтобы атмосферные осадки не попадали внутрь (датчик-то будет расположен на улице).

Корпус для Arduino я сделал из пластмассовой коробки от mp3-плеера Explay C360.

Backend, принимающий данные:

500 000 записей вместо 10 000 000)

Во время длительной работы датчика обнаружилась проблема, иногда он самопроизвольно (раз в 3-4 часа) выдаёт рандомное значение. Поэтому я добавил проверку на изменение температуры больше чем на 1 градус в течении 15 секунд. Такие значения игнорируются.

Что из этого всего вышло:

На своём сайте я разместил страничку с термометром и добавил график температуры за последние сутки.
Посмотреть можно тут: Ethernet термометр.

Недостатки:

Точность датчика 0.5* С, что для меня недостаточно. Но есть способ улучшить его характеристики. Понадобится ещё один, или более датчиков (желательно из разных партий). Получаем данные со всех датчиков и считаем среднее арифметическое. Так можно добиться точности до сотых градуса.

Планы на будущее:
  • датчик влажности
  • датчик давления
  • датчик скорости ветра
  • датчик освещённости
  • поставить несколько таких в городе и делать свои прогнозы погоды
  • питать Arduino по Power over Ethernet
  • автоматизировать включение и частоту вращения вентилятора в зависимости от освещения
  • удалённое управление
  • сброс данных на случай отсутствия связи (для меня это критично)
Известные мне недостатки:

— высокая цена — 2180 руб. (Freeduino 2009 (800 р.) + Ethernet Shield v2 (1300 р.) + 1 датчик (80 р.))
— если вентилятор включить слишком быстро, то он сам вносит погрешность в температуру, обдувая датчик. Он не должен сдувать, а лишь проталкивать воздух.


Источник: habr.com