Отображение показаний с нескольких DS18B20 с помощью веб-сервера на ESP8266 NodeMCU

Добавлено 5 сентября 2020 в 14:45

Вы когда-нибудь хотели, чтобы датчики были разбросаны по всему дому и саду, регулярно сообщая о своей температуре на центральный сервер? Тогда этот IoT проект может стать для вас хорошей отправной точкой!

Отображение показаний с нескольких DS18B20 с помощью веб-сервера на ESP8266 NodeMCU
Отображение показаний с нескольких DS18B20 с помощью веб-сервера на ESP8266 NodeMCU

В этом проекте NodeMCU ESP8266 используется в качестве устройства управления, которое легко подключается к существующей сети Wi-Fi и создает веб-сервер. Когда любое подключенное устройство обращается к этому веб-серверу, ESP8266 считывает температуру с нескольких датчиков температуры DS18B20 и отправляет эти показания веб-браузеру подключенного устройства, выводя их в приятном интерфейсе. Интересно? Давайте начнем!

Несколько датчиков DS18B20 на одной шине

Одна из важнейших особенностей DS18B20 заключается в том, что на одной шине 1-Wire могут сосуществовать несколько DS18B20. Поскольку каждый DS18B20 имеет уникальный 64-битный серийный номер, записанный на заводе, их легко отличить друг от друга.

Эта особенность может быть огромным преимуществом, если вы хотите контролировать множество датчиков DS18B20, распределенных по большой площади. В данном руководстве мы это и сделаем.

Подключение нескольких датчиков DS18B20 ESP8266 NodeMCU

Подключить датчики DS18B20 к ESP8266 NodeMCU довольно просто.

Рисунок 1 Распиновка датчика температуры DS18B20 в корпусе TO-92 и в водонепроницаемом корпусе
Рисунок 1 – Распиновка датчика температуры DS18B20 в корпусе TO-92 и в водонепроницаемом корпусе

Начните с параллельного соединения всех датчиков DS18B20, то есть соединения всех выводов GND, затем всех выводов VDD, и последнее, всех сигнальных выводов. Затем подключите VDD к выходу 3.3V на NodeMCU, GND – к GND на NodeMCU, и сигнальных выводов к цифровому выводу D2 на ESP8266 NodeMCU.

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

Рисунок 2 Подключение нескольких датчиков температуры DS18B20 к ESP8266
Рисунок 2 – Подключение нескольких датчиков температуры DS18B20 к ESP8266

Подготовка IDE Arduino

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

Установка библиотеки для DS18B20

Протокол Dallas 1-Wire несколько сложен и требует много кода для парсинга связи. Чтобы скрыть эту ненужную сложность, мы установим библиотеку DallasTemperature.h, чтобы мы могли выполнять простые команды для получения показаний температуры от датчика.

Чтобы установить библиотеку, перейдите в раздел «Скетч»→ «Подключить библиотеку» → «Управление библиотеками…». Подождите, пока менеджер библиотеки загрузит индекс библиотек и обновит список установленных библиотек.

Чтобы отфильтровать результаты поиска, введите «ds18b20». Там должна быть пара записей. Ищите DallasTemperature от Miles Burton. Нажмите на эту запись, а затем выберите Установка.

Рисунок 3 Установка библиотеки DallasTemperature в Arduino IDE
Рисунок 3 – Установка библиотеки DallasTemperature в Arduino IDE

Эта библиотека DallasTemperature является аппаратно-зависимой библиотекой, которая обрабатывает функции более низкого уровня. Она должна быть связана с библиотекой OneWire для связи с любым устройством 1-Wire, а не только с DS18B20. Установите и эту библиотеку.

Рисунок 4 Установка библиотеки OneWire в Arduino IDE
Рисунок 4 – Установка библиотеки OneWire в Arduino IDE

Поиск адресов DS18B20 в шине

Мы знаем, что каждому DS18B20 назначен уникальный 64-битный адрес, помогающий отличать их друг от друга. Сначала мы найдем этот адрес, чтобы пометить каждый датчик соответствующим образом. Затем этот адрес можно использовать для считывания показаний каждого датчика по отдельности.

Следующий скетч обнаруживает все датчики DS18B20, присутствующие на шине, и выводит их адреса на шине 1-Wire в монитор последовательного порта.

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

#include <OneWire.h>
#include <DallasTemperature.h>

// Шина данных подключена к выводу D2 на ESP8266
#define ONE_WIRE_BUS D2

// Настройка объекта oneWire для связи с любыми устройствами OneWire
OneWire oneWire(ONE_WIRE_BUS);

// Передаем ссылку на объект oneWire объекту Dallas Temperature.
DallasTemperature sensors(&oneWire);

// Переменная для хранения адресов устройств
DeviceAddress Thermometer;

int deviceCount = 0;

void setup(void)
{
  // запуск последовательного порта
  Serial.begin(115200);

  // запуск библиотеке
  sensors.begin();

  // определение устройств на шине
  Serial.println("Locating devices...");
  Serial.print("Found ");
  deviceCount = sensors.getDeviceCount();
  Serial.print(deviceCount, DEC);
  Serial.println(" devices.");
  Serial.println("");
  
  Serial.println("Printing addresses...");
  for (int i = 0;  i < deviceCount;  i++)
  {
    Serial.print("Sensor ");
    Serial.print(i+1);
    Serial.print(" : ");
    sensors.getAddress(Thermometer, i);
    printAddress(Thermometer);
  }
}

void loop(void)
{ }

void printAddress(DeviceAddress deviceAddress)
{ 
  for (uint8_t i = 0; i < 8; i++)
  {
    Serial.print("0x");
    if (deviceAddress[i] < 0x10) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
    if (i < 7) Serial.print(", ");
  }
  Serial.println("");
}

Теперь откройте монитор последовательного порта. У вас должно получиться примерно следующее.

Рисунок 5 Нахождение адресов 1-Wire всех датчиков DS18B20 на шине
Рисунок 5 – Нахождение адресов 1-Wire всех датчиков DS18B20 на шине

Скопируйте все адреса по мере необходимости в следующий скетч.

Создание веб-сервера NodeMCU ESP8266, используя Wi-Fi режим Station (STA)

Теперь мы собираемся настроить ESP8266 в режим станции (STA) и создать веб-сервер для выдачи веб-страниц любому подключенному клиента в существующей сети.

Если вы хотите узнать о создании веб-сервера с ESP8266 NodeMCU в режиме AP/STA, ознакомьтесь с этим руководством:

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

Чтобы ESP8266 NodeMCU мог установить соединение с существующей сетью, вам необходимо изменить следующие две переменные в соответствии с учетными данными вашей сети.

const char* ssid = "YourNetworkName";   // SSID
const char* password = "YourPassword";  // пароль

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

uint8_t sensor1[8] = { 0x28, 0xEE, 0xD5, 0x64, 0x1A, 0x16, 0x02, 0xEC };
uint8_t sensor2[8] = { 0x28, 0x61, 0x64, 0x12, 0x3C, 0x7C, 0x2F, 0x27 };
uint8_t sensor3[8] = { 0x28, 0x61, 0x64, 0x12, 0x3F, 0xFD, 0x80, 0xC6 };

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

#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// Шина данных подключена к выводу D2 на ESP8266
#define ONE_WIRE_BUS D2

// Настройка объекта oneWire для связи с любыми устройствами OneWire
OneWire oneWire(ONE_WIRE_BUS);

// Передаем ссылку на объект oneWire объекту Dallas Temperature.
DallasTemperature sensors(&oneWire);

float tempSensor1, tempSensor2, tempSensor3;

uint8_t sensor1[8] = { 0x28, 0xEE, 0xD5, 0x64, 0x1A, 0x16, 0x02, 0xEC  };
uint8_t sensor2[8] = { 0x28, 0x61, 0x64, 0x12, 0x3C, 0x7C, 0x2F, 0x27  };
uint8_t sensor3[8] = { 0x28, 0x61, 0x64, 0x12, 0x3F, 0xFD, 0x80, 0xC6  };

