Система мониторинга окружающей среды на основе ESP32 (2 линии датчиков DS18B20 + DHT22)

Система мониторинга окружающей среды, основанная на использовании микроконтроллера ESP32, представляет собой универсальное решение для сбора и анализа данных о температуре и влажности в реальном времени. Она включает в себя несколько ключевых компонентов, обеспечивающих её функциональность и надежность.

Компоненты системы:

Микроконтроллер ESP32

Сердцем системы является микроконтроллер ESP32, который управляет всеми компонентами устройства и осуществляет связь с внешним миром посредством Wi-Fi. Этот мощный модуль обладает встроенным процессором, памятью и поддержкой множества интерфейсов, что делает его идеальным выбором для IoT-приложений. Основные характеристики ESP32 включают:

  • Процессор: Двухъядерный процессор Tensilica Xtensa LX6 с тактовой частотой до 240 МГц.
  • Память: 520 КБ SRAM и 16 МБ флеш-память.
  • Интерфейсы: UART, SPI, I²C, I²S, PWM, ADC, DAC, SDIO, Ethernet MAC, Wi-Fi, Bluetooth.
  • Поддержка Wi-Fi и Bluetooth: Встроенная поддержка стандартов IEEE 802.11 b/g/n и Bluetooth v4.2 BR/EDR и BLE.

Датчики температуры DS18B20

Для измерения температуры система использует цифровые датчики DS18B20, работающие по протоколу 1-Wire. Эти датчики обладают следующими характеристиками:

  • Диапазон измерения температуры: От -55°C до +125°C.
  • Точность: Измерение температуры с точностью до ±0.5°C в диапазоне от -10°C до +85°C.
  • Протокол 1-Wire: Позволяет подключить множество датчиков к одному проводу, что упрощает разводку схемы.
  • Энергопотребление: Низкое потребление энергии, что критично для автономных систем.

Датчики влажности и температуры DHT22

Помимо DS18B20, система оснащена двумя датчиками DHT22, которые позволяют одновременно измерять температуру и относительную влажность воздуха. Характеристики DHT22:

  • Диапазон измерения температуры: От -40°C до +80°C с точностью ±0.5°C.
  • Диапазон измерения влажности: От 0% до 99.9% с точностью ±2%.
  • Время отклика: До 2 секунд.
  • Напряжение питания: 3.3V — 6V.

OLED дисплей SSH1106_128x64

Для визуализации собранных данных используется OLED дисплей с разрешением 128×64 пикселей. Этот компактный дисплей подключается через интерфейс I²C и позволяет отображать текущее состояние датчиков в удобочитаемом формате. Основные характеристики OLED дисплея SSH1106_128x64:

  • Разрешение: 128×64 пикселя.
  • Тип экрана: OLED (Organic Light Emitting Diode), что обеспечивает высокую точность изображений.
  • Интерфейс: Подключение через интерфейс I²C позволяет эффективно интегрировать дисплей в систему.
  • Размер: Небольшой размер экрана облегчает его использование в компактных устройствах.

Программы и библиотеки

Управление системой осуществляется с помощью специализированного программного обеспечения, написанного на языке C++, которое использует различные библиотеки:

  • ESPAsyncWebServer: Создание веб-сервера для удаленного доступа к данным.
  • GyverOLED: Обслуживание OLED дисплея, включая удобные методы для вывода текста и графики.
  • OneWire: Работа с датчиками DS18B20 по протоколу 1-Wire.
  • DHT: Работа с датчиками DHT22 для измерения температуры и влажности.

Скетч:

#include <ESPAsyncWebServer.h>

#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
#endif

//---Для датчиков DS18B20
#include<OneWire.h>  //подключение библиотеки 1-Wire для ESP32 ЗИП ФАЙЛ OneWire-master
#define POWER_MODE 0 //режим питания  для шины 1-Wire, 0- внешнее, 1-паразитное

// линия №1 шины 1-Wire датчиков температуры DS18B20
OneWire sensDs (14);    // 5 датчиков подключены к выводу 14 >> (линия №1 шины 1-Wire)
// массив адресов датчиков DS18B20 (уникальный адрес)
byte sensAdd_L1[5][8]={
// адреса датчиков на макетной плате 
{0x28,0x1B,0x15,0x3E,0x00,0x00,0x00,0x4E},  //уникальный адрес 1 датчика
{0x28,0x4A,0xFF,0x3C,0x00,0x00,0x00,0x37},  //уникальный адрес 2 датчика 
{0x28,0x97,0xAA,0x3C,0x00,0x00,0x00,0xFE},  //уникальный адрес 3 датчика
{0x28,0xC4,0xE3,0x3C,0x00,0x00,0x00,0x93},  //уникальный адрес 4 датчика
{0x28,0x00,0xED,0x3D,0x00,0x00,0x00,0xFD},  //уникальный адрес 5 датчика
};

boolean flagWire_L1;       // флаг состояния 1 линии 1-Wire _ true – присутствие устройств, false – нет устройств (обрыв линии)
boolean flagCRC_L1[5];     // флаги ошибки считывания данных с датчика DS18B20 , true - (ошибка СRC или обрыв линии датчика)
boolean flag_timeDS_L1;    // флаг активности временной задержки для преобразования температуры
byte Nstr_L1;              // номер строки массива (номер-индекс датчика)
byte bufData_L1[9];        // буфер данных, 9 байт считанных с датчика 
byte fazaDS_L1 ;           // номер фазы в цикле инициализации DS18B20
float titDS_L1[5];         // измеренная температура >>массив из 5 значений температуры
uint64_t timeDS_L1;   // временная задержка для преобразования датчиком температуры и временная задержка в фазе цикла измерения 5
//---

