Снова о автономной arduino-метеостанции на батарейках

Содержание

Скетч

Прошейте контроллер скетчем через Arduino IDE.

weather-station-display.ino
// библиотека для работы I²C
#include <Wire.h>
// библиотека для работы с метеосенсором
#include <TroykaMeteoSensor.h>
// Подключаем библиотеку для работы с дисплеем
#include <QuadDisplay2.h>
 
// создаём объект для работы с метеосенсором
TroykaMeteoSensor meteoSensor;
// создаём объект класса QuadDisplay и передаём номер пина CS
QuadDisplay qd(10);
 
// создаем объект класса long для хранения счетчиков
unsigned long respite_Time = ;
unsigned long respite_Meteo = ;
 
// создаем объект для регулировки времени показа значений на экране
int slowdown_qd = 1000;
 
void setup() {
  // инициализация дисплея
  qd.begin();
  // инициализируем метеосенсор
  meteoSensor.begin();
}
 
void loop() {
  // запускаем бесконечный счетчик. Его содержимое будет обрабатываться каждые 1000 миллисекунд
  if (millis() - respite_Time > slowdown_qd) {
    // запускаем функции вывода температуры и влажности по очереди
    if (millis() - respite_Meteo < 2 * slowdown_qd) {
      showTemperatureC();
    }
    else if (millis() - respite_Meteo < 3 * slowdown_qd ) {
      showHumidity();
    }
    // гасим экран и обнуляем цикл
    else if (millis() - respite_Meteo < 4 * slowdown_qd ) {
      qd.displayDigits(QD_NONE, QD_NONE, QD_NONE, QD_NONE);
      respite_Meteo = millis();
    }
    respite_Time = millis();
  }
}
 
// функция работы датчика температуры
void showTemperatureC() {
  // считываем данные с датчика
  int stateSensor = meteoSensor.read();
  // проверяем состояние данных
  switch (stateSensor) {
    // выводим показания температуры на дисплей
    case SHT_OK
      qd.displayTemperatureC(meteoSensor.getTemperatureC());
      break;
    // выводим сообщение "Errd", если ошибка данных или сенсор не подключён
    case SHT_ERROR_DATA
      qd.displayDigits(QD_E, QD_r, QD_r, QD_d);
    // выводим сообщение "ErrC", если ошибка контрольной суммы
    case SHT_ERROR_CHECKSUM
      qd.displayDigits(QD_E, QD_r, QD_r, QD_C);
      break;
  }
}
 
// функция работы датчика влажности
void showHumidity() {
  // считываем данные с датчика
  int stateSensor = meteoSensor.read();
  // проверяем состояние данных
  switch (stateSensor) {
    // выводим показания влажности на дисплей
    case SHT_OK
      qd.displayHumidity(meteoSensor.getHumidity());
      break;
    // выводим сообщение "Errd", если ошибка данных или сенсор не подключён
    case SHT_ERROR_DATA
      qd.displayDigits(QD_E, QD_r, QD_r, QD_d);
    // выводим сообщение "ErrC", если ошибка контрольной суммы
    case SHT_ERROR_CHECKSUM
      qd.displayDigits(QD_E, QD_r, QD_r, QD_C);
      break;
  }
}

Часто задаваемые вопросы

Как установить библиотеку

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

Дисплей 16×4 LCD1604

Подробнее о дисплее и работе с ним погуглите «Работа с символьными ЖКИ на базе HD44780». Отметим, что нужно внимательно отнестись к полярности подключения питания к ЖК-индикатору и чтобы напряжение питания было в диапазоне +4,5…5,5 В. Невнимательное отношение к этому может привести к выходу индикатора из строя!

Пин LCD 1604 Arduino MEGA Arduino UNO Описание
VSS GND GND GND
VDD 5 V 5 V 4,7 — 5,3V
RS 22 4 Высокий уровень означает, что сигнал на выходах DB0—DB7 является данными, низкий — командой
RW GND GND Определяет направление данных (чтение/запись). Так как операция чтения данных из индикатора обычно бывает невостребованной, то можно установить постоянно на этом входе низкий уровень
E 23 5 Импульс длительностью не менее 500 мс на этом выводе определяет сигнал для чтения/записи данных с выводов DB0-DB7, RS и WR
DB4 24 8 Входящие/исходящие данные
DB5 25 9
DB6 26 10
DB7 27 11
LED A+ +5V или резистор 220 Ом → +5VLED-A
LED B- GND
V0 GND или подстроечник на 10кОм

Программная инициализация будет выглядеть так:

Температура, влажность DHT11

Подключение датчика температуры и влажности DHT11 (SainSmart). Датчик расположите лицевой стороной вверх, выводы будут описаны слева направо.

