Урок №15 Собираем все вместе!
В данном уроке мы объединим все что мы знаем и построим настоящую IoT Теплицу!
Описание
Функционал у нее будет как можно более полный:

По датчикам:
1. Считывание температуры и влажности воздуха в теплице
2. Температура почвы
3. Уровень освещения
4. И замер влажности почвы
5. Переключение между экранами с помощью датчика касания

Данные будут передаваться по Wi-Fi сети, с точки доступа которую раздает ESP32 на IP адрес 192.168.1.1 (либо тот, который вы зададите). Страницу надо будет обновлять для отслеживания изменений в показаниях датчиков.

Что нам понадобится?
Достаньте и подготовьте необходимые детали из коробки.
Arduino Uno
Мозг нашей схемы
Популярный микроконтроллер, его мощности достаточно пока нам для начальных экспериментов
Светодиод
Любого цвета
Длинная ножка на положительно заряженный, короткая на отрицательно
Макетная плата
на 400 точек
Соединения идут параллельно, плата разделена на 2 части горизонтальной линией
Резистор
На 10 кОм
О резисторах подробно мы подробно поговорим чуть ниже в разделе "Базовые знания"
Подключаем все датчики вместе.

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

5V по обеим сторонам подключаем к плюсовым линиям.

Все минусы и плюсы на датчиках соединяем с минусовыми и плюсовыми линиями на макетной плате.

Сигнальные порты – S, AOUT, out, I\O, желтый провод - соединяем с портами, указанными ниже (для удобства смотрите картинку с Распиновкой ESP32 с урока №8)



1. DS18B20 (Датчик температуры почвы) - порт GPIO17

2. Модуль 4-х канального реле - порты GPIO5, GPIO18, GPIO23, GPIO19 ( если у вас есть)

3. Датчик температуры и влажности воздуха DHT22 - порт GPIO22

4. Датчик касания ttp223 - порт GPIO21

5. Датчик влажности почвы – порт GPIO37

6. Датчик освещения (фоторезистор) - порт GPIO36

Схема подключения
Финальный код
#include <OneWire.h>
#include <WiFi.h>

/* Введите данные своей точки доступа */
const char* ssid = "Nazvanie";  // Название точки доступа 
const char* password = "Parol";  // Пароль для точки доступа

/* Данные сервера */
IPAddress local_ip(192,168,1,1); //IP адрес
IPAddress gateway(192,168,1,1); //Шлюз
IPAddress subnet(255,255,255,0); //Маска сети
WiFiServer server(80);

/* OLED экран SSD1306 */
#include "SSD1306.h" 
#define SDA_PIN 4// GPIO4 -> SDA
#define SCL_PIN 15// GPIO15 -> SCL
#define SSD_ADDRESS 0x3c //I2C адрес экрана
SSD1306  display(SSD_ADDRESS, SDA_PIN, SCL_PIN);

OneWire ds(17); //порт датчика температуры ds18b20. Датчик температуры для почвы.
int lightSensor = 0; // Фоторезистор переменная для хранения уровня освещения
int MoistureSensor = 0; //Датчик влажности почвы переменная для хранения влажности

/* DHT датчик температуры и влажности воздуха */
#include "DHT.h"
#define DHTPIN 22  
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);
float localHum = 0; // Переменная для хранения уровня влажности воздуха
float localTemp = 0; // Переменная для хранения уровня температуры воздуха

#define ctsPin 21 // Пин Сенсорного модуля ttp223b
boolean touch = 1;// Переменная для переключения экранов

float temperature; //Переменная для хранения температуры почвы с датчика ds18b20

/*Переменные для подключения веб-сервера*/
char linebuf[80]; 
int charcount=0;

void setup() {
  Serial.begin(115200); //Настраиваем serial подключение с компьютером
 
  pinMode(ctsPin, INPUT);//Обьявляем порт как Входящий. Порт сенсорного модуля
  
  /*Включаем и настраиваем экран*/
  pinMode(16,OUTPUT); 
  digitalWrite(16, LOW);    
  delay(50); 
  digitalWrite(16, HIGH); 
  display.init();
  display.flipScreenVertically();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10); // установка шрифта варианты 10, 15, 25
  Serial.println("OLED экран SSD1306 настроен");
  /*----------------------------*/
  
  dht.begin(); // Включаем датчик DHT22
  Serial.println("Датчик DHT22 включен");

  /*Настраиваем и включаем точку доступа*/
  WiFi.softAP(ssid, password);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  delay(100);
  server.begin(); //Запускаем веб сервер
  Serial.println("Точка доступа и сервер запущены");
  /*-----------------------------------*/
}

void loop() {  
 getLight(); //Считывание данных освещения
 getMoist(); //Считывание данных влажности почвы
 getDHT(); //Считывание влажности и температуры воздуха
 getTemp(); //Считывание температуры почвы
 displayData(); //Отображение данных на экране
 wifiAPserver(); //Запуск сервера и показ данных 
 delay(100);
}

