ESP8266 NodeMCU не может отправлять команды TCP - такой же код работает на Arduino Uno? - PullRequest
0 голосов
/ 28 марта 2020

Я новичок в этом, так что, надеюсь, глупо очевидный.

Я пытаюсь создать простой датчик температуры / влажности, который берет показания с DHT22 и использует ESP8266, чтобы пинговать их до API Thingspeak для последующего составления графика / хранения и т. Д. c.

Я вставил код ниже - он работал на Arduino Uno, и я пытаюсь сжать его на ESP8266, чтобы я мог производить очень мало температуры датчики по всему дому.

Симптомы

  • Это нормально подключается к Wi-Fi
  • Это генерирует правильную строку API (я проверял вручную вырезая и вставляя его в браузер)
  • Температурные датчики также генерируют правильные показания
  • Возвращается «Ошибка данных!» в последовательном мониторе, предполагая, что это именно та точка в коде, где происходит ошибка

Не могу сказать, странно ли, что переход из Arduino Uno в ESP8266 вызвал проблему (ie требуются разные библиотеки, разные команды TCP и т. д. c)

Любая помощь от более опытного ветерана будет высоко ценится!

Вот фрагмент вывода последовательного монитора и код (просто пароли / apis et c)

22:16:50.266 -> **************
22:16:57.579 -> Wifi Connection Successful
22:16:57.579 -> The IP Address of the Sensor is:192.168.1.211
22:16:57.579 -> Humidity: 41.50
22:16:57.579 -> Temperature: 21.70
22:16:57.579 -> AT+CIPSTART="TCP","api.thingspeak.com",80
22:17:00.574 -> AT+CIPSEND=63
22:17:01.561 -> AT+CIPCLOSE
22:17:02.577 -> Data Fail!
22:17:02.577 -> GET /update?apikey=<REMOVED>&field1=21.70&field2=41.50


#include<stdlib.h>
#include "DHT.h"
#include <ESP8266WiFi.h>

#define SSID "<REMOVED>" //your network name
#define PASS "<REMOVED>" //your network password
#define API "<REMOVED>" //api string
#define IP "api.thingspeak.com" // thingspeak.com
#define DHTPIN 4     // what pin the DHT sensor is connected to
#define DHTTYPE DHT22   // Change to DHT22 if that's what you have
#define Baud_Rate 115200 //Another common value is 9600
#define DELAY_TIME 300000 //time in ms between posting data to ThingSpeak

//Can use a post also
String GET = String("GET /update?apikey=") + API + "&field1=";
String FIELD2 = "&field2=";

//if you want to add more fields this is how
//String FIELD3 = "&field3=";

bool updated;

DHT dht(DHTPIN, DHTTYPE);

//this runs once
void setup()
{
  delay(5000);
  Serial.begin(Baud_Rate);
  // Connect to WIFI
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print("*");
  }

  Serial.println("");
  Serial.println("Wifi Connection Successful");
  Serial.print("The IP Address of the Sensor is:");
  Serial.println(WiFi.localIP()); //Print the IP Address


  //initalize DHT sensor
  dht.begin();
}

//this runs over and over
void loop() {
  float h = dht.readHumidity();
  Serial.print("Humidity: ");
  Serial.println(h);
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float c = dht.readTemperature();
  Serial.print("Temperature: ");
  Serial.println(c);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(c)) {
    Serial.println("Reading DHT22 Failed, exiting");
    return;
  }

  //update ThingSpeak channel with new values
  updated = updateTemp(String(c), String(h));

   //wait for delay time before attempting to post again
  delay(DELAY_TIME);
}

bool updateTemp(String tempC, String humid) {
  //initialize your AT command string
  String cmd = "AT+CIPSTART=\"TCP\",\"";

  //add IP address and port
  cmd += IP;
  cmd += "\",80";

  //connect
  Serial.println(cmd);
  delay(2000);
  if (Serial.find("Error")) {
    return false;
  }

  //build GET command, ThingSpeak takes Post or Get commands for updates, I use a Get
  cmd = GET;
  cmd += tempC;
  cmd += FIELD2;
  cmd += humid;
  cmd += "\r\n";  

  //continue to add data here if you have more fields such as a light sensor
  //cmd += FIELD3;
  //cmd += <field 3 value>

  //Serial.println(cmd);
  //Use AT commands to send data
  Serial.print("AT+CIPSEND=");
  Serial.println(cmd.length());
  if (Serial.find(">")) {
    //send through command to update values
    Serial.print(cmd);
  } else {
    Serial.println("AT+CIPCLOSE");
  }

  if (Serial.find("OK")) {
    //success! Your most recent values should be online.
    Serial.println("Data Sent!");
    return true;
  } else {
    Serial.println("Data Fail!");
    Serial.println(cmd);
    return false;
  }
}