DHT11 Arduino Mega
DATA Digital pin 2 (PWM) (см. ниже DHTPIN)
VCC 3,3—5 В (рекомендуется 5 В, лучше внешнее питание)
GND GND

Программная инициализация

Барометр BMP180

Подключение датчика атмосферного давления BMP180 (барометр) + температура по интерфейсу I2C/TWI.

BMP180 Arduino Mega
VCC не подключен
GND GND
SCL 21 (SCL)
SDA 20 (SDA)
3,3 3,3 В

Для UNO: A4 (SDA), A5 (SCL).

nRF24L01+

Краткие характеристики:

  • Диапазон частот 2,401 — 2,4835 Ггц
  • 126 каналов. Нулевой канал начинается с 2400 Мгц и далее с шагом 1 Мгц, например 70 канал находится соответственно на 2470 Мгц. При установке скорости передачи 2Mbps занимается ширина канала в 2 Мгц
  • Питание 1,9 — 3,6 В (рекомендуется 3,3 В)

Вот распиновка модуля.

Некоторые советуют сразу же припаять керамический конденсатор 100nF (можно 1µF, 10µF) на выводы питания RF для избежания электрических помех.

Распиновка nRF24L01+ (смотреть сверху платы там где чип, пины должны быть внизу) :

пин 2 3,3V пин 4 CSN пин 6 MOSI пин 8 IRQ
пин 1 GND пин 3 CE пин 5 SCK пин 7 MISO

Подключение для метеостанции:

Arduino Mega nRF24L01+
3,3 В VCC пин 2 (лучше внешнее питание)
пин D8 CE пин 3 (chip enable in)
SS пин D53 CSN пин 4 (chip select in)
SCK пин D52 SCK пин 5 (SPI clock in)
MOSI пин D51 SDI пин 6 (SPI Data in)
MISO пин D50 SDO пин 7 (SPI data out)
IRQ пин 8 (Interrupt output) не подсоединен
GND GND пин 1 (ground in)

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

ESP8266

Распиновка ESP8266 (смотреть сверху платы там где чипы, пины должны быть внизу):

GND GPIO2 GPIO0 RX
TX CH_PD RESET VCC

Подключение ESP8266 для метеостанции:

ESP8266 Arduino Mega
TX 10 пин (SoftwareSerial RX)
RX 11 пин (SoftwareSerial TX)
VCC 3,3 В
GND GND
CH_PD Через резистор 10К к 3,3 В Arduino
GPI0 Необязательно. Через резистор 10К к 3,3 В Arduino
GPI2 Необязательно. Через резистор 10К к 3,3 В Arduino

КДПВ

Центральный блок в сборе. «Материнскую плату» вырезал из картонной коробки из-под обуви и к ней винтиками на 3 прикрутил всё остальное.

Как видим в этом месте всё питание осуществляется от пинов Ардуино, т.е. к блоку питания напрямую ничего не идёт, и пока мощи хватает.

Вроде всё. Ничего не забыл.

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

Android

Теперь напишем простое приложение для Андроид, которое запрашивает, получает, декодирует JSON-данные и отображает информацию на экране.

Наше Android-приложение будет простым насколько это возможно, только сама суть технологии. Далее вокруг этого «скелета» уже можно будет наворачивать различные «красивости».

Вот скриншот того, что должно получиться в итоге

Как видим UI просто спартанский, основан на LinearLayout, ничего лишнего.

В верхней части TextView показывает ID датчиков и их метео-данные. Кнопка «Обновить» инициирует повторный запрос к веб-серверу. Далее в EditText расположена единственная настройка программы — это URL запроса в виде

Что необходимо отметить?

В манифест добавьте строки разрешающие интернет и проверку состояния сетевого соединения :

Работа с сетью и получение данных с веб-сайта происходит следующим образом.

Используем AsyncTask, чтобы создать фоновую задачу отдельно от главного потока пользовательского интерфейса. Эта фоновая задача берет URL запроса и использует его для создания .

После того, как соединение установлено, AsyncTask загружает содержимое веб-страницы (JSON) как InputStream. Далее InputStream преобразуется в строку, которая декодируется с помощью JSONObject и отображается в пользовательском интерфейсе методом .

В MainActivity.java измените URL на ваш :

он будет использоваться по умолчанию при первом запуске Android приложения.

Исходный код

Код автономной части

meteo_sensor.ino
#include <Arduino.h>
#include <SHT1x.h>
#include <LowPower_Teensy3.h>
#include <ampline.h>
 
 
// Таймаут между посылками (не более 65535)
#define TIMEOUT 60000
 
// Количество попыток отправки посылки
#define ATTEMPTS 3
 