/* Введите SSID и пароль от вашей сети*/
const char* ssid = "YourNetworkName";   // SSID
const char* password = "YourPassword";  // пароль

ESP8266WebServer server(80);             
 
void setup() 
{
  Serial.begin(115200);
  delay(100);
  
  sensors.begin();              

  Serial.println("Connecting to ");
  Serial.println(ssid);

  // подключиться к вашей локальной wi-fi сети
  WiFi.begin(ssid, password);

  // проверить, выполнено ли подключение wi-fi сети
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  server.on("/", handle_OnConnect);
  server.onNotFound(handle_NotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop() 
{
  server.handleClient();
}

void handle_OnConnect() 
{
  sensors.requestTemperatures();
  tempSensor1 = sensors.getTempC(sensor1); // Получить значение температуры
  tempSensor2 = sensors.getTempC(sensor2); // Получить значение температуры
  tempSensor3 = sensors.getTempC(sensor3); // Получить значение температуры
  server.send(200, "text/html", SendHTML(tempSensor1,tempSensor2,tempSensor3)); 
}

void handle_NotFound()
{
  server.send(404, "text/plain", "Not found");
}

String SendHTML(float tempSensor1,float tempSensor2,float tempSensor3)
{
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  ptr +="<title>ESP8266 Temperature Monitor</title>\n";
  ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
  ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
  ptr +="</style>\n";
  ptr +="</head>\n";
  ptr +="<body>\n";
  ptr +="<div id=\"webpage\">\n";
  ptr +="<h1>ESP8266 Temperature Monitor</h1>\n";
  ptr +="<p>Living Room: ";
  ptr +=tempSensor1;
  ptr +="&deg;C</p>";
  ptr +="<p>Bedroom: ";
  ptr +=tempSensor2;
  ptr +="&deg;C</p>";
  ptr +="<p>Kitchen: ";
  ptr +=tempSensor3;
  ptr +="&deg;C</p>";
  ptr +="</div>\n";
  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}

Доступ к веб-серверу

После загрузки скетча откройте монитор последовательного порта со скоростью 115200 бит/с и нажмите кнопку RST на NodeMCU. Если всё в порядке, он выведет динамический IP адрес, полученный от вашего маршрутизатора, и покажет сообщение о том, что HTTP сервер запущен.

Рисунок 6 Монитор последовательного порта сервер запущен
Рисунок 6 – Монитор последовательного порта – сервер запущен

Затем загрузите браузер и введите IP адрес, указанный в мониторе последовательного порта. ESP8266 NodeMCU должен выдать веб-страницу, показывающую температуры со всех датчиков DS18B20.

Рисунок 7 Показания с нескольких датчиков DS18B20 на странице веб-сервера ESP8266 (без CSS)
Рисунок 7 – Показания с нескольких датчиков DS18B20 на странице веб-сервера ESP8266 (без CSS)

Подробное объяснение кода

Скетч начинается с включения следующих библиотек:

  • библиотека ESP8266WebServer.h предоставляет специальные методы ESP8266 NodeMCU для работы с Wi-Fi, которые мы вызываем для подключения к сети. Она также имеет несколько методов, которые помогут нам настроить сервер и обрабатывать входящие HTTP-запросы, не беспокоясь о деталях низкоуровневой реализации;
  • библиотека DallasTemperature.h – это аппаратно-зависимая библиотека, которая обрабатывает низкоуровневые функции. Она работает в паре с библиотекой One Wire;
  • библиотека OneWire.h взаимодействует с любым устройством на шине 1-Wire, а не только с DS18B20.
#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>

Затем мы создаем объекты, необходимые для датчика температуры, и переменные для хранения показаний температуры. Датчик температуры подключен к GPIO D2.

// Шина данных подключена к выводу D2 на ESP8266
#define ONE_WIRE_BUS D2

// Настройка объекта oneWire для связи с любыми устройствами OneWire
OneWire oneWire(ONE_WIRE_BUS);

// Передаем ссылку на объект oneWire объекту Dallas Temperature.
DallasTemperature sensors(&oneWire);

float tempSensor1, tempSensor2, tempSensor3;

Далее вводим адреса, которые были ранее выяснены, для каждого датчика температуры. В нашем случае имеем следующее.

uint8_t sensor1[8] = { 0x28, 0xEE, 0xD5, 0x64, 0x1A, 0x16, 0x02, 0xEC  };
uint8_t sensor2[8] = { 0x28, 0x61, 0x64, 0x12, 0x3C, 0x7C, 0x2F, 0x27  };
uint8_t sensor3[8] = { 0x28, 0x61, 0x64, 0x12, 0x3F, 0xFD, 0x80, 0xC6  };

Поскольку мы настраиваем ESP8266 в режиме станции (STA), он подключится к существующей сети Wi-Fi. Следовательно, нам необходимо предоставить ему SSID и пароль вашей сети. Затем мы запускаем веб-сервер на порту 80.

/* Введите SSID и пароль от вашей сети*/
const char* ssid = "YourNetworkName";   // SSID
const char* password = "YourPassword";  // пароль

ESP8266WebServer server(80); 

Внутренности функции setup()

Внутри функции setup() мы настраиваем наш HTTP-сервер перед его запуском. Прежде всего, мы инициализируем последовательную связь с ПК и инициализируем объект DallasTemperature с помощью функции begin(). Он инициализирует шину и обнаруживает все присутствующие на ней датчики DS18B20. Затем каждому датчику присваивается индекс и устанавливается разрядность 12 бит.

Serial.begin(115200);
delay(100);
  
sensors.begin(); 

Теперь нам нужно подключиться к сети Wi-Fi с помощью функции WiFi.begin(). Данная функция принимает в качестве параметров SSID (имя сети) и пароль.

Serial.println("Connecting to ");
Serial.println(ssid);

// подключиться к вашей локальной wi-fi сети
WiFi.begin(ssid, password);

Пока ESP8266 пытается подключиться к сети, мы проверяем статус подключения с помощью функции WiFi.status().

// проверить, выполнено ли подключение wi-fi сети
while (WiFi.status() != WL_CONNECTED) 
{
  delay(1000);
  Serial.print(".");
}

После подключения ESP8266 к сети скетч выводит IP-адрес, назначенный ESP8266, напечатав значение результата метода WiFi.localIP() в монитор последовательного порта.

Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

Чтобы обрабатывать входящие HTTP запросы, нам нужно указать, какой код выполнять при введении определенного URL. Для этого мы используем метод on(). Этот метод принимает два параметра. Первый – это URL путь, а второй – имя функции, которую мы хотим выполнить при входе на этот URL.

Приведенный ниже код указывает, что когда сервер получает HTTP запрос по корневому пути (/), он запускает функцию handle_OnConnect(). Обратите внимание, что указанный URL адрес представляет собой относительный путь.

server.on("/", handle_OnConnect);

Мы не указали, что должен делать сервер, если клиент запрашивает какой-либо URL, отличающийся от указанных в server.on(). Он должен выдать ответ с HTTP статусом 404 (Not Found, «страница не найдена») и сообщением для пользователя. Помещаем эти действия в отдельную функцию и используем метод server.onNotFound(), чтобы указать серверу, что он должен выполнить, когда получит запрос на URI, который не был задан с помощью server.on().

server.onNotFound(handle_NotFound);

Теперь, чтобы запустить сервер, вызываем метод begin() для объекта server.

server.begin();
Serial.println("HTTP server started");

Внутренности функции loop()

Чтобы обработать реальные входящие HTTP-запросы, нам нужно вызвать метод handleClient() объекта server.

server.handleClient();

Далее нам нужно создать функцию, которую мы прикрепили к корневому (/) URL с помощью server.on(). Помните?

В начале этой функции мы получаем показания температуры от каждого датчика. Чтобы ответить на HTTP-запрос, используем метод send(). Хотя этот метод можно вызывать с другим набором аргументов, его самая простая форма состоит из HTTP кода ответа, типа контента и самого контента.

В нашем случае мы отправляем код 200 (один из кодов состояния HTTP), который соответствует ответу OK. Затем мы указываем тип контента как "text/html", и, наконец, мы вызываем пользовательскую функцию SendHTML(), которая создает динамическую HTML-страницу, содержащую значения показаний температуры.

void handle_OnConnect() 
{
  sensors.requestTemperatures();
  tempSensor1 = sensors.getTempC(sensor1);
  tempSensor2 = sensors.getTempC(sensor2);
  tempSensor3 = sensors.getTempC(sensor3);
  server.send(200, "text/html", SendHTML(tempSensor1,tempSensor2,tempSensor3)); 
}

Точно так же нам нужно создать функцию для обработки страницы ошибки 404.

void handle_NotFound()
{
  server.send(404, "text/plain", "Not found");
}

Отображение веб-страницы HTML

Функция SendHTML() отвечает за создание веб-страницы всякий раз, когда веб-сервер ESP8266 получает запрос от веб-клиента. Она просто объединяет HTML-код в большую строку и возвращает ее в функцию server.send(), которую мы обсуждали ранее. Данная функция в качестве параметров для динамического генерирования HTML контента принимает значения температур.

Первый текст, который вы всегда должны отправлять, – это объявление <!DOCTYPE>, которое указывает, что мы отправляем HTML-код.

String SendHTML(float tempSensor1,float tempSensor2,float tempSensor3)
{
  String ptr = "<!DOCTYPE html> <html>\n";

Затем <meta> элемент viewport делает веб-страницу адаптивной в любом веб-браузере. Далее тег title устанавливает заголовок страницы.

ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP8266 Temperature Monitor</title>\n";

Стилизация веб-страницы

Далее идет немного CSS кода для стилизации внешнего вида веб-страницы. Мы выбираем шрифт Helvetica, определяем контент, который будет отображаться в виде inline-block и выровнен по центру.

ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";

Следующий код устанавливает цвет, шрифт и поля вокруг элементов body, H1, H3 и p.

ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";

Установка заголовка веб-страницы

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

ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 Temperature Monitor</h1>\n";

Отображение показаний температуры на веб-странице

Чтобы динамически отображать показания температуры, мы помещаем эти значения в теги параграфов. Для отображения символа градуса мы используем сущность HTML &deg;.

  ptr +="<p>Living Room: ";
  ptr +=tempSensor1;
  ptr +="&deg;C</p>";
  ptr +="<p>Bedroom: ";
  ptr +=tempSensor2;
  ptr +="&deg;C</p>";
  ptr +="<p>Kitchen: ";
  ptr +=tempSensor3;
  ptr +="&deg;C</p>";
  ptr +="</div>\n";
  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}

Стилизация веб-страницы, чтобы она выглядела более профессионально

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

Рисунок 8 Показания с нескольких датчиков DS18B20 на странице веб-сервера ESP8266 (с CSS)
Рисунок 8 – Показания с нескольких датчиков DS18B20 на странице веб-сервера ESP8266 (с CSS)

Довольно красиво, правда? Давайте без лишних слов, применим стиль к нашей предыдущей HTML-странице. Для начала скопируйте и вставьте приведенный ниже код, чтобы заменить в приведенном выше скетче функцию SendHTML().

String SendHTML(float tempSensor1,float tempSensor2,float tempSensor3)
{
  String ptr = "<!DOCTYPE html>";
  ptr +="<html>";
  ptr +="<head>";
  ptr +="<title>ESP8266 Temperature Monitor</title>";
  ptr +="<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  ptr +="<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600' rel='stylesheet'>";
  ptr +="<style>";
  ptr +="html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #444444;}";
  ptr +="body{margin-top: 50px;} ";
  ptr +="h1 {margin: 50px auto 30px;} ";
  ptr +=".side-by-side{display: table-cell;vertical-align: middle;position: relative;}";
  ptr +=".text{font-weight: 600;font-size: 19px;width: 200px;}";
  ptr +=".temperature{font-weight: 300;font-size: 50px;padding-right: 15px;}";
  ptr +=".living-room .temperature{color: #3B97D3;}";
  ptr +=".bedroom .temperature{color: #F29C1F;}";
  ptr +=".kitchen .temperature{color: #26B99A;}";
  ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -5px;top: 15px;}";
  ptr +=".data{padding: 10px;}";
  ptr +=".container{display: table;margin: 0 auto;}";
  ptr +=".icon{width:82px}";
  ptr +="</style>";
  ptr +="</head>";
  ptr +="<body>";
  ptr +="<h1>ESP8266 Temperature Monitor</h1>";
  ptr +="<div class='container'>";
  ptr +="<div class='data living-room'>";
  ptr +="<div class='side-by-side icon'>";
  ptr +="<svg enable-background='new 0 0 65.178 45.699'height=45.699px id=Layer_1 version=1.1 viewBox='0 0 65.178 45.699'width=65.178px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><polygon fill=#3B97D3 points='8.969,44.261 8.969,16.469 7.469,16.469 7.469,44.261 1.469,44.261 1.469,45.699 14.906,45.699 ";
  ptr +="14.906,44.261 '/><polygon fill=#3B97D3 points='13.438,0 3,0 0,14.938 16.438,14.938 '/><polygon fill=#3B97D3 points='29.927,45.699 26.261,45.699 26.261,41.156 32.927,41.156 '/><polygon fill=#3B97D3 points='58.572,45.699 62.239,45.699 62.239,41.156 55.572,41.156 '/><path d='M61.521,17.344c-2.021,0-3.656,1.637-3.656,3.656v14.199H30.594V21c0-2.02-1.638-3.656-3.656-3.656";
  ptr +="c-2.02,0-3.657,1.636-3.657,3.656v14.938c0,2.021,1.637,3.655,3.656,3.655H61.52c2.02,0,3.655-1.637,3.655-3.655V21";
  ptr +="C65.177,18.98,63.54,17.344,61.521,17.344z'fill=#3B97D3 /><g><path d='M32.052,30.042c0,2.02,1.637,3.656,3.656,3.656h16.688c2.019,0,3.656-1.638,3.656-3.656v-3.844h-24";
  ptr +="L32.052,30.042L32.052,30.042z'fill=#3B97D3 /><path d='M52.396,6.781H35.709c-2.02,0-3.656,1.637-3.656,3.656v14.344h24V10.438";
  ptr +="C56.053,8.418,54.415,6.781,52.396,6.781z'fill=#3B97D3 /></g></svg>";
  ptr +="</div>";
  ptr +="<div class='side-by-side text'>Living Room</div>";
  ptr +="<div class='side-by-side temperature'>";
  ptr +=(int)tempSensor1;
  ptr +="<span class='superscript'>&deg;C</span></div>";
  ptr +="</div>";
  ptr +="<div class='data bedroom'>";
  ptr +="<div class='side-by-side icon'>";
  ptr +="<svg enable-background='new 0 0 43.438 35.75'height=35.75px id=Layer_1 version=1.1 viewBox='0 0 43.438 35.75'width=43.438px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><g><path d='M25.489,14.909H17.95C13.007,14.908,0,15.245,0,20.188v3.688h43.438v-3.688";
  ptr +="C43.438,15.245,30.431,14.909,25.489,14.909z'fill=#F29C1F /><polygon fill=#F29C1F points='0,31.25 0,35.75 2.5,35.75 4.5,31.25 38.938,31.25 40.938,35.75 43.438,35.75 43.438,31.25 ";
  ptr +="43.438,25.375 0,25.375 	'/><path d='M13.584,11.694c-3.332,0-6.033,0.973-6.033,2.175c0,0.134,0.041,0.264,0.105,0.391";
  ptr +="c3.745-0.631,7.974-0.709,10.341-0.709h1.538C19.105,12.501,16.613,11.694,13.584,11.694z'fill=#F29C1F /><path d='M30.009,11.694c-3.03,0-5.522,0.807-5.951,1.856h1.425V13.55c2.389,0,6.674,0.081,10.444,0.728";
  ptr +="c0.069-0.132,0.114-0.268,0.114-0.408C36.041,12.668,33.34,11.694,30.009,11.694z'fill=#F29C1F /><path d='M6.042,14.088c0-2.224,3.376-4.025,7.542-4.025c3.825,0,6.976,1.519,7.468,3.488h1.488";
  ptr +="c0.49-1.97,3.644-3.489,7.469-3.489c4.166,0,7.542,1.801,7.542,4.025c0,0.17-0.029,0.337-0.067,0.502";
  ptr +="c1.08,0.247,2.088,0.549,2.945,0.926V3.481C40.429,1.559,38.871,0,36.948,0H6.49C4.568,0,3.009,1.559,3.009,3.481v12.054";
  ptr +="c0.895-0.398,1.956-0.713,3.095-0.968C6.069,14.41,6.042,14.251,6.042,14.088z'fill=#F29C1F /></g></svg>";
  ptr +="</div>";
  ptr +="<div class='side-by-side text'>Bedroom</div>";
  ptr +="<div class='side-by-side temperature'>";
  ptr +=(int)tempSensor2;
  ptr +="<span class='superscript'>&deg;C</span></div>";
  ptr +="</div>";
  ptr +="<div class='data kitchen'>";
  ptr +="<div class='side-by-side icon'>";
  ptr +="<svg enable-background='new 0 0 48 31.5'height=31.5px id=Layer_1 version=1.1 viewBox='0 0 48 31.5'width=48px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><circle cx=24.916 cy=15.75 fill=#26B99A r=15.75 /><path d='M14.917,15.75c0-5.522,4.478-10,10-10c2.92,0,5.541,1.26,7.369,3.257l1.088-1.031";
  ptr +="c-2.103-2.285-5.106-3.726-8.457-3.726c-6.351,0-11.5,5.149-11.5,11.5c0,3.127,1.252,5.958,3.277,8.031l1.088-1.031";
  ptr +="C16.011,20.945,14.917,18.477,14.917,15.75z'fill=#FFFFFF /><path d='M45.766,2.906c-1.232,0-2.232,1-2.232,2.234v11.203c0,0,2.76,0,3,0v12H48v-12V2.906";
  ptr +="C48,2.906,46.035,2.906,45.766,2.906z'fill=#26B99A /><path d='M6.005,2.917v5.184c0,0.975-0.638,1.792-1.516,2.083V2.917H3.021v7.267c-0.878-0.29-1.516-1.107-1.516-2.083";
  ptr +="V2.917H0v5.458c0,1.802,1.306,3.291,3.021,3.592v16.376H4.49v-16.38c1.695-0.318,2.979-1.8,2.979-3.588V2.917H6.005z'fill=#26B99A /></svg>";
  ptr +="</div>";
  ptr +="<div class='side-by-side text'>Kitchen</div>";
  ptr +="<div class='side-by-side temperature'>";
  ptr +=(int)tempSensor3;
  ptr +="<span class='superscript'>&deg;C</span></div>";
  ptr +="</div>";
  ptr +="</div>";
  ptr +="</body>";
  ptr +="</html>";
  return ptr;
}

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

На нашей веб-странице мы будем использовать шрифт Open Sans от Google. Обратите внимание, что вы не можете видеть шрифт Google, без активного подключения к интернету на устройстве, с которого вы собираетесь получить доступ к странице. Шрифты Google загружаются на лету.

ptr +="<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600' rel='stylesheet'>";

Иконки, используемые для отображения показаний температуры, на самом деле является масштабируемой векторной графикой (SVG), определенной в теге <svg>. Создание SVG не требует каких-либо специальных навыков программирования. Для создания графики для вашей страницы вы можете использовать любой редактор SVG. Мы использовали эти иконки SVG.

Рисунок 9 SVG иконки
Рисунок 9 – SVG иконки

Улучшение кода - автоматическое обновление страницы

Одно из улучшений, которое вы можете сделать с нашим кодом, – это автоматическое обновление страницы для обновления показаний датчиков.

Добавив один мета-тег в ваш HTML-документ, вы можете дать браузеру команду автоматически перезагружать страницу с заданным интервалом.

<meta http-equiv="refresh" content="2" >

Поместите этот код в тег <head> вашего документа, и этот мета-тег укажет браузеру обновлять страницу каждые две секунды. Довольно изящно!

Динамическая загрузка данных датчиков с помощью AJAX

Если ваша веб-страница много весит, то полное ее обновление не слишком практично. Лучше использовать асинхронный Javascript и Xml (AJAX), чтобы мы могли запрашивать данные с сервера асинхронно (в фоновом режиме), не обновляя страницу.

Для выполнения AJAX на веб-страницах в JavaScript обычно используется объект XMLHttpRequest. Он тихо выполняет GET-запрос на сервер и обновляет элемент на странице. AJAX – это не новая технология или другой язык, а просто существующие технологии, используемые по-новому. Кроме того, AJAX также позволяет:

  • запрашивать данные с сервера после загрузки страницы;
  • получать данные с сервера после загрузки страницы;
  • отправлять данные на сервер в фоновом режиме.

Ниже приведен скрипт AJAX, который мы будем использовать. Поместите этот скрипт непосредственно перед закрывающим тегом </head>.

ptr +="<script>\n";
ptr +="setInterval(loadDoc,1000);\n";
ptr +="function loadDoc() {\n";
ptr +="var xhttp = new XMLHttpRequest();\n";
ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.body.innerHTML =this.responseText}\n";
ptr +="};\n";
ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";
ptr +="</script>\n";

