МОНИТОРИНГ НА ESP 8266
Реализация мониторинга температуры, давления и влажности с помощью ESP 8266 на отладочной плате Node Mcu и отправка на народный мониторинг.
Начать стоит издалека. При этом стоит ответить на несколько вопросов.
1. Почему именно мониторинг погоды?
У каждого свой ответ на этот вопрос. Мне же просто интересно мониторить текущую ситуацию с температурой и влажностью, примерно знать каких изменений погоды стоит ожидать, да и просто знать как одеться перед выходом.
2. Почему именно NODE MCU?
Я хотел сделать универсальный проект для любого, кто захочет его повторить. Даже с минимальными навыками в пайке и программировании. Впаять ее в плату гораздо проще чем голую есп’шку. К тому же на борту уже имеется стабилизатор на 3.3 вольта.
У меня во время учебы в университете был собран термометр на макетке и датчиком DHT 22, закрепленным на УКВ антенне за окном. Жил я тогда на 8 этаже и особых проблем с перегревом датчика не испытывал. Пластиковый корпус и крепление антенны создавали неплохой экран. Закончив учебу кучу проводов я разобрал. Примерно в этот момент я узнал о существовании народного мониторинга и подумал а почему бы и нет? Вот так и начал свое существование этот проект.
Заказав на али node mcu я стал упражняться в отправке температуры на народный мониторинг. Получая температуру с ардуино на компьютер через ком порт. Выяснилось, что ничего сложного в этом нет. Получаешь температуру, формируешь пакет и шлешь по UDP. Ну или TCP, кому как нравится.
В итоге имеем такую конфигурацию:
- Node Mcu — мозг, который рулит всем.
- DHT 22 — датчик, который пережил 1 зиму на улице. Будет размещен на улице
- DHT 11 — датчик для мониторинга влажности в комнате. Погрешность и пределы измерений для комнаты вполне приемлемы
- BME180 — покупался как датчик давления. Возможность измерять температуру — приятный бонус. Тянуть iic за пределы устройства особого желания не имею
- DS18B20 — кандидат на мониторинг погоды на окном наравне с DHT 22. Пока не решено кто именно будет измерять уличную температуру. Так же из-за 1wire шины хочу измерять температуры на балконе, батарей отопления и проч.
- LCD 1602 — дисплей для вывода текущих показаний.
- Заводская печатка, для того, чтоб снизить уровень вхождения в проект.
Специально для пикабу — SDK портативная версия со всеми либами и исходником.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
#include <Wire.h> #include <Adafruit_BMP085.h> #include <Adafruit_Sensor.h> #include <DHT.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); #include <OneWire.h> #include <DallasTemperature.h> #include <ESP8266WiFi.h> #include <DNSServer.h> #include <ESP8266WebServer.h> #include <WiFiManager.h> #define debug true // вывод отладочных сообщений #define postingInterval 300000 // интервал между отправками данных в миллисекундах (5 минут) #define ONE_WIRE_BUS 2 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature DS18B20(&oneWire); DeviceAddress insideThermometer; char temperatureCString[6]; float tempC; // ------------------------------------------ Конфигурация DHT ------------------------------------------ #define DHTPIN 0 // dht на gpio02 // Uncomment the type of sensor in use: //#define DHTTYPE DHT11 // DHT 11 #define DHTTYPE DHT22 // DHT 22 (AM2302) //#define DHTTYPE DHT21 // DHT 21 (AM2301) // Lib instantiate DHT dht(DHTPIN, DHTTYPE); // ------------------------------------------ Конфигурация барометра ------------------------------------------ Adafruit_BMP085 bmp; // ------------------------------------------ Конфигурация wifi ------------------------------------------ unsigned long lastConnectionTime = 0; // время последней передачи данных String Hostname; //имя железки - выглядит как ESPAABBCCDDEEFF т.е. ESP+mac адрес. unsigned long lastCheckTime = 0; int checkInt = 2000; // ------------------------------------------ Конфигурация служебных переменных ------------------------------------------ float dhttemp; // буферная переменная для хранения температуры от dht22 float dhthum; // буферная переменная для хранения влажности от dht22 float lastTemp = 0; // предыдущее значение температуры float lastHum = 0; // предыдущее значение влажности int NAN_count = 0; // количество обработанных NaN int topwm; // хранит значение для шима яркости дисплея int barLCD; // Необходимо для отображения строки давления void wifimanstart() { // Волшебная процедура начального подключения к Wifi. // Если не знает к чему подцепить - создает точку доступа ESP8266 и настроечную таблицу http://192.168.4.1 // Подробнее: https://github.com/tzapu/WiFiManager WiFiManager wifiManager; wifiManager.setDebugOutput(debug); wifiManager.setMinimumSignalQuality(); if (!wifiManager.autoConnect("ESP8266")) { if (debug) Serial.println("failed to connect and hit timeout"); delay(3000); //reset and try again, or maybe put it to deep sleep ESP.reset(); delay(5000); } if (debug) Serial.println("connected..."); } // ------------------------------------------ Конфигурация иконок ------------------------------------------ byte Temp[8] = {0x4, 0x6, 0x4, 0x6, 0x4, 0x4, 0x1F, 0xE} ; byte Sig [8] = {0x2, 0x1, 0x9, 0x1, 0xa, 0x8, 0x1c, 0x1c}; byte Sig1[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f}; byte Sig2[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1f}; byte Sig3[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1f, 0x1f}; byte Sig4[8] = {0x0, 0x0, 0x0, 0x0, 0x1f, 0x1f, 0x1f, 0x1f}; byte Sig5[8] = {0x0, 0x0, 0x0, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f}; byte Sig6[8] = {0x0, 0x0, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f}; void setup() { // pinMode(3, OUTPUT); // gpio14 будет шимить подсветку дисплея Hostname = "ESP" + WiFi.macAddress(); Hostname.replace(":", ""); WiFi.hostname(Hostname); wifimanstart(); Serial.begin(115200); Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); Serial.print("Narodmon ID: "); Serial.println(Hostname); // выдаем в компорт мак и айпишник железки, так же выводим на дисплей // инициализация экрана lcd.begin(4, 5); // sda=gpio04, scl=gpio05 lcd.backlight(); analogWrite(3, 0); // ------------------------------------------ Конфигурация символов ------------------------------------------ lcd.createChar(1, Sig); lcd.createChar(2, Temp); lcd.createChar(3, Sig1); lcd.createChar(4, Sig2); lcd.createChar(5, Sig3); lcd.createChar(6, Sig4); lcd.createChar(7, Sig5); lcd.createChar(8, Sig6); lcd.setCursor(0, 0); lcd.print("Initialisation:"); lcd.setCursor(0, 1); lcd.print(WiFi.localIP()); delay (1000); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Initialisation:"); lcd.setCursor(0, 1); lcd.print(WiFi.SSID()); delay (1000); // инициализация датчика температуры и давления bmp180 dht.begin(); if (!bmp.begin()) // если датчик не обнаружен, сообщаем об этом в компорт и на дисплей { Serial.println("Could not find BMP180 or BMP085 sensor at 0x77"); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Initialisation:"); lcd.setCursor(0, 1); lcd.print("BMP180 FAILED"); while (1) {} } lcd.clear(); lcd.setCursor(0, 0); lcd.print("Initialisation:"); lcd.setCursor(0, 1); lcd.print("BMP_xx init OK"); delay (1000); DS18B20.begin(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Initialisation:"); lcd.setCursor(0, 1); lcd.print(DS18B20.getResolution(insideThermometer)); lcd.print("_init ok"); delay (1000); WiFi.hostname(Hostname); wifimanstart(); //Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); Serial.print("Narodmon ID: "); Serial.println(Hostname); // выдаем в компорт мак и айпишник железки, так же выводим на дисплей //lcd.clear(); //lcd.setCursor(0, 0); // lcd.print(WiFi.localIP()); // lcd.setCursor(0, 1); // lcd.print(Hostname); lastConnectionTime = millis() - postingInterval + 15000; //первая передача на народный мониторинг через 15 сек. lcd.clear(); } void WriteLcdTemp (void) { // заполнение дисплея. происходит каждые 2 секунды после получения данных с датчиков lcd.setCursor(0, 0); lcd.print(char(2)); //lcd.setCursor(2, 0); //lcd.print(dhttemp); lcd.print(tempC); lcd.print(char(0xDF)); lcd.setCursor(9, 0); lcd.print("H"); lcd.print(dhthum); lcd.print("% "); lcd.setCursor(0, 1); lcd.print("P"); lcd.print(bmp.readPressure() / 133.3); lcd.setCursor(9, 1); lcd.print(char(2)); //lcd.print(tempC); //lcd.print(bmp.readTemperature()); lcd.print(dhttemp); lcd.print(char(0xDF)); // lcd.print(NAN_count); } bool SendToNarodmon() { // Собственно формирование пакета и отправка. WiFiClient client; String buf; buf = "#" + Hostname + "#ESP_Mon" + "\r\n"; //заголовок И ИМЯ, которое будет отображаться в народном мониторинге, чтоб не палить мак адрес buf = buf + "#T1#" + String(dhttemp) + "\r\n"; //температура dht22 buf = buf + "#H1#" + String(dhthum) + "\r\n"; //влажность buf = buf + "#T2#" + String(bmp.readTemperature()) + "\r\n"; //температура bmp180 buf = buf + "#P1#" + String(bmp.readPressure()) + "\r\n"; //давление buf = buf + "#T3#" + String(tempC) + "\r\n"; //Температура DS18B20 buf = buf + "#S1#" + String(WiFi.RSSI()) + "\r\n"; //Уровень сигнала buf = buf + "##\r\n"; // закрываем пакет lcd.clear(); lcd.print("Sending"); if (!client.connect("narodmon.ru", 8283)) { // попытка подключения Serial.println("connection failed"); lcd.clear(); lcd.print("connect failed"); return false; // не удалось; } else { lcd.print("."); client.print(buf); // и отправляем данные lcd.print("."); if (debug) Serial.print(buf); lcd.print("."); while (client.available()) { String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial Serial.print(line); } } lcd.clear(); return true; //ушло lcd.print("Send Sucess"); delay (1000); lcd.clear(); } void baroLCD (void) { // заполнение дисплея. происходит каждые 5 минут после получения данных с датчиков lcd.setCursor(0, 0); lcd.print("T="); lcd.print(dhttemp); barLCD = map(dhttemp, 0, 35, 0, 15); lcd.setCursor(0, 1); if (barLCD >= 0) { lcd.print(" "); } lcd.setCursor(0, 1); if (barLCD >= 1) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(1, 1); if (barLCD >= 2) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(2, 1); if (barLCD > 3) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(3, 1); if (barLCD >= 4) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(4, 1); if (barLCD >= 5) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(5, 1); if (barLCD >= 6) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(6, 1); if (barLCD >= 7) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(7, 1); if (barLCD >= 8) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(8, 1); if (barLCD >= 9) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(9, 1); if (barLCD >= 10) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(10, 1); if (barLCD >= 11) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(11, 1); if (barLCD >= 12) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(12, 1); if (barLCD >= 13) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(13, 1); if (barLCD >= 14) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(14, 1); if (barLCD >= 15) { lcd.print(char(0xFF)); lcd.print(" "); } lcd.setCursor(15, 1); if (barLCD >= 16) { lcd.print(char(0xFF)); lcd.print(" "); } } void loop() { //автояркость topwm = map(analogRead(A0), 1023, 0, 0, 1023); analogWrite(3, topwm); delay(100); // нужна, беж делея у меня не подключался к вайфаю if (millis() - lastCheckTime > checkInt) { lastTemp = dhttemp; lastHum = dhthum; dhttemp = dht.readTemperature(); // сохравняем в буферные переменные данные с dht22, чтобы удобно было оперировать dhthum = dht.readHumidity(); // --------------- Проверка наличия ошибок ----------------- if ( isnan(dhttemp) == 1 || isnan(dhthum) == 1) { dhttemp = lastTemp; dhthum = lastHum; NAN_count = NAN_count + 1 ; } // --------------- читаем данные с DS18B20 ----------------- DS18B20.requestTemperatures(); tempC = DS18B20.getTempCByIndex(0); WriteLcdTemp(); lastCheckTime = millis(); } if (millis() - lastConnectionTime > postingInterval) { // ждем 5 минут и отправляем if (WiFi.status() == WL_CONNECTED) { // ну конечно если подключены if (SendToNarodmon()) { lastConnectionTime = millis(); } else { lastConnectionTime = millis() - postingInterval + 15000; //следующая попытка через 15 сек } } else { lastConnectionTime = millis() - postingInterval + 15000; //следующая попытка через 15 сек Serial.println("Not connected to WiFi"); lcd.clear(); lcd.print("No WiFi"); } } yield(); } |