개발자/Arduino

Nano 33 IoT WiFi 연결 불안정을 해결하는 코드

지구빵집 2021. 5. 20. 20:44
반응형

 

 

Nano 33 IoT WiFi 연결 불안정을 해결하는 코드 

 

어떤 방법을 무엇을 시도하든 WiFiNINA를 사용하여 안정적인 WiFi 연결을 관리할 수 ​​없습니다. 평균 12 시간 동안 Nano는 알 수 없는 이유로 연결이 끊어지고 다시 연결해야 합니다. 평균 30 시간 동안 2 분 안에 재 연결이 불가능하고 Watchdog이 나노를 재설정 한 다음 재 연결이 다시 작동합니다.

 

내 액세스 포인트는 Fritz Box 7490입니다. 채널을 변경하지 않도록 AP를 구성했습니다.이 경우에도 연결이 끊어지지만 내 액세스 포인트는 정의된 채널에 남아 있습니다. 비교를 위해 두 번째 나노 33을 리피터 FritzRepeater 1200에 연결했습니다.

 

Nano 33은 모두 최신 펌웨어가 설치되어 있으며 "firmwareVersion ()"에 "1.2.3"으로 표시됩니다. 저는 2 Nano 33 IoT에서 약간 수정된 다른 예제 Scetches (예제 클라이언트가 30 초 모두를 요청하고 예제 서버가 30 초를 모두 요청함)를 실행하고 둘 다 동일한 동작을 보여줍니다. 주변 장치가 없는 하나.

 

WiFi 신호는 -51 및 -67dBm (WiFi.RSSI ())의 강도가 좋습니다. 다시 연결하기 전에 항상 "WiFi.end ()"를 호출하여 재연결이 더 자주 발생하도록 합니다.

 

재연결에 실패하면 "WiFi.reasonCode()"가 한 번만 202 (WIFI_REASON_AUTH_FAIL) 또는 1 (WIFI_REASON_UNSPECIFIED) 동안 거의 표시되지 않지만 대부분의 경우 무한 루프에서 0 이 표시됩니다. 실패한 재 연결은 4 (WL_CONNECT_FAILED), 드물게 255 (WL_NO_SHIELD) 또는 0 (WL_IDLE_STATUS) 상태를 표시합니다.

 

Watchdog은 2 분으로 설정됩니다. (Adafruit_SleepyDog.h 및 Adafruit_ZeroTimer.h 사용). 매초 타이머 ISR에서 WD를 재설정하고 2 분 시간 초과를 직접 추적합니다. 루프의 변수를 시간으로 설정하고 ISR의 시간을 비교하십시오.

 

동일한 네트워크에 있는 Nano 33 IoT 보드는 문제없이 한 달 동안 연결 상태를 유지하길 소망합니다. 

 

loop ()에서 호출된 My Reconnect 코드를 참고하세요. 마지막 검토할 문제는 코드 아래부분의 코멘트를 참고하세요.

 

void reconnectWiFi()
{
  int statusWiFi = WiFi.status();

  // attempt to connect to Wifi network:
  while ( statusWiFi != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    Serial.print("Status: ");
    Serial.println(statusWiFi);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    statusWiFi = WiFi.begin(ssid, pass);
    reconnectCounter ++;
    if( statusWiFi != WL_CONNECTED )
    {
      Serial.print("Connect Fail - call end() wait 5s status:");
      Serial.println(statusWiFi);      

      Serial.print("Reason code: ");
      Serial.println(WiFi.reasonCode());

      // Connect was not successful... retry
      WiFi.end();
      delay( 5000 );
    } else {
      // Give it 1s connected...
      delay( 1000 );
    }
    
  }
}

 

위 코드를 반영한 전체 리필스테이션 오늘자 코드를 울려둔다. 아직은 잘 된다. 중간 중간 재 연결은 피할 수 없다. ㅠ.ㅠ.

 

#include <SPI.h>
#include <WiFiNINA.h> // NANO 33 IoT에서 Wi-Fi 기능을 사용하기 위한 라이브러리 입니다.
#include <PubSubClient.h>
#include <SimpleDHT.h>
#include "arduino_secrets.h"

//please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

//24V on off Relay
int relay_control = 2; //Relay LOW Enable

//define DHT11 pin connection
int pinDHT11 = 9;
SimpleDHT11 dht11(pinDHT11);

