Зависание Nano+ESP от помехи

DenBak
Offline
Зарегистрирован: 30.01.2017

Доброго времени суток всем

Порядка года использую связку Nano+ESP для контроля работы локальной очистной установки ТОПАС. При переключении компрессоров отпадает подключение к wi-fi.

Кратко все это опишу. ТОПАС - содержит два воздушных компрессора (по 80Вт), которые аэрируют сточные воды и переключаются в зависимости от уровня воды в приемной камере поплавковым переключателем.

Девайс - связка Наны и ESP, контролирует уровень воды в приемной камере (еще один аварийный поплавок – сигнализация о переливе), температуру (ds18b20), работу каждого компрессора (по наличию сетевого напряжения на нем, развязка через оптопару PC817), потребляемый установкой ток (ACS712 5a). Данные каждую минуту выдаются на сервер IoT и по UDP в домашнюю сеть. Питается все это безобразие от HLK-PM01, 3,3 вольта для ESP получаю с конвертера на LM2596.

Собственно проблема: все работает хорошо, до момента переключения компрессоров поплавковым переключателем. В этот момент ESP в 40-60% случаев отваливается от сети, подключение восстанавливается только минуты через 3-4. Иногда подключается через пару часов, иногда вообще больше не подключается до сброса питания. Повторное подключение к сети WI-FI в коде предусмотрено, в процедуре дополнительно "передергивается CH_PD" + после подается AT+RST. Активирован ВатчДог. По коду бесконечный цикл предусмотрен только в ожидании подключения к WI-FI. Код и схему могу выложить для анализа, но подозреваю что не в нем дело. Самое печальное, что непонятно что виснет: ESP, нанка или и то и другое.

Вопрос: как бороться с данной помехой? Поставить варистор, LC-фильтр со стороны 220в? Есть вероятность, что помеха не по питанию, а какие то наводки в сигнальных кабелях (кабели на аварийный поплавок и на датчик температуры довольно длинные)? Радикальным решением было бы вообще коммутировать компрессоры симисторами с контролем нуля, но не хочется сильно вмешиваться существующую схему, боюсь в надежности потерять.

Извиняюсь за много букв…

Deamon
Offline
Зарегистрирован: 21.09.2017

а если поставить твердотельные реле на компрессоры?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

DenBak, без полной схемы и фотогорафий монтажа тут не о чем разговаривать.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Это не помеха,это код. Ищите ошибку ,сами же написали что включение компрессоров отслеживается Для проверки запивайте схему от аккумулятора или батареек.

DenBak
Offline
Зарегистрирован: 30.01.2017

 

brokly пишет:

Это не помеха,это код. Ищите ошибку ,сами же написали что включение компрессоров отслеживается Для проверки запивайте схему от аккумулятора или батареек.

Код и схему выложу. По поводу запитывания от аккумуляторов - хорошая идея, попробую.

Так включение/отключение компрессора отслеживается просто чтением пина и установкой соотвествующего флага. Состояние каждую минуту опрашивается. Развязка через оптопару.

У меня мысль, что при отключении компрессора (а там приличный электромагнит) идет мощный скачок напряжения, возможно импульс проходит через блок питания и нанка/ESP его не переваривают.

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

Изначально стояло ESP-01, недавно на ESP-07 поменял с внешней антенной, думал стабильнее будет из-за металлического корпуса, но по ощущениям стало хуже.

Ниже один из графиков - работа компрессоров. Если работает первый - в канал каждую минуту 1 отправляется, если второй, то 2. Видно, что последнее время пару раз оживал во время работы второго компрессора.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

я бы сделал так. подключил дисплей или ноут с открытым монитором порта, а в скетче добавил вывод инфы, и дергал бы управляющий поплавок.. все будет видно что зависает, ардуинка или модуль вайфай.

DenBak
Offline
Зарегистрирован: 30.01.2017

Baks пишет:

я бы сделал так. подключил дисплей или ноут с открытым монитором порта, а в скетче добавил вывод инфы, и дергал бы управляющий поплавок.. все будет видно что зависает, ардуинка или модуль вайфай.

Тоже вариант, соседи конечно офигеют - уже канализацию с ноутбуком настраивают :)

Update: не получится с буком малой кровью - там нанка с одним портом, он уже занят ESP.

Выкладываю код. В 115-120 строке - программный костыль, из-за слишком большого сопротивления резисторов (или малой емкости конденсатора), не очень уверенно определялось включение компрессоров, пришлось исправлять программно.

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

DS18B20 (два) подключены к D3, оптопара 1 компрессора к D5, второго к D7, аварийный поплавок D11, датчик тока к A1.