// Информационный пин передатчика
#define RF_PIN 5
 
// Пины датчика температуры и влажности
#define GND1_PIN 10
#define VCC1_PIN 11
#define GND2_PIN 7
#define VCC2_PIN 8
#define DATA_PIN 12
#define CLK_PIN  9
 
 
AmperkaLine rf(RF_PIN);
SHT1x sht1x(CLK_PIN, DATA_PIN);
 
 
void loop(void);
 
 
// Функция усыпления платы. Каждые TIMEOUT секунд
// будет вызываться функция loop_func.
TEENSY3_LP LP = TEENSY3_LP();
sleep_block_t* LP_config;
 
void sleep_mode(void)
{
    LP_config = (sleep_block_t*)calloc(1,sizeof(sleep_block_t));
 
    // Просыпаться будем по таймеру
    LP_config->modules = (LPTMR_WAKE);
    // Задаём таймаут для таймера
    LP_config->lptmr_timeout = TIMEOUT;
    // По истечении таймаута будет вызываться функция loop
    LP_config->callback = loop;
 
    LP.Hibernate(LP_config);
}
 
 
// Функция включения периферии
void periferial_start(void)
{
    // Включаем линию передачи данных
    pinMode(RF_PIN, OUTPUT);
 
    // Включаем питания и земли датчиков температуры и влажности
    pinMode(GND1_PIN, OUTPUT);
    pinMode(GND2_PIN, OUTPUT);
    pinMode(VCC1_PIN, OUTPUT);
    pinMode(VCC2_PIN, OUTPUT);
    digitalWrite(GND1_PIN, LOW);
    digitalWrite(GND2_PIN, LOW);
    digitalWrite(VCC1_PIN, HIGH);
    digitalWrite(VCC2_PIN, HIGH);
 
    // Включаем светодиод для индикации передачи
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
 
    // Выбираем в качестве опорного напряжения внутренний
    // источник (=1.2 В)
    analogReference(INTERNAL);
}
 
 
// Функция выключения периферии
void periferial_stop(void)
{
    // Выключаем линию передачи данных
    pinMode(RF_PIN, INPUT);
 
    // Выключаем датчик температуры и влажности
    pinMode(GND1_PIN, INPUT);
    pinMode(GND2_PIN, INPUT);
    pinMode(VCC1_PIN, INPUT);
    pinMode(VCC2_PIN, INPUT);
 
    pinMode(18, INPUT_PULLUP);
    pinMode(19, INPUT_PULLUP);
 
    // Выключаем светодиод
    digitalWrite(LED_BUILTIN, LOW);
}
 
void setup(void)
{
    // Ничего не инициализируем, сразу засыпаем
    sleep_mode();
}
 
// Эта функция выполняется раз в TIMEOUT секунд
void loop(void)
{
    unsigned long msg;
    byte temp, humidity, voltage;
 
    // Включаем периферию
    periferial_start();
 
    // Подождём, пока включится датчик температуры и влажности
    delay(30);
 
    // Получаем входные данные с сенсоров
    temp = (byte)(sht1x.readTemperatureC() + 40.)*2;
    humidity = (byte)sht1x.readHumidity();
    voltage = analogRead(A0)4;
 
    // Составляем из данных посылку
    msg = ;
    msg |= voltage;
    msg <<= 8;
    msg |= humidity;
    msg <<= 8;
    msg |= temp;
 
    // Отправляем несколько раз посылку
    for(int i = ; i < ATTEMPTS; i++) rf.send(msg);
 
    // Выключаем периферию
    periferial_stop();
 
    // После выхода из функции плата снова уснёт
}

Код платы, работающей в помещении

receiver.ino
#include <Arduino.h>
#include <SPI.h>
#include <Ethernet.h>
#include <ampline.h>
 
 
byte mac = { 0x90, 0xA7, 0xDA, 0x0F, 0xBC, 0x75 };
 
char server = "narodmon.ru";
 
EthernetClient client;
 
const int rfpin = 7;
AmperkaLine rf(rfpin);
 
void setup(void)
{
    pinMode(rfpin, INPUT);
    pinMode(6, OUTPUT);
 
    Serial.begin(9600);
    Serial.println("Started.");
}
 
