Arduino + ESP8266 отправляет POST один раз, но каждый раз терпит неудачу - PullRequest
0 голосов
/ 30 марта 2020

Я использую esp8266 с моим Arduino Mega и управляю им по последовательному каналу с помощью команд AT (я знаю, что это не лучший способ работы с ESP, но я не знал, как это сделать по-другому) ... Так что моя проблема в том, что я сформулировал свой запрос POST и отправил его на мою веб-страницу .... Он отлично работает с первой попытки, но после этого, при каждой попытке l oop, он терпит неудачу ... Пожалуйста, кто-нибудь может проверить мой код и посмотреть, если вы можете найти ошибку, которая может вызвать это?

Это моя функция для отправки данных:

void SendData(){



cmd = "AT+CIPSTART=\"TCP\",\"";
cmd+= server;
cmd+="\",80";
Serial1.println(cmd);
Serial.println(cmd);
delay(1000);
 if(Serial1.find("OK"))
  {
    Serial.println("\r\nReady to send data!");
  }



String retazec="cz="+cas_zaznamu; ////DATA from sensors etc.
retazec=retazec+"&tep="+t;
retazec=retazec+"&vlhv="+vv;
retazec=retazec+"&vlhp="+vp;
retazec=retazec+"&zav="+za;
retazec=retazec+"&kur="+ku;
retazec=retazec+"&vet="+ve;
retazec=retazec+"&pz="+datum_zavlaha;

int retazec_len=retazec.length();
retazec.toCharArray(retaz,70);

cmd = "POST /arduino.php"; ////POST request 
cmd+=" HTTP/1.1\r\n";
cmd+="Host: myhost.com\r\n";
cmd+="Content-Type: application/x-www-form-urlencoded\r\n";
cmd+="Connection:Close\r\n";
cmd+="Content-Length: ";
cmd+=retazec_len;
cmd+="\r\n\r\n";

int size=cmd.length()+retazec_len+2;

Serial1.print("AT+CIPSEND=");
Serial1.println(size);
Serial.print("AT+CIPSEND=");
Serial.println(size);
delay(2000);
if (Serial1.find(">")){
  Serial.println("Sending data...");
} else {
  Serial1.println("AT+CIPCLOSE");
  Serial.println("COnnection closed");
  return;
}
Serial.print(cmd);
Serial1.print(cmd);
for(int i=0;i<=retazec_len;i++){
    Serial.print(retaz[i]);
    Serial1.print(retaz[i]);
  }
 Serial1.print("\r\n");

if(Serial1.find("OK"))
    {
      Serial.println("Succesfuly send!");
    }


ReadString(); /// emptying the buffer by reading serial1
delay(5000); 
Serial.println("-----end");

}

Также у меня есть другая функция для запроса GET, очень похожая на приведенную выше, и она работала несколько раз подряд (не Я хочу сказать, что каждый раз, когда он работал только несколько минут).

Пожалуйста, примите во внимание любые предложения. :)

1 Ответ

0 голосов
/ 30 марта 2020

Мое обоснованное предположение: класс String в сочетании с командами at
Попробуйте избавиться от класса String в веб-сценарии ios. Причина: вы хотите, чтобы стабильная среда работала долгое время. Класс String использует динамическую память для динамического построения и уничтожения базовых структур, которые ему необходимы, например, для добавления строк (... = .. + .. + ..). Так как нет так называемой коллекции garbagge (и памяти в любом случае было бы недостаточно), небольшая память относительного элемента была разрезана на маленькие блоки, в которых (при определенной длине) строка больше не помещается -> cra sh, reset = > потерянный запрос POST или GET.
Используйте фиксированные глобальные массивы (ы) char для создания ваших сообщений, они скомпилированы в fla sh и останавливают «кровотечение из памяти».
Прилагается пример (хотя я не понять - от вашего языка - имя или содержимое переменных и без указания типа, который я должен был угадать)

char retazec[256] = {'\0'}; /* Defined globally - Used for retazec functions max 255 chars */
char cmd[512] = {'\0'}; /* Defined globally - Used for POST/GET functions max 511 chars */
char numBuffer[16] = {'\0'}; /* Defined globally - Used for uint32_t or smaller number conversions to char */
unsigned long timeStamp = 0;
unsigned long delayTime = 2000;

