Конфликт analogread и pubsubclient

Тема в разделе "ESP8266, ESP32", создана пользователем Дмитрий9150518, 2 фев 2020.

  1. может кто сталкивался, как только раскомментирую строку //t = analogRead(A0);
    nodemcu (ESP8266) постоянно теряет соединение с mqtt. Как решить?

    Код (C++):
    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>

    // Update these with values suitable for your network.

    const char* ssid = "";
    const char* password = "";
    const char* mqtt_server = "";

    WiFiClient espClient;
    PubSubClient client(espClient);
    long lastMsg = 0;
    char msg[50];
    int value = 0;

    String waterlockstr;
    String serenagasstr;
    String wateralarmstr;
    String waterlevelstr;
    float diff = 150;
    int gas = 0;
    int t = 0;
    bool serena;

    void setup_wifi() {

      delay(10);
      // We start by connecting to a WiFi network
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);

      WiFi.begin(ssid, password);

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

      randomSeed(micros());

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

      pinMode(D2, OUTPUT);  //Waterlock
      digitalWrite(D2, LOW);
      pinMode(D6, OUTPUT); //Waterlock
      digitalWrite(D6, LOW);
      pinMode(D1, OUTPUT); //Serena
      digitalWrite(D1, LOW);
      pinMode(A0, INPUT); //Gas
    }

    void callback(char* topic, byte* payload, unsigned int length) {
      Serial.print("Message arrived [");
      Serial.print(topic);
      Serial.print("] ");
      String strTopic = String(topic);
      String message;
      for (int i = 0; i < length; i++) {
        message = message + (char)payload[i];  //Conver *byte to String  
      }
      Serial.print(message);
      Serial.println();
     
    if(strTopic == "waterlock") {
        waterlockstr = message;
      }
            else if(strTopic == "serenagas") {
        serenagasstr = message;
      }
            else if(strTopic == "fermentation/water_alarm") {
        wateralarmstr = message;
      }
            else if(strTopic == "fermentation/water_level") {
        waterlevelstr = message;
      }

    }

    void reconnect() {
      // Loop until we're reconnected
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Create a random client ID
        String clientId = "ESP8266Client-";
        clientId += String(random(0xffff), HEX);
        // Attempt to connect
        if (client.connect(clientId.c_str())) {
          Serial.println("connected");
          // Once connected, publish an announcement...
          client.subscribe("waterlock");
          client.subscribe("serenagas");
          client.subscribe("fermentation/water_alarm");
          client.subscribe("fermentation/water_level");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }

    void setup() {
      Serial.begin(115200);
      setup_wifi();
      client.setServer(mqtt_server, 1883);
      client.setCallback(callback);
    }

    void loop() {
       //t = analogRead(A0);

      if (!client.connected()) {
        reconnect();
      }
      client.loop();
        getAll();

    if (wateralarmstr == "ALARM" || waterlevelstr == "ALARM" || waterlockstr == "1") {
        digitalWrite(D6, LOW);
        digitalWrite(D2, HIGH);
        }
        else if (wateralarmstr == "no worries" && waterlevelstr == "no worries" && waterlockstr == "0") {
        digitalWrite(D6, HIGH);
        digitalWrite(D2, LOW);
        }
       
    if (serenagasstr == "1") digitalWrite(D1, HIGH);    
        else if (serenagasstr == "0") digitalWrite(D1, LOW);
     
    }

    bool checkBound(float newValue, float prevValue, float maxDiff) {
      return !isnan(newValue) &&
             (newValue < prevValue - maxDiff || newValue > prevValue + maxDiff);
    }

    void getAll() {
        int newgas = t; //gas level
       
        if ((checkBound(newgas, gas, diff))) {
          gas = newgas;
         if (gas >= 150){
          client.publish("serenagas", "1", true);
        }
        else if (gas < 150) {
          client.publish("serenagas", "0", true);
        }
        }
    }
     
  2. SergeiL

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

    Да нет там никаких проблем.
    Работают у меня несколько ESP с чтением АЦП и передачей данных по MQTT. Работают очень стабильно.

    Думаю ваш код начинает очень часто публиковать данные, когда переменная t начинает меняться.

    И разберитесь с типами данных.
    В случае вызова функции, тип переменных должен соответствовать типу переменных в описании функции.
    Ну, или нужно делать явное преобразование типов при передаче параметров в функцию.

    Код (C++):
    bool checkBound(float newValue, float prevValue, float maxDiff) {
      return !isnan(newValue) &&
             (newValue < prevValue - maxDiff || newValue > prevValue + maxDiff);
    }

    void getAll() {
        int newgas = t; //gas level
     
        if ((checkBound(newgas, gas, diff))) {
          gas = newgas;
         if (gas >= 150){
          client.publish("serenagas", "1", true);
        }
        else if (gas < 150) {
          client.publish("serenagas", "0", true);
        }
        }
    }
    Зачем вам float ?
     
  3. Спасибо за замечания. Поправил.
     
  4. убрал публикацию (void getAll()) совсем. все равно mqtt отваливался, пока не ограничил чтение АЦП раз в пять сек
     
  5. SergeiL

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

    У меня на ESP АЦП читается раз в секунду, на Leeonardo ETH каждые 100мс. На каждом цикле, думаю, точно не нужно.
    Данные собираются, усредняются (30 значений) обрабатываются, и если отличаются от предыдущего - отправляются по mqtt.
    Выкладывайте измененный скетч, посмотрим что там.
     
  6. Вот этот вариант кривой, но вроде работает

    Код (C++):
    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>

    // Update these with values suitable for your network.

    const char* ssid = "";
    const char* password = "";
    const char* mqtt_server = "192.168.1.1";

    WiFiClient espClient;
    PubSubClient client(espClient);
    long lastMsg = 0;
    char msg[50];
    int value = 0;

    String waterlockstr;
    String serenagasstr;
    String wateralarmstr;
    String waterlevelstr;
    int diff = 150;
    int gas = 0;
    int t = 0;
    unsigned long timepast = 0;
    int diff1 = 1;
    bool g = 0; // для публикации статуса waterlock
    bool t1; // для публикации статуса waterlock

    void setup_wifi() {

      delay(10);
      // We start by connecting to a WiFi network
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);

      WiFi.begin(ssid, password);

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

      randomSeed(micros());

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

      pinMode(D2, OUTPUT);  //Waterlock
      digitalWrite(D2, LOW);
      pinMode(D6, OUTPUT); //Waterlock
      digitalWrite(D6, LOW);
      pinMode(D1, OUTPUT); //Serena
      digitalWrite(D1, LOW);
      pinMode(A0, INPUT); //Gas
    }

    void callback(char* topic, byte* payload, unsigned int length) {
      Serial.print("Message arrived [");
      Serial.print(topic);
      Serial.print("] ");
      String strTopic = String(topic);
      String message;
      for (int i = 0; i < length; i++) {
        message = message + (char)payload[i];  //Conver *byte to String  
      }
      Serial.print(message);
      Serial.println();
     
    if(strTopic == "waterlock") {
        waterlockstr = message;
      }
            else if(strTopic == "serenagas") {
        serenagasstr = message;
      }
            else if(strTopic == "fermentation/water_alarm") {
        wateralarmstr = message;
      }
            else if(strTopic == "fermentation/water_level") {
        waterlevelstr = message;
      }
    }

    void reconnect() {
      // Loop until we're reconnected
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Create a random client ID
        String clientId = "ESP8266Client-";
        clientId += String(random(0xffff), HEX);
        // Attempt to connect
        if (client.connect(clientId.c_str())) {
          Serial.println("connected");
          // Once connected, publish an announcement...
          client.subscribe("waterlock");
          client.subscribe("serenagas");
          client.subscribe("fermentation/water_alarm");
          client.subscribe("fermentation/water_level");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }

    void setup() {
      Serial.begin(115200);
      setup_wifi();
      client.setServer(mqtt_server, 1883);
      client.setCallback(callback);
    }

    void loop() {

     
      if ((millis()-timepast) > 5000) {
      t = analogRead(A0);
      t1 = digitalRead(D2);
      timepast = millis();
      }

      if (!client.connected()) {
        reconnect();
      }
      client.loop();
        getAll();

    if (wateralarmstr == "no worries" && waterlevelstr == "no worries" && waterlockstr == "1") {
        digitalWrite(D6, LOW);
        digitalWrite(D2, HIGH);
        }
        else if (waterlockstr == "0") {
        digitalWrite(D6, HIGH);
        digitalWrite(D2, LOW);
        }
       if (wateralarmstr == "ALARM" && waterlockstr == "1") client.publish("waterlock", "0", true);
       if (waterlevelstr == "ALARM" && waterlockstr == "1") client.publish("waterlock", "0", true);
     
    if (serenagasstr == "1") digitalWrite(D1, HIGH);    
        else if (serenagasstr == "0") digitalWrite(D1, LOW);
       
       delay(200);
    }

    bool checkBound(int newValue, int prevValue, int maxDiff) {
      return !isnan(newValue) &&
             (newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff);
    }

    void getAll() {
        int newgas = t; //gas level
        bool newg = t1;// state waterlock
       
        if ((checkBound(newgas, gas, diff))) {
          gas = newgas;    
          if (gas >= 150){
          client.publish("serenagas", "1", true);
          }
          else if (gas < 150) {
          client.publish("serenagas", "0", true);
        }
        }
          if (checkBound(newg, g, diff1)){
          g = newg;
          client.publish("waterlock", String(g).c_str(), true);
        }    
    }
     
  7. SergeiL

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

    А для чего вы вызываете isnan? У нее параметр double, а вы ей int передаете.
     
  8. SergeiL

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

    Вы монитор порта смотрели? Что выводится.
    Добавьте в setup :
    Код (C++):
      Serial.println("Setup start");
     
    Будет понятно когда ESP перезагружается.
    Плюс побольше подобных строк в код, и по монитору порта смотреть, что происходит.
    Так вроде не видно причины, во втором варианте у вас есть таймаут в конце loop в 200мс, должно было все работать нормально и без этих 5 сек.
     
  9. delay я уже потом добавил. в следующие выходные займусь отладкой. спасибо за подсказки

    а вообще у mosquitto есть предел по количеству топиков или сообщений в секунду?
     
  10. SergeiL

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

    Я не сталкивался.
    Нарывался на проблему с одинаковым Id клиента. Когда только начинал, код с одного ESP в дугой залил, не исправив.
    Один точно постоянно переподключался, второй уже не помню. В начале 16-го это было.
    После этого использую в качестве ID - часть MAC адреса.
    Код (C++):
    byte        MAC[6];                     // the MAC address of your ESP
    char        Device_Name[14];            // ESP_+ last 3 byts of MAC address of your ESP
    char        Login[] = "YourLogin";
    char        Password[] = "YourPassword";

      WiFi.macAddress(MAC);
      sprintf(Device_Name,"ESP_%02X%02X%02X",(unsigned)MAC[3],(unsigned)MAC[4],(unsigned)MAC[5]);
        ............................

      if (client.connect(Device_Name,Login,Password))

        ............................
    Я string не использую. Мне проще со строками в char.
     
    Дмитрий9150518 нравится это.
  11. Ваша система на даче? Из чего состоит, чем управляет?
     
  12. SergeiL

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

    Основное все - дома. Брокер Москито + OpenHAB + HomeKit.
    Все на малине.
    Здесь есть очень интересная и познавательная тема от @ИгорьК.
    В этой теме Игоря, код для ESP на Lua, но от этого смысл не меняется.

    Дома подключено все верхнее освещение, датчики движения, NTP-часы с измерением температуры и влажности в каждой комнате, модуль внешней температуры с двумя датчиками (с двух сторон дома - берется минимальная температура), счетчики воды, снятия информации и управление системой защиты от протечек, мониторинг и управление теплым полом в ванной. Все на ESP8266. Свой вариант управления освещением выкладывал здесь
    Если все ушли и дома - свет по всей квартире отключается.

    На работе, контроль температуры в двух серверных, мониторинг сети и генератора. Серверные на Leonardo ETH, а генератор на ESP.

    На даче мониторинг аккумуляторных батарей в подвале +контроль питания + управление. Тоже Leonardo ETH.
    Сигнализация там давно, но SMS + звонки, переделывать пока нет смысла - работает.

    В этом году на даче у родителей жены подключил контроль температуры дома, ну и заодно, на улице + включение нагревателя к приезду. - сделано на ESP.

    Недавно делал модуль мониторинга и управления для машины.
    Прототип делал на Меге + GPRS Shield + Relay Shield. Здесь писал
    Связь через GPRS модем по протоколу mqtt на OpenHAB, со всеми вытекающими из этого плюшками ;).
    Очень хотелось подключить машину, со всеми возможностями контроля и уведомлений, в OpenHAB,
    и при этом сделать систему не сильно прожорливой, без WiFi и роутера.
    Пока система показала себя надежной.
    Хочу в последствии перенести модуль для машины на ESP + SIM800. Даже железо уже нашел, 2 месяца лежит, но руки не доходят. :(

    Вот, все это хозяйство к домашнему OpenHAB подключается, и с него же управляется.
     
    Дмитрий9150518 и Daniil нравится это.
  13. без малинки не обойтись? у меня москито на роутере установлен, а в качестве сервера ESP32, с нарисованной вэб мордой, которую keenetic публикует в интернет . так что нам не страшен серый ip. Имеет такая схема право на жизнь?
     
  14. KindMan

    KindMan Гуру

    Перешитый? Москито как туда поставили?
     
  15. нет. не перешитый. здесь инструкция

     
    KindMan нравится это.
  16. SergeiL

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

    Конечно имеет право на жизнь, она же работает!
    Как по мне - с малиной логичнее, да и в обслуживании ИМХО проще.
    У меня на малину только два порта прокинуты. Москито и NGINX.
    Перед глобальными изменениями просто делаю бэкап карты и все.
    Скажу больше, у меня две малины с OpenHAB работают. Одна рабочая, со старой версией, а вторая для экспериментов, с последней. ;)