Меленький скетчик...

Discriminator

New member
Судьба данного скетчика на усмотрение Администрации. Но "фишка" в следующем:
Из за всяких несостыковок с libm в SDK(отписывался тут, хотя и "ардуиновская" среда не решила проблем/тоже отписывался/), а так же по причине, что макет надо было накидать побыстрее - прибился на время к Arduino IDE (потом переделаю на SDK). Столкнулся с такой ситуацией:

Реализован некий сервер на ESP его задача принять информацию с нескольких разнородных датчиков и отдать микроконтроллеру. Варианта 2:
1. Принимаем информацию с датчиков, аккумулируем ее в некий единый блок и передаем на сервер.
2. Передаем каждый поток данных отдельно как есть, но предусматриваем как сделать чтоб каждый блок уходил целиком.
Пока был выбран второй вариант - чтоб избежать, по возможности, лишней обработки на сервере.
Играясь с размерами приемных буферов и количеством возможных клиентов на сервере удалось добиться(в рамках того что делаю), что сервер не вылетает и вроде как стабильно гонит данные. Но при начальных, хоть и избыточных, условиях, были неоднократные случаи вылета и перезагрузки "серверка", что вело к потере потока данных. Естественно "программная схема" клиента была изначально построена по семплу из IDE:
Код:
/*
*  This sketch sends data via HTTP GET requests to data.sparkfun.com service.
*
*  You need to get streamId and privateKey at data.sparkfun.com and paste them
*  below. Or just customize this script to talk to other HTTP servers.
*
*/

#include <ESP8266WiFi.h>

const char* ssid     = "your-ssid";
const char* password = "your-password";

const char* host = "data.sparkfun.com";
const char* streamId   = "....................";
const char* privateKey = "....................";

void setup() {
  Serial.begin(115200);
  delay(10);

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

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

int value = 0;

void loop() {
  delay(5000);
  ++value;

  Serial.print("connecting to ");
  Serial.println(host);

  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }

  // We now create a URI for the request
  String url = "/input/";
  url += streamId;
  url += "?private_key=";
  url += privateKey;
  url += "&value=";
  url += value;

  Serial.print("Requesting URL: ");
  Serial.println(url);

  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  delay(10);

  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
}

Вобщем, чуток поразмыслив, изменил схему на такую:
Код:
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#define SerialDebug 1   // set to true to get Serial output for debugging

const char* aSSID = "youSSID";
const char* aPassword = "youPassword";
int homePort = 23, astroport = 4242;

WiFiClient MeasClient;
IPAddress astroIP(192,168,4,1), classCMASK(255,255,255,0), astroGW(192,168,4,1);

long count;

void setup() {
  Serial.begin(115200, SERIAL_8N1);
  Serial.println("\r\nIN SETUP!!!\r\n");

  while(1) {
    Serial.print("$PSTMSETPAR,1201,0x01100000*\r\n$PSTMSAVEPAR\r\n");
    if(!Serial.available()) { yield(); continue; }
    size_t len = Serial.available();
    uint8_t sbuf[len];
    Serial.readBytes(sbuf, len);
    if(strstr((const char *)sbuf, "$PSTMSAVEPAROK") || strstr((const char *)sbuf, "$PSTMSAVEPARERROR")) break;
    delay(500);
  }

  WiFi.disconnect();
  WiFi.mode(WIFI_STA);

//  WiFi.begin(aSSID, aPassword);
  WiFi.begin(aSSID);

  count = millis();
}

void loop() {
  uint8_t stat;
  stat = WiFi.status();
  if(stat != WL_CONNECTED && stat != WL_IDLE_STATUS) {
    if(millis() - count > 10000) {
      MeasClient.stop();
      WiFi.disconnect();
      WiFi.begin(aSSID);
      count = millis();
    }
  }

  if(stat == WL_CONNECTED || stat == WL_IDLE_STATUS) {
    if(!MeasClient.connected()) {
      if(MeasClient.connect(astroIP, astroport)) MeasClient.setNoDelay(true);
    }
  }
  while(Serial.available()){
    size_t len = Serial.available();
    uint8_t sbuf[len];
    Serial.readBytes(sbuf, len);
    if(MeasClient.connected()) MeasClient.write(sbuf, len);
  }
  yield();
}