void getDHT(){
  float tempIni = localTemp;
  float humIni = localHum;
  localTemp = dht.readTemperature();
  localHum = dht.readHumidity();
  if (isnan(localHum) || isnan(localTemp))   
  {
    localTemp = tempIni;
    localHum = humIni;
    return;
  }
}

void displayData() {
  display.setFont(ArialMT_Plain_16);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  
  int ctsValue = digitalRead(ctsPin);//Считывание данных с сенсорного датчика
  if (ctsValue == HIGH){
    display.clear();   // Очистка дисплея
    display.drawString(0, 0,  "light: " + String(lightSensor) + "%");
    display.drawString(0, 20, "moisture: " + String(MoistureSensor) + "%");
    display.drawString(0, 40, "air temp: " + String(localTemp) + "C");
    display.display();   // Отображение данных на экране из буфера
  }
  if (ctsValue == LOW){
    display.clear();   // Очистка дисплея
    display.drawString(0, 0, "humidity: " + String(localHum) + "%");
    display.drawString(0, 20, "gr temp: " + String(temperature) + "C");
    //display.drawString(0, 40, "r1:0 r2:0 r3:0 r4:0");
    display.display();   // Отображение данных на экране из буфера
  } 
  delay(10);
}

void getTemp() {
  // Определяем температуру от датчика DS18b20
  byte data[2]; // Место для значения температуры
  ds.reset(); // Начинаем взаимодействие со сброса всех предыдущих команд и параметров
  ds.write(0xCC); // Даем датчику DS18b20 команду пропустить поиск по адресу. В нашем случае только одно устрйоство 
  ds.write(0x44); // Даем датчику DS18b20 команду измерить температуру. Само значение температуры мы еще не получаем - датчик его положит во внутреннюю память
  delay(1000); // Микросхема измеряет температуру, а мы ждем.    
  ds.reset(); // Теперь готовимся получить значение измеренной температуры
  ds.write(0xCC); 
  ds.write(0xBE); // Просим передать нам значение регистров со значением температуры
  // Получаем и считываем ответ
  data[0] = ds.read(); // Читаем младший байт значения температуры
  data[1] = ds.read(); // А теперь старший
  // Формируем итоговое значение: 
  //    - сперва "склеиваем" значение, 
  //    - затем умножаем его на коэффициент, соответсвующий разрешающей способности (для 12 бит по умолчанию - это 0,0625)
  temperature =  ((data[1] << 8) | data[0]) * 0.0625;
  }

void getLight() {
 int lightRead = analogRead(36);//Считывание данных с фоторезистора.
 lightSensor = map(lightRead, 0, 4095, 0, 100); //Преобразовывание данных об освещенности в проценты
    }

void getMoist() {
 int moistRead  = analogRead(37); //Считывание данных с датчика влажности
 MoistureSensor = 100 - map(moistRead, 2000, 3500, 0, 100); //Преобразование данных в проценты
  }

void wifiAPserver(){
    // анализируем канал связи, высматривая входящих клиентов:
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New client");  //  "Новый клиент"
    memset(linebuf,0,sizeof(linebuf));
    charcount=0;
    // HTTP-запрос заканчивается пустой строкой:
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // считываем HTTP-запрос, символ за символом:
        linebuf[charcount]=c;
        if (charcount<sizeof(linebuf)-1) charcount++;
        // если добрались до конца строки (т.е. получили
        // символ новой строки) и строка пуста,
        // это значит, что HTTP-запрос закончился;
        // следовательно, можно отправлять ответ:
        if (c == '\n' && currentLineIsBlank) {
          // отправляем стандартный заголовок HTTP-ответа:
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");  
                     //  "Тип контента: text/html"
          client.println("Connection: close");
                     //  "Соединение: отключено";
                     //  после отправки ответа связь будет отключена
          client.println();
          client.println("<!DOCTYPE HTML><html><head>");
          client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
          client.println("<h1>ESP32 - Web Server</h1>");
          client.println("AIR TEMPERATURE</p><p>");
          client.println(localTemp);
          client.println("*C</p><p>");
          client.println("AIR HUMIDITY</p><p>");
          client.println(localHum);
          client.println("%</p></div>");
          client.println("LIGHT SENSOR</p><p>");
          client.println(lightSensor);
          client.println("%</p></div>");
          client.println("MOISTURE SENSOR</p><p>");
          client.println(MoistureSensor);
          client.println("%</p></div>");
          client.println("GROUND TEMP</p><p>");
          client.println(temperature);
          client.println("*C</p></div>");
          client.println("</body></html>");
          client.println("</html>");
          break;
        }
         }
    }
    // даем веб-браузеру время, чтобы получить данные:
    delay(1);
 
    // закрываем соединение:
    client.stop();
    Serial.println("client disconnected");  //  "клиент отключен"
  }
  }
После загрузки кода подключитесь к WiFi сети которую вы создали. Через браузер зайдите на страницу 192.168.1.1. Вы увидите показания с датчиков.
Вопросы и задания
1. Разберите код на блоки, посмотрите какой блок из какого урока вам уже знаком.

2. Возьмите растение и выявите оптимальные показания для важности, температуры для него.

3. Попробуйте поменять функцию client.println() чтобы изменить вывод информации на веб странице.