void loop(void)
{
    static unsigned long pushtimeout = ;
    static float temp, humidity, voltage;
    unsigned long msg;
    int res;
 
    if((res = rf.receive(&msg)) == )
    {
        temp = ((float)(msg&0xFF))2. - 40.;
        msg >>= 8;
        humidity = (float)(msg&0xFF);
        msg >>= 8;
        voltage = (float)(msg&0xFF)  256. * 1.2 * 10 * 1.1;
 
        digitalWrite(6, HIGH);
 
        Serial.print("Temp: ");
        Serial.print(temp);
        Serial.print(", humidity: ");
        Serial.print(humidity);
        Serial.print(", voltage: ");
        Serial.println(voltage);
 
        digitalWrite(6, LOW);
    }
    else Serial.println('E');
 
    if(millis() - pushtimeout > 60000*5)
    {
        pushtimeout = millis();
 
        Serial.println("Starting Ethernet...");
 
        if (Ethernet.begin(mac) == )
        {
            Serial.println("Failed to configure Ethernet using DHCP");
            while(1) { }
        }
        delay(1000);
        Serial.println("connecting...");
 
        if (client.connect(server, 8283))
        {
            Serial.println("connected");
 
            client.println("#90-A7-DA-0F-BC-75#Sensor#55.751775#37.616856#0.0");
 
            client.print("#90A7DA0FBC7501#");
            client.print(temp, DEC);
            client.println("#In");
 
            client.print("#90A7DA0FBC7502#");
            client.print(humidity, DEC);
            client.println("#Humidity");
 
            client.print("#90A7DA0FBC7503#");
            client.print(voltage, DEC);
            client.println("#Voltage");
 
            client.println("##");
        } 
        else Serial.println("connection failed");
 
        {
            unsigned long tm = millis();
 
            while(millis() - tm < 5000) {
                if (client.available()) {
                    char c = client.read();
                    Serial.print(c);
                }
            }
        }
 
        client.stop();
    }
}

Датчик на Arduino Uno и плате расширения Troyka Shield

Рассмотрим еще одну погодную станцию. Ее особенности:

  • использование цифрового метеосенсора troyka;
  • термометр DS18B20;
  • барометр Troyka V2.
  • хранение данных на карточке MicroSD — для удобства их последующего анализа на любом устройстве.

Компоненты

Для проекта требуются:

  • контроллер Arduino Uno;
  • плата расширения Troyka Shield;
  • метеодатчик;
  • четырехразрядный цифровой дисплей-индикатор;
  • барометр с troyka-блоком подтяжки;
  • картридер и карточка micro-SD.

Порядок сборки

Система собирается по шагам.

  1. Установить плату расширения на Ардуино.
  2. Подключить к пинам шины I2C метеодатчик.
  3. Подсоединить дисплей в разъемы e-f на схеме. Пин CS идет на пин 10 микрокомпьютера Ардуино.
  4. Барометр вставляется в слот B, пины шины I2C.
  5. Термометр подключается в слот C, пин 4. Для его работы потребуется дополнительный модуль подтяжки.
  6. И, наконец, к слоту D и на пин 8 подключается картридер.

Общий принцип работы

Измеряющая данные окружающей среды метеостанция на Ардуино состоит из нескольких основных компонентов:

  • собственно плата управления Arduino (например, Uno). На нее поступает информация со внешних датчиков, контроллер выполняет вычисления и выводит информацию на экран;
  • электронный дисплей — служит для отображения поступивших с контроллера данных в понятной человекочитаемой форме;
  • сенсор влажности температуры. В подобных схемах популярны датчики DHT11 и DHT22. Они регистрируют данные среды и отдают их контроллеру;
  • макетная плата — основа для сборки всех компонентов. На ней фиксируются все элементы метеостанции, по ней же прокладываются электрические соединения;
  • соединительные провода — с «оголенными» концами под пайку или оснащенные штекерами.

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

Создание метеостанции на базе Arduino и датчика температуры и влажности DHT22

Для создания метеостанции нам необходимо:

  • Arduino
  • Датчик температуры и влажности DHT22 (существуют модификации DHT11 или DHT21, но они имеют меньшую точность измерений)

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

Двухстрочный дисплей  LCD 1602А

Его подключение вы можете найти в предыдущей статье.
Начнем, пожалуй, с подключения нашего датчика температуры и влажности к Arduino. Две крайние ножки датчика это питание: крайняя левая +5V, крайняя правая — GND (земля). Ножка, отмеченная на схеме голубым проводом – сигнал (S), ее мы подключаем к порту на плате и обязательно подтягиваем резистором к питанию (10 кОм). Именно его в дальнейшем и пропишем в программе как пин, с которого мы будем считывать данные.  Отлично, теперь датчик подключен, перейдем к программированию.
Так как DHT22 является конденсационным, да и в своем устройстве он не так уж прост, для работы будем использовать готовую библиотеку, с помощью которой работа с датчиками сводится к использованию готовых функций.Итак, подключаем библиотеку DHT-master.

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