На выходных буду экспериментировать с питанием.

#include <OneWire.h>
#include <DallasTemperature.h>
#include <avr/wdt.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 3
#define KOMPR_1 5
#define KOMPR_2 7
#define POPLAVOK 11
#define SSID "XXXXXX" //имя сети
#define PASS "XXXXX" //пароль
#define DST_IP "52.7.53.111" //ip web сервера
#define INTERVAL 60000UL //интервал отправки сообщений
#define MAX_KOMP_CIKL 14400000UL //максимальный цикл компрессора 4 часа

const byte id=1; // id устройства
const DeviceAddress addr_vnutr = {0x28,0xC8,0xB9,0x1E,0x00,0x00,0x80,0x3D};
const DeviceAddress addr_water = {0x28,0x44,0x1E,0x04,0x00,0x00,0x80,0xEB};
static unsigned long time_fade=0;
unsigned long pvl=0;
unsigned long kompr1_start=0; //время старта первого компрессора
unsigned long kompr2_start=0; //время старта второго компрессора
unsigned long kompr_run=0; //время работы компрессора
unsigned long nasos_start=0; //время старта насоса
boolean k1=true;
boolean k2=true;
boolean nasos=false; //работает насос

//String ip = "";  //переменная для хранения ip устройства
char character;
char buf[20];

boolean ESPConnected = false;
boolean Error = false;
int ESPSendErrorCounter = 0;
int ESPNumberConnectRetries = 30;


int hardReset = 9; // пин arduino? на котором весит ch_pd

float tempC;
String msg="";

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);



void setup()
{
  wdt_disable();
  wdt_enable (WDTO_8S);
  Serial.begin(115200);
  Serial.setTimeout(5000);
  pinMode(hardReset, OUTPUT);
  pinMode(POPLAVOK,INPUT_PULLUP); //поплавок
  pinMode(KOMPR_1,INPUT_PULLUP); //компрессор 1 - работает если false
  pinMode(KOMPR_2,INPUT_PULLUP); //компрессор 2 - работает если false
  if (!digitalRead(KOMPR_1))
  {
    kompr1_start=millis()+1;
  }
  else
  {
    kompr2_start=millis()+1;
  }
 

  sensors.begin();

  sensors.requestTemperatures();

  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  wdt_reset();
  ESPConnected=connectWiFi();
  while ( !ESPConnected ) { wdt_reset(); delay(7000); wdt_reset(); ESPConnected = connectWiFi(); } 
  digitalWrite(13, HIGH);
  Serial.println("AT+CIPMUX=1");
}