//define timer sampling rate 1000=1sec
uint32_t sampleRate = 1000; //sample rate in milliseconds, determines how often TC5_Handler is called

//time variable

uint32_t time_tick_onesecond=0;
uint32_t flag_300seconds = 0;

const char* mqtt_server = "115.68.112.59"; // MQTT 서버를 입력합니다.
const char* mqtt_username = "wapple";
const char* mqtt_password = "refill2021!";
const char* machine_code = "ne0005";

WiFiClient espClient;
PubSubClient client(espClient);

long lastMsg = 0;
char msg[50];
int value = 0;

unsigned char pumpout_flag = 0;
int Loop = 0; // LED의 토글을 위해 사용되는 변수입니다.
String ordercode;
String pubstring;
int pumpout_time;

int reconnectCounter = 0; //insert 20210520

void setup() {
    pinMode(relay_control, OUTPUT);     // 2번 relay control - low enable
    digitalWrite(relay_control, HIGH);
    Serial.begin(9600);
    setup_wifi();

    //setup Timer
    tcConfigure(sampleRate); //configure the timer to run at <sampleRate>Hertz
    tcStartCounter(); //starts the timer

    //setup MQTT server
    client.setServer(mqtt_server, 1883); // Wait----MQTT 서버에 연결합니다.
    if(client.connect(machine_code, mqtt_username, mqtt_password)) //27second
    {
        client.subscribe("operate"); //20210520 insert
        Serial.println("\tMQTT Connected");
    }
    client.setCallback(callback);
    Serial.println("\tSetup End...");
}

void loop() {       
    //여기 MQT 서버 연결 확인
    if (!client.connected()) {
        reconnect();
        Serial.println("\tReconnecting...");
    }
    client.loop();

    // 5분에 한 번씩 보낸다. test는 10초 만들어 
    //client.publish("log", "kawng, re12345, 25.6, 67.4"); //기계코드(string), 온도(float), 습도(float), 정상유무(bool) ->> kawng, re12345, 25.6, 67.4" - 5분 
    //client.publish("complete", "기계코드, T/F");
    // 두번째는 용량 보내면 동작 후 보낸다. 기계코드, T/F

    //flag를 두어야지   
    if(flag_300seconds > 300) //every 5minute send
    {
        send_temphumi();
        flag_300seconds = 0;     
    }

    if(pumpout_flag == 1)
    {    
        // 시간만큼 동작한다.
        pump_operate(pumpout_time);
        pumpout_flag = 0;        
    }

    if(WiFi.status() != WL_CONNECTED)
    {
        setup_wifi();
        Serial.print("reconnected times: ");
        Serial.println(reconnectCounter);

        //setup MQTT server
        client.setServer(mqtt_server, 1883); // Wait----MQTT 서버에 연결합니다.
        if(client.connect(machine_code, mqtt_username, mqtt_password)) //27second
        {
            client.subscribe("operate"); //20210520 insert
            Serial.println("\tMQTT Connected");
        }
        client.setCallback(callback);        
    }
}

/*void setup_wifi() {
    delay(10);
    WiFi.begin(ssid, pass); // 앞서 설정한 ssid와 페스워드로 Wi-Fi에 연결합니다.
    while (WiFi.status() != WL_CONNECTED) 
    { //처음 연결될 때 까지 0.5초 마다 Wi-Fi 연결상태를 확인합니다.
        Serial.println("Connecting WiFi...");
        WiFi.begin(ssid, pass);
        delay(1000);
    }
    //randomSeed(micros()); // 렌덤 문자를 위한 렌덤 시드를 설정합니다.
    Serial.println("Connected to WiFi. print Wifi Status");
    printWifiStatus();
}*/

//setup_wifi replace below code 20210520