// линия №2 шины 1-Wire датчиков температуры DS18B20
OneWire sensDs2 (27);    // 5 датчиков подключены к выводу 27 >> (линия №2 шины 1-Wire)
// массив адресов датчиков DS18B20 (уникальный адрес)
byte sensAdd_L2[5][8]={
// адреса датчиков на макетной плате   
{0x28,0xB7,0x0F,0x3E,0x00,0x00,0x00,0xAE},  //уникальный адрес 1 датчика
{0x28,0xAD,0xFB,0x3D,0x00,0x00,0x00,0x0B},  //уникальный адрес 2 датчика 
{0x28,0x4A,0x11,0x3D,0x00,0x00,0x00,0xC0},  //уникальный адрес 3 датчика
{0x28,0x0B,0xBC,0x3E,0x00,0x00,0x00,0xD5},  //уникальный адрес 4 датчика
{0x28,0xC6,0x13,0x3E,0x00,0x00,0x00,0x5C},  //уникальный адрес 5 датчика
};

boolean flagWire_L2;       // флаг состояния 1 линии 1-Wire _ true – присутствие устройств, false – нет устройств (обрыв линии)
boolean flagCRC_L2[5];     // флаги ошибки считывания данных с датчика DS18B20 , true - (ошибка СRC или обрыв линии датчика)
boolean flag_timeDS_L2;    // флаг активности временной задержки для преобразования температуры
byte Nstr_L2;              // номер строки массива (номер-индекс датчика)
byte bufData_L2[9];        // буфер данных, 9 байт считанных с датчика 
byte fazaDS_L2 ;           // номер фазы в цикле инициализации DS18B20
float titDS_L2[5];         // измеренная температура >>массив из 5 значений температуры
uint64_t timeDS_L2;   // временная задержка для преобразования датчиком температуры и временная задержка в фазе цикла измерения 5
//---

//---Для датчиков DHT
#include "DHT.h"
// Раскомментируйте одну из строк ниже в зависимости от того, какой датчик вы используете!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

//датчик DHT №01
uint8_t DHTPin_1 = 13;    // пин подключения датчика DHT
DHT dht_1(DHTPin_1, DHTTYPE);                
float TempDHT_1;          // температура DHT
float HumDHT_1;           // влажность DHT
boolean flagFautDht_1;    // флаг ошибки считывания данных с датчика DHT22
uint64_t timeDht_1;  // период временной задержки для измерения датчиком DHT22
//---
//датчик DHT №02
uint8_t DHTPin_2 = 19;    // пин подключения датчика DHT
DHT dht_2(DHTPin_2, DHTTYPE);                
float TempDHT_2;          // температура DHT
float HumDHT_2;           // влажность DHT
boolean flagFautDht_2;    // флаг ошибки считывания данных с датчика DHT22
uint64_t timeDht_2;  // период временной задержки для измерения датчиком DHT22
//---

//---Для дисплея
//---Для OLED дисплея (SSH1106_128x64 1,3) с 4-мя контактами I2C
#include <GyverOLED.h> //Лёгкая и быстрая библиотека для OLED дисплея
GyverOLED<SSH1106_128x64> oled;
uint64_t timeOled;    // период временной задержки для смены информации на дисплее
uint8_t kadrOled;          // номер кадра 
uint8_t timekadrOled;      // длительность кадра в секундах
//---

const char* ssid     = "Table DS18B20_DHT22";
const char *password = "01234567"; // пароль обязательно должен быть длиннее 8-ми символов

// Настройки IP адреса 
IPAddress local_IP(192,168,13,2);
IPAddress gateway(192,168,13,2);
IPAddress subnet(255,255,255,0);

// Создаем объект AsyncWebServer на порту 80
AsyncWebServer server(80);