boolean connectWiFi() {
  //set ESP8266 mode with AT commands
  Serial.println("AT+CWMODE=1");
  delay(2000);

  //build connection command
  String cmd = "AT+CWJAP=\"";
  cmd += SSID;
  cmd += "\",\"";
  cmd += PASS;
  cmd += "\"";

  //connect to WiFi network and wait 5 seconds
  Serial.println(cmd);
  delay(5000);

  //if connected return true, else false
  if (Serial.find("OK")) {
    Serial.println("WIFI connected");
    return true;
  } else {
    Serial.println("WIFI not connected");
    return false;
  }
}


Ответы [ 2 ]

1 голос
/ 29 марта 2020

Прежде чем обсуждать проблему, с которой вы столкнулись, вам необходимо понять два различных способа использования ESP8266:

  • Использовать его как модем WiFi;
  • Использовать его в качестве автономного MCU.

При использовании его в качестве модема WiFi вы связываетесь с ним с помощью AT-команды, и по умолчанию это то, что делает большинство модулей ESP8266, он поставляется с At- прошивка команды.

Когда вы используете ESP8266 в качестве MCU, вы набираете sh ESP8266 с эскизом Arduino, который переопределяет прошивку AT-Command и загружает ее с загрузчиком Arduino, и позволяет использовать ESP8266 как автономный MCU, такой как Arduino.

Вы упомянули, что вы можете без проблем общаться с ESP8266 при использовании Arduino Uno, что предполагает, что вы общались с ESP8266 с помощью AT-команды (и вашего кода предположил, что это так).

Когда вы загружаете эскиз Arduino в ESP8266, чтобы использовать его в качестве автономного MCU, вам необходимо соединитесь с ESP8266, используя библиотеку Arduino, такую ​​как ESP8266WiFi, которая позаботится о низком уровне связи с чипом ESP8266. Вот почему вы можете установить sh WiFi, используя возможности, предоставляемые ESP8266WiFi классом.

Однако ваш код в вашем updateTemp() все еще использует AT-команду, которая больше не работает. Вам понадобится либо библиотека ESP8266WebClient, либо ESP8266HTTPClient (эта проще и проще) для установления http-соединения. Вот код, который я изменил для использования библиотеки ESP8266HTTClient для обработки HTTP-запросов. Кстати, код скомпилирован хорошо, но я не тестировал его с сервером thinkpeak, поскольку я не использую thinkpeak и не имею для этого API-ключа.

#include <DHT.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

#define SSID "<REMOVED>" //your network name
#define PASS "<REMOVED>" //your network password
#define API "<REMOVED>" //api string
#define IP "api.thingspeak.com" // thingspeak.com
#define PORT 80
#define DHTPIN 4     // what pin the DHT sensor is connected to
#define DHTTYPE DHT22   // Change to DHT22 if that's what you have
#define BAUD_RATE 115200 //Another common value is 9600
#define DELAY_TIME 300000 //time in ms between posting data to ThingSpeak

DHT dht(DHTPIN, DHTTYPE);

//this runs once
void setup()
{
  Serial.begin(BAUD_RATE);

  // Connect to WIFI
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print("*");
  }
  Serial.println("");
  Serial.println("Wifi Connection Successful");
  Serial.print("The IP Address of the Sensor is:");
  Serial.println(WiFi.localIP());

  //initalize DHT sensor
  dht.begin();
}

//this runs over and over
void loop() {
  float h = dht.readHumidity();
  Serial.print("Humidity: ");
  Serial.println(h);
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float c = dht.readTemperature();
  Serial.print("Temperature: ");
  Serial.println(c);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(c)) {
    Serial.println("Reading DHT22 Failed, exiting");
    return;
  }

  //update ThingSpeak channel with new values
  updateTemp(c, h);

  //wait for delay time before attempting to post again
  delay(DELAY_TIME);
}