Скрипт начинается с тега <script>, так как AJAX-скрипт – это не что иное, как javascript, и поэтому нужно писать его в теге <script>. Чтобы данная функция вызывалась повторно, мы будем использовать функцию javascript setInterval(). Она принимает два параметра: функцию для выполнения и интервал времени (в миллисекундах), через который выполнять указанную функцию.

ptr +="<script>\n";
ptr +="setInterval(loadDoc,1000);\n";

Сердцем этого скрипта является функция loadDoc(). Внутри этой функции создается объект XMLHttpRequest(). Данный объект используется для запроса данных с веб-сервера.

ptr +="function loadDoc() {\n";
ptr +="var xhttp = new XMLHttpRequest();\n";

Функция xhttp.onreadystatechange() вызывается каждый раз, когда изменяется readyState. Свойство readyState хранит состояние XMLHttpRequest. Возможны следующие значения:

  • 0: запрос не инициализирован;
  • 1: установлено подключение к серверу;
  • 2: запрос получен;
  • 3: обработка запроса;
  • 4: запрос завершен, и ответ готов.

Свойство status содержит статус объекта XMLHttpRequest. Возможны следующие значения:

  • 200: OK;
  • 403: запрещено;
  • 404: страница не найдена.

Когда readyState равен 4, а status – 200, ответ готов. Теперь обновляется содержимое элемента body (содержащего значения температуры).

ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.body.innerHTML =this.responseText}\n";
ptr +="};\n";

Затем HTTP-запрос инициируется с помощью функций open() и send().

ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";

Теги

Arduino IDEDS18B20ESP8266EspressifIoT (интернет вещей)NodeMCUДатчикДатчик температурыИзмерение температурыМикроконтроллерТемператураУмный дом

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.


  • 2023-10-03виталик каник

    А как сделать не сервер а на дисплей

  • 2022-02-16алексей

    ptr +="<meta http-equiv="refresh" content="2">"; так обновление работает

  • 2022-02-16алексей

    ptr +="<meta http-equiv="refresh" content="2">"; так обновление работает

  • 2022-01-10Сергей

    Не получается так, всё равно сотые показывает. Может другой способ есть?

  • 2022-01-08Сергей

    Спасибо за проект, очень поучительно. Подскажите как при положительных температурах отображать знак + ?

  • 2021-11-22Павел Старцев

    В html-коде напротив датчиком стоит (int) - целое число, а для дробных чисел (double). Попробуй сначала совсем убрать скольки и содержимое - должно получиться, так как в коде уже double. Либо прописать double в скобках вместо int, но тут могут быть свои сложности может выскочить много цифр после запятой.

  • 2021-09-14Олег Климов

    А, как сделать так, чтоб отображался один знак после запятой?