setup(){...}

//The parts you gave "translated"into char manuipulation
const char* cmdStart[] = "POST /arduino.php HTTP/1.1\r\n Host: myhost.com\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection:Close\r\nContent-Length: ";
const char* cmdEnd[] = "\r\n\r\n";  


strcpy (retazec, "cz=");
itoa(cas_zaznamu, numBuffer, 10); // convert int DATA from sensors etc.
// If its a float use this command
// dtostrf(floatvar, StringLengthIncDecimalPoint, numVarsAfterDecimal, charbuf);
// dtostrf(cas_zaznamu, 3, 2, numBuffer); // -> xx.xx
strcat(retazec, numBuffer);
strcat(retazec, "&tep=");
itoa(t, numBuffer, 10);
// or dtostrf(t, 4, 2, numBuffer); // -> xxx.xx
strcat(retazec, numBuffer);
strcat(retazec, "&vlhv=");
....
// ... till datum_zavlaha;

int retazec_len=strlen(retazec); // gives you the length
 // not needed we have a char array allready retazec.toCharArray(retaz,70);

strcpy(cmd, cmdStart);
iota (retazec_len, numBuffer);
strcat(cmd, numBuffer);
strcat(cmd, cmdEnd);

int size=strlen(cmd)+retazec_len+2;
if (millis() - timeStamp > delayTime) {
    Serial1.print("AT+CIPSEND=");
    Serial1.println(size);
    Serial.print("AT+CIPSEND=");
    Serial.println(size);
    timeStamp = millis();
}
// NO NEVER delay(2000);
if (Serial1.find(">")){
   Serial.println("Sending data...");
} else {
   Serial1.println("AT+CIPCLOSE");
   Serial.println("COnnection closed");
   return;
}

Вторая проблема - задержка (она перестает обрабатывать мертвые записи) в вашем случае процессор ждет 2 se c перед перезапуском - не очень хорошая идея при использовании протоколов связи. Я реализовал неблокирующую задержку - если она вам нужна где-то еще, как я уже говорил, вы даете фрагменты кода
EDIT после обратной связи с OP
Следует избегать использования строкового класса в целом в динамике c коммуникационный сценарий ios так во всех частях программы.
Должен ли я использовать одну большую строку (маленький массив s = char), которая просто копирует то, что делает исходный код, но вместо String с массивом char.
Таким образом, imho, структура должна быть просто адаптирована к массиву символов без больших изменений (кроме точного преобразования чисел в символы). Кстати, то же самое происходит, когда вы добавляете переменную в String

uint8_t aNumber = 12;
String myBigString = "A number is " + aNumber;

внутренне в библиотека String такая же, как

uint8_t aNumber = 12;
char numBuffer [16] = {'\0'} ;
char myBigString [32] = {'\0'} ;  
strcpy (myBigString, "A number is ");
iota (aNumber, numBuffer, 10);
strcat (myBigString, numBuffer);

Разница в том, что вы пишете строки, а не лениво используете плохую библиотеку, но с полным контролем над памятью и преимуществом для ее компиляции в fla sh, экономя память , Const char на самом деле вызывается с помощью указателя - поэтому в дальнейшем есть функции, позволяющие получать только определенные части массива, чтобы создавать переменные сообщения из одного большого массива.
После анализа кода на github возникает еще одна большая проблема: использование задержки блокировки ():

loop() {
   delay(1000);

   // lot of code

   delay(3000);
}

заменить неблокируемой задержкой unsigned long timeStamp = 0;

setup(){}

loop() {
  if (millis() - timeStamp > 4000) {

   // lot of code
   timeStamp = millis(); // reset the timer
   }
}

и, как написано ранее, избавиться от всех строк (например)

///////////PREMENNE PRIJIMANÝCH ÚDAJOV///////
String mode;
String inzavlaha;
String inkurenie;
String invetranie;
String invlhkost_p;
String invlhkost_v;
String incas;
String intrvanie;
String inopakovanie;
String inteplota;

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

...