Почти год назад я купил плату разработки Amica NodeMCU V3 с ESP-12E, который ESP8266MOD, и BOSCH BME6801), чтобы сделать барометр. Но… В Tasmota нет нормального драйвера для этого датчика2)! А решиться и взяться за Arduino и его Arduino C, для которых доступна полноценная библиотека BSEC3), все не мог – никогда с этой средой разработки не работал, как и с C++ вообще. А тут…
Кстати, помимо датчика BME680, туда предполагалось подключить еще реле для управления светом на балконе, для чего тогда же был куплен безымянный пятивольтовый модуль.
Облегченная, переработанная и дополненная версия скетча находится тут.
В общем итоге нужно:
В этих ваших интернетах бродит несколько вариантов подключения, но этот самый логичный, т.к. используются выводы по умолчанию, и, главное, рабочий.
NodeMCU | BME680 |
---|---|
D1 | SCL |
D2 | SDA |
3V3 | VCC |
GND | GND |
GND | SDO |
NodeMCU | Relay |
D5 | IN |
3V35) | VCC |
GND | GND |
NodeMCU | Power |
VIN | +5V |
GND | GND |
Важные замечания:
Первым делом необходимо загрузить Arduino IDE7), затем добавить в него поддержку плат ESP8266 и дополнительных библиотек.
Краткое изложение этой статьи:
http://arduino.esp8266.com/stable/package_esp8266com_index.json
в «Дополнительные ссылки для Менеджера плат»;esp8266
и установить;Дополнительно может потребоваться выбрать COM-порт в меню «Инструменты» → «Порт: […]».
Собственно, нужны только две дополнительные библиотеки, остальное уже есть в комплекте с IDE и платой.
Краткое изложение и перевод этой статьи:
compiler.libraries.ldflags=
;{compiler.libraries.ldflags}
.Загрузить отсюда10) и через меню «Скетч» → «Подключить библиотеку» → «Добавить .ZIP библиотеку…».
Ниже представлен рабочий11) скетч12), который подключается к Wi-Fi, передает данные с датчика и получает команды для реле по MQTT.
// Written by Nikolay Soloshin (nikolay@soloshin.su) for NodeMCU v3 with ESP-12E & BME680 @ 2022.02 /* Подключение библиотек */ #include <ESP8266WiFi.h> // v3.0.2 (ESP8266 Community) #include <PubSubClient.h> // v2.8.0 #include <bsec.h> // v1.6.1480 /* Инвертирование значений*/ #define iHIGH LOW #define iLOW HIGH /* Пользовательские настройки */ const char* wifi_ssid = "SSiD"; const char* wifi_pwd = "pWd"; const char* mqtt_server = "192.168.XXX.XXX"; const int mqtt_port = 1883; const char* mqtt_login = "user"; const char* mqtt_pwd = "pwd"; const char* mqtt_clientid = "bme680_XXXXXX"; const char* mqtt_sub_power = "barometer_XXXXXX/cmnd/POWER"; const char* mqtt_pub_power = "barometer_XXXXXX/stat/POWER"; const char* mqtt_pub_sensor = "barometer_XXXXXX/tele/SENSOR"; const char* mqtt_lwt_topic = "barometer_XXXXXX/tele/LWT"; const char* mqtt_state_topic = "barometer_XXXXXX/tele/STATE"; // Частота публикации данных в MQTT (часы * минуты * секунды * 1000) const int mqtt_pub_freq = 5 * 60 * 1000; // Каждые 2 часа = 2 * 60 * 60 * 1000 // Сдвиг для приведения к уровню моря в Па. // Уменьшение давления на 100 Па с увеличением высоты на 8 м. // https://www.fxyz.ru/формулы_по_физике/механика/аэростатика/атмосферное_давление/# const int bme_p_offset = 2225; // Высота датчика (178 м.) / 8 * 100. // Корректировка показаний температуры в °C const int bme_t_offset = -1.1; // К примеру, -1.1, 0 или 1.15 // Константа для перевода Па в мм.р.с. const float bme_mmHg = 0.0075; // Состояние реле при загрузке const uint8_t relay_state = iLOW; // iHIGH - включено, iLOW - выключено // Назначение GPIO const int bme_led = D0; const int status_led = LED_BUILTIN; const int relay = D5; // Выключение светодиодов через некоторое время const boolean leds_off = true; // false - не выключать long leds_off_delay = 60 * 1000; // Через 2 минуты = 2 * 60 * 1000 /* Прочие нужные дела */ const char* sk_version = "1.0.0 (sk1)"; // Версия скетча // Объявление функций void checkIaqSensorStatus(void); void BMEerrLeds(void); void MQTTErrorLED (void); // Создание объектов WiFiClient espClient; PubSubClient MQTT(espClient); Bsec iaqSensor; // Объявление служебных переменных String bme_output; long lastReconnectAttempt = 0; unsigned long MQTTLastPubTime = 0; boolean leds_off_status; /* Настройка при запуске */ void setup() { // Инициализация GPIO pinMode(bme_led, OUTPUT); pinMode(status_led, OUTPUT); pinMode(relay, OUTPUT); // Выключение LED и реле при запуске digitalWrite(bme_led, iLOW); digitalWrite(relay, relay_state); // Инициализация COM Serial.begin(115200); delay(3000); // Инициализация Wi-Fi WiFi.begin(wifi_ssid, wifi_pwd); Serial.println(F("Hi guys and girls!")); Serial.print(F("Connecting to Wi-Fi")); while (WiFi.status() != WL_CONNECTED) { digitalWrite(status_led, iHIGH); delay(250); Serial.print("."); digitalWrite(status_led, iLOW); delay(250); } Serial.print(F("\nConnected to Wi-Fi: ")); Serial.print(WiFi.SSID()); Serial.print(F(" (IP: ")); Serial.print(WiFi.localIP()); Serial.println(F(")!")); digitalWrite(status_led, iLOW); // Инициализация MQTT MQTT.setServer(mqtt_server, mqtt_port); MQTT.setCallback(MQTTcallback); while (!MQTT.connected()) { Serial.println(F("Connecting to MQTT...")); if (MQTT.connect(mqtt_clientid, mqtt_login, mqtt_pwd)) { Serial.println(F("MQTT connected!")); MQTT.publish(mqtt_state_topic, "MQTT connected!"); digitalWrite(status_led, iHIGH); } else { digitalWrite(status_led, iHIGH); delay(500); Serial.print(F("Failed with state ")); Serial.println(MQTT.state()); digitalWrite(status_led, iLOW); delay(500); } } // Подписка и публикация начальных значений MQTT.subscribe(mqtt_sub_power); MQTT.publish(mqtt_lwt_topic, "Online", true); MQTT.publish(mqtt_pub_power, digitalRead(relay) == iHIGH ? "ON" : "OFF"); // Инициализация BSEC Wire.begin(); iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire); bme_output = "BSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix); checkIaqSensorStatus(); bsec_virtual_sensor_t sensorList[10] = { BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY, BSEC_OUTPUT_RAW_GAS, BSEC_OUTPUT_IAQ, BSEC_OUTPUT_STATIC_IAQ, BSEC_OUTPUT_CO2_EQUIVALENT, BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, }; iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP); checkIaqSensorStatus(); digitalWrite(bme_led, iHIGH); bme_output += ", Sketch version " + String(sk_version) + ". Loading complete!"; Serial.println(bme_output); MQTT.publish(mqtt_state_topic, bme_output.c_str()); } /* Функция MQTT для приема сообщений и работы реле */ void MQTTcallback(char* topic, byte* payload, unsigned int length) { // Преобразование нагрузки в строку String message; for (int i = 0; i < length; i++) { message = message + (char)payload[i]; } // Переключение реле if (message == "ON") { digitalWrite(relay, iHIGH); } else if (message == "OFF") { digitalWrite(relay, iLOW); } else if (message == "TOGGLE") { if (digitalRead(relay) == iHIGH) { digitalWrite(relay, iLOW); } else { digitalWrite(relay, iHIGH); } } // Публикация статуса реле char* relay_status; if (digitalRead(relay) == iHIGH) { relay_status = "ON"; } else { relay_status = "OFF"; } MQTT.publish(mqtt_pub_power, relay_status); } /* Основной цикл */ void loop() { unsigned long now = millis(); // Чтение данных с датчика BME680 if (iaqSensor.run()) { // Есть новые данные (раз в 3 секунды) // Сборка строки bme_output = "{\"pressure_st\":" + String(iaqSensor.pressure * bme_mmHg); bme_output += ",\"pressure_sl\":" + String((iaqSensor.pressure + bme_p_offset) * bme_mmHg); bme_output += ",\"temperature\":" + String(iaqSensor.temperature + bme_t_offset); bme_output += ",\"humidity\":" + String(iaqSensor.humidity); bme_output += ",\"pressure_raw\":" + String(iaqSensor.pressure); //bme_output += ",\"temperature_raw\":" + String(iaqSensor.rawTemperature); //bme_output += ",\"humidity_raw\":" + String(iaqSensor.rawHumidity); bme_output += ",\"iaq\":" + String(iaqSensor.iaq); bme_output += ",\"iaq_accuracy\":" + String(iaqSensor.iaqAccuracy); bme_output += ",\"static_iaq\":" + String(iaqSensor.staticIaq); bme_output += ",\"co2_equivalent\":" + String(iaqSensor.co2Equivalent); bme_output += ",\"breath_voc_equivalent\":" + String(iaqSensor.breathVocEquivalent); bme_output += "}"; Serial.println(bme_output); // Сообщения для отладки //String bme_debug = "New data is available from "; //unsigned long time_trigger = millis(); //bme_debug += String(time_trigger) + "!"; //MQTT.publish(mqtt_state_topic, bme_debug.c_str()); } else { checkIaqSensorStatus(); } // Проверка соединения с брокером MQTT if (!MQTT.connected()) { if (now - lastReconnectAttempt > 5000) { lastReconnectAttempt = now; MQTTErrorLED(); Serial.println(F("MQTT disconnected!")); if (MQTTreconnect()) { lastReconnectAttempt = 0; digitalWrite(status_led, iHIGH); Serial.println(F("MQTT reconnected!")); MQTT.publish(mqtt_state_topic, "MQTT reconnected!"); // Сброс состояния выключения LED leds_off_status = false; leds_off_delay = now + 60000; // Выключить через минуту } } } else { // Публикация телеметрии датчика if (now - MQTTLastPubTime > mqtt_pub_freq || now - MQTTLastPubTime < 0) { MQTTLastPubTime = now; Serial.println(F("Publishing MQTT message...")); MQTT.publish(mqtt_pub_sensor, bme_output.c_str()); } } // Выключение светодиодов if (leds_off && now > leds_off_delay && !leds_off_status) { Serial.println(F("Turning off LEDs by timeout!")); MQTT.publish(mqtt_state_topic, "Turning off LEDs by timeout!"); digitalWrite(status_led, iLOW); digitalWrite(bme_led, iLOW); leds_off_status = true; } // Циклы библиотеки MQTT MQTT.loop(); } /* Функция проверки BSEC и датчика BME680 */ void checkIaqSensorStatus(void) { if (iaqSensor.status != BSEC_OK) { if (iaqSensor.status < BSEC_OK) { bme_output = "BSEC error code: " + String(iaqSensor.status); Serial.println(bme_output); MQTT.publish(mqtt_state_topic, bme_output.c_str()); for (;;) BMEerrLeds(); // Остановка в случае сбоя } else { bme_output = "BSEC warning code: " + String(iaqSensor.status); Serial.println(bme_output); MQTT.publish(mqtt_state_topic, bme_output.c_str()); } } if (iaqSensor.bme680Status != BME680_OK) { if (iaqSensor.bme680Status < BME680_OK) { bme_output = "BME680 error code: " + String(iaqSensor.bme680Status); Serial.println(bme_output); MQTT.publish(mqtt_state_topic, bme_output.c_str()); for (;;) BMEerrLeds(); // Остановка в случае сбоя } else { bme_output = "BME680 warning code: " + String(iaqSensor.bme680Status); Serial.println(bme_output); MQTT.publish(mqtt_state_topic, bme_output.c_str()); } } } /* Функция сигнализации о сбое BME или BSEC */ void BMEerrLeds(void) { digitalWrite(bme_led, iLOW); delay(100); digitalWrite(bme_led, iHIGH); delay(100); } /* Функция сигнализации о сбое Wi-Fi или MQTT */ void MQTTErrorLED (void) { digitalWrite(status_led, iHIGH); delay(100); digitalWrite(status_led, iLOW); delay(100); digitalWrite(status_led, iHIGH); delay(100); digitalWrite(status_led, iLOW); delay(100); digitalWrite(status_led, iHIGH); delay(100); digitalWrite(status_led, iLOW); } /* Функция переподключения MQTT */ boolean MQTTreconnect() { if (MQTT.connect(mqtt_clientid, mqtt_login, mqtt_pwd)) { MQTT.publish(mqtt_lwt_topic, "Online", true); MQTT.subscribe(mqtt_sub_power); } return MQTT.connected(); } // With love from Vladivostok.
Если будет терять соединение с Wi-Fi, смотреть сюда.
%HOMEPATH%\Documents\ArduinoData\packages\esp8266\hardware\esp8266
\x.x.x, а для версии, скачанной с сайта, тут – %HOMEPATH%\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266
\x.x.x, где «x.x.x» версия ядра ESP8266.
Обсуждение