В функции voidsetup() подключаем монитор порта (его мы будем использовать только для тестирования, потом выведем показания на дисплей) и инициализируем начало работы с датчиком температуры и влажности

В основном блоке программы (void loop()) ставим задержку между двумя последовательными измерениями и описываем считывание данных с датчика с помощью библиотечных функций

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

Загружаем программу в плату и, чтобы увидеть показания, которые нам присылает DHT22, открываем монитор порта (Ctrl+Shift+M или Инструменты — Монитор порта) следим за изменениями температуры и влажности в комнате.Итак, LevelUP: теперь давайте освоим вывод показаний на двухстрочный дисплей.Для того, чтобы компьютер (ноутбук) не использовался исключительно как монитор для вывода показаний с датчика, мы будем использовать двухстрочный дисплей LCD 1602А, как устройство внешнего вывода.Для этого обратимся к статье подключение двухстрочного дисплея.Добавим пару элементов в программе, которые позволят нам использовать для вывода именно дисплей: подключим библиотеку для работы с дисплеем, и также, как и DHT22, создадим класс LiquidCrystal, в котором в качестве параметров указаны пины, используемые, как сигнальные для дисплея.

Далее в теле функции void setup() инициализируем дисплей: lcd.begin(16, 2) т.е. определяем максимальное количество символов в строке и количество строк и выводим название нашего мини-проекта.

А теперь приступим к основному блоку программы. В функции void loop() опишем считывание показания с датчика температуры и влажности и опишем его вывод на дисплей.

Собираем наше устройство, загружаем программу и наша портативная метеостанция готова к работе. Чтобы она работала постоянно, можно использовать питание не от USB, а от батарейки, разъем для которой есть на плате.

Arduino

  • 80

А как же камера?

Пока никак. Сделанные фото можно передавать на WeatherUnderground. Это сделать несложно через ftp

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

Альтернативной является передача изображения на narodmon.ru,

Собственно, время от времени (раз в полчаса) дёргаем ручку /api/v1/capture_photo (которая зовёт take_photo). Например, будем звать через cron этот bash-скрипт:

На сервисе сразу появится снимок:

Плюс, не забываем время от времени (например раз в семь дней) чистить старые изображения:

HTTP GET и JSON

Вопрос, который нужно решить в первую очередь — это каким образом будет происходить передача данных от веб-сервера к Андроид-приложению.

Придумывать тут ничего не нужно, всё уже придумано за нас — это HTTP GET и JSON.

В нашем случае простой GET запрос к веб-серверу можно составить и отладить вручную, пока Андроид приложение ещё не готово.

В Java и в Android есть готовые библиотеки для обработки данных в формате JSON. JSON текстовый формат, читается человеком, что полезно для отладки.

Для того, чтобы сформировать текущие данные от датчиков метеостанции создадим на веб-сервере новый PHP скрипт last-data-to-json.php.

Вызов скрипта :

где , как мы помним, это секретный ключ доступа к БД.

Пример ответа в формате JSON :

Необходимо напомнить, что у нас 3 датчика. Их ID и тип (DHT или BMP) жёстко закодированы по всему коду метеостанции. Такой способ хардкордного кодирования идеологически неверен, но для наколенного прототипа (где необходимо быстрое и простое решение) это разумный компромисс.

Скрипт берет из БД самые последние данные от этих разнотипных датчиков и упаковывает в формат JSON. Выборка данных из БД «с конца» просходит таким способом :

Метеостанция на Arduino от А до Я. Часть 5 +9

  • 12.10.18 05:28


tim4dev

#426019

Хабрахабр

2400

Разработка под Arduino, DIY или Сделай сам

Окончание. Предыдущая часть.

  • Часть 1. Требования. Выбор железа. Общая схема
  • Часть 2. Софт. Центральный блок, железо
  • Часть 3. Центральный блок, софт
  • Часть 4. Заоконный датчик
  • Часть 5. MySQL, PHP, WWW, Android

Заоконный датчик. Программное обеспечение

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

Напомню, что сервер — это центральный, домашний блок, который может общаться с интернет через WiFi, а клиент — это удалённый, заоконный датчик, который передаёт данные на сервер по радиоканалу.

Исходный код как для сервера, так и для клиента находится здесь.
Исходные тексты снабжены подробными комментариями.

На клиенте почти ничего настраивать не надо.

Радиопередатчик nRF24L01+, точнее библиотека RadioHead, требует указания адресов сервера и клиента. Адреса предусмотрены на тот случай, если у вас будет серверов и клиентов больше чем один. Адрес — это просто любое целое число. Когда клиент посылает пакет с данными на сервер, то он указывает для какого сервера предназначен этот пакет. Сервер зная свой собственный адрес, в свою очередь, определяет для него ли предназначен этот пакет.

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

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