void loop()
{
   
  wdt_reset();
  if (  ESPSendErrorCounter >= 5  )
    { ESPConnected = connectWiFi();
      wdt_reset();
      while ( !ESPConnected ) { wdt_reset(); delay(7000); wdt_reset(); ESPConnected = connectWiFi(); } 
      
      ESPSendErrorCounter=0;
      Serial.println("AT+CIPMUX=1");
      ESPFlushSerial(1000);
    }


    if(millis()-time_fade>INTERVAL)
    {
      time_fade=millis();
      //Читаем температурные датчики
      wdt_reset();
      msg="&field1=";
      msg+=dtostrf(sensors.getTempC(addr_vnutr), 4, 1, buf);
      msg+="&field2=";
      msg+=dtostrf(sensors.getTempC(addr_water), 4, 1, buf);

      sensors.requestTemperatures();


      //работаем с компрессорами
      k1=true;
      k2=true;
      for(int i = 0; i < 100; i++) {
        if (!digitalRead(KOMPR_1)) k1=false;
        if (!digitalRead(KOMPR_2))    k2=false;
        if (!(k1 and k2)) break;
        delay(1);
      }
      if (!k1 and (kompr2_start>0)) //переключился со второго на первый компрессор
      {
        kompr_run=millis()-kompr2_start;
        msg+="&field3=";
        msg+=(unsigned long)(kompr_run/60000);
        kompr2_start=0;
        kompr1_start=millis();
      }
      if (!k2 and (kompr1_start>0)) //переключился с первого на второй компрессор
      {
        kompr_run=millis()-kompr1_start;
        msg+="&field4=";
        msg+=(unsigned long)(kompr_run/60000);
        kompr1_start=0;
        kompr2_start=millis();
      }
      msg+="&field5=";
      if (k1 and k2) msg+="0";
      if (!k1 and !k2) msg+="3";
      else
        if (!k1) msg+="1";
        else
          if (!k2) msg+="2";
      
      //проверяем ток
      float average = 0;
      for(int i = 0; i < 1000; i++) {
        average = average + sq(.0264 * analogRead(A1) -13.523) / 1000;
        delay(1);
      }
      average=sqrt(abs(average));
      msg+="&field6=";
      msg+=dtostrf(average, 4, 3, buf);
      if (average>0.8)
      {
        if (!nasos)
          {
            nasos=true;
            nasos_start=millis();
          } 
      }
      else
      {
        nasos=false;
        nasos_start=0;
      }
      
      wdt_reset();

        //логика рассылки широковещательных сообщений об ошибках
        Error=false;
        digitalWrite(13, LOW);
        if (!digitalRead(POPLAVOK)) //сработал аварийный датчик уровня
        {
          Error=true;
          msg+="&field7=1";
          if(sendUDPMSG(id,1))
          {
            ESPSendErrorCounter = 0;
            digitalWrite(13, HIGH);
          }
          else
          {
            ESPSendErrorCounter++;
          }
        }
        else
        {
         msg+="&field7=0";     
        }
        wdt_reset();
        if ((k1 and k2) or (!k1 and !k2) or (!k1 and (millis()-kompr1_start)>MAX_KOMP_CIKL) or (!k2 and (millis()-kompr2_start)>MAX_KOMP_CIKL) ) //непорядок с циклами компрессоров (больше трех часов)
         {
          Error=true;
          if(sendUDPMSG(id,2))
          {
            ESPSendErrorCounter = 0;
            digitalWrite(13, HIGH);
          }
          else
          {
            ESPSendErrorCounter++;
          }
        }
        wdt_reset();
        if (nasos and (millis() - nasos_start)>180000) //насос работает слишком долго
        {
          Error=true;
          if(sendUDPMSG(id,3))
          {
            ESPSendErrorCounter = 0;
            digitalWrite(13, HIGH);
          }
          else
          {
            ESPSendErrorCounter++;
          }
        }       
        wdt_reset();
        if (!Error) //если все хорошо, то посылаем дежурное сообщение
         {
          if(sendUDPMSG(id,0))
          {
            ESPSendErrorCounter = 0;
            digitalWrite(13, HIGH);
          }
          else
          {
            ESPSendErrorCounter++;
          }
        }
          digitalWrite(13, LOW);
        wdt_reset();
        if(sendMSG(msg))
        {
            ESPSendErrorCounter = 0;
            digitalWrite(13, HIGH);
        }
        else
        {
            ESPSendErrorCounter++;
        }
        msg="";
        wdt_reset();       
       
    }  
}
/*функция отправки сообщения web-серверу*/
boolean sendMSG(String value)
{   
        ESPFlushSerial(100);
        Serial.println("AT+CIPSTATUS");
        delay(300);
        wdt_reset();
        if(!Serial.find("STATUS:3"))       
        {  
          wdt_reset();
          ESPFlushSerial(100);
          String cmd = "AT+CIPSTART=0,\"TCP\",\"";
          cmd += DST_IP;
          cmd += "\",80";
          Serial.println(cmd);
          //Serial.print("Connecting to WebServer ");
          //Serial.println(DST_IP);
          //Serial.println(cmd);
          Serial.flush();
          delay(1000);
          wdt_reset();
        if(Serial.find("OK"))
          {
              //Serial.print("OK, Connected to WebServer ");
              //Serial.println(DST_IP);
              
          }
          else
          {
              //Serial.print("Can not connect to WebServer ");
              //Serial.println(DST_IP);
 
             return false;      
          }
        } 
    wdt_reset();
    ESPFlushSerial(300);  
    String msg= "GET /update?api_key=XXXXXX";      
    msg+= value;
    msg+= " HTTP/1.1\r\nHost: ";
    msg+= DST_IP;
    msg+=  ":80\r\n\r\n";
 
    Serial.print("AT+CIPSEND=0,");
    Serial.println(msg.length());
    //Serial.println("Senting MSG");
    delay(300);
    wdt_reset();
    if (Serial.find(">"))
    {
        //Serial.print("MSG text: ");
        //Serial.println(msg);
        Serial.print(msg);
        wdt_reset();
        Serial.flush();
    }
    delay(300);
    wdt_reset();
    if(Serial.find("SEND OK"))
    {
        Serial.print("AT+CIPCLOSE=0");
        return true;
        
    }
    else
    {
        Serial.print("AT+CIPCLOSE=0");
        return false;
        
    }
}

//функция отправки UDP сообщения