//void reconnectWiFi()
void setup_wifi()
{
  int statusWiFi = WiFi.status();

  // attempt to connect to Wifi network:
  while ( statusWiFi != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    Serial.print("Status: ");
    Serial.println(statusWiFi);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    statusWiFi = WiFi.begin(ssid, pass);
    reconnectCounter ++;
    if( statusWiFi != WL_CONNECTED )
    {
      Serial.print("Connect Fail - call end() wait 5s status:");
      Serial.println(statusWiFi);      

      Serial.print("Reason code: ");
      Serial.println(WiFi.reasonCode());

      // Connect was not successful... retry
      WiFi.end();
      delay( 5000 );
    } else {
      // Give it 1s connected...
      delay( 1000 );
    }
    
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
    // Topic에 메시지가 도착하면 실행되는 콜백입니다.
    //Serial.println(length);

    String myString = String((char *)payload);
    String realString = myString.substring(0, length);
    Serial.println(myString.length());
    Serial.println(realString);

    //parsing: 기계코드와 용량 분리
    /// 서버에서 용량을 보낸다. 기계코드, 추출량 ml, 주문번호(추출 완료 후 다시 보낸다)
    int first = realString.indexOf(","); // 첫번째 콤마위치
    int second = realString.indexOf(",",first+1); // 두번째 콤마 위치
    int third = realString.indexOf(",",second+1); // 세번째 콤마 위치
    int strlength = realString.length(); // 문자열 길이
    String str1 = realString.substring(0, first); // 첫번째 토큰
    String str2 = realString.substring(first+1, second); // 두번째 토큰*/
    ordercode = realString.substring(second+1, strlength); // 세번째 토큰*/
    Serial.println(str1);
    Serial.println(str2);
    Serial.println(ordercode);

    pumpout_time = str2.toInt();
    if(str1 == machine_code) //머신코드가 자기라면
    {
        Serial.print("pump operate time");
        Serial.println(str1);
        pumpout_flag = 1;
    }    
}

void pump_operate(int pump_out_time)
{
    //pump_out_time = 57;
    Serial.print(pump_out_time);
    Serial.println(" * 100msecond pump on");
    
    digitalWrite(relay_control, LOW);
    delay(pump_out_time * 100);
    digitalWrite(relay_control, HIGH);    
    
    pubstring="";
    pubstring = machine_code;
    pubstring += ",";
    pubstring += ordercode;
    pubstring += ",";
    pubstring += "T";
    Serial.print(pubstring);
    //client.publish("complete", toCharArray(pubstring));
    if(!client.connected()) 
    {
        client.connect(""); // 앞서 설정한 클라이언트 ID로 연결합니다.
        client.subscribe("operate"); // inTopic 토픽을 듣습니다. topic 츨 구독
    }
    if (client.connected()) 
    {
        client.publish("complete", toCharArray(pubstring));
        Serial.print("complete");
    }  
}

/*void reconnect() {
    while (!client.connected()) {
//       String clientId = "ArduinoNANO33IoTClinet-"; // 클라이언트 ID를 설정합니다.
//        clientId += String(random(0xffff), HEX); // 같은 이름을 가진 클라이언트가 발생하는것을 방지하기 위해, 렌덤 문자를 클라이언트 ID에 붙입니다.
//        if (client.connect(clientId.c_str())) 
        { // 앞서 설정한 클라이언트 ID로 연결합니다.
            if (client.connect("")) 
            { // 앞서 설정한 클라이언트 ID로 연결합니다.
                client.subscribe("operate"); // inTopic 토픽을 듣습니다. topic 구독
            } 
            else 
            {
                delay(1000); //5000
            }
        }
    }
}*/
void reconnect()
{
     //setup MQTT server
     client.setServer(mqtt_server, 1883); // Wait----MQTT 서버에 연결합니다.
     if(client.connect(machine_code, mqtt_username, mqtt_password)) //27second
     {
        client.subscribe("operate"); //20210520 insert
        Serial.println("\tMQTT Connected");
     }
     client.setCallback(callback);
}

void send_temphumi()
{
    //Serial.println("=================================");
    //Serial.println("Sample DHT11...");
  
    // read without samples.
    byte temperature = 0;
    byte humidity = 0;
    int err = SimpleDHTErrSuccess;
    if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
        Serial.print("Read DHT11 failed, err="); Serial.print(SimpleDHTErrCode(err));
        Serial.print(","); Serial.println(SimpleDHTErrDuration(err)); delay(1000);
        return;
    }
  
    //Serial.print("Sample OK: ");
    //Serial.print((int)temperature); Serial.print(" *C, "); 
    //Serial.print((int)humidity); Serial.println(" H");
    
    pubstring="";
    pubstring = machine_code;
    pubstring += ",";
    pubstring += String((int)temperature);
    pubstring += ",";
    delay(500);  
    pubstring += String((int)humidity);
    pubstring += ",";
    pubstring += "T";

    client.publish("log", toCharArray(pubstring));
    Serial.print(pubstring);
}

