Отправка данных на домашний mqtt сервер

Тема в разделе "ESP8266, ESP32", создана пользователем Alex20280, 3 дек 2020.

  1. Alex20280

    Alex20280 Нерд

    Здравствуйте.

    Пытаюсь наладить интервал отправки данных с датчика BME20 (на базе Node mcu) на mqtt сервер. Использую следующий код:

    Код (C++):
    #include "ESP8266WiFi.h"
    #include "PubSubClient.h"
    #include "Wire.h"
    #include "cactus_io_BME280_I2C.h"
    #include <SoftwareSerial.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <SPI.h>

    WiFiClient espClient;
    PubSubClient client(espClient);
    BME280_I2C bme(0x76);

    const char* SSID                  = "***************";
    const char* PASSWORD              = "***************";

    const char* MQTT_BROKER           = "192.168.1.1";
    const int   MQTT_PORT             = 1883;
    const char* MQTT_TOPIC            = "mqttHome/bedroom";
    const char* MQTT_CLIENT_NAME      = "alexmqtt";
    const char* mqttPassword          = "****************";

    const int   BME280_DELAY          = 3000; //3000
    const int   RECHECK_INTERVAL      = 700; //700
    const int   PUBLISH_INTERVAL      = 2000; //2000

    long        lastReconnectAttempt  = 0;
    long        lastPublishAttempt    = 0;


    const char* wl_status_to_string(wl_status_t status) {
      switch (status) {
        case WL_NO_SHIELD: return "WL_NO_SHIELD";
        case WL_IDLE_STATUS: return "WL_IDLE_STATUS";
        case WL_NO_SSID_AVAIL: return "WL_NO_SSID_AVAIL";
        case WL_SCAN_COMPLETED: return "WL_SCAN_COMPLETED";
        case WL_CONNECTED: return "WL_CONNECTED";
        case WL_CONNECT_FAILED: return "WL_CONNECT_FAILED";
        case WL_CONNECTION_LOST: return "WL_CONNECTION_LOST";
        case WL_DISCONNECTED: return "WL_DISCONNECTED";
      }
    }

    void setup()
    {
      setupWifi();
      setupMQTT();;
      setupBME280();
    }

    void loop()
    {
      long now = millis();
     
      if(!client.connected())
      {
        if(now - lastReconnectAttempt > RECHECK_INTERVAL)
        {
          lastReconnectAttempt = now;
          client.connect(MQTT_CLIENT_NAME);

          if(client.connected())
          {
            // Resubscribe to any topics, if necessary
            // This is also a good place to publish an error to a separate topic!
          }
        }
      }
      else
      {
        if(now - lastPublishAttempt > PUBLISH_INTERVAL)
        {
          lastPublishAttempt = now;

          readAndPublishData(); //read data from BME and send to mqtt

          client.loop();
        }
      }
    }


    void setupWifi()
    {
      Serial.println("");
      Serial.print("Connecting to ");
      Serial.print(SSID);

      WiFi.begin(SSID, PASSWORD);

      while(WiFi.status() != WL_CONNECTED)
      {
        delay(RECHECK_INTERVAL);
        Serial.print(".");
        yield();
      }

      Serial.println("");
      Serial.println("WiFi connected");
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
    }

    void setupBME280()
    {
      Serial.println("");
      Serial.print("Setting up BME280");

      while(!bme.begin())
      {
        delay(RECHECK_INTERVAL);
        Serial.print(".");
        yield();
      }
     
      Serial.println("");
      Serial.println("BME280 found!");
      delay(BME280_DELAY);
    }

    void setupMQTT()
    {
      client.setServer(MQTT_BROKER, MQTT_PORT);
      client.setCallback(callback);
      Serial.println(WiFi.localIP());
      while (!client.connected()) {
        Serial.println("Connecting to MQTT...");
        if (client.connect("ESP8266Client", MQTT_CLIENT_NAME, mqttPassword )) {
          Serial.println("connected");
        } else {
          Serial.print("failed with state ");
          Serial.print(client.state());
          delay(2000);
        }
      }
       client.publish("mqttHome/bedroom/status", wl_status_to_string(WiFi.status()));
       client.subscribe("mqttHome/bedroom/status");
    }

    void readAndPublishData()
    {
      if(client.connected()) {
    bme.readSensor();

    getPressure();
    getTemperature();
    getHumidity();;
      }

    void callback(char* topic, byte* payload, unsigned int length) {
      Serial.print("Message arrived in topic: ");
      Serial.println(topic);
      Serial.print("Message:");
      for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
      }
      Serial.println();
      Serial.println("-----------------------");
    }

    }
    Данный код отправляет данные на сервер раз в 2 сек. Мне нужно чтобы данные отправлялись раз в минуту.
    Когда я величиваю RECHECK_INTERVAL или PUBLISH_INTERVAL до 20 000 то данные отправляются раз в 20 секунд, а если ставлю 20 000, то отправляются через 30 сек после включения, а пото вовсе не отправляются.
    Подскажите пожалуйста, что не так.
     
  2. SergeiL

    SergeiL Оракул Модератор

    Этот код и раз в 2 секунды не будет отправлять данные. Там нет отправки.
    Да и в конце со скобками Вы запутались.
     
  3. Alex20280

    Alex20280 Нерд

    Отправляет. Я подписался на топики с помощью mqtt.fx и получаю данные каждые 2 секунды.
    Со скобками может и напутал, так как удалялл не нужное, что не касается вопроса.
     
  4. SergeiL

    SergeiL Оракул Модератор

    Если отправляет - значит используется не тот код, что в первом посте.
    В том, который в первом посте, только один publish есть:
    Код (C++):
    client.publish("mqttHome/bedroom/status", wl_status_to_string(WiFi.status()));
    И он только в setupMQTT().
    Про скобки написал.
    Смысл его смотреть?
    Ну интервалы у Вас const int (максимальное значение должно быть не более 32767), а millis() возвращает unsigned long.
    Лучше константы через #define определить.
     
  5. Alex20280

    Alex20280 Нерд

    Вот весь код:

    Код (C++):
    #include "ESP8266WiFi.h"
    #include "PubSubClient.h"
    #include "Wire.h"
    #include "cactus_io_BME280_I2C.h"
    #include <SoftwareSerial.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <SPI.h>

    #define CO2_TX D6 // CO2
    #define CO2_RX D7 // CO2
    #define LOG_PERIOD 15000  //Период регистрации в миллисекундах, рекомендуемое значение 15000-60000.
    #define MAX_PERIOD 60000  //Максимальный период регистрации.

    WiFiClient espClient;
    PubSubClient client(espClient);
    BME280_I2C bme(0x76);

    SoftwareSerial SerialCO2(CO2_TX, CO2_RX); //CO2
    byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
    unsigned char response[9];
    uint8_t responseHigh;
    uint8_t responseLow;

    unsigned long counts;     //Gauge
    unsigned long cpm;      
    unsigned int multiplier;
    unsigned long previousMillis;
    float uSv;            // Переменная для перевода в микроЗиверты
    float ratio = 0.0057; // Коофициент для перевода импульсов в микроЗиверты
    float uP = 0;
    const byte interruptPin = D5; // Порт ESP к которому подключен счетчик

    void ICACHE_RAM_ATTR tube_impulse(){       //Функция подсчета имульсов
      counts++;
    }

    const char* SSID                  = "************";
    const char* PASSWORD              = "************";

    const char* MQTT_BROKER           = "192.168.1.1";
    const int   MQTT_PORT             = 1883;
    const char* MQTT_TOPIC            = "mqttHome/bedroom";
    const char* MQTT_CLIENT_NAME      = "alexmqtt";
    const char* mqttPassword          = "********";

    const int   BME280_DELAY          = 3000;
    const int   RECHECK_INTERVAL      = 700;
    const int   PUBLISH_INTERVAL      = 2000;

    long        lastReconnectAttempt  = 0;
    long        lastPublishAttempt    = 0;


    const char* wl_status_to_string(wl_status_t status) {
      switch (status) {
        case WL_NO_SHIELD: return "WL_NO_SHIELD";
        case WL_IDLE_STATUS: return "WL_IDLE_STATUS";
        case WL_NO_SSID_AVAIL: return "WL_NO_SSID_AVAIL";
        case WL_SCAN_COMPLETED: return "WL_SCAN_COMPLETED";
        case WL_CONNECTED: return "WL_CONNECTED";
        case WL_CONNECT_FAILED: return "WL_CONNECT_FAILED";
        case WL_CONNECTION_LOST: return "WL_CONNECTION_LOST";
        case WL_DISCONNECTED: return "WL_DISCONNECTED";
      }
    }

    void setup()
    {
      setupWifi();
      setupMQTT();
      setupGauge();
      setupBME280();
      SerialCO2.begin (9600);

    }

    void loop()
    {
      long now = millis();
     
      if(!client.connected())
      {
        if(now - lastReconnectAttempt > RECHECK_INTERVAL)
        {
          lastReconnectAttempt = now;
          client.connect(MQTT_CLIENT_NAME);

          if(client.connected())
          {
            // Resubscribe to any topics, if necessary
            // This is also a good place to publish an error to a separate topic!
          }
        }
      }
      else
      {
        if(now - lastPublishAttempt > PUBLISH_INTERVAL)
        {
          lastPublishAttempt = now;

          readAndPublishData();

          client.loop();
        }
      }
    }



    void setupGauge(){
      counts = 0;
      cpm = 0;
      multiplier = MAX_PERIOD / LOG_PERIOD;    
      Serial.begin(115200);
      interrupts();
      pinMode(interruptPin, INPUT);
      attachInterrupt(digitalPinToInterrupt(interruptPin), tube_impulse, FALLING); //Определяем количество импульсов через внешнее прерывание на порту
    }

    void setupWifi()
    {
      Serial.println("");
      Serial.print("Connecting to ");
      Serial.print(SSID);

      WiFi.begin(SSID, PASSWORD);

      while(WiFi.status() != WL_CONNECTED)
      {
        delay(RECHECK_INTERVAL);
        Serial.print(".");
        yield();
      }

      Serial.println("");
      Serial.println("WiFi connected");
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
    }

    void setupBME280()
    {
      Serial.println("");
      Serial.print("Setting up BME280");

      while(!bme.begin())
      {
        delay(RECHECK_INTERVAL);
        Serial.print(".");
        yield();
      }
     
      Serial.println("");
      Serial.println("BME280 found!");
      delay(BME280_DELAY);
    }

    void setupMQTT()
    {
      client.setServer(MQTT_BROKER, MQTT_PORT);
      client.setCallback(callback);
      Serial.println(WiFi.localIP());
      while (!client.connected()) {
        Serial.println("Connecting to MQTT...");
        if (client.connect("ESP8266Client", MQTT_CLIENT_NAME, mqttPassword )) {
          Serial.println("connected");
        } else {
          Serial.print("failed with state ");
          Serial.print(client.state());
          delay(2000);
        }
      }
       client.publish("mqttHome/bedroom/status", wl_status_to_string(WiFi.status()));
       client.subscribe("mqttHome/bedroom/status");
    }



    void readAndPublishData()
    {
      if(client.connected()) {
    bme.readSensor();

    getPressure();
    getTemperature();
    getHumidity();
    getCO2();
    getGauge();
      }
    }



    void callback(char* topic, byte* payload, unsigned int length) {
      Serial.print("Message arrived in topic: ");
      Serial.println(topic);
     
      Serial.print("Message:");
      for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
      }
      Serial.println();
      Serial.println("-----------------------");
    }

    void getPressure(){
    float pressurePascals =  bme.getPressure_MB();
    String msgPr = String(pressurePascals);
    char msgAsCharAway[msgPr.length()];
    msgPr.toCharArray(msgAsCharAway, msgPr.length());
    Serial.print(bme.getPressure_MB()); Serial.print(" мм.рт.ст.\t");
    client.publish("mqttHome/bedroom/pressure", msgAsCharAway);
    }


    void getTemperature(){
    float temperature = bme.getTemperature_C();
    String msgTempC = String (temperature);
    char msgAsCharAwayTempC[msgTempC.length()];
    msgTempC.toCharArray(msgAsCharAwayTempC, msgTempC.length());
    client.publish("mqttHome/bedroom/temperature", msgAsCharAwayTempC);
    Serial.print(bme.getTemperature_C()); Serial.print(" C\t  ");
    }

    void getHumidity(){
    float humidity = bme.getHumidity();
    String msgHum = String (humidity);
    char msgAsCharAwayHum[msgHum.length()];
    msgHum.toCharArray(msgAsCharAwayHum, msgHum.length());
    client.publish("mqttHome/bedroom/humidity", msgAsCharAwayHum);
    Serial.print(bme.getHumidity()); Serial.print (" %\t\t");
    }

    void getGauge(){
    unsigned long currentMillis = millis();
      if(currentMillis - previousMillis > LOG_PERIOD){
        previousMillis = currentMillis;
        cpm = counts * multiplier;
        uSv = cpm * ratio;

        String msgGau = String (uSv);
        char msgAsCharAwayGau[msgGau.length()];
        msgGau.toCharArray(msgAsCharAwayGau, msgGau.length());
        client.publish("mqttHome/bedroom/uSv", msgAsCharAwayGau);
        Serial.println("uSv: "); Serial.print (uSv);
        Serial.println("cpm: "); Serial.print (cpm);

        counts = 0;
      }
    }


    void getCO2() //чтение показаний датчика MH-Z14A
    {
      SerialCO2.write(cmd, 9); //отправляем команду датчику
      memset(response, 0, 9);
      SerialCO2.readBytes(response, 9); //получаем ответ
     
      uint8_t crc = 0;
      for (int i = 1; i < 8; i++) crc+=response[i]; //считаем контрольную сумму
      crc = ~crc;
      crc++;

      if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) ) // сравниваем ответ с  контрольной суммой
      {
        Serial.println("CRC error: " + String(crc) + " / "+ String(response[8])); //выводим ошибку
      }
      else
      {
        uint8_t responseHigh = (uint8_t) response[2];
        uint8_t responseLow = (uint8_t) response[3];

      float CO2 = (256*responseHigh) + responseLow;
      String msgCO2 = String (CO2);
      char msgAsCharAwayCO2[msgCO2.length()];
      msgCO2.toCharArray(msgAsCharAwayCO2, msgCO2.length());
      client.publish("mqttHome/bedroom/CO2", msgAsCharAwayCO2);
      Serial.println("CO2 "+String((256*responseHigh) + responseLow)+"ppm"); //выводим показания датчика
      }
    }
     
  6. Andrey12

    Andrey12 Гик

    Ну в принципе правильно писали выше что вместо
    constint RECHECK_INTERVAL =700;
    constint PUBLISH_INTERVAL =2000;

    надо сделать
    const uint32_t RECHECK_INTERVAL =700UL;
    const uint32_t PUBLISH_INTERVAL =2000UL;

    и эти тоже
    long lastReconnectAttempt = 0;
    long lastPublishAttempt = 0;

    переделать на
    uint32_t lastReconnectAttempt = 0UL;
    uint32_t lastPublishAttempt = 0UL;

    и это тоже
    long now = millis();

    на
    uint32_t now = millis();
     
  7. Alex20280

    Alex20280 Нерд

    Поставил
    const uint32_t RECHECK_INTERVAL = 700UL; //700
    const uint32_t PUBLISH_INTERVAL = 10000UL; //2000

    uint32_t lastReconnectAttempt = 0UL;
    uint32_t lastPublishAttempt = 0UL;

    uint32_t now = millis();

    Когда PUBLISH_INTERVAL ставлю 10000UL, то данные отправляются раз в 10 сек, но когда ставлю 30000UL или 60000UL, то данные вообще не уходят. Может также нужно менять значения RECHECK_INTERVAL, lastReconnectAttempt, или lastPublishAttempt?