//---страница показаний датчиков DS18B20, DHT22--------------------------------
const char table_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>ESP32 opros DS18B20, DHT</title>
<style>
  html { font-family: Times; display: inline-block; margin: 0px auto; text-align: center;}
  body{margin-top: 10px;} h1 {color: #444444;margin: 20px auto 10px;} h3 {color: #FF8077;margin-bottom: 10px;}
  p {font-size: 20px;color: #888;margin-bottom: 7px;}
  caption {border: solid 1px silver;background-color:#DDDDDD;font-size:18px;
  td{text-align:center;font-size:25px;}
</style>
</head>
<body>
<h3>ESP32 опрос датчиков DS18B20, DHT</h3>
<center>

<table  border="1" width="340" height="26" cellspacing="2">
<tr>
   <td width="180" style="font-size:16px;text-align: left;">Период опроса 3 сек.</td>
   <td style="font-size:18px;color:#0000FF;text-align:center;"><b><i><span id="connect">text1 </span></i></b></td>
</tr>
</table>

<br> 
<table  border="0" width="340" height="50" cellspacing="2"> 
<caption><i><b>Температура-T(&deg;С) на линии №1<br> датчиков DS18B20</b></i></caption> 
<tr>
  <td width="240" style="font-size:16px;">Показания датчика №1</td>
  <td >Т11:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T11_html">T11</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №2</td>
  <td>Т12:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T12_html">T12</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №3</td>
  <td>Т13:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T13_html">T13</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №4</td>
  <td>Т14:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T14_html">T14</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №5</td>
  <td>Т15:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T15_html">T15</span></td>      
</tr>
</table>

<br> 
<table  border="0" width="340" height="50" cellspacing="2"> 
<caption><i><b>Температура-T(&deg;С) на линии №2<br> датчиков DS18B20</b></i></caption> 
<tr>
  <td width="240" style="font-size:16px;">Показания датчика №1</td>
  <td >Т21:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T21_html">T21</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №2</td>
  <td>Т22:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T22_html">T22</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №3</td>
  <td>Т23:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T23_html">T23</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №4</td>
  <td>Т24:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T24_html">T24</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Показания датчика №5</td>
  <td>Т25:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T25_html">T25</span></td>      
</tr>
</table>

<br> 
<table  border="0" width="340" height="50" cellspacing="2"> 
<caption><i><b>Температура-T(&deg;С),<br>влажность-H(%) датчиков DHT22</b></i0></caption> 
<tr>
  <td width="240" style="font-size:16px;">Температура датчика №1</td>
  <td >Т31:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T31_html">T31</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Отн. влажность датчика №1</td>
  <td>H31:</td>     
  <td style="font-size:20px;text-align:center;"><span id="H31_html">H31</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Температура датчика №2</td>
  <td>Т41:</td>     
  <td style="font-size:20px;text-align:center;"><span id="T41_html">T41</span></td>      
</tr>
<tr>
  <td style="font-size:16px;text-align: left;">Отн. влажность датчика №2</td>
  <td>H41:</td>     
  <td style="font-size:20px;text-align:center;"><span id="H41_html">H41</span></td>      
</tr>
</table> 
</center>

<script>
var text1 = document.getElementById('connect');

var T11 = document.getElementById('T11_html');
var T12 = document.getElementById('T12_html');
var T13 = document.getElementById('T13_html');
var T14 = document.getElementById('T14_html');
var T15 = document.getElementById('T15_html');

var T21 = document.getElementById('T21_html');
var T22 = document.getElementById('T22_html');
var T23 = document.getElementById('T23_html');
var T24 = document.getElementById('T24_html');
var T25 = document.getElementById('T25_html');

var T31 = document.getElementById('T31_html');
var H31 = document.getElementById('H31_html');
var T41 = document.getElementById('T41_html');
var H41 = document.getElementById('H41_html');

oprosData();
setInterval(oprosData,3000);

function oprosData(){
  document.getElementById('connect').innerHTML = "disconnect";
  var dataJson = '/text_json?';
  fetch(dataJson)
      .then(function(response){return response.json();})
      .then(function(result) {
        text1.innerHTML =  result.text1;
        T11.innerHTML = result.T11;
        T12.innerHTML = result.T12;
        T13.innerHTML = result.T13;
        T14.innerHTML = result.T14;
        T15.innerHTML = result.T15;

        T21.innerHTML = result.T21;
        T22.innerHTML = result.T22;
        T23.innerHTML = result.T23;
        T24.innerHTML = result.T24;
        T25.innerHTML = result.T25;

        T31.innerHTML = result.T31;
        H31.innerHTML = result.H31;
        T41.innerHTML = result.T41;
        H41.innerHTML = result.H41;                      
      });
};

</script>
</body>
</html>
)rawliteral";
//-------------------------------------------------------------------------------------------------------------------
//===================================================================================================================
void setup()
{
  Serial.begin(115200);

 // для точки доступа
  WiFi.softAPConfig(local_IP, gateway, subnet);
  WiFi.softAP(ssid, password);
  //WiFi.softAP(ssid);
  delay(100);
  /*
  // для обычного Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
 */
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
  
  // Распечатать локальный IP-адрес 
  //Serial.println(WiFi.localIP());

  // Маршрут для корневой веб-страницы
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
  {
    request->send(200, "text/html", table_html);
  });
 // Маршрут для Json запроса
  server.on("/text_json", HTTP_GET, [] (AsyncWebServerRequest *request) 
  {
  //значения для ключей json формата
  String stTIT1;
  String stTIT2;
  String stTIT3;
  String stTIT4;
  String stTIT5;

  String stTIT21;
  String stTIT22;
  String stTIT23;
  String stTIT24;
  String stTIT25;

  String stTIT31;
  String stH31;  
  String stTIT41;
  String stH41;  
  //---
  //JSON (англ. JavaScript Object Notation) — текстовый формат обмена данными, основанный на JavaScript.

  if (flagWire_L1==false)// если обрыв линии №1 1-Wire
      {stTIT1 = stTIT2 = stTIT3 = stTIT4 = stTIT5 = "\"ERROR\"";}
  else
      { //если ошибка CRC датчика                       
        if (flagCRC_L1[0])  {stTIT1= "\"-CRC-\"";} else {stTIT1=String(titDS_L1[0],1);}     
        if (flagCRC_L1[1])  {stTIT2= "\"-CRC-\"";} else {stTIT2=String(titDS_L1[1],1);} 
        if (flagCRC_L1[2])  {stTIT3= "\"-CRC-\"";} else {stTIT3=String(titDS_L1[2],1);} 
        if (flagCRC_L1[3])  {stTIT4= "\"-CRC-\"";} else {stTIT4=String(titDS_L1[3],1);} 
        if (flagCRC_L1[4])  {stTIT5= "\"-CRC-\"";} else {stTIT5=String(titDS_L1[4],1);}         
      }

  if (flagWire_L2==false)// если обрыв линии №2-Wire 
      {stTIT21 = stTIT22 = stTIT23 = stTIT24= stTIT25= "\"ERROR\"";}
  else
      {
        if (flagCRC_L2[0])  {stTIT21= "\"-CRC-\"";} else {stTIT21=String(titDS_L2[0],1);}     
        if (flagCRC_L2[1])  {stTIT22= "\"-CRC-\"";} else {stTIT22=String(titDS_L2[1],1);} 
        if (flagCRC_L2[2])  {stTIT23= "\"-CRC-\"";} else {stTIT23=String(titDS_L2[2],1);} 
        if (flagCRC_L2[3])  {stTIT24= "\"-CRC-\"";} else {stTIT24=String(titDS_L2[3],1);} 
        if (flagCRC_L2[4])  {stTIT25= "\"-CRC-\"";} else {stTIT25=String(titDS_L2[4],1);}         
      }

  if (flagFautDht_1 ==true)//ошибка считывания датчика DHT
      {stTIT31 = stH31= "\"FAUT\"";}
  else 
      {
       stTIT31=String(TempDHT_1,1);
       stH31=String(HumDHT_1,0); 
      }

  if (flagFautDht_2 ==true)//ошибка считывания датчика DHT
      {stTIT41 = stH41= "\"FAUT\"";}
  else 
      {      
       stTIT41=String(TempDHT_2,1);
       stH41=String(HumDHT_2,0);
      }

  String response = ""; // ответ клиенту

  response += "{\"text1\": \"connect ESP32\",\"T11\": "+(stTIT1);
  response += ",\"T12\": "+(stTIT2);
  response += ",\"T13\": "+(stTIT3);
  response += ",\"T14\": "+(stTIT4);
  response += ",\"T15\": "+(stTIT5);
  response += ",\"T21\": "+(stTIT21);
  response += ",\"T22\": "+(stTIT22);
  response += ",\"T23\": "+(stTIT23);
  response += ",\"T24\": "+(stTIT24);
  response += ",\"T25\": "+(stTIT25);
  response += ",\"T31\": "+(stTIT31);
  response += ",\"H31\": "+(stH31);
  response += ",\"T41\": "+(stTIT41);
  response += ",\"H41\": "+(stH41)+" }";

    request->send(200, "application/json", response);
  });
//------------------------------------------------------------------------------------------------------------------------
//---для датчиков DHT 
 pinMode(DHTPin_1, INPUT); 
 dht_1.begin();
 pinMode(DHTPin_2, INPUT);
 dht_2.begin();
//--- 

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

//--- загрузка в дисплей
  oled.clear();   // очистить дисплей (или буфер)  
  oled.setScale(1); 
  oled.setCursorXY(7, 0); // курсор в (пиксель X, пиксель Y)
  oled.print("opros DS18B20,DHT22"); 
  oled.setScale(3); 
  oled.setCursorXY(0, 17); // курсор в (пиксель X, пиксель Y)
  oled.print("ESP 32"); 
  oled.setScale(1); 
  oled.setCursorXY(0,48); // курсор в (пиксель X, пиксель Y) 
  oled.print("WEBSER:AP132.168.13.2");
  oled.update(); 

  delay(7000);
  // Запустить сервер
  server.begin();
  Serial.println("HTTP server started");
}
//===============================================================================================================
void loop()
{
  oprosDS18B20_L1(); // процедура опроса датчиков DS18B20 линии №1 полный цикл
  oprosDht_1();      // процедура опроса датчика DHT №1
  oprosDS18B20_L2(); // процедура опроса датчиков DS18B20 линии №2
  oprosDht_2();      // процедура опроса датчика DHT №2
  oledText_I2();     // процедура вывода информации на дисплей
}  
//===================================================================================================================

//---Процедура измерения температуры датчикоми DS18B20 на линии №1------------------------------------------------------------
void oprosDS18B20_L1() 
{//опрос датчиков по полному циклу - при конветировании температуры потребление энергии только одним датчиком,
 // но увеличивается время опроса каждого датчика (время на 1 датчик * кол-во датчиков на линии плюс время промежуточного кода структуры LOOP)
switch (fazaDS_L1)
   {
   case 0: 
      if (sensDs.reset()==true) // сброс шины
        {
        flagWire_L1=true; // на линии 1-Wire устройства присутствуют
        fazaDS_L1 =1; 
        }
      else
        {
        flagWire_L1=false; // “обрыв” линии 1-wire или нет устройств 1-wire на линии
        fazaDS_L1 =5;     // переводим цикл опроса датчика в фазу 5 
        Serial.println("*L1_1wi:faut");// для отладки- неполадки с линией 1-Wire 
        }
    break;
            // команда инициализация датчика по адресу датчика
    case 1: sensDs.write(0x55,POWER_MODE); fazaDS_L1 =2;
            // посылаем адрес датчика
            sensDs.write(sensAdd_L1 [Nstr_L1][0],POWER_MODE);   // 1 байт адреса
            sensDs.write(sensAdd_L1 [Nstr_L1][1],POWER_MODE);   // 2 байт адреса
            sensDs.write(sensAdd_L1 [Nstr_L1][2],POWER_MODE);   // 3 байт адреса
            sensDs.write(sensAdd_L1 [Nstr_L1][3],POWER_MODE);   // 4 байт адреса
            sensDs.write(sensAdd_L1 [Nstr_L1][4],POWER_MODE);   // 5 байт адреса
            sensDs.write(sensAdd_L1 [Nstr_L1][5],POWER_MODE);   // 6 байт адреса
            sensDs.write(sensAdd_L1 [Nstr_L1][6],POWER_MODE);   // 7 байт адреса
            sensDs.write(sensAdd_L1 [Nstr_L1][7],POWER_MODE);   // 8 байт адреса
           // команда конвертирования температуры
           sensDs.write(0x44,POWER_MODE); fazaDS_L1 =2;
    break; 
    case 2: 
        // организуем временную задержку для измерения температуры датчиком DS18B20 - по даташифту минимальное время 750 mc                                                                                                                                                                                                       
        if ((millis()- timeDS_L1)>=800) // для UNO примерно раз в 50 дней количество миллисекунд сбрасывается на ноль.
           {
           timeDS_L1 = millis(); 
           fazaDS_L1 =3;          // по окончании временной задержки переход в следующую фазу цикла 
           }
    break;
    case 3: 
        if (sensDs.reset()==true) // сброс шины
           {
           flagWire_L1=true;// на линии 1-Wire устройства присутствуют   
           fazaDS_L1 =4;   // продолжаем цикл опроса датчиков
           }
        else
           {
           flagWire_L1=false; // “обрыв” линии 1-wire или нет устройств 1-wire на линии
           fazaDS_L1=5;      // переводим цикл опроса датчика в фазу 5
           Serial.println("*L1_1-Wire:faut 2");// для отладки   
           }
    break;                  
            // команда инициализация датчика по адресу датчика
    case 4: sensDs.write(0x55,POWER_MODE);    
             // посылаем адрес датчика
             sensDs.write(sensAdd_L1 [Nstr_L1][0],POWER_MODE);  // 1 байт адреса
             sensDs.write(sensAdd_L1 [Nstr_L1][1],POWER_MODE);  // 2 байт адреса
             sensDs.write(sensAdd_L1 [Nstr_L1][2],POWER_MODE);  // 3 байт адреса
             sensDs.write(sensAdd_L1 [Nstr_L1][3],POWER_MODE);  // 4 байт адреса
             sensDs.write(sensAdd_L1 [Nstr_L1][4],POWER_MODE);  // 5 байт адреса
             sensDs.write(sensAdd_L1 [Nstr_L1][5],POWER_MODE);  // 6 байт адреса
             sensDs.write(sensAdd_L1 [Nstr_L1][6],POWER_MODE);  // 7 байт адреса
             sensDs.write(sensAdd_L1 [Nstr_L1][7],POWER_MODE);  // 8 байт адреса
             // команда чтения
             sensDs.write(0xBE,POWER_MODE);  
             bufData_L1[0]=sensDs.read();    // чтение памяти датчика 
             bufData_L1[1]=sensDs.read();    // чтение памяти датчика
             bufData_L1[2]=sensDs.read();    // чтение памяти датчика 
             bufData_L1[3]=sensDs.read();    // чтение памяти датчика
             bufData_L1[4]=sensDs.read();    // чтение памяти датчика 
             bufData_L1[5]=sensDs.read();    // чтение памяти датчика
             bufData_L1[6]=sensDs.read();    // чтение памяти датчика 
             bufData_L1[7]=sensDs.read();   // чтение памяти датчика
             bufData_L1[8]=sensDs.read();    // чтение памяти датчика,
        // данные готовы
        if (OneWire::crc8(bufData_L1,8)==bufData_L1[8]) //проверка CRC
           {
             //данные правильные 
            flagCRC_L1[Nstr_L1]=false;
            if(bitRead(bufData_L1[1],7)==1) //температура <0 градусов
              { //если температура отрицательная, то данные в дополнительном коде
                // преобазуем в прямой код             
               byte t12=~bufData_L1[0]; byte t22=~bufData_L1[1];//инверсия байт
               titDS_L1[Nstr_L1]=(float)(((int)t12 |((int)t22<<8)+1) *0.0625+0.03125)*-1; // измеренная отрицательная температура

               // где 0.0625 град. С - вес разряда, а 0.03125 = 0.0625/2 половинка разряда для большей точности 
               // при разрешение преобразования  в 12 бит.
               // источник >> https://mypractic.ru/-Урок 26. Подключение термодатчиков DS18B20 к Ардуино. Библиотека OneWire. Точный Ардуино термометр-регистратор.
               // в этом же источнике приведен пример вывода по одному байту в линию 1- Wire c использованием таймера по времени.
             } 
            else 
              {//температура >=0 градусов
               titDS_L1[Nstr_L1]=(float)((int)bufData_L1[0] |((int)bufData_L1[1]<<8)) *0.0625+0.03125; // измеренная температура
              } 
               // передача температуры на компьютер
                Serial.print("*L1T"); Serial.print(Nstr_L1); Serial.print(":");  
                Serial.println(titDS_L1[Nstr_L1]);
            } // конец условия по правильной температуре
        else 
            {
             // ошибка CRC
            flagCRC_L1[Nstr_L1]=true;
            Serial.print("*L1T"); Serial.print(Nstr_L1); Serial.print(":"); Serial.println("_CRC");  
            }  // конец условия по ошибки CRC
        // цикл измерения закончен, перевод в следующий цикл для следующего датчика
        fazaDS_L1=5; 
        Nstr_L1= Nstr_L1+1;       // Nstr_L1 >> кол-во датчиков на линии (число строк массива уникальных адресов датчиков)
        if (Nstr_L1>=5) Nstr_L1=0;// переходим на нулевой датчик в линии
 break;     
 case 5: 
        if (flagWire_L1==false) // если обрыв линии, то опрос ведем через 5 секунд, дабы не "засорять" вывод информации 
           {
           if (flag_timeDS_L1==true)
              {
              if ((millis()- timeDS_L1)>=5000) // временная задержка 2 секунды
                 {
                 fazaDS_L1 =0;// переходим на нулевую фазу (начало цикла)
                 flag_timeDS_L1=false; //сбрасываем флаг активности временной задержки
                 }          
              }            
           else 
              { 
              timeDS_L1 = millis();
              flag_timeDS_L1=true; //устанавливаем флаг активности временной задержки
              fazaDS_L1 =5;       //остаемся в этой же фазе цикла    
              }
           }  
        else
           {
           fazaDS_L1 =0;// // переходим на нулевую фазу (начало цикла) при измерении без ошибки линии
           }  

  break;     
  }// завершение цикла switch (fazaDS)
} // завершение процедуры измерения температуры датчиком DS18B20
//--------------------------------------------------------------------------------------------------------------------------------------

//---Процедура измерения температуры датчикоми DS18B20 на линии №2----------------------------------------------------------
void oprosDS18B20_L2() 
{//опрос датчиков по неполному циклу >> используем команду "пропуск ROM" - при конвентировании температуры потребление энергии всеми датчиками на линии,
 //время опроса каждого датчика немного больше времени преобразования температуры == 800 мс.плюс время промежуточного кода структуры LOOP
switch (fazaDS_L2)
  {
   case 0: 
    if (sensDs2.reset()==true) // сброс шины
       {
        flagWire_L2=true; // на линии 1-Wire устройства присутствуют
        fazaDS_L2 =1; 
        }
    else
        {
         flagWire_L2=false; // “обрыв” линии 1-wire или нет устройств 1-wire на линии
         fazaDS_L2=5;      // переводим цикл опроса датчика в фазу 5 
         Serial.println("*L2_1-Wire:faut");// для отладки 
        }
   break;// выход из цикла
      
            // команда пропуск ROM
    case 1: sensDs2.write(0xCC,POWER_MODE);
            // команда конвертирования температуры
            sensDs2.write(0x44,POWER_MODE); fazaDS_L2 =2; break;
    // организуем временную задержку 900 mc для измерения температуры датчиком DS18B20 - по даташифту минимальное время 750 mc 
    case 2: 
      if (flag_timeDS_L2==true)
         {
         /*
         В отличие от Ардуино счетчики ESP32 имеют разрядность 64 бита, что позволяет
         реализовывать временные циклы со значительно более длительными периодами, не
         заботясь о переполнении счетчика.
         */
           if ((millis()- timeDS_L2)>=900) // для UNO примерно раз в 50 дней количество миллисекунд сбрасывается на ноль.
              {
               fazaDS_L2 =3;         // переходим на следующую фазу
               flag_timeDS_L2=false; // сбрасываем флаг активности временной задержки
              }          
          }            
      else 
          { 
           timeDS_L2 = millis(); // присваиваем время
           flag_timeDS_L2=true;  // устанавливаем флаг активности временной задержки
           fazaDS_L2 =2;         // переходим на эту же фазу  
          }
    break;
    case 3: 
      if (sensDs2.reset()==true) // сброс шины
         { 
         flagWire_L2=true;// на линии 1-Wire устройства присутствуют 
         fazaDS_L2=4;
         }
     else 
         {  
         flagWire_L2=false; // “обрыв” линии 1-wire или нет устройств на линии 1-wire 
         fazaDS_L2=5;      // переводим цикл опроса датчика в фазу 5
         Serial.println("*L2_1-Wire:faut 2");// для отладки 
         }
     break;
     
            // команда инициализация датчика по адресу датчика  
    case 4: sensDs2.write(0x55,POWER_MODE); 
            // посылаем адрес датчика
            sensDs2.write(sensAdd_L2 [Nstr_L2][0],POWER_MODE);  // 1 байт адреса
            sensDs2.write(sensAdd_L2 [Nstr_L2][1],POWER_MODE);  // 2 байт адреса
            sensDs2.write(sensAdd_L2 [Nstr_L2][2],POWER_MODE);  // 3 байт адреса
            sensDs2.write(sensAdd_L2 [Nstr_L2][3],POWER_MODE);  // 4 байт адреса
            sensDs2.write(sensAdd_L2 [Nstr_L2][4],POWER_MODE);  // 5 байт адреса
            sensDs2.write(sensAdd_L2 [Nstr_L2][5],POWER_MODE);  // 6 байт адреса
            sensDs2.write(sensAdd_L2 [Nstr_L2][6],POWER_MODE);  // 7 байт адреса
            sensDs2.write(sensAdd_L2 [Nstr_L2][7],POWER_MODE);  // 8 байт адреса
            // команда чтения памяти
            sensDs2.write(0xBE,POWER_MODE); 
           // чтение 9 регистров датчика 
           bufData_L2[0]=sensDs2.read();   // чтение памяти датчика 0 байт: температура мл.
           bufData_L2[1]=sensDs2.read();   // чтение памяти датчика 1 байт: температура ст.  
           bufData_L2[2]=sensDs2.read();   // чтение памяти датчика 2 байт: TH регистр 
           bufData_L2[3]=sensDs2.read();   // чтение памяти датчика 3 байт: TL регитстр  
           bufData_L2[4]=sensDs2.read();   // чтение памяти датчика 4 байт: Регистр конфигурации
           bufData_L2[5]=sensDs2.read();   // чтение памяти датчика 5 байт: зарезирвирован (FFh) 
           bufData_L2[6]=sensDs2.read();   // чтение памяти датчика 6 байт: зарезирвирован (0Ch) 
           bufData_L2[7]=sensDs2.read();   // чтение памяти датчика 7 байт: зарезирвирован (10h)   
           bufData_L2[8]=sensDs2.read();   // чтение памяти датчика 8 байт: циклический код CRC 
              // данные готовы
             if (OneWire::crc8(bufData_L2,8)==bufData_L2[8]) //проверка CRC
                {
                //данные правильные 
                flagCRC_L2[Nstr_L2]=false;
                if(bitRead(bufData_L2[1],7)==1) 
                  { //если температура отрицательная, то данные в дополнительном коде
                    // преобазуем в прямой код             
                    byte t12=~bufData_L2[0]; byte t22=~bufData_L2[1];//инверсия байт
                    titDS_L2[Nstr_L2]=(float)(((int)t12 |((int)t22<<8)+1) *0.0625+0.03125)*-1; // измеренная отрицательная температура
                  } 
                 else 
                  {//температура >=0 градусов
                  titDS_L2[Nstr_L2]=(float)((int)bufData_L2[0] |((int)bufData_L2[1]<<8)) *0.0625+0.03125; // измеренная температура
                  } 
               // передача температуры на компьютер
                Serial.print("*L2T"); Serial.print(Nstr_L2); Serial.print(":");  
                Serial.println(titDS_L2[Nstr_L2]);
                } // конец условия по правильной температуре
            else 
                {
                // ошибка CRC
                flagCRC_L2[Nstr_L2]=true;
                Serial.print("*L2T"); Serial.print(Nstr_L2); Serial.print(":"); Serial.println("_CRC");  
                }  // конец условия по ошибки CRC
            // цикл опроса закончен, перевод в следующий цикл для следующего датчика 
            Nstr_L2= Nstr_L2+1;
            if (Nstr_L2>=5) // количество датчиков на линии согласно массиву адресов
               {
                Nstr_L2=0;// переходим на нулевой датчик в линии
                fazaDS_L2=5;
               }
            else
               {  
                fazaDS_L2=3; // переходим на следующий датчик
              }    
    break;
              
    case 5: 
        if (flagWire_L2==false) // если обрыв линии, то опрос ведем через 5 секунд, дабы не "засорять" вывод информации 
           {
           if (flag_timeDS_L2==true)
              {
              if ((millis()- timeDS_L2)>=5000) // временная задержка 5 секунд
                 {
                 fazaDS_L2 =0;// переходим на нулевую фазу (начало цикла)
                 flag_timeDS_L2=false; //сбрасываем флаг активности временной задержки
                 }          
              }            
           else 
              { 
              timeDS_L2 = millis();
              flag_timeDS_L2=true; //устанавливаем флаг активности временной задержки
              fazaDS_L2 =5;       //остаемся в этой же фазе цикла    
              }
           }  
        else
           {
           fazaDS_L2 =0; // переходим на нулевую фазу (начало цикла) при измерении без ошибки линии
           }  
  break;                
   }// конец цикла switch (fazaDS_L2)
}//--- end процедуры oprosDS18B20_L2()
//----------------------------------------------------------------------------------------------------------------------------------------------

//---процедура опроса датчика DHT №01
void oprosDht_1() 
{
//Delay(2000); // 2 секунды - необходимая временная задержка для измерения датчиком DHT22
if (millis()- timeDht_1>=2000)
 {
  timeDht_1= millis(); // для UNO примерно раз в 50 дней количество миллисекунд сбрасывается на ноль
  
  HumDHT_1=dht_1.readHumidity();     // считываем влажность
  TempDHT_1=dht_1.readTemperature();  // считываем температуру
 // проверка удачно  ли прошло ли считывание
  if (isnan(HumDHT_1) || isnan (TempDHT_1)) 
     { 
     flagFautDht_1 =true;   // установка флага ошибки считывания
     Serial.println ("*DHT_1:ERROR");
     }
  else
     {  
     flagFautDht_1 =false; // сброс флага ошибки считывания
     Serial.print ("*dhtH_1:"); Serial.println (HumDHT_1); 
     Serial.print ("*dhtT_1:"); Serial.println (TempDHT_1);
     }
 } 
}//---конец процедуры опроса датчика DHT №01

//---процедура опроса датчика DHT №02
void oprosDht_2() 
{
//Delay(2000); // 2 секунды - необходимая временная задержка для измерения датчиком DHT22
if (millis()- timeDht_2>=2000)
 {
  timeDht_2= millis(); // для UNO примерно раз в 50 дней количество миллисекунд сбрасывается на ноль
  
  HumDHT_2=dht_2.readHumidity();     // считываем влажность
  TempDHT_2=dht_2.readTemperature();  // считываем температуру
 // проверка удачно  ли прошло ли считывание
  if (isnan(HumDHT_2) || isnan (TempDHT_2)) 
     { 
     flagFautDht_2 =true;   // установка флага ошибки считывания
     Serial.println ("*DHT_2:ERROR");
     }
  else
     {  
     flagFautDht_2 =false; // сброс флага ошибки считывания
     Serial.print ("*dhtH_2:"); Serial.println (HumDHT_2); 
     Serial.print ("*dhtT_2:"); Serial.println (TempDHT_2);
     }
 } 
}//---конец процедуры опроса датчика DHT №02

 //---процедура вывода информации на дисплей------------------------------------------------------------
void oledText_I2()
{
  if ((millis()- timeOled)>=1000)
     {
      timeOled = millis();

      timekadrOled=timekadrOled+1;
      if (timekadrOled>=3){kadrOled=1;}    //отображение показаний датчика T12,T13,T14,T15 7сек.
      if (timekadrOled>=10){kadrOled=2;}    //отображение показаний 1 датчика DHT  2сек.
      if (timekadrOled>=12){kadrOled=3;}    //отображение показаний датчика T21 3сек
      if (timekadrOled>=15){kadrOled=4;}    //отображение показаний датчика T22,T23,T24,T25 7сек. 
      if (timekadrOled>=22){kadrOled=5;}    //отображение показаний 2 датчика DHT  2сек. 
      if (timekadrOled>=24){kadrOled=0;timekadrOled=0;}  //отображение показаний датчика T11 3сек.
      Serial.print("kadrOled=");Serial.println(kadrOled);//для отладки

     }
 switch (kadrOled)
  { 
   case 0:
   {
    // температура T11
    oled.clear();   // очистить дисплей (или буфер) 
    oled.setScale(1); 
    oled.setCursorXY(5,0); // курсор в (пиксель X, пиксель Y)
    oled.print("L01  SENSOR: DS18B20");
    oled.setScale(2); 
    oled.setCursorXY(0, 21); // курсор в (пиксель X, пиксель Y)
    oled.print("T1:");
    oled.setScale(3); 
    oled.setCursorXY(40, 18); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L1[0]||!flagWire_L1) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L1[0],1);} 
    oled.setScale(1); 
    oled.setCursorXY(15,48); // курсор в (пиксель X, пиксель Y) 
    oled.print("IP: ");oled.print("168.192.13.2");
    oled.update();
   break;  
   }
   case 1:
   {
    // температура T12,T13,T14,T15
    oled.clear();   // очистить дисплей (или буфер) 
    oled.setScale(1); 
    oled.setCursorXY(5,0); // курсор в (пиксель X, пиксель Y)
    oled.print("L01  SENSOR: DS18B20");
    oled.setCursorXY(0, 21); // курсор в (пиксель X, пиксель Y) 
    oled.print("T2");  
    oled.setScale(2); 
    oled.setCursorXY(15, 15); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L1[1]||!flagWire_L1) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L1[1],1);}
    oled.setScale(1);   
    oled.setCursorXY(67, 21); // курсор в (пиксель X, пиксель Y) 
    oled.print("T3");  
    oled.setScale(2); 
    oled.setCursorXY(82, 15); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L1[2]||!flagWire_L1) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L1[2],1);} 
    oled.setScale(1);  
    oled.setCursorXY(0, 46); // курсор в (пиксель X, пиксель Y) 
    oled.print("T4");  
    oled.setScale(2); 
    oled.setCursorXY(15, 41); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L1[3]||!flagWire_L1) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L1[3],1);}
    oled.setScale(1);   
    oled.setCursorXY(67, 46); // курсор в (пиксель X, пиксель Y) 
    oled.print("T5");  
    oled.setScale(2); 
    oled.setCursorXY(82, 41); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L1[4]||!flagWire_L1) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L1[4],1);}  
    oled.update();
   break;  
   }
   case 2:
   {
 // DHT22 T31 - температура, H31 - относительная влажность
     oled.clear();   // очистить дисплей (или буфер)
     oled.setScale(1); 
     oled.setCursorXY(5, 0); // курсор в (пиксель X, пиксель Y)
     oled.print("SENSOR TYPE: DHT22");
     if  (!flagFautDht_1)
       {
         oled.setScale(2); 
         oled.setCursorXY(0, 15); // курсор в (пиксель X, пиксель Y)
         oled.print("T31:");
         oled.setScale(3);
         oled.setCursorXY(48, 12); // курсор в (пиксель X, пиксель Y)
         oled.print(TempDHT_1,1);
         oled.setScale(2); 
         oled.setCursorXY(0, 43); // курсор в (пиксель X, пиксель Y)
         oled.print("H31:");
         oled.setScale(3); 
         oled.setCursorXY(54, 40); // курсор в (пиксель X, пиксель Y)
        oled.print(HumDHT_1,0); oled.print("%"); 
       }
     else
       {
         oled.setScale(2); 
         oled.setCursorXY(10, 25); // курсор в (пиксель X, пиксель Y)
         oled.print("FAUT DHT");
       } 
    
     oled.update();
     break;  
   }
   case 3:
   { 
    // температура T21
    oled.clear();   // очистить дисплей (или буфер) 
    oled.setScale(1); 
    oled.setCursorXY(5,0); // курсор в (пиксель X, пиксель Y)
    oled.print("L02  SENSOR: DS18B20");
    oled.setScale(2); 
    oled.setCursorXY(0, 21); // курсор в (пиксель X, пиксель Y)
    oled.print("T1:");
    oled.setScale(3); 
    oled.setCursorXY(40, 18); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L2[0]||!flagWire_L2) {oled.print("FAUT");} // флаг состояния 2 линии 1-Wire
    else {oled.print(titDS_L2[0],1);} 
    oled.setScale(1); 
    oled.setCursorXY(15,48); // курсор в (пиксель X, пиксель Y) 
    oled.print("IP: "); oled.print("168.192.13.2");
    //oled.print(WiFi.localIP());// для режима STA WebSer>Режим станции (STA) (WiFi Station).
    oled.update();
   break;  
   }
  case 4:
   {
    // температура T22,T23,T24,T25
    oled.clear();   // очистить дисплей (или буфер) 
    oled.setScale(1); 
    oled.setCursorXY(5,0); // курсор в (пиксель X, пиксель Y)
    oled.print("L02  SENSOR: DS18B20");
    oled.setCursorXY(0, 21); // курсор в (пиксель X, пиксель Y) 
    oled.print("T2");  
    oled.setScale(2); 
    oled.setCursorXY(15, 15); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L2[1]||!flagWire_L2) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L2[1],1);}
    oled.setScale(1);   
    oled.setCursorXY(67, 21); // курсор в (пиксель X, пиксель Y) 
    oled.print("T3");  
    oled.setScale(2); 
    oled.setCursorXY(82, 15); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L2[2]||!flagWire_L2) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L2[2],1);} 
    oled.setScale(1);  
    oled.setCursorXY(0, 46); // курсор в (пиксель X, пиксель Y) 
    oled.print("T4");  
    oled.setScale(2); 
    oled.setCursorXY(15, 41); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L2[3]||!flagWire_L2) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L2[3],1);}
    oled.setScale(1);   
    oled.setCursorXY(67, 46); // курсор в (пиксель X, пиксель Y) 
    oled.print("T5");  
    oled.setScale(2); 
    oled.setCursorXY(82, 41); // курсор в (пиксель X, пиксель Y)
    if (flagCRC_L2[4]||!flagWire_L2) {oled.print("FAUT");} // флаг ошибки CRC датчика или флаг состояния 1 линии 1-Wire
    else {oled.print(titDS_L2[4],1);}  
    oled.update();
   break;  
   }
   case 5:
   { 
     // DHT22 T41 - температура, H41 - относительная влажность
     oled.clear();   // очистить дисплей (или буфер)
     oled.setScale(1); 
     oled.setCursorXY(5, 0); // курсор в (пиксель X, пиксель Y)
     oled.print("SENSOR TYPE: DHT22");
     if  (!flagFautDht_2)
       {
         oled.setScale(2); 
         oled.setCursorXY(0, 15); // курсор в (пиксель X, пиксель Y)
         oled.print("T41:");
         oled.setScale(3);
         oled.setCursorXY(48, 12); // курсор в (пиксель X, пиксель Y)
         oled.print(TempDHT_2,1);
         oled.setScale(2); 
         oled.setCursorXY(0, 43); // курсор в (пиксель X, пиксель Y)
         oled.print("H41:");
         oled.setScale(3); 
         oled.setCursorXY(54, 40); // курсор в (пиксель X, пиксель Y)
        oled.print(HumDHT_2,0); oled.print("%"); 
       }
     else
       {
         oled.setScale(2); 
         oled.setCursorXY(10, 25); // курсор в (пиксель X, пиксель Y)
         oled.print("FAUT DHT");
       } 
    
     oled.update();
     break;  
   }       
  }
 }
