Основной задачей проекта является мониторинг температуры в теплице удаленной от дома на 11-15 метров. Без возможности организации прокладки UTP и питания до нее.

Тепличная часть:

  1. Снять температуру/влажность датчиком DHT-11 при помощи pro micro
  2. Отправить fs1000a при помощи pro micro

Домашняя часть:

  1. Принять значения на mx-rm-5v при помощи Uno
  2. Отправить на сервер при помощи Ethernet shield (WIZNET W5100HR911105A)
  3. Записать в базу mysql
  4. Отрисовать график (jpgraph)



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

Список необходимых пакетов не огромен и зависит от дистрибутива, а именно nginx, php-gd, php-mysql, mysql-server. Для jpgraph могут понадобиться ttf шрифты.

Подготовим nginx
server {
listen 80;
listen [::]:80;
root /var/www/html;
 location / {
               }
location ~ \.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    # With php7.0-cgi alone:
    # fastcgi_pass 127.0.0.1:9000;
    # With php7.0-fpm:
    fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    fastcgi_buffer_size 128k;
    fastcgi_buffers 256 32k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;
    fastcgi_connect_timeout 1s;
    fastcgi_ignore_client_abort off;
    fastcgi_next_upstream timeout;
    fastcgi_read_timeout 5m;
    fastcgi_send_timeout 5m;
    }
}


Для uno нам нужны следующие библиотеки:
SPI.h
Ethernet.h
DHT.h

Код для UNO
#include <SPI.h>
#include <Ethernet.h>
#include <DHT.h>

// MAC address for controller
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//Адрес шилда
byte ip[] = { 192, 168, 156, 192 };
//Маска
byte subnet[] = { 255, 255, 255, 0 };
//Шлюз
byte gateway[] = { 192, 168, 0, 1 };
//Адрес сервера с базой
char server[] = "192.168.156.186";
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE); 

//Запуск клиента
EthernetClient client;

void setup() 
{
 dht.begin();
   
    Serial.begin(9600);
    while (!Serial) {
        ; // wait for serial port to connect
    }
   
{        Ethernet.begin(mac,ip,gateway,subnet);
    }

    // give the Ethernet shield a second to initialize
    delay(1000);
   }

void loop()
{
  if (client.connect(server, 80))
  {
  // give the Ethernet shield a second to initialize
  float h = dht.readHumidity();
  float t = dht.readTemperature();
         Serial.println("connected");
        // Отправляем GET запрос с данными
        client.println(String("GET /index.php?temp=")+ t +"&hum="+h);
           client.println();
        Serial.println("connection close");
      } else Serial.println("connection failed");
      delay(60000);
}


Cкетч каждую минуту отправляет GET запрос скрипту (index.php):

index.php
<?php
/**
 * @param string            $message
 * @param PDOException|null $exception
 */
function writeMessage($message, $exception = null)
{
    $logfile = '/var/www/html/data/arduino.log';
    $datetime = date('d.m.Y H:i:s', time());

    if ($exception !== null) {
        $message .= ': ' . $exception->getFile() . ' (line: ' . $exception->getLine() . ') - ' . $exception->getMessage();
    }

    file_put_contents($logfile, '[' . $datetime . '] ' . $message."\n", FILE_APPEND);
}

/* Подключение к базе данных MySQL с помощью вызова драйвера */
$dsn = 'mysql:dbname=greenhouse;host=localhost';
$user = 'arduino';
$password = 'парол';

try {
    $dbh = new PDO($dsn, $user, $password, [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
    ]);
} catch (PDOException $e) {
    writeMessage('Произошла ошибка', $e);
}

try {
    $sth = $dbh->prepare('INSERT INTO data (sensor, temperature, humidity, created_at) VALUES (?, ?, ?, NOW())');
    $sth->execute(['grass', $_REQUEST['temp'], $_REQUEST['hum']]);

} catch (PDOException $e) {
    writeMessage('Произошла ошибка', $e);
}


который в свою очередь отправляет значения в базу:

Создание таблицы
CREATE DATABASE `greenhouse` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sensor` varchar(255) DEFAULT NULL,
  `temperature` decimal(6,3) DEFAULT '0.00',
  `humidity` decimal(6,3) DEFAULT '0.00',
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;



Добавляем пользователя и выдаем права
CREATE USER 'arduino'@''' IDENTIFIED BY 'парол';

GRANT ALL PRIVILEGES ON * . * TO 'arduino'@'';

FLUSH PRIVILEGES;



Проверяем:

select * from data;

+-----+--------+-------------+----------+---------------------+
| id  | sensor | temperature | humidity | created_at          |
+-----+--------+-------------+----------+---------------------+
|   1 | grass  |        NULL |     NULL | 2019-07-15 13:29:13 |
|   2 | grass  |      24.100 |   49.000 | 2019-07-15 13:44:44 |
|   3 | grass  |      24.100 |   49.000 | 2019-07-15 13:44:54 |
|   4 | grass  |      24.000 |   49.000 | 2019-07-15 13:45:04 |
|   5 | grass  |      24.000 |   49.000 | 2019-07-15 13:45:15 |
|   6 | grass  |      24.100 |   49.000 | 2019-07-15 13:45:25 |
|   7 | grass  |      24.100 |   49.000 | 2019-07-15 13:45:35 |
|   8 | grass  |      24.100 |   49.000 | 2019-07-15 13:45:45 |
|   9 | grass  |      24.100 |   49.000 | 2019-07-15 13:45:55 |
|  10 | grass  |      24.100 |   48.000 | 2019-07-15 13:46:47 |
|  11 | grass  |      24.100 |   48.000 | 2019-07-15 13:46:58 |
|  12 | grass  |      24.100 |   48.000 | 2019-07-15 13:47:08 |

Данные в базе!

Устанавливаем библиотеку JpGraph

убираем его в /var/www/src

Теперь рисуем график(day.php):

day.php
<?php // content="text/plain; charset=utf-8"
 
//define('__ROOT__', dirname(dirname()));
require_once ('/var/www/src/jpgraph.php');
require_once ('/var/www/src/jpgraph_line.php');
require_once ('/var/www/src/jpgraph_error.php');
require_once ('/var/www/src/jpgraph_date.php');

$x_axis = array();
$y_axis = array();
$i = 0;
 
$con=mysqli_connect('localhost','arduino','парол','greenhouse');
$result = mysqli_query($con,"SELECT * FROM data");
while($row = mysqli_fetch_array($result)) {
$x_axis[$i] =  strtotime($row["created_at"]);
$y_axis[$i] = $row["temperature"];
    $i++;
}
    mysqli_close($con);
$start = time();
$end = $start+NDATAPOINTS*SAMPLERATE;

for( $i=0; $i < NDATAPOINTS; ++$i ) {
    $x_axis[$i] = rand(50,70);
    $xdata[$i] = $start + $i * SAMPLERATE;
}
 
$graph = new Graph(1000,400);
$graph->img->SetMargin(50,30,30,80);  
$graph->img->SetAntiAliasing();
$graph->SetScale('datlin');
$graph->xaxis->scale->SetDateFormat('d:m H:i');
$graph->SetShadow();
$graph->title->Set("Дневной график температуры");
$graph->xaxis->title->Set('время');
$graph->xaxis->SetLabelAngle(45);
$graph->yaxis->title->Set('температура');
$graph->xaxis->scale->SetTimeAlign(DAYADJ_1);
$graph->title->SetFont(FF_TIMES,FS_BOLD);
 
// Use 20% "grace" to get slightly larger scale then min/max of
// data
$graph->yscale->SetGrace(0);

$p1 = new LinePlot($y_axis,$x_axis);
$p1->mark->SetType(MARK_FILLEDCIRCLE);
$p1->mark->SetFillColor("red");
$p1->mark->SetWidth(4);
$p1->SetColor("blue");
$p1->SetCenter();
$graph->Add($p1);
 
$graph->Stroke();


Получаем вот такую красоту:



Вот и все на данный момент. Сейчас тружусь над настройкой связки двух плат по радиоканалу о чем напишу во второй части.

Комментарии (26)


  1. gabirx
    18.07.2019 10:24

    DHT-22 в сухом погребе стал врать по температуре через определенное время. Влажность в теплице не убьет DHT-11 ?


    1. LosChikatilos Автор
      18.07.2019 10:59

      DS18B20 присматриваю для конечного варианта.

      Врать стал рандомно или отклонился в какую либо сторону?


      1. gabirx
        18.07.2019 11:44

        Стабильно на десяток градусов стал завышать в итоге.


  1. VladSMR
    18.07.2019 10:32

    Одно уточнение: Ethernet shield, судя по фотографии, сделан не на HR911105A (это просто обозначение разъёма RJ45 со встроенными трансформаторами), а на основе чипа WIZNET W5100.


    1. LosChikatilos Автор
      18.07.2019 10:56

      Спасибо поправил!


  1. iig
    18.07.2019 11:44
    +1

    "Без возможности организации прокладки UTP и питания"


    Странное самоограничение. Свет, обогрев, полив — для этого кабель удалось проложить?
    И mysql это перебор. sqlite достаточно.


    1. LosChikatilos Автор
      18.07.2019 12:29

      Этого всего пока нет.
      По БД учту.


  1. avs24rus
    18.07.2019 12:25
    +1

    Завязывайте вы уже с этими датчиками DHT11(22), ибо они какашка!


    1. LosChikatilos Автор
      18.07.2019 12:30

      Для старта подойдет. Выше коммент, что они уходят в + через время.


    1. Duss
      18.07.2019 12:42

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


      1. avs24rus
        18.07.2019 12:46
        +1

        Например Si7021 или BME280.


        1. alexpp
          18.07.2019 15:15
          +1

          Сгодятся для улицы при минус 20?


          1. build_your_web
            18.07.2019 19:21

            Это довольно легко гуглится.
            Например, BME280 предназначен для работы в диапазоне -40С..+85С


            1. alexpp
              18.07.2019 19:34

              Спасибо, я в курсе про Гугл. Я про реальную работу за окном на улице под снегом и дождём.


          1. avs24rus
            19.07.2019 04:21

            Вполне сгодятся. Сам использую Si7021, работают уже несколько лет на улице, бывает и -40.
            Месяц назад заменил один такой на BME280, просто ради интереса.
            Ну и в любом случае, после пары лет работы, стоит проверять датчики. Просто расположить рядом аналогичный и проверить значения в течении непродолжительного времени.


  1. avs24rus
    18.07.2019 12:31

    А где установлены nginx и mysql? Не понятно.
    Если на домашнем компьютере, то это, на мой взгляд, плохое решение.
    Надо или на каком нибудь домашнем NAS, если он есть, а если нет, то лучшее решение — что то Малинка — подобное.


    1. iig
      18.07.2019 12:36

      Тысячи облачных решений для выгрузки данных есть, у многих есть халявные тарифы. Многие доступны прямо из Arduino IDE :)


      1. avs24rus
        18.07.2019 12:39
        -1

        Сам использую thingspeak.com/channels/public, причем совершенно бесплатно.


    1. DimNS
      18.07.2019 13:10
      +1

      А вдруг малинки у человека нет, а домашний сервер уже есть, предлагаете купить специально ещё и малинку?

      У кого-то и NAS нет, у меня вот нет ни NAS ни сервера, зато есть малинка


      1. avs24rus
        18.07.2019 13:14
        -1

        Если нет ни NAS, ни Малинки — я предлагаю сливать на внешний сервис. Но держать ради этого постоянно включенный комп — уж точно не стоит!


        1. DimNS
          18.07.2019 13:19

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

          А так конечно если ничего нет под рукой, то сервис по вашей ссылке, классное решение


        1. avs24rus
          19.07.2019 04:22

          Интересно, что в этом ответе такого, за что минус жмут?


  1. avs24rus
    18.07.2019 12:35

    Или даже, если нужен просто график (графики), то можно смело лить на внешний ресурс. Например вот этот.


  1. SRichard
    18.07.2019 13:30
    -1

    Не понимаю зачем вообще нужна «Домашняя часть». ESP через домашний WiFi вполне может слать все сразу на thingspeak


    1. LosChikatilos Автор
      18.07.2019 14:32

      Не достреливает до роутера.


      1. iig
        18.07.2019 14:41
        +3

        В статье

        Без возможности организации прокладки UTP и питания

        На фото — ethernet кабель.
        Я что-то затрудняюсь понять, что там происходит ;)