char* toCharArray(String str) {
  return &str[0];
}

//void publish(string doc, string topic) {
//  client.publish(toCharArray(topic), toCharArray(buffer));
//}


void printWifiStatus() 
{
    // print the SSID of the network you're attached to:
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());

    // print your board's IP address:
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);

    // print the received signal strength:
    long rssi = WiFi.RSSI();
    Serial.print("signal strength (RSSI):");
    Serial.print(rssi);
    Serial.println(" dBm");
}

//온도 습도 데이터를 수집하여 5분에 한번 보낸다. 데이터는 int
int get_temp()
{
  //delay(2000);
  byte temperature = 0;
  byte humidity = 0;
  
  if (dht11.read(pinDHT11, &temperature, &humidity, NULL)) {
    Serial.print("Read DHT11 temp failed.");
    return 0;
  }
  else{
    return (int)temperature;  
  }
}

int get_humi()
{
  //delay(2000);
  byte temperature = 0;
  byte humidity = 0;
  
  if (dht11.read(pinDHT11, &temperature, &humidity, NULL)) {
    Serial.print("Read DHT11 humi failed.");
    return 0;
  }else{
    return (int)humidity;
  }
}




void test_topic_split()
{
  String readTopic="abcdefghijklmn,300";
  int length = readTopic.length();
  Serial.println(length);
  String readTopicLength = readTopic.substring(0, length);
 
  //parsing: 기계코드와 용량 분리
  /// 서버에서 용량을 보낸다. 기계코드, 추출량 단위는 ml
  int first = readTopicLength.indexOf(","); // 첫번째 콤마위치
  int second = readTopicLength.indexOf(",",first+1); // 두번째 콤마 위치
  int strlength = readTopicLength.length(); // 문자열 길이
  String str1 = readTopicLength.substring(0, first); // 첫번째 토큰
  String str2 = readTopicLength.substring(first+1, second); // 두번째 토큰
  Serial.println(str1);
  Serial.println(str2);

  int operationTime = str2.toInt();
  
}


//Here Start Timer function
//this function gets called by the interrupt at <sampleRate>Hertz

void TC5_Handler (void) {
  //YOUR CODE HERE  
  time_tick_onesecond++;
  flag_300seconds++;

  Serial.println(time_tick_onesecond);
  
  // END OF YOUR CODE
  TC5->COUNT16.INTFLAG.bit.MC0 = 1; //Writing a 1 to INTFLAG.bit.MC0 clears the interrupt so that it will run again
}


/* 
 *  TIMER SPECIFIC FUNCTIONS FOLLOW
 *  you shouldn't change these unless you know what you're doing
 */

//Configures the TC to generate output events at the sample frequency.
//Configures the TC in Frequency Generation mode, with an event output once
//each time the audio sample frequency period expires.
 void tcConfigure(int sampleRate)
{
 // select the generic clock generator used as source to the generic clock multiplexer
 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ;
 while (GCLK->STATUS.bit.SYNCBUSY);

 tcReset(); //reset TC5

 // Set Timer counter 5 Mode to 16 bits, it will become a 16bit counter ('mode1' in the datasheet)
 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
 // Set TC5 waveform generation mode to 'match frequency'
 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
 //set prescaler
 //the clock normally counts at the GCLK_TC frequency, but we can set it to divide that frequency to slow it down
 //you can use different prescaler divisons here like TC_CTRLA_PRESCALER_DIV1 to get a different range
 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024 | TC_CTRLA_ENABLE; //it will divide GCLK_TC frequency by 1024
 //set the compare-capture register. 
 //The counter will count up to this value (it's a 16bit counter so we use uint16_t)
 //this is how we fine-tune the frequency, make it count to a lower or higher value
 //system clock should be 1MHz (8MHz/8) at Reset by default
 TC5->COUNT16.CC[0].reg = (uint16_t) (SystemCoreClock / sampleRate);
 while (tcIsSyncing());
 
 // Configure interrupt request
 NVIC_DisableIRQ(TC5_IRQn);
 NVIC_ClearPendingIRQ(TC5_IRQn);
 NVIC_SetPriority(TC5_IRQn, 0);
 NVIC_EnableIRQ(TC5_IRQn);

 // Enable the TC5 interrupt request
 TC5->COUNT16.INTENSET.bit.MC0 = 1;
 while (tcIsSyncing()); //wait until TC5 is done syncing 
} 

//Function that is used to check if TC5 is done syncing
//returns true when it is done syncing
bool tcIsSyncing()
{
  return TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
}

//This function enables TC5 and waits for it to be ready
void tcStartCounter()
{
  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; //set the CTRLA register
  while (tcIsSyncing()); //wait until snyc'd
}

//Reset TC5 
void tcReset()
{
  TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
  while (tcIsSyncing());
  while (TC5->COUNT16.CTRLA.bit.SWRST);
}

//disable TC5
void tcDisable()
{
  TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
  while (tcIsSyncing());
}
// end of code.

 

아래 코멘트 포럼의 주소를 연결한다. 문제는 언제나 아무때고 발생한다. 우리는 해결한다. 포럼의 다른 주소를 참고.

 

  • bastelbastler : Nano 33에는 최신 펌웨어가 설치되어 있으며 "firmwareVersion ()"에 "1.2.3"으로 표시됩니다. 최신 NINA 펌웨어는 1.3.0입니다. Arduino IDE 1.8.12로 업데이트하고 펌웨어를 업데이트 한 다음 다시 테스트하여 문제가 계속 발생하는지 확인하십시오.
  • @ bastelbastler의 버그 보고서 : https://github.com/arduino-libraries/WiFiNINA/issues/103
  • 응용 프로그램의 연결이 끊겼을 때를 감지하고 그 위에 사용중인 WiFi 및 기타 프로토콜을 다시 시작해야합니다. 예 : UDP 및 MQTT. 내 테스트 보드가 일주일 이상 실행되었으며 내 Wi-Fi에 다시 연결됩니다. 그 시간 동안 30 개의 재 연결 이벤트가 있지만 그 외에는 모든 것이 잘 작동합니다. 따라서 WiFi 모듈은 소프트웨어로만 관리 할 수 ​​있으며 지금까지 전원을 껐다 켜거나 하드 리셋 할 필요가 없습니다. 애플리케이션을 견고하게하려면 다른 보드에도 필요합니다. 몇 달에 한 번 씩만 필요할 수 있지만 동일한 솔루션이 있습니다.
  • 안녕하세요 Klaus_K, 예, Reconnect는 대부분의 경우 몇 주에 걸쳐 작동합니다. 또한 한 달을 실행하려면 어떤 시점에서 다시 연결이 더 이상 작동하지 않기 때문에 워치 독과 함께 몇 주 동안 재설정해야합니다. 그러나 : 여전히 중요한 버그입니다. 그리고 여전히 단절이 있습니다-이제 당신도 증명했습니다. 이것은 정상이 아니며 ESP32와 같은 보드는 중단없이 한 달 동안 연결 상태를 끊지 않습니다. 다시 연결하는 것은 견고성을위한 해결 방법이며 필수 사항입니다. 이러한 모든 연결 해제로 인해 Nano 33은 많은 애플리케이션에 사용할 수 없습니다. 스마트 홈에서 조명을 켜기위한 간단한 존재 감지기를 상상해보십시오. 방에 들어갔을 때 1 분 동안 WiFi가 없어서 100 번 중 1 번 작동하지 않습니다. 경보 장비, 수중 경보기, 블라인드 용 바람 센서, 전기차를 연결하는 순간의 충전소에 대해 이야기하지 않습니다 .... 대부분의 애플리케이션에서 몇 시간 동안 1 분 동안 오프라인 상태로있는 것은 허용되지 않습니다. ... 죄송하지만 Smart Home 또는 대부분의 다른 IOT 장치의 경우 현재 Nano 33은 빈번한 연결 끊김으로 인해 사용할 수 없습니다. 나는 이것에 더 많은 관심이없는 이유를 상처 입히고, 정말 멋진 보드를 실질적으로 쓸모 없게 만듭니다.
  • Klaus_K : 애플리케이션의 연결이 끊겼을 때이를 감지하고 그 위에서 사용중인 WiFi 및 기타 프로토콜을 다시 시작해야합니다. 예 : UDP 및 MQTT. 내 테스트 보드가 일주일 이상 실행되었으며 내 Wi-Fi에 다시 연결됩니다. 그 시간 동안 30 개의 재 연결 이벤트가 있지만 그 외에는 모든 것이 잘 작동합니다. 따라서 WiFi 모듈은 소프트웨어로만 관리 할 수 ​​있으며 지금까지 전원을 껐다 켜거나 하드 리셋 할 필요가 없습니다.
  • UdoZucker '20 5월 확인을 위해서만 : 나는 현재 세 개의 Nano 33 IoT를 실행하고, 모두 서로 다른 센서를 연중 무휴 24 시간 모니터링하며, 60 초마다 로컬 웹 서버에서 데이터를 선택합니다. 모든 Nano 33 IoT는 수시로 연결이 끊어집니다. 때로는 자주, 다른 때는 더 드물게. 이러한 연결 끊김에 대한 패턴을 볼 수 없습니다. 제 경우에는 펌웨어 1.3.0으로 업그레이드해도 눈에 띄는 차이가 없습니다 (이 문제에서). "유일한"해결 방법은 위의 Klaus_K가 제안한대로 이러한 연결 해제를 감지 한 다음 다시 연결을 시도하는 동안 내 센서 판독 값을 버퍼링하고 성공적으로 해당 버퍼를 전송하는 코드를 추가하는 것입니다. 1 x FritzBox 2400 및 3 x FritzBox 1200으로 구성된 메시에 걸쳐있는 FritzBox 7490을 사용합니다. 제가 관찰 할 수있는 것은 이러한 연결 끊김이 rssi 불량으로 인한 것이 아니라는 것입니다. Nano 33 IoT는 훌륭한 장치이지만 위에서 말했듯이 Nano 33 IoT는 WiFi가 더 안정적인 경우 IoT에 정말 훌륭한 마이크로 일뿐입니다.
  • WiFi 코드를 별도의 기능에 배치하고이를 작은 단계로 나누었습니다. 각 단계는 switch 문의 케이스입니다. 이것은 함수를 상태 머신으로 바꿉니다. 단계는 WiFi 하드웨어 확인 WiFi 네트워크에 연결 MQTT 브로커에 연결 수신 콜백 설정 및 주제 구독 MQTT 클라이언트 폴링 및 브로커 연결 여부 확인 MQTT 메시지 보내기 MQTT 메시지 보내기 ... MQTT 메시지를 보내고 상태를 다시 폴링으로 설정 기본적으로 모든 상태 변수 지우기, 모든 프로토콜 중지, WiFi 연결 해제, WiFi 종료 트로프 루프를 실행할 때마다 함수를 호출합니다. 문제가있을 때마다 다음 번에 기본값을 트리거하는 값으로 상태를 설정합니다. 궁금한 점이 있으면 알려주세요. 예를 들어 게시하려면 스케치를 약간 잘라야합니다.
  • 최근에 해결되었다고 생각했지만 아니요. 며칠마다 라우터와 인터넷 연결이 끊어집니다. 저는 독일에서 수입 한 Fritzbox 라우터, Adafruit AirLift FeatherWing ESP32가 장착 된 Metro Mini를 사용하고 있습니다. Adafruit의 WiFiNINA 포크를 사용하고 있습니다. 구독이 아닌 MQTT 브로커에만 게시하고 있습니다. 잠재적 인 연결 끊김을 포착하기 위해 항상 직렬 인쇄를 위해 랩톱을 연결된 상태로 둘 수 없기 때문에 FeatherWing의 온보드 RGB LED를 사용하여 설정 상태를 알려 주려고했습니다. 분명히 내 코드가 옳지 않거나 라우터에 특이한 것이 있거나 코드 재 연결의 타이밍 또는 다른 것이 있습니다. 연결이 끊어지면 (MQTT 브로커가 더 이상 들어오는 데이터를 표시하지 않음) 다시 연결이 중단되는 위치를 찾기 위해 주황색 또는 청록색 RGB LED 피드백을받지 못합니다. 흥미롭게도 USB를 통해 설정을 내 노트북에 연결하고 다시 업로드하거나 설정의 재설정 버튼을 눌러도 효과가 없습니다. 약 10 ~ 20 초 동안 만 전원을 차단하면 설정이 라우터, 인터넷 및 MQTT 브로커에 다시 연결되는 것을 볼 수 있습니다. GitHub ESP32 스레드에서 " WL_Connected"는 ESP에 IP 주소가 있는지 확인하기 때문에 완벽하지 않습니다. ESP는 Wi-Fi 연결이 끊어진 후 "및" if (WiFi.status ()! = WL_CONNECTED)는 ESP에 WLAN 액세스 권한이 있지만 아직 라우터에서 DHCP를 통해 IP 주소를받지 못한 경우 true를 반환합니다. 다른 함수가 (MQTT 브로커와 같은) 게시를 원할 때 필연적으로 거기에 멈출 것입니다. "그러나 아무도 거기에 안전 장치가없는 것 같습니다. 안정적으로 다시 연결하는 방법에 대한 제안이 있습니까? 당신이 해결 한 것처럼 들렸다.
  • Arduino Nano 33 IoT의 예입니다. ArduinoMqttCLient 라이브러리가 필요합니다. 또한 MQTT 브로커 IP 및 포트에 대해 두 줄로 arduino_secrets 파일을 확장해야합니다.

 

위 코멘트에 대해 도움을 주는 샘플 코드 2개는 아래와 같다.

 

void loop()
{
  connectToWLAN();
  connectToMQTT();

  readSensors();
  feed.publish(data);
}


void connectToWLAN()
{
  if (WiFi.status() == WL_NO_MODULE)
  {
    WiFi.setLEDs(0, 255, 255); // Magenta = WLAN module malfunction
    while (true);
  }

  if (WiFi.status() == WL_CONNECTED)
  {
    return;
  }

  WiFi.setLEDs(96, 255, 0); // Orange = no WLAN router connection yet

  do
  {
    status = WiFi.begin(WLAN_SSID, WLAN_PASS);
    delay(100);
  }
  while (status != WL_CONNECTED);

  WiFi.setLEDs(224, 255, 0); // Yellow = WLAN router connection established
  delay(3000); // To better see the status indicating RGB LED's state
}


void connectToMQTT()
{
  if (mqtt.connected())
  {
    return;
  }

  int8_t MQTTerrorString;

  while ((MQTTerrorString = mqtt.connect()) != 0)
  {
    if (MQTTerrorString >= 0)
    {
      mqtt.disconnect();

      WiFi.setLEDs(255, 0, 255); // Cyan = MQTT connection failed
      delay(3000); // Wait before returning to loop() and trying again
    }
  }

  WiFi.setLEDs(255, 0, 0); // Green = MQTT broker connection established
  delay(3000); // To better see the status indicating RGB LED's state
}

 