Настройки вольтметра для измерения питающего напряжения батареи необходимо изменить:

Для экономии энергии используется библиотека Lightweight low power library for Arduino.

Вот мои замеры фактического потребления для Arduino Pro Mini с этой либой :

  • обычно 25mA
  • при работе с DHT то же самое
  • при радио передаче 38 mA
  • при LowPower.idle 15 mA
  • при LowPower.powerDown 7.5 mA

Клиент делает замеры температуры, влажности и напряжения питания, упаковывает всё это в структуру данных, отсылает данные на сервер и «засыпает». Если при передаче произошли ошибки, то передача тут же повторяется.

Сервер (центральный, домашний блок) в свою очередь данные принимает, подтверждает прием и обрабатывает их.

База данных, MySQL, PHP, WWW-сервер

После проделанной работы у нас есть вполне работоспособная конструкция метеостанции. Но сейчас таких метеостанций пруд пруди, локальные поделки это уже не модно. У нас ведь интернет вещей.

Поэтому поговорим о том, как осуществляется выход в эти ваши интернеты, приделаем к нашей метеостанции базу данных и веб-морду к ней.

Постановка задачи для «вебки» :

  • принимать и хранить данные метеостанции: температура, влажность, атмосферное давление, напряжение питания
  • отображать эти данные
  • строить графики.

При этом нам понадобится хостинг с поддержкой Apache, PHP и MySQL с модулем mysqli. И этим условиям удовлетворяет практически любой хостинг на планете Земля. Либо вместо хостинга будет ваш компьютер играющий роль сервера, подключённый к домашнему сетевому маршрутизатору и имеющий выход в Интернет.

Как сделать метеостанцию на LM35

В следующем скетче для определения температуры был использован датчик LM35, подключенный к аналоговому порту. Для точности измерений температуры необходимо будет откалибровать датчик. В этом примере измеряется только температура, при этом данные отправляются на смартфон только в том случае, если произошло изменение температуры или нажата кнопка «Обновить» в приложении.

Скетч для метеостанции на Ардуино с LM35

#include <SoftwareSerial.h>    //  подключение библиотеки SoftwareSerial.h
SoftwareSerial mySerial(2, 3); // указываем пины rx и tx соответственно

int temp1;  // освобождаем память для переменной "temp1"
int temp2;  // освобождаем память для переменной "temp2"
int temp3;  // освобождаем память для переменной "temp3"
float temp; // освобождаем память для переменной "temp"
byte val;   // освобождаем память для переменной "val"

String stringT = String("*");

void setup() {
  pinMode(A0, INPUT);    // сенсор LM35 подключим к аналоговому входу A0
  Serial.begin(9600);   // запуск аппаратного последовательного порта
  mySerial.begin(9600); // запуск программного последовательного порта
}

void loop() {
  temp1 = analogRead(A0); // считываем значение с датчика
  delay(60000);
  temp2 = analogRead(A0); // повторно считываем значение с датчика
  temp3 = temp1 - temp2;  // определяем, изменилась ли температура

  // отправляем сообщение только, когда изменилась температура
  
    if (temp3 != 0) {
  temp = ( temp2/1023.0 )*5.0*1000/10; // вычисляем значение температуры
  mySerial.println(temp + stringT);    // отправляем температуру на телефон
  Serial.println(temp + stringT);      // отправляем температуру на монитор
  Serial.println("");
}

  // отправляем сообщение, когда нажата кнопка "обновить" в приложении
  
    if (Serial.available()) // проверяем, поступают ли какие-то команды
  {
    val = Serial.read(); // переменная val равна полученной команде

    if (val == '1') {
  temp = ( temp2/1023.0 )*5.0*1000/10; // вычисляем значение температуры
  mySerial.println(temp + stringT);    // отправляем температуру на телефон
  Serial.println(temp + stringT);      // отправляем температуру на монитор
  Serial.println("");
}
  }

}

Шаг первый. Подключаем термистор

У меня самый простой термистор: если его нагреть, сопротивление уменьшится, если охладить — вырастет. Такие элементы называют термисторами с отрицательным температурным коэффициентом или NТС (от английских слов Negative Temperature Coefficent).

К сожалению, на Ардуино нет встроенных инструментов для измерения сопротивления, поэтому будем выкручиваться. В эксперименте с батарейками мы использовали делитель напряжения: пара сопротивлений помогла снизить напряжение вдвое. Использую ту же схему, только одно сопротивление заменю термистором.

При комнатной температуре, 25 по Цельсию, его сопротивление равно 10 килоомам — столько же, сколько и у постоянного резистора. Теперь выходное напряжение цепи зависит только от сопротивления термистора. Измерю напряжение, подключив цепь к контакту А5.

Теперь я знаю всё, что нужно для определения сопротивления термистора. Воспользуюсь общей формулой делителя напряжения, чтобы найти сопротивление моего термистора.

Чтобы не возиться с подключением экрана раньше времени — вдруг мой сенсор не заработает — выведу показания с платы на экран компьютера. Передам данные по USB, с помощью интерфейса последовательного порта. Запищу передачу командой Serial.begin. Текст сообщений буду составлять с помощью функций Serial.print и Serial.println. Первая просто добавляет данные к текущей строке, вторая — сначала добавляет данные, затем заканчивает строку. Загружу в Ардуинку первую программу.

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

Это можно сделать в верхнем меню редактора кода (монитор порта находится во вкладке инструменты) или с помощью комбинации клавиш Ctrl+Shift+M.

При комнатной температуре у меня получилось, что напряжение срезалось вдвое. Это подтверждает, что мой термистор сейчас имеет сопротивление 10 кОм.

Код:

Копируем этот код и вставляем в IDE

#include <LCD_1602_RUS.h> // подключаем библиотеку для датчика
LCD_1602_RUS lcd(0x27, 20, 4); // определяем адрес дисплея и его размер
#include <DHT.h> // подключаем библиотеку для датчика
DHT dht(2, DHT11); // сообщаем на каком порту будет датчик