//---------------------------------------------------------------------------------------------------------------------------------------------
  1. Пин 14 (sensDs):
    • Используется для подключения линии №1 шины 1-Wire, к которой подключено пять датчиков DS18B20. Через этот пин осуществляется обмен данными с этими датчиками.
  2. Пин 27 (sensDs2):
    • Используется для подключения линии №2 шины 1-Wire, к которой также подключено пять датчиков DS18B20. Аналогично пину 14, через этот пин идет обмен данными с датчиками второй линии.
  3. Пин 13 (DHTPin_1) и пин 19 (DHTPin_2):
    • Используются для подключения двух датчиков DHT22. Эти пины отвечают за получение данных о температуре и влажности от соответствующих датчиков.

При подключении датчиков DS18B20 к ESP32 необходимо использовать подтягивающий резистор между линией данных и питанием (VCC). На коротких линиях чаще всего применяется резистор 4.7 кОм, но на длинных линиях для надежной передачи сигнала могут понадобиться резисторы меньшего номинала. В данном проекте использовались телефонные кабели ШТЛП-2 и ШТЛП-4, и наиболее стабильная работа была достигнута с резистором 3.2 кОм.

Принципы работы

Система работает следующим образом:

  1. Инициализация компонентов: При старте устройства происходит настройка всех необходимых модулей и библиотек, устанавливаются параметры Wi-Fi соединения, создаются объекты для работы с датчиками и дисплеем.
  2. Сбор данных: Периодически проводится опрос датчиков DS18B20 и DHT22 для получения текущих значений температуры и влажности. Данные обрабатываются и проверяются на наличие ошибок, таких как неправильное значение CRC или обрыв линий связи.
  3. Отображение данных: Собранные данные выводятся на OLED дисплей. Информация на экране меняется в соответствии с установленным интервалом обновления, что позволяет отслеживать изменения параметров окружающей среды в реальном времени.
  4. Удаленный доступ: Пользователи могут получить доступ к данным через веб-интерфейс, созданный с помощью библиотеки ESPAsyncWebServer. Для обновления данных без необходимости перезагрузки веб-страницы используется технология JSON, которая позволяет динамически обновлять информацию на странице.

Применение

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

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

Заключение

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

Автор проекта — Vid_PB (vid_pb@mail.ru)

Фото проекта:

Дополнительный материал:

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

Войти с помощью: