NodeMcu – платформа на основе ESP8266, аналог arduino с wi-fi модулем, что позволяет сразу из коробки взаимодействовать с устройствами в сети локальной или интернет.
Например с его помощью можно сделать умную лампочку, розетку, датчик показания которого можно отправить в интернет.
Предистория
Была у меня мечта не знаю зачем и почему, сделать мониторинг температуры в каждой комнате. Сначала когда то давным-давно я сделал это на ардуино и ds18b20, потом как то еще и на dht11. Позже делал в связке с arduino + orange pi pc. На оранж пай брал с серийного порта показания ds18b20 и писал вместе с датой в файл, морда была на php, можно было зайти и посмотреть температуру за прошедший период. По оранж пай отдельная тема, он у меня долгое время работал как приставка к телевизору витязь с kodi и плейлистами iptv.
Как это работает у меня сейчас
Теперь же в который раз я затеял все это на Nodemcu, сейчас у меня три платы с датчиками температуры ds18b20, dht11, dht22 и датчиками качества воздуха mq135. В каждой есть своя морда в локальной сети по статическому ip адресу, на главной плате которая в комнате страничка с iframe которая таким образом собирает все показания воедино и обновляется раз в 30 секунд обновляя все фреймы. Так же каждая из плат раз в 10 минут посылает данные на thingspeak.com. Из thingspeak.com их берет Алиса через навык кузя и озвучивает. С переходом на джино хостинг планирую еще отправлять на сайт.
Как я сделать страничку Nodemcu в локальной сети и статический ip адрес
Сначала я стал искать способ сделать страничку, что бы можно было выводить данные в локальную сеть и наткнулся на эту статью. Потом начал искать способ настроить статический ip адрес:
IPAddress ip(192,168,1,17); //статический IP
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
void setup() {
WiFi.config(ip, gateway, subnet);
}
Code language: Arduino (arduino)
Отправка на thingspeak.com
Ещё хотелось данные куда отправлять что бы были видны показания из интернета. Нашел пример скетча отправляющего данные на thingspeak.com. Дальше расположив датчики в комнатах столкнулся с неудобством таскать их каждый раз к компу что бы поправить код, стал искать способ как можно прошить по wifi и нашел его.
В итоге
В итоге у меня получился такой код, на плате dht22 и mq135:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "DHT.h"
#include <MQ135.h> // подключение библиотеки
#define analogPin A0 // аналоговый выход MQ135 подключен к пину A0 Arduino
MQ135 gasSensor = MQ135(analogPin); // инициализация объекта датчика
// Раскомментируйте одну из строк ниже в зависимости от того, какой датчик вы используете!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
/* Введите свои SSID и пароль */
const char* ssid = "wifiname"; // SSID
const char* password = "11111"; // пароль
IPAddress ip(192,168,100,100); //статический IP
IPAddress gateway(192,168,100,1);
IPAddress subnet(255,255,255,0);
ESP8266WebServer server(80);
// датчик DHT
uint8_t DHTPin = D2; //Пин датчика DHT22 (Совпадает с маркировкой nodemcu)
// инициализация датчика DHT.
DHT dht(DHTPin, DHTTYPE);
float Temperature; //Переменная температуры
float Humidity; //Переменная влажности
unsigned long timing; // Переменная для хранения точки отсчета
//Файл для загрузки должен иметь расширение *.bin
#include <ESP8266HTTPUpdateServer.h>
#define OTAUSER "admin" // Логин для входа в OTA
#define OTAPASSWORD "admin" // Пароль для входа в ОТА
#define OTAPATH "/firmware"// Путь, который будем дописывать после ip адреса в браузере.
#define SERVERPORT 80 // Порт для входа, он стандартный 80 это порт http
ESP8266HTTPUpdateServer httpUpdater;
//-----------------------------------------------------------------
void setup()
{
Serial.begin(115200);
delay(100);
pinMode(DHTPin, INPUT); //пин датчика DHT настраиваем на прием
dht.begin();
Serial.println("Connecting to ");
Serial.println(ssid);
// подключаемся к локальной wi-fi сети
WiFi.begin(ssid, password);
WiFi.config(ip, gateway, subnet); //Строка отвечающая за статический ip 192.168.100.100, так же как и строки IPAddress выше
// проверить, подключился ли wi-fi модуль к 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()); //IP адрес
Serial.print("macAddress: "); Serial.println(WiFi.macAddress()); //получаем MAC-адрес WeMos
Serial.print("subnetMask: "); Serial.println(WiFi.subnetMask()); //маску подсети
Serial.print("gatewayIP: "); Serial.println(WiFi.gatewayIP()); //IP- шлюза
Serial.print("WiFi.SSID: "); Serial.println(WiFi.SSID());// имя сети, к которой подключен WeMos
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
httpUpdater.setup(&server, OTAPATH, OTAUSER, OTAPASSWORD); //OTA апдейтер, для прошивки по воздуху
}
int timer = 10 * 60 * 1000; //Таймер отправки на https://thingspeak.com/
void loop()
{
server.handleClient();
if (millis() - timing > timer){ // Если настоло время(таймер из переменной timer), то отправляем данные
timing = millis();
Serial.println ("10 minut proshlo nachinaem otpravku");
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
float ppm = gasSensor.getPPM(); // чтение данных концентрации CO2
float rzero = gasSensor.getRZero(); // чтение калибровочных данных
sendTeperatureTS(temperature, humidity, ppm, rzero); //Функция отправки, код функции ниже
}
}
void handle_OnConnect() //если набрал адрес платы
{
Temperature = dht.readTemperature(); // получить значение температуры
Humidity = dht.readHumidity(); // получить значение влажности
float ppm = gasSensor.getPPM(); // чтение данных концентрации CO2
float rzero = gasSensor.getRZero(); // чтение калибровочных данных
server.send(200, "text/html", SendHTML(Temperature,Humidity, ppm, rzero, timing)); //SendHTML строка с html кодом страницы, чуть ниже код
Serial.print("T:");
Serial.println(Temperature);
Serial.print("H:");
Serial.println(Humidity);
}
void handle_NotFound() //если зашел на не существующий адрес
{
server.send(404, "text/plain", "Not found");
}
String SendHTML(float Temperaturestat,float Humiditystat, float ppm, float rzero, int timing)//Строка с html кодом странички с нужными переменными с датчиков
{
char* vozduh = ""; //Условие взависимости от показаний ppm, выводит краткое пояснение о качестве воздуха.
if(400>ppm){vozduh = "<p style='color: #329D27;'>Идеальный воздух для здоровья человека.</p>";}
else{
if(600>ppm){vozduh = "<p style='color: #D8FA3F;'>Нормальное качество воздуха.</p>";}
else {
if(800>ppm){vozduh = "<p style='color: #A6A400;'>Не очень, появляются единичные жалобы на качество воздуха.</p>";}
else{
if(1000>ppm){vozduh = "<p style='color: #A66600;'>Не очень, более частые жалобы на качество воздуха.</p>";}
else{
if(2000>ppm){vozduh = "<p style='color: #A60C00;'>Плохой воздух. Общий дискомфорт, слабость, головная боль, проблемы с концентрацией внимания.</p>";}
else {
if(2000<ppm){vozduh = "<p style='color: #860049; font-size: 150%;'>Нельзя находится.</p>";}
}
}
}
}
}
int lastsend = (millis() - timing) / 1000 / 60; //Последняя отправка, переменная в которой вычисляется когда последний раз была отправка на thingspeak.com
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta charset=utf-8 name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<meta http-equiv=refresh content=30>"; //Автообновление страницы каждый 30 секунд
ptr +="<title>"; //Тег заголовка страницы, удобно смотреть в заголовок вкладки и видеть основные данные
ptr +=Temperaturestat;
ptr +="°C|";
ptr +=Humiditystat;
ptr +="%|";
ptr +=ppm;
ptr +="ppm - NodeMcu</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center; background: #485936;} #webpage{background: #fff; margin: 5px auto; padding: 5px; border-radius: 5px; max-width: 460px;} a{color: #93a368;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;}\n";
ptr +="p {font-size: 24px;color: #444444; margin:0px;}\n";
ptr +="h1{color: #444444; margin:0px;}\n";
ptr +="iframe{max-width: 265px; margin-left: 0px auto; border: 0px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>Погода в комнате</h1>\n";
ptr +="<p>Температура: ";
ptr +=Temperaturestat;
ptr +="°C</p>";
ptr +="<p>Влажность: ";
ptr +=Humiditystat;
ptr +="%</p>";
ptr +="<p>Качество воздуха: ";
ptr +=ppm;
ptr +=" ppm<br>";
ptr +=vozduh;
ptr +=" rzero: ";
ptr +=rzero;
ptr +="</p>";
ptr +="<h1 style='margin-bottom:0px;'>Погода в зале</h1>";
ptr +="<iframe style='height: 80px;' src='http://192.168.100.101'>Ваш браузер не поддерживает плавающие фреймы!</iframe>"; //Подгружаем фрейм с Nodemcu из зала
ptr +="<h1>Погода на кухне</h1>\n";
ptr +="<iframe style='height: 200px;' src='http://192.168.100.102'>Ваш браузер не поддерживает плавающие фреймы!</iframe>";//Подгружаем фрейм с Nodemcu из кухни
ptr +="<p style='font-size: 50%'>Последняя отправка на thingspeak.com: "; //Выводим сколько минут назад была последняя отправка
ptr +=lastsend;
ptr +=" минут назад.</p>";
ptr +="<p style='font-size: 50%'>ESP8266 NodeMCU Weather Report</p>";
ptr +="<p style='font-size: 50%'>Прошивка: <a href='http://192.168.100.100/firmware' target='_blank'>комната</a> | <a href='http://192.168.100.101/firmware' target='_blank'>зал</a> | <a href='http://192.168.100.102/firmware' target='_blank'>кухня</a></p>"; //ссылки на прошивку
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
//функция отправки на thingspeak
const char* server_send = "184.106.153.149";
String apiKey =""; //APIKEY ОБЯЗАТЕЛЬНО ЗАПОЛНИТЬ
int sent=0;
void sendTeperatureTS(float temp, float humidity, float ppm, float rzero)
{
WiFiClient client;
Serial.println("(1)Connect to thingspeak.");
int count = 2;
int status_connect;
while(!client.connect(server_send, 80)){ //если с первого раза не получилось соединиться с thingspeak.com ждем 10 секунд и выводим количество попыток
Serial.print("(");
Serial.print(count);
Serial.println(")Connect to thingspeak.");
delay(1000);
}
if (client.connect(server_send, 80)) { // use ip 184.106.153.149 or api.thingspeak.com
//Serial.println("WiFi Client connected ");
//отправка каждой переменной в нужный field
String postStr = apiKey;
postStr += "&field1=";
postStr += String(temp);
postStr += "&field2=";
postStr += String(humidity);
postStr += "&field4=";
postStr += String(ppm);
//postStr += "&field5=";
// postStr += String(rzero);
postStr += "\r\n\r\n";
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
delay(1000);
Serial.println("Step sendTeperatureTS end");
}//end if
else {
Serial.println("thingspeak non conect");
}
sent++;
client.stop();
Serial.println("Step sendTeperatureTS exit");
}//end send
Code language: Arduino (arduino)
Озвучивание Алисой данных с thingspeak
По данному адресу будет фид канала такого вида:
{"channel":{"id":1293384,"name":"Home","description":"NodeMcu \u0026 DHT22 \u0026 MQ135 + NodeMcu \u0026 DS18B20 + Алиса озвучивает ","latitude":"0.0","longitude":"0.0","field1":"DHT22T","field2":"DHT22H","field3":"DS18B20","field4":"MQ135_PPM","field5":"DHT11T","field6":"DHT11H","field7":"MQ135_PPM","created_at":"2021-01-31T07:37:24Z","updated_at":"2021-03-08T18:56:29Z","last_entry_id":7159},"feeds":[{"created_at":"2021-03-08T19:01:19Z","entry_id":7159,"field1":null,"field2":null,"field3":null,"field4":null,"field5":"26.00","field6":"35.00","field7":"2514.08\r\n\r\n"}]}
Code language: JSON / JSON with Comments (json)
В данном моем случае что бы получить ответ по температуре и влажности field 1 и field 2 ответ кузи должен выглядеть так:
Температура {feeds.0.field1} градусов, Влажность {feeds.0.field2} процентов.
Отдельно стоит упомянуть что кузю нужно объединять с колонкой, а именно надиктовать ей код для того что бы объединить.
привет! не могли бы вы мне помочь с чтением данных с dht11 на orange pi 3, я новичок в этих делах
Добрый день! К сожалению я не знаю, знаю что это несколько сложнее чем с платами с поддержкой arduino ide