За основу взят проект robotchip.ru/meteostantsiya-na-bme280-i-esp8266/. Он выводит показания датчика BME280 на веб-страницу в браузер. В проект добавлен дисплей SSD1306 (dmitrysnotes.ru/domashnyaya-meteostanciya-na-esp8266-i-datchike-bme280) для вывода показаний температуры, влажности и атмосферного давления. Также добавлен NTP клиент (radioprog.ru/post/910) для вывода на дисплей текущего времени вашей часовой зоны.
Вначале на макетной плате соберите схему, показанную на рисунке:
Подразумевается, что среда Arduino IDE установлена и в список плат добавлена NodeMCU 1.0 (ESP-12E Module).
Для работы скетча необходимы библиотеки Adafruit_BME280.h, Adafruit_Sensor.h, SSD1306.h. Как установить их, описано на dmitrysnotes.ru/domashnyaya-meteostanciya-na-esp8266-i-datchike-bme280. Библиотеку ESP8266WiFi.h можно скачать с martyncurrey.com/download/esp8266wifi-library/. В скачанном списке библиотек есть WiFiUdp.h. Как установить NTPClient.h, описано на radioprog.ru/post/910.
Также скетч и библиотеки можно скачать в Каталоге файлов.
Запустите Arduino IDE и выберите Файл -> Новый. В окне удалите текст предлагаемой заготовки скетча и вставьте текст скетча bme_ntp.ino.
Скетч bme_ntp_day.ino
/*
Тестировалось на Arduino IDE 1.8.19
Дата тестирования 14.01.2024г.
*/
#include <ESP8266WiFi.h> // Подключаем библиотеку ESP8266WiFi
#include <Wire.h> // Подключаем библиотеку Wire
#include <Adafruit_BME280.h> // Подключаем библиотеку Adafruit_BME280
#include <Adafruit_Sensor.h> // Подключаем библиотеку Adafruit_Sensor
#include "SSD1306.h" // Подключаем OLED SSD1306
#include <NTPClient.h>
#include <WiFiUdp.h>
#define SDA 14
#define SCL 12
#define I2C 0x3C
SSD1306 display (I2C, SDA, SCL);
const long utcOffsetInSeconds = 32400; // timezone +9 (Chita): 9*60*60=32400
char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
// Определение NTP-клиента для получения времени
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
#define SEALEVELPRESSURE_HPA (1013.25) // Задаем высоту
Adafruit_BME280 bme; // Установка связи по интерфейсу I2C
const char* ssid = "*******"; // Название Вашей WiFi сети
const char* password = "************"; // Пароль от Вашей WiFi сети
WiFiServer server(80); // Указываем порт Web-сервера
String header;
void setup() {
display.init();
display.flipScreenVertically();
display.clear();
display.display();
Serial.begin(115200); // Скорость передачи 115200
bool status;
if (!bme.begin(0x76)) { // Проверка инициализации датчика
// Serial.println("Could not find a valid BME280 sensor, check wiring!"); // Печать об ошибке инициализации
while (1); // Зацикливаем
}
Serial.print("Connecting to "); // Отправка в Serial port
Serial.println(ssid); // Отправка в Serial port
WiFi.begin(ssid, password); // Подключение к WiFi Сети
while (WiFi.status() != WL_CONNECTED) { // Проверка подключения к WiFi сети
delay(500); // Пауза
Serial.print("."); // Отправка в Serial port
}
Serial.println(""); // Отправка в Serial port
Serial.println("WiFi connected."); // Отправка в Serial port
Serial.print("IP address: "); // Отправка в Serial port
Serial.println(WiFi.localIP()); // Отправка в Serial port
server.begin();
timeClient.begin();
}
void loop() {
WiFiClient client = server.available(); // Получаем данные, посылаемые клиентом
if (client) {
Serial.println("New Client."); // Отправка "Новый клиент"
String currentLine = ""; // Создаем строку для хранения входящих данных от клиента
while (client.connected()) { // Пока есть соединение с клиентом
if (client.available()) { // Если клиент активен
char c = client.read(); // Считываем посылаемую информацию в переменную "с"
Serial.write(c); // Отправка в Serial port
header += c;
if (c == '\n') { // Вывод HTML страницы
if (currentLine.length() == 0) {
client.println("HTTP/1.1 200 OK"); // Стандартный заголовок HT
client.println("Content-type:text/html ");
client.println("Connection: close"); // Соединение будет закрыто после завершения ответа
client.println("Refresh: 10"); // Автоматическое обновление каждые 10 сек
client.println();
client.println("<!DOCTYPE html><html>"); // Веб-страница создается с использованием HTML
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<meta charset='UTF-8'>"); // Делаем русскую кодировку
client.println("<link rel=\"icon\" href=\"data:,\">");
client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial;}");
client.println("table { border-collapse: collapse; width:40%; margin-left:auto; margin-right:auto; }");
client.println("th { padding: 12px; background-color: #0043af; color: white; }");
client.println("tr { border: 1px solid #ddd; padding: 12px; }");
client.println("tr:hover { background-color: #bcbcbc; }");
client.println("td { border: none; padding: 12px; }");
client.println(".sensor { color:white; font-weight: bold; background-color: #bcbcbc; padding: 1px; }");
client.println("</style></head><body><h1>Метеостанция на BME280 и ESP8266</h1>");
client.println("<table><tr><th>Параметр</th><th>Показания</th></tr>");
client.println("<tr><td>Температура</td><td><span class=\"sensor\">");
client.println(bme.readTemperature());
client.println(" *C</span></td></tr>");
client.println("<tr><td>Давление</td><td><span class=\"sensor\">");
client.println(bme.readPressure() * 0.0075F);
client.println(" mmHg</span></td></tr>");
client.println("<tr><td>Влажность</td><td><span class=\"sensor\">");
client.println(bme.readHumidity());
client.println(" %</span></td></tr>");
client.println("<tr><td>Приблизительная высота над уровнем моря</td><td><span class=\"sensor\">");
client.println(bme.readAltitude(SEALEVELPRESSURE_HPA));
client.println(" m</span></td></tr>");
client.println("</body></html>");
client.println();
break;
} else {
currentLine = "";
}
} else if (c != '\r') {
currentLine += c;
}
}
}
header = "";
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
timeClient.update();
Serial.print(daysOfTheWeek[timeClient.getDay()]);
Serial.print(", ");
Serial.print(timeClient.getHours());
Serial.print(":");
Serial.print(timeClient.getMinutes());
Serial.print(":");
Serial.println(timeClient.getSeconds());
//Serial.println(timeClient.getFormattedTime());
float tempC = bme.readTemperature();
float humidity = bme.readHumidity();
float pressuremmHg = bme.readPressure() * 0.007500616; // перевод атм. давления Pa в mmHg
display.clear();
display.setFont(ArialMT_Plain_16);
display.drawString(20, 1, String(daysOfTheWeek[timeClient.getDay()]) + " " + String(timeClient.getHours()) + " : " + String(timeClient.getMinutes()));
display.setFont(ArialMT_Plain_10);
display.drawString(5, 22, "Temperature = " + String(tempC) + " *C");
display.drawString(5, 35, "Humidity = " + String(humidity) + " %");
display.drawString(5, 48, "Pressure = " + String(pressuremmHg) + " mmHg");
display.display();
delay (5000);
}
Скачать скетч и библиотеки
В скетче вместо звездочек пропишите название и пароль вашей Wi-Fi сети. Также для NTP клиента вам нужно рассчитать константу utcOffsetInSeconds для вашей часовой зоны. Как рассчитать, описано в [3]. У меня поправка относительно UTC времени равна +9 (зона Читы, Якутска), поэтому константа получилась 9*60*60 = 32400.
Если скетч не работает, то попробуйте подобрать адреса устройств на шине I2C (0x3D для SSD1306 или 0x77 для BME280). Загрузите скетч I2C_Scanner.ino для сканирования адресов устройств на шине I2C и замените в скетче bme_ntp_day.ino адреса на свои. Как просканировать адреса, описано в статье Arduino метеостанция на BMP180, DHT11 и LCD1602.
IP адрес веб-страницы метеостанции выводится в сообщениях монитора порта.
Информация на дисплее SSD1306 обновляется каждые 5 секунд, на веб-странице — каждые 10 секунд.
При необходимости вы можете настроить вывод в градусах Фаренгейта и давления в гПа. Как это сделать, можно прочитать на ресурсе [2].
В результате у вас получились часы с выводом данных о погоде. Дни недели выводятся тремя символами по-английски Sun (Sunday - воскресенье), Mon (Monday - понедельник), Tue (Tuesday - вторник), Wed (Wednesday - среда), Thu (Thursday - четверг), Fri (Friday - пятница), Sat (Saturday - суббота).
Чтобы получить доступ к веб-странице через интернет, вам надо сделать дополнительные настройки. В роутере домашней сети вам нужно закрепить за NodeMCU постоянный (статический) IP адрес, также надо настроить для NodeMCU проброс порта 80 (port forwarding). На каком-нибудь динамическом DNS сервисе зарегистрировать домен для вашей веб-страницы. Как это настроить, подробно описано в статье Как получить доступ по интернету к датчикам в квартире.
Но тут есть одна закавыка. DNS сервис предлагает установить утилиту, которая периодически посылает на сервис текущий IP адрес. Когда провайдер выдаст вашему роутеру другой IP адрес, утилита сообщит новый IP адрес на DNS сервис. Сервис заменит устаревший IP адрес на текущий на DNS серверах. Вашему домену (имени сайта) будет соответствовать уже новый IP адрес и ваше устройство снова будет доступно в интернете. На NodeMCU нет возможности установить такую утилиту, но если у вас в сети есть компьютер Windows или Linux (Raspberry Pi), то вы можете установить эту утилиту на один из этих компьютеров. Он должен быть практически постоянно включен. Проще всего использовать Raspberry Pi или подобный компьютер. Как настроить доступ из интернета на Raspberry Pi, также написано в статье Как получить доступ по интернету к датчикам в квартире.
Последнее изменение 14.01.2024
Использованные ресурсы
1. https://robotchip.ru/meteostantsiya-na-bme280-i-esp8266/
2. https://dmitrysnotes.ru/domashnyaya-meteostanciya-na-esp8266-i-datchike-bme280
3. https://radioprog.ru/post/910
4. https://blog.squix.org/wp-content/uploads/2018/09/esp8266weatherstationgettingstartedguide-20180911.pdf
5. Internet_of_Things_with_ESP8266, Marco_Schwartz 2016 Packt Publishing 226 p.
6. Интернет вещей с ESP8266, Шварц Марко, Пер. с англ. — СПб.: БХВ-Петербург, 2018 192 с.
7. http://www.martyncurrey.com/download/esp8266wifi-library/
8. https://lastminuteengineers.com/esp8266-ntp-server-date-time-tutorial/
|