boolean sendUDPMSG(byte modul_id,byte msg_id)
{      
     ESPFlushSerial(1000);
     String cmd = "AT+CIPSTART=4,\"UDP\",\"";
     cmd += "192.168.1.255";
     cmd += "\",48569,1112,0";
     Serial.println(cmd);
     //Serial.print("Connecting to WebServer ");
     //Serial.println(cmd);
     wdt_reset();
     Serial.flush();
     ESPFlushSerial(300);  
     String msg= "+++";      
     msg+= modul_id;
     msg+= msg_id;
     Serial.print("AT+CIPSEND=4,");
     Serial.println(msg.length());
     //Serial.println("Senting MSG");
     delay(300);
     wdt_reset();
     if (Serial.find(">"))
     {
        //Serial.print("MSG text: ");
        //Serial.println(msg);
        Serial.print(msg);
        wdt_reset();
        Serial.flush();
     }
     delay(300);
     wdt_reset();
     if(Serial.find("SEND OK"))
    {
        Serial.print("AT+CIPCLOSE=4");
        return true;
        
    }
    else
    {
       Serial.print("AT+CIPCLOSE=4");
        return false;
        
    }
}


/*функция конекта к wifi сети*/
boolean connectWiFi()
{
    digitalWrite(hardReset, LOW);
    ESPFlushSerial(100);
    digitalWrite(hardReset, HIGH);
    ESPFlushSerial(5000);
    wdt_reset();
    Serial.println("AT+RST");
    ESPFlushSerial(5000);
    wdt_reset();
   // Serial1.println("AT+CSYSWDTENABLE");
   // ESPFlushSerial(100);
    Serial.println("AT+CWMODE=1");
    ESPFlushSerial(1000);
    String cmd="AT+CWJAP=\"";
    cmd+=SSID;
    cmd+="\",\"";
    cmd+=PASS;
    cmd+="\"";
    //Serial.print("Connecting to ");
    //Serial.println(SSID);
    //Serial.println(cmd);
    Serial.println(cmd);
    delay(1000);
    wdt_reset();
    if(Serial.find("OK"))
    {
        //Serial.println("OK, Connected to WiFi.");
       /* ESPFlushSerial(500);
        Serial.println("AT+CIFSR");
        Serial.flush();
        delay(1000);
        while(Serial.available())
        {
            character = Serial.read();
            if(character=='.' || character>='0' && character<='9')
                ip.concat(character);
        }
        if(ip != "")
        {
            //Serial.print("IP Address of ESP8266: ");
            //Serial.println(ip);
        }*/
        ///включаем режим приема/передачи
        ESPFlushSerial(500);
        Serial.println("AT+CIPMODE=0");
        ESPFlushSerial(500);
        wdt_reset();
        return true;
    }
    else
    {
        //Serial.println("Can not connect to the WiFi.");
        ESPFlushSerial(100);
        wdt_reset();
        return false;
    }
}


void ESPFlushSerial(int delaymsec)
{
  delay(delaymsec);
  Serial.flush();
  while ( Serial.available() ) { Serial.read(); }
}

 

GarryC
Offline
Зарегистрирован: 08.08.2016

Если есть лишняя ножка просто поставьте светодиод и мигайте с периодом секунд 5-6 с задержкой после включения на 20 - сразу увидите, если зависает МК. Но, скорее всего, проходит бросок по питанию, который ESP портит, а МК не успевает сброситься.

DenBak
Offline
Зарегистрирован: 30.01.2017

Подключил питание удлинителем от другой фазы. Стабильнее работать не стало...

Отсюда делаю вывод, что все-таки наводки имеют место быть.

Буду пробовать последовательно отключать "периферию". Под основным подозрением - аварийный поплавок (там провод около 3м), выносной термодатчик (провод около 2м) и датчик тока.

Если конечно наводка идет на антенну ESP, тогда вообще печально... 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DenBak пишет:
соседи конечно офигеют - уже канализацию с ноутбуком настраивают :)
Ничо! Перетерпят!

Это ж умный дом, а не хрен собачий! А умный дом - это как-то так

DenBak
Offline
Зарегистрирован: 30.01.2017

Докладываю общественности :)

Проблема все-таки носила частично программный характер. Решение парадоксальное - отказался от ожидания подключения к WI-FI в цикле. Плюс увеличил время низкого уровня на CH_PD со 100 до 500мс для сброса. Ну и вкорячил варистор 431. Что именно из этого помогло - не стал разбираться ибо холодно уже на улице. Не исключено, что ESP после сброса успевало само подключаться к точке доступа до выдачи явной команды на подключение и команда на подключение к этой же точке выдавала ошибку, за счет этого, функция подключения к WI-FI никогда не возвращала TRUE.

При переключении компрессоров теперь иногда бывает пауза в передаче на пару тройку минут, но наглухо не виснет. Уже 10 дней полет нормальный.