bool updateTemp(float tempC, float humid) {

  WiFiClient client;    // Create a WiFiClient to for TCP connection

  if (!client.connect(IP, PORT)) {
   Serial.println("HTTP connection failed");
   return false;
  }

  Serial.println("Sending data to server");
  if (client.connected()) {
    client.print("GET /update?api_key="); client.print(API);
    client.print("&field1="); client.print(String(tempC));
    client.print("&field2="); client.print(String(humid));
    client.println(" HTTP/1.1");
    client.print("Host: "); client.println(IP);
    client.println("Connection: close");
    client.println();    //extra "\r\n" as per HTTP protocol
  }

  // wait for data to be available
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
     Serial.println("HTTP Client Timeout !");
     client.stop();
     return false;
    }
  }

  Serial.println("Receiving HTTP response");
  while (client.available()) {
   char ch = static_cast<char>(client.read());
   Serial.print(ch);
  }
  Serial.println();

  Serial.println("Closing TCP connection");
  client.stop();
  return true;
}
0 голосов
/ 28 марта 2020

Есть три вопроса, которые вы должны решить: Избавьтесь от delay () и я имею в виду не то, что вам не следует время от времени вызывать подпрограммы, чтобы не забивать ваш сервер. Причина: функция delay () останавливает процессор на указанное время.
ОК в программе настройки для ожидания инициализации некоторого HW и ОК для быстрой проверки / отладки простых процедур. ПЛОХАЯ идея в сценарии сервер / клиент (где коммуникационные задачи работают параллельно пользовательским задачам) и смертельно опасна, например, в ESP32 с 2 процессорами. Краткое описание вашей программы.

unsigned long previousMillis = 0; 

setup() {
 ....
} 

loop(){
  if (millis() - previousMillis > DELAY_TIME) {   // we check for elapsed time

   // What ever needs to be done all DELAY_TIME ms  

   previousMillis  = millis(); // we "reset" the timer
   }
// other code which needs no delayed execution
}

Измените также код для Arduino и переведите его на новый уровень -
Второй момент: избавьтесь от класса String и используйте вместо него фиксированные символы.
Класс Reasonthe String имеет плохое управление памятью и ломает вашу кучу, что заставляет ESP рано или поздно обработать sh, символы скомпилированы в fla sh и не имеют этой проблемы. Краткий пример того, как с одной из ваших команд / функций:

// instead of #define API "<REMOVED>" //api String use
const char* API = "<REMOVED>" // pointer to the char API

//Can use a post also
char fixPartGET[128] = '\0';  // takes 255 chars and the terminator, if needed enlarge
char cmd[256] = '\0';  // takes 127 chars and the terminator, if needed enlarge
char numBuffer [16] = '\0'; // we use for float conversions
strcpy (fixPartGET, "GET /update?apikey="); // Copy empties
strcat (fixPartGET, API);
strcat (fixPartGET, "&field1=");
const char* FIELD2 = "&field2=";

setup(){
    ....
}

loop(){
    ....
}

bool updateTemp( float c, float h) {

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

  //build GET command, ThingSpeak takes Post or Get commands for updates, I use a Get
  strcpy(cmd, fixPartGET); // start building the GET command
  // The dtostrf() function converts the double value passed in into an ASCII representation
  dtostrf(c, 6, 2, numBuffer); // change to what you need as precision
  strcat(cmd, numBuffer);
  strcat(cmd, FIELD2);
  dtostrf(h, 6, 2, numBuffer); // change to what you need as precision
  strcat(cmd, numBuffer);
  strcat(cmd, "\r\n");  

  //continue to add data here if you have more fields such as a light sensor
  //strcat(cmd, FIELD3);

  //Some other code to discuss
return true;
}

И в качестве последней точки
Связь WiFi с AP - посмотрите на примеры библиотеки Wi-Fi и избавьтесь от проблем с последовательным AT команды. На данный момент эти команды запускаются по USB-кабелю, а не по WiFi. NodeMCU - это мощная машина по сравнению с Arduino, но гораздо более подверженная нестабильности из-за технической концепции. Мои предложенные изменения 1 и 2 могут и должны быть реализованы на Arduino как первое привыкание к этим методам. Если это работает go для изменения функциональности клиента AT на WiFi на NodeMCU. ESP8266WiFi.h lib примеры WiFiClientBasi c и WiFiClient могут помочь получить быстрые результаты (ищите client.print (...)).

...