#if SerialDebug
void statuss(wl_status_t stat) {
  switch(stat) {
    case WL_NO_SHIELD: Serial.println("WL_NO_SHIELD"); break;
    case WL_IDLE_STATUS: Serial.println("WL_IDLE_STATUS"); break;
    case WL_NO_SSID_AVAIL: Serial.println("WL_NO_SSID_AVAIL"); break;
    case WL_SCAN_COMPLETED: Serial.println("WL_SCAN_COMPLETED"); break;
    case WL_CONNECTED: Serial.println("WL_CONNECTED"); break;
    case WL_CONNECT_FAILED: Serial.println("WL_CONNECT_FAILED"); break;
    case WL_CONNECTION_LOST: Serial.println("WL_CONNECTION_LOST"); break;
    case WL_DISCONNECTED: Serial.println("WL_DISCONNECTED"); break;
    default: {
      Serial.print("Unknown connect status ");
      Serial.println(stat);
    } break;
  }
}
#endif
После этого соединение вроде как стало "само" восстанавливаться при перезагрузке серверной ESP-шки. Ну по тексту тут у меня заложен 10 секундный таймаут по недоступности сервера...

Маленький комментарий по остальной "специфике" - данный скетч про сериал-порту принимает данные с GPS/GLONASS датчика GL8088s и как есть передает их на "сервер". В начале есть некий диалог "снюхивания" с датчиком - там всего навсего даю посылку чтоб датчик выдавал только строки с текущими временем/датой и текущими координатами без излишней, для моей задачи, информации по спутникам и прочей фигне...
 
Добрый день!
Подскажите пожалуйста:
1. Вы используете стандартную прошивку модуля? или NodeMCu или что то другое?
2. Я правильно понял, что Вы проверяете подключение к WiFI и если нету его, то переподключаетесь? а Вы не пробовали использовать сторожевой таймер (если правильно называю его)?

Заранее спасибо!
 

jmms

Moderator
Команда форума
@PavelNikolaevich Отвечу пока есть пару мыслей на эту тему.

1. Вы используете стандартную прошивку модуля? или NodeMCu или что то другое?
В посте написано Arduino IDE и C++.

2. Я правильно понял, что Вы проверяете подключение к WiFI и если нету его, то переподключаетесь? а Вы не пробовали использовать сторожевой таймер (если правильно называю его)?
А как использовать сторожевой таймер для переподключения? То есть делать просто перезагрузку модуля, если пропало соединение?
 
@PavelNikolaevich Отвечу пока есть пару мыслей на эту тему.


В посте написано Arduino IDE и C++.


А как использовать сторожевой таймер для переподключения? То есть делать просто перезагрузку модуля, если пропало соединение?
Ну да. Просто у меня модуль бывает подвисает именно, и собственно не работает, в таком случае только перезагрузка нужна.
я не говорю Вам как надо делать, просто спрашиваю. А вообще красиво сделано, изучаю, беру на заметку )
 

jmms

Moderator
Команда форума
(Если что статья не моя, скетч интересный, да.) Сторож вроде бы срабатывает при отсутствии активности или зависании на какой-то функции. Самому хочется узнать принцип срабатывания сего механизма. Если кто ни будь прольет свет на данный вопрос, тому большое спасибо!
 
(Если что статья не моя, скетч интересный, да.) Сторож вроде бы срабатывает при отсутствии активности или зависании на какой-то функции. Самому хочется узнать принцип срабатывания сего механизма. Если кто ни будь прольет свет на данный вопрос, тому большое спасибо!
По принципу работы сторожа, как я понял.
1. Активируется сторож
2. выставляется время через которое он перезагрузить должен плату
3. при работе модуля, выполняется команда "Продлить время" или сброс счетчика времени(получается что сторож начинает считать с нуля)
4. пока в программе сбрасывается счетчик, модуль соответтсвенно не перегружается
5. как только счетчик досчитал,(завис модуль или написали большуший код и не вставили в него сброс счетчика) то модул перегружается..