집요하다. 영악하다. 몰입하다. 가차없다. 남김없다. 전부다. 그만이다. 전부였다.

 

/*
  WiFi MQTT Sender example

  The wifiTask will continously attempt to connect when the connection to the MQTT broker is lost.

  The circuit:
  - Arduino Nano 33 IoT,

  This example code is in the public domain.
*/

#include <SPI.h>
#include <WiFiNINA.h>
#include "arduino_secrets.h"
#include <ArduinoMqttClient.h>

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

//----------------------------------------------------------------------------------------------------------------------
// MQTT
//----------------------------------------------------------------------------------------------------------------------

WiFiClient wifiClient;
MqttClient mqttClient( wifiClient );

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
const char broker[] = MQTT_BROKER_IP;     // e.g. "192.168.XXX.XXX"
int        port     = MQTT_BROKER_PORT;   // e.g. 1883

const char topicDeviceName[] = "nano33iot/name";
const char topicMqttReconnectCount[] = "nano33iot/mqtt_rcc";

bool newDataRecorded = false;

int WIFI_LED_PIN =  LED_BUILTIN;

void setup()
{
  Serial.begin( 9600 );
  // while ( !Serial );

  pinMode( WIFI_LED_PIN, OUTPUT );

  Serial.println( "WiFi MQTT Example" );
}


void loop()
{
#define INTERVAL 60 * 1000
  static unsigned long previousMillis = 0;

  wifiTask();

  // Run your code here
  // Do not use delay
  unsigned long currentMillis = millis();
  if ( currentMillis - previousMillis > INTERVAL )
  {
    previousMillis = currentMillis;

    newDataRecorded = true;
  }

  loopAnalysis();
}

