Оживляя цикл публикаций про Raspberry Pi и Arduino, хочу написать статью о сборке домашней метеостанции на основе ESP8266 и цифрового датчика BME280.
BME280 разработан в группе компаний Bosch и включает в себя термометр, барометр и гигрометр. По результатам сравнительного исследования он является наиболее точным из недорогих датчиков подобного типа, часто используемых в DIY электронике.
Себестоимость используемых компонентов составляет меньше $10, а процесс сборки устройства займет не более 1 — 1.5 часов.
Содержание
Что нам понадобится
Для реализации описываемого в статье проекта понадобится:
- NodeMCU v3 или другая ESP8266-совместимая плата
- датчик BME280
- 0.96″ OLED дисплей
- макетная плата, провода
Продавцы, ссылки на которых я привел выше, проверены мной лично. Я сам заказывал у них эти товары и остался доволен качеством и скоростью выполнения заказа.
Датчик BME280 (как и многие другие подключаемые модули для Arduino / ESP8266) поставляется с нераспаянными ножками. Они идут в комплекте, но подпаивать их придется самостоятельно. Для пайки могу порекомендовать вот эту паяльную пасту.
Подключение ESP8266 к ПК
Изначально я хотел написать отдельную статью о подключении плат на основе ESP8266 к компьютеру и видах прошивок для них чтобы ссылаться на эту статью в дальнейшем. Но статья «не пошла», поэтому напишу здесь вкратце, а более подробную информацию по любому из непонятных моментов можно найти в интернете.
Для того, чтобы компьютер увидел плату, нужно установить драйвер для USB-UART (USB -> COM TTL) моста. Используемые для этого моста контроллеры могут различаться в зависимости от версии платы, соответственно, будут различаться и устанавливаемые драйвера. Например, в моем случае используется модуль CH340G, но также могут использоваться модули CP2102. Хорошие, ответственные производители обычно пишут название используемого контроллера на самой плате, но их можно отличить и на глаз: CH340G — маленькая прямоугольная микросхема, а CP2102 имеет квадратную форму.
Если драйвер подобран и установлен правильно, то после подключения ESP8266 к компьютеру USB-кабелем в разделе «Порты (COM и LPT)» диспетчера устройств Windows появится новый виртуальный COM-порт, через который будет проходить обмен данными с платой.
Затем нужно загрузить на ESP8266 Arduino-совместимую прошивку от Ai-Thinker (легко находится и скачивается в интернете) через программу ESP8266Flasher.
Финальный шаг — запустить Arduino IDE и добавить поддержку ESP-модулей. После этого ESP8266 можно программировать как обычную плату Arduino.
Важный момент: не рекомендуется прикасаться к ESP8266 во включенном состоянии, особенно — если плата подключена к USB-порту компьютера. Очень легко случайно замкнуть пальцами контакты на плате, от чего в самом неудачном раскладе может сгореть как сам модуль, так и USB-порт.
Сборка схемы
Для удобства сборки следует использовать макетные платы и DuPont-провода. И то и другое можно найти как на AliExpress, так и в оффлайновых магазинах с радиодеталями.
Подключение BME280 к ESP8266:
3V — VIN
G — GND
D5 — SCL
D6 — SDA
Подключение OLED-дисплея:
G — GND
3V — VDD
D5 — SCK
D6 — SDA
И дисплей, и датчик BME280 используют I2C-шину и потому подключаются к одним и тем же пинам.
Скетч 1: метеостанция с OLED-дисплеем
Для компиляции и загрузки скетча нужно установить в Arduino дополнительные библиотеки:
После установки в файле библиотеки BME280 нужно вручную поправить адрес с 0x77 на 0x76:
(Установленные библиотеки Arduino IDE хранит в папке \Documents\Arduino\libraries текущего пользователя Windows)
После чего остается только скомпилировать и загрузить в память ESP8266 следующий скетч:
#include "Wire.h" #include "Adafruit_Sensor.h" #include "Adafruit_BME280.h" #include "SSD1306.h" const float SEA_LEVEL_PRESSURE_HPA = 1013.25; const int DELAY = 3000; const int STARTUP_DELAY = 500; Adafruit_BME280 bme; SSD1306 display(0x3c, D6, D5); void setup() { Serial.begin(115200); Wire.begin(D6, D5); Wire.setClock(100000); if(!bme.begin()) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1) { yield(); delay(DELAY); } } delay(STARTUP_DELAY); display.init(); display.flipScreenVertically(); } void loop() { float tempC = bme.readTemperature(); float humidity = bme.readHumidity(); float pressurePascals = bme.readPressure(); // Print to serial monitor printToSerial(tempC, humidity, pressurePascals); // Display data on screen in metric units drawWithMetricUnits(tempC, humidity, pressurePascals); yield(); delay(DELAY); } void drawWithMetricUnits(float tempC, float humidity, float pressurePascals) { float pressureHectoPascals = pressurePascals / 100.0; display.clear(); display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); display.setFont(ArialMT_Plain_16); display.drawString(35, 3, "BME280"); 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(pressureHectoPascals) + " h,Pa"); display.display(); } void printToSerial(float tempC, float humidity, float pressurePascals) { // Temperature float tempF = 9.0/5.0 * tempC + 32.0; Serial.println("Temperature:"); printValueAndUnits(tempC, "*C"); printValueAndUnits(tempF, "*F"); //printValueAndUnits(tempC, "°C"); //printValueAndUnits(tempF, "°F"); Serial.println(""); // Barometric pressure float pressureHectoPascals = pressurePascals / 100.0; float pressureInchesOfMercury = 0.000295299830714 * pressurePascals; Serial.println("Pressure:"); printValueAndUnits(pressurePascals, "Pa"); printValueAndUnits(pressureHectoPascals, "hPa"); printValueAndUnits(pressureInchesOfMercury, "inHg"); Serial.println(""); // Humidity Serial.println("Humidity:"); printValueAndUnits(humidity, "%"); Serial.println(""); // Approximate altitude float altitudeMeters = bme.readAltitude(SEA_LEVEL_PRESSURE_HPA); float altitudeFeet = 3.28 * altitudeMeters; Serial.println("Approx. Altitude:"); printValueAndUnits(altitudeMeters, "m"); printValueAndUnits(altitudeFeet, "ft"); Serial.println(); } void printValueAndUnits(float value, String units) { Serial.print(" "); Serial.print(value); Serial.print(" "); Serial.println(units); }
Вот так будет выглядеть собранное устройство в работе:
Датчик меряет все доступные ему показатели (температура, влажность, давление) и они выводятся на экран. Показатели обновляются — обновляется информация на экране. Все.
К слову, на фотографии выше можно увидеть какой низкий уровень влажности стоит в помещении зимой в период работы центрального отопления. Низкая влажность негативно влияет на самочувствие людей и комнатных растений, а также ускоряет деградацию деревянной мебели и картин.
Регулярное отслеживание показателей микроклимата в помещении может стать первым шагом к его оздоровлению путем установки увлажнителей воздуха, термостатов и автоматических проветривателей.
Скетч 2: метеостанция с веб-сервером
Еще один хороший вариант использование датчика BME280 — метеостанция с возможностью удаленного мониторинга через браузер.
В данном случае дисплейный модуль не задействован. ESP8266 подключается к Wi-Fi сети и поднимает веб-сервер, содержащий обновляемую показателями датчика страницу, которую можно открыть в браузере.
Хорошая статья на эту тему находится на англоязычном блоге Embedded Lab и там же можно скачать архив с готовым скетчем. Хочу только обратить внимание, что:
- У автора той статьи задействованы пины D3 и D4, тогда как у меня D5 и D6. Можно переподключить провода как предлагает он, а можно собрать устройство по моей схеме и переправить пины в скетче.
- Перед компиляцией скетча нужно ввести в него SSID и пароль своей Wi-Fi сети
Заключение
Вот так на основе ESP8266 и нескольких недорогих модулей можно собрать метеостанцию для домашнего использования.
Можно модернизировать схему, добавив в нее газоанализатор и датчик CO2, превратив тем самым устройство в полноценный монитор качества воздуха, точности которого будет более чем достаточно для домашнего применения.
Еще один вариант развития идеи — настроить отсылку данных с датчиков по MQTT-протоколу, благодаря чему устройство можно интегрировать в любую платформу умного дома и использовать получаемые данные для управления другими умными девайсами.
Дмитрий, а может быть, сделаете отдельную подробную статью по созданию метеостанции на веб-сервере?
Я позднее планировал про MQTT поподробнее написать. Если нужно удаленно смотреть показатели, то это практичнее чем веб-сервер, как мне кажется.
Очень интересны такие станции, особенно, если они умеют писать в БД показания. У нас на работе была похожая, и на сайте можно было посмотреть, как меняется температура в течении времени, т.е. можно сравнить, было ли теплее например год назад
Есть платы с распаянным дисплеем на ESP32, пробовали их?
Видел такие в продаже, но не пробовал.
Я читал, что OLED-дисплеи выгорают при активном использовании и сильно теряют в яркости. Если это так, то подключать дисплей отдельным модулем выходит практичнее.
Спасибо за статью. Тоже хочу поднять такой проект.Есть вопрос.В своем проекте я не хочу поднимать Web-сервер на NodeMCU, а использовать для мониторинга показателей уже развернутый сервер на Raspberry.Насколько я понимаю — возможно с нода информацию отправлять сразу на малинку. Или я ошибаюсь?
Можно, например по MQTT-протоколу. На Raspberry Pi ставится Mosquitto и связывается с каким-нибудь сервером умного дома (они все поддерживают mqtt-устройства), а в скетч для ESP8266 добавляется функция MQTT-клиента.
ESP8266 отправляет данные, MQTT-брокер на Raspberry Pi их получает, а сервер умного дома обрабатывает и выводит в наглядном виде (в виде графика, например, или еще как-то).
Выдает ошибку..
exit status 1
‘DISPLAY_WIDTH’ was not declared in this scope
аналогично exit status 1
‘DISPLAY_WIDTH’ was not declared in this scope
Эта строка рисует рамку на экране, ее можно просто закомментировать или исправьте строку на
display.drawRect(0, 0, display.getWidth(), display.getHeight());
При компиляции в Arduino IDE выдает ошибку:
error: ‘D6’ was not declared in this scope
13 | SSD1306 display(0x3c, D6, D5);
| ^~
error: ‘D5’ was not declared in this scope
13 | SSD1306 display(0x3c, D6, D5);