где то натыкался на этом форуме на команды.. wdt.Enable wdt.Feed что то такое.. сам еще не пробовал, поэтому и спросил, думал расскажете )
 
  • Like
Реакции: jmms

Discriminator

New member
Извиняюсь, я временно на "нерегулярном" интернете....
1. Это "собственная" прошивка. Разработана в Arduino IDE(C/C++). Такое своеобразное бутылочное горлышко Arduino API поверх Espressif SDK. Как было написано потом я это сделаю на "чистом" SDK. Многие возможности самого SDK получаются "скрыты". Однако можно и самому API дополнить и при желании достучаться до самих функций.
2. WDT я не использовал. Не помню есть ли в SDK call back функция для WDT, но в ардуиновское API она не вынесена. Однако сам таймер включен по дефолту и при зависаниях исправно перезагружает модуль. В частности мной был сделан такой вывод на зависаниях модуля на тригонометрии... Тут таймер " отсутствия связи" сделан внутри программы. Ну и кроме всего прочего - если я правильно понимаю, WDT служит для отработки зацикливаний и т.п. Посему врятли вы сможете отследить в нем отсутствие связи... Если, конечно ваш алгоритм не зацикливается в отсутствии оной...
 

Discriminator

New member
Ну и мое ИМХО - Arduino API хороший инструмент для "эскизов", а окончательную картину лучше рисовать в SDK(Ну или в чем то подобном с более широким набором доступных функций устройства)
 

kkozyrev

New member
замечательный пример. двигаюсь в вашем направлении. но у меня одна проблемма. :( ESP-шка конектиться к роутеру. получает внутренний ip, но никак не подключается к удаленному сайту.... в чем проблемма?
 

Discriminator

New member
у меня одна проблемма. :( ESP-шка конектиться к роутеру. получает внутренний ip, но никак не подключается к удаленному сайту.... в чем проблемма?
Ну, как вариант, раутер не дает ESP-шке адреса DNS-ов(если, конечно пытаетесь достучаться по "символическому" имени), либо какая та проблема с маршрутизацией в Вашей сети...
 

pvvx

Активный участник сообщества
По принципу работы сторожа, как я понял.
1. Активируется сторож
при инициализации SDK.
2. выставляется время через которое он перезагрузить должен плату
3. при работе модуля, выполняется команда "Продлить время" или сброс счетчика времени(получается что сторож начинает считать с нуля)
4. пока в программе сбрасывается счетчик, модуль соответтсвенно не перегружается
5. как только счетчик досчитал,(завис модуль или написали большуший код и не вставили в него сброс счетчика) то модул перегружается..
Так было в старых SDK. В новых - по другому. Там работает таймер, который перезапускает счетчик WDT + ведется счет исполненных задач (task/post по таблицам). Всё это, включая программные таймеры отрабатывают только из функции ROM-BIOS ets_run(), выхода из которой нет. Она запускается один раз, после инициализации SDK и всё остальное работает из неё по событиям. Она их запускает и распределяет. По старинке, сброс WDT счетчика не поможет :p
 

kkozyrev

New member
Discriminator, ваш первый скетч прекрасно заработал с сайтом sparkfun. Спасибо ;)
Данные отсылаются без пропусков, а в порт ответ от сервера выдается, то постоянно, а то через 3-4 раза.
Вопросик: почему так?
 

Discriminator

New member
@kkozyrev
Первый скетч это какой ? Он у меня один - GPS.ino . Если Вы про WiFiClient.ino - то он не мой - это из примеров, которые идут с Arduino IDE.
Ну а на счет того, что работает через 3-4 раза причины может быть 2:
1. Алгоритм Нейгла - для чего у меня и применено MeasClient.setNoDelay(true);
2. Банальные задержки на сети, в связи с чем надо менять алгоритм этого фрагмента
Код:
// This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  delay(10);
  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }
постоянная задержка(см. delay()) годится только в условиях где Вам гарантировано время ответа и доставки...

UPD: По поводу алгоритма Нейгла. По ситуации можно применить и что-то типа client.flush(); после отправки своих данных.
 
Последнее редактирование:
Сверху Снизу