void wifiTask( void )
{
  static int state = 0;
  static int wifiConnectTry = 0;
  static int mqttConnectTry = 0;
  static int mqttReconnectCount = 0;
  static int wifiStatus = WL_IDLE_STATUS;
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = 0;

#define WIFI_CONNECT_TIMEOUT 10000
#define WIFI_MQTT_POLL_INTERVALL 10

  enum WIFI_STATE_TYPE { WIFI_CONNECT,
                         WIFI_MQTT_CONNECT,
                         WIFI_MQTT_SUBSCRIBE,
                         WIFI_MQTT_POLL,
                         WIFI_MQTT_SEND_NAME,
                         WIFI_MQTT_SEND_RCC,
                         WIFI_STATE_RESTART = 255
                       };
  switch ( state )
  {
    case WIFI_CONNECT:
      if ( wifiStatus == WL_CONNECTED )
      {
        state++;
        digitalWrite( WIFI_LED_PIN, HIGH );
        break;
      }
      if ( millis() - previousMillis < WIFI_CONNECT_TIMEOUT && wifiConnectTry > 0 )
      {
        // just continue with rest of program for now
        break;
      }
      if ( wifiConnectTry > 10 )
      {
        // could not connect, clear everything and try again later
        state = WIFI_STATE_RESTART;
        break;
      }
      wifiStatus = WiFi.begin( ssid, pass );
      previousMillis = millis();
      wifiConnectTry++;
      Serial.print( "Try: " );
      Serial.print( wifiConnectTry );
      Serial.print( " Status: " );
      Serial.println( wifiStatus );
      break;
    case WIFI_MQTT_CONNECT:
      if ( mqttClient.connect( broker, port ) )
      {
        state++;
        Serial.println( "MQTT broker connected" );
      }
      else
      {
        mqttConnectTry++;
        if ( mqttConnectTry > 10 )
        {
          state = WIFI_STATE_RESTART;
        }
      }
      break;
    case WIFI_MQTT_SUBSCRIBE:
      // set the message receive callback
      // mqttClient.onMessage( onMqttMessage );

      // mqttClient.subscribe( topicDateTime );

      state++;
      break;
    case WIFI_MQTT_POLL:
      currentMillis = millis();
      if ( currentMillis - previousMillis > WIFI_MQTT_POLL_INTERVALL )
      {
        previousMillis = currentMillis;
        // call poll() regularly to allow the library to send MQTT keep alives which
        // avoids being disconnected by the broker
        mqttClient.poll();

        if ( !mqttClient.connected() )
        {
          state = WIFI_STATE_RESTART;
          mqttReconnectCount++;
          break;
        }
      }

      if ( newDataRecorded )
      {
        newDataRecorded = false;
        state++;
      }
      break;
    case WIFI_MQTT_SEND_NAME:
      mqttClient.beginMessage( topicDeviceName );
      mqttClient.print( "Nano 33 IoT" );
      mqttClient.endMessage();

      state++;
      break;
    case WIFI_MQTT_SEND_RCC:
      mqttClient.beginMessage( topicMqttReconnectCount );
      mqttClient.print( mqttReconnectCount );
      mqttClient.endMessage();

      state = WIFI_MQTT_POLL;
      break;
    default:
      state = 0;
      wifiConnectTry = 0;
      mqttConnectTry = 0;
      wifiStatus = WL_IDLE_STATUS;
      WiFi.disconnect();
      WiFi.end();
      digitalWrite( WIFI_LED_PIN, LOW );
      Serial.println( "WiFi restart" );
      break;
  }
} // wifiTask


// void onMqttMessage( int messageSize )
// {

// }



void loopAnalysis()
{
  static unsigned long previousMillis = 0;
  static unsigned long lastMillis = 0;
  static unsigned long minLoopTime = 0xFFFFFFFF;
  static unsigned long maxLoopTime = 0;
  static unsigned long loopCounter = 0;

#define INTERVAL 1000

  unsigned long currentMillis = millis();
  if ( currentMillis - previousMillis > INTERVAL )
  {
    Serial.print( "Loops: " );
    Serial.print( loopCounter );
    Serial.print( " ( " );
    Serial.print( minLoopTime );
    Serial.print( " / " );
    Serial.print( maxLoopTime );
    Serial.println( " )" );
    previousMillis = currentMillis;
    loopCounter = 0;
    minLoopTime = 0xFFFFFFFF;
    maxLoopTime = 0;
  }
  loopCounter++;
  unsigned long loopTime = currentMillis - lastMillis;
  lastMillis = currentMillis;
  if ( loopTime < minLoopTime )
  {
    minLoopTime = loopTime;
  }
  if ( loopTime > maxLoopTime )
  {
    maxLoopTime = loopTime;
  }
}

 

 

 

 

 

 

 

어디서 가져온건지

 

 

 

반응형