void setup()
{
lcd.init(); // Инициализация дисплея
lcd.backlight(); // Подключение подсветки
lcd.clear(); // Чистим дисплей
dht.begin(); // запускаем датчик DHT11
}
void loop()
{
float h = dht.readHumidity(); // считываем температуру (t)
float t = dht.readTemperature(); // и влажность (h)
lcd.setCursor(0, 0); // Устанавливаем курср на нулевую символ и нулевой строки
lcd.print(«Влажн. :»); // выводим надпись «Влажн.:»
lcd.print(h,1); // выводим значение влажности с одним символом после запятой
lcd.print(» %»); // выволим знак процента
lcd.setCursor(0, 1); // Устанавливаем курср на нулевой символ первой строки
lcd.print(«Темпер.:»); // выводим надпись «Темпер.:»
lcd.print(t,1); // выводим значение влажности с одним символом после запятой
lcd.print(«\337C»); // выволим знак градуса (337 символ в талице) и «С»
delay(2000); // ждём 2000 микросикенд (2 секунды)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

#include <LCD_1602_RUS.h>         // подключаем библиотеку для датчика

LCD_1602_RUS lcd(0x27,20,4);// определяем адрес дисплея и его размер

#include <DHT.h>                  // подключаем библиотеку для датчика

DHT dht(2,DHT11);// сообщаем на каком порту будет датчик

voidsetup()

{

lcd.init();// Инициализация дисплея  

lcd.backlight();// Подключение подсветки

lcd.clear();// Чистим дисплей

dht.begin();// запускаем датчик DHT11

}

voidloop()

{

floath=dht.readHumidity();// считываем температуру (t)

floatt=dht.readTemperature();// и влажность (h)

lcd.setCursor(,);// Устанавливаем курср на нулевую символ и нулевой строки

lcd.print(«Влажн. :»);// выводим надпись «Влажн.:»

lcd.print(h,1);// выводим значение влажности с одним символом после запятой

lcd.print(» %»);// выволим знак процента

lcd.setCursor(,1);// Устанавливаем курср на нулевой символ первой строки  

lcd.print(«Темпер.:»);// выводим надпись «Темпер.:»

lcd.print(t,1);// выводим значение влажности с одним символом после запятой

lcd.print(«\337C»);// выволим знак градуса (337 символ в талице) и «С»

delay(2000);// ждём 2000 микросикенд (2 секунды)

}

Копируем его в поле для кода IDE:

и жмём загрузить:


Кнопка «загрузить»
Загрузка завершена

Ждём несколько секунд и наша метеостанция работает:


Метеостанция работает

Настройка ThingSpeak

Структурная схема работы нашего проекта представлена на следующем рисунке и она содержит 4 секции. Вначале с помощью датчика температуры и влажности DHT11 измеряются эти параметры атмосферы. Затем плата Arduino Uno считывает эти данные с DHT11 и преобразует их в нужную для нас форму, а затем она передает их на Wi-Fi модуль. После этого Wi-Fi модуль ESP8266 передает эти данные на сервер ThingSpeak. Затем сервис ThingSpeak анализирует эти данные и показывает их в удобной графической форме. Также дополнительно значения температуры и влажности показываются на экране ЖК дисплея.

1. Вначале нам необходимо создать аккаунт на ThingSpeak.com, заходим туда, жмем Sign In, а потом Get Started.

2. Затем идем в пункт меню ‘Channels’ (каналы) и создаем новый канал с помощью кнопки New Channel.

3. После этого увидите форму для создания нового канала, заполните там поля Name (имя) и Description (описание) по своему усмотрению. Затем напишите ‘Humidity’ (влажность) и ‘Temperature’ (температура) в Field 1 (поле 1) и Field 2 (поле 2) и поставьте галочки в чек-боксах напротив этих полей. Также поставьте галочку в чек-боксе ‘Make Public’ (сделать общедоступным) в форме ниже и сохраните канал (Save the Channel). Теперь новый канал для вас создан.

4. Теперь откройте вкладку ‘API keys’ чтобы записать свои ключи с этой вкладки. Нам будет нужен только ключ для записи (Write key). Скопируйте этот ключ в переменную char *api_key в тексте программы (приведен в конце статьи).

5. После этого кликните на ‘Data Import/Export’ и скопируйте Update Channel Feed GET Request URL, который будет примерно вида https://api.thingspeak.com/update?api_key=SIWOYBX26OXQ1WMS&field1=0.

6. Теперь необходимо открыть api.thingspeak.com используя функцию httpGet с postUrl в виде “update?api_key=SIWOYBX26OXQ1WMS&field1=0” и затем передать данные используя адрес обновления запроса.

Перед передачей данных необходимо отредактировать строку запроса или postUrl с полями данных температуры и влажности как показано в программном коде ниже. Здесь мы добавили в строку оба параметра, которые нам необходимо передать используя GET запрос к серверу, после этого необходимо использовать httpGet чтобы передать данные на сервер. Более подробно все эти процессы представлены в полном тексте программы, представленном в конце статьи.

В рассматриваемом проекте плата Arduino передает сигнал старта (после которого начинаются измерения) на датчик DHT, а в ответ датчик DHT передает Arduino сигнал, содержащий необходимые данные измерений. Плата Arduino собирает и извлекает эти данные в два приема: сначала извлекается влажность, а потом извлекается температура. Далее эти данные обрабатываются и передаются на ЖК дисплей 16×2 и сервер ThingSpeak. Сервис ThingSpeak отображает данные температуры и влажности в виде графиков, пример которых показан на следующем рисунке.

Прошивка

Устройство готово. Осталось его прошить и смонтировать. Начнем с прошивки. Как я уже говорил выше, то желания изобретать велосипед у меня не было. И смыла изобретать его тоже не было.

Я уже довольно давно работаю с альтернативной прошивкой для датчиков Sonoff, которая называется Tasmota. Я устанавливаю эту прошивку на модули умного дома Sonoff. Эта прошивка прекрасно работает по MQTT с моим сервером умного дома. Задача по мониторингу температуры и влажности для этой прошивки более чем тривиальная. При этом не нужно собирать какой-то кастомный билд прошивки. Берем готовую прошивку и заливаем. Хочешь из hex файла, хочешь, компилируешь в среде arduino ide и заливаешь.

Для тех кому не нравится Tasmota, можете использовать проект espeasy. С этой прошивкой тоже все будет работать, но опыта ее использования у меня практически нет.

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

Не вижу большого смысла описывать все нюансы прошивки, которая используется в готовом виде. Просто прикладываю скрины со своими настройками:

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

Android

Теперь напишем простое приложение для Андроид, которое запрашивает, получает, декодирует JSON-данные и отображает информацию на экране.

Наше Android-приложение будет простым насколько это возможно, только сама суть технологии. Далее вокруг этого «скелета» уже можно будет наворачивать различные «красивости».

Вот скриншот того, что должно получиться в итоге

Как видим UI просто спартанский, основан на LinearLayout, ничего лишнего.

В верхней части TextView показывает ID датчиков и их метео-данные. Кнопка «Обновить» инициирует повторный запрос к веб-серверу. Далее в EditText расположена единственная настройка программы — это URL запроса в виде

Что необходимо отметить?

В манифест добавьте строки разрешающие интернет и проверку состояния сетевого соединения :

Работа с сетью и получение данных с веб-сайта происходит следующим образом.

Используем AsyncTask, чтобы создать фоновую задачу отдельно от главного потока пользовательского интерфейса. Эта фоновая задача берет URL запроса и использует его для создания .

После того, как соединение установлено, AsyncTask загружает содержимое веб-страницы (JSON) как InputStream. Далее InputStream преобразуется в строку, которая декодируется с помощью JSONObject и отображается в пользовательском интерфейсе методом .

В MainActivity.java измените URL на ваш :

он будет использоваться по умолчанию при первом запуске Android приложения.