• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

скетч с конфигуратором в eeprom, сервер и клиент

Vitaly

Member
Возможно надо проверять наличие клиента на AP и ждать, когда он деактивируется.
Вот давно интересовало, через ардуиновые либы есть возможность узнать о подключении клиента к нашей AP
В самих либах ничего не нашел) Наверное пока никак

А про отключении AP и проверки клиентов - если бы это был не режим настройки необходимый раз в полгода, обязательно надо было б проверять.
Но раз это только на время смены настроек точки, то думаю можно оставить как есть.
 

pvvx

Активный участник сообщества
Вот давно интересовало, через ардуиновые либы есть возможность узнать о подключении клиента к нашей AP
В самих либах ничего не нашел) Наверное пока никак
Разве нет доступа к [inline]i = wifi_softap_get_station_num(); // Number count of stations which connected to ESP8266 soft-AP[/inline] ?
Без обработки событий WiFi (wifi_set_event_handler_cb(wifi_handle_event_cb)) жить сложно, т.к. текущий порт Arduino IDE для ESP не многозадачен...
 

random1st

New member
Не нашел я времени переписать скрипт. Я немного другое для себя писал, более узкозаточенное. Вот, выкладываю переписанные процедуры работы с EEPROM:
http://pastebin.com/Tj3EiZbe

Да, еще - нет никакой необходимости писать свой веб-сервер. Есть готовая реализация <ESP8266WebServer.h> -там только обработчики на урлы повесить и все замечательно, поддерживает и post, и get, и параметры парсить умеет (правда, не умеет url_decode и html_escape)
 

kod.begemot

New member
Спасибо большое! Это очень интересно, буду пробовать. Из примеров "в лоб" не получилось, а так намного проще.
И ещё, прошу прощения за "ламерский" вопрос, но - чтобы писать / читать ещё данные, кроме этих, нужно дописать их в структуру "eeprom_data_t", и этого достаточно - правильно?
 

sivix

New member
Не могу загрузить IPиз EEPROM

День добрый! Делаю проект и столкнулся с проблемой. Сохроняю в EEPROM

IPадрес . далее пытаюсь его прочитать и передать IPAddress server(EEPROM.read(7), EEPROM.read(8), EEPROM.read(9), EEPROM.read(10));

Но увы клиент не конектится к серверу. Если прописать все руками то работает. Но мне нужен динамический адрес .
 

Vitaly

Member
ничего не понятно, для tcp подключения адрес используется в строковом виде, не нужен тип IPAddress
чтоб иметь возможность менять адрес лучше использовать dns
работа с еепром в есп нестандартная, учтено ли это:
http://esp8266.ru/arduino-ide-esp8266/#eeprom
Необходимо вызвать функцию EEPROM.begin(size) каждый раз перед началом чтения или записи, размер (указывается в байтах) соответствует размеру данных, которые вы намереваетесь использовать в EEPROM. Размер данных должен быть в диапазоне от 4 до 4096 байт.
итд.
 

sivix

New member
Виталий приветствую! О EEPROM.begin(size) конечно знаю. Все остальные параметры у меня подгружаются. это не важно. Важно то что не работает. Сейчас попытаюсь объяснить. Тут я выкладываю код проблемы, а не свой скетч. Я накидал скетч он прошивается и подключается к WIFI и серверу MQTT. Как вы и говорили можно просто текст для IP адреса передать.
Но проблема осталось.
Начнем по порядку. Что-бы стартануть память нужно вызвать в setup() EEPROM.begin(512) ,до setup не получится . Тем самым переносим ниже setup PubSubClient client(wclient, ip);. Все память стартует записывает изменения в переменную IP, вроде как все должно работать но модуль конектится к адресу указному в месте объявления переменной IP. Далее тестовый код . Я не стал в тестовом коде реализовывать чтение из памяти. А просто создал переменную IP String . до setup. и в setup пытаюсь поменять текст. Но модуль подключается MQTT серверу прописному при объявлении переменной. Вывод в терминал такой. при старте выводит прописанный при создании переменной, после прохождения setup выводит измененный IP. В теории все должно работать. Но по факту берет IP который записан до Setup.
Дело даже не в чтении памяти. И не знаю как быть.

Вывод из терминала

Код:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "DHT.h"
#define DHTPIN D2
#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE,11);

const char *ssid =    ".......";        // cannot be longer than 32 characters!
const char *pass =    "......";        //

// Update these with values suitable for your network.

char* pubTopic = "home/data/#";
char* dev_top = "home/data/device";
char* statTopic = "home/data/status/";
String mqtt_user = "test";
String mqtt_pass = "test";
String mqtt_client_id = "00001";
String mqtt_client = "DHT_sensor";
unsigned long lastMqtt = 0;
boolean callback_set = true;
String ip = "IP сервера MQTT";




void setup() {
  // Setup console
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println(ip);
  dht.begin();
//  client.set_callback(callback);
  ip = "192.168.1.1";
  Serial.println(ip);
}
//IPAddress server(EEPROM.read(7), EEPROM.read(8), EEPROM.read(9), EEPROM.read(10));

WiFiClient wclient;
PubSubClient client(wclient, ip);

void callback(const MQTT::Publish& sub) {
  Serial.print("Get data from subscribed topic ");
  Serial.print(sub.topic());
  Serial.print(" => ");
  Serial.println(sub.payload_string());


  client.publish(statTopic, "test");
  Serial.println(statTopic);

  // echo
  MQTT::Publish newpub(pubTopic, sub.payload(), sub.payload_len());
  client.publish(newpub);
}
void loop() {

   if(callback_set){
     client.set_callback(callback);
     callback_set =false;
 
  }
  if (lastMqtt > millis()) lastMqtt = 0;
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);

    if (WiFi.waitForConnectResult() != WL_CONNECTED)
      return;
    Serial.println("WiFi connected");
  }

  if (WiFi.status() == WL_CONNECTED) {
    if (!client.connected()) {
      if (client.connect(mqtt_client)) {
        client.publish(dev_top, mqtt_client_id);
        float h = dht.readHumidity();
       float t = dht.readTemperature();
       char char_temp[10]; //Временная переменная для перевода Float в char
       char char_hum[10];
       dtostrf(h, 1, 0, char_temp);
       dtostrf(t, 1, 0, char_hum);
       client.publish("home/data/status/sensor/DHT_00001_t", char_temp);
       client.publish("home/data/status/sensor/DHT_00001_h", char_hum);
        client.subscribe("home/data/action/#");
      }
    }

    if (client.connected())
      client.loop();
  }
  if (millis() > (lastMqtt + 50000)) {
    if (!client.connected()) {
      if (client.connect("system_01V_eth")) client.subscribe("home/data/action/#");
    }
    if (client.connected()) {
       float h = dht.readHumidity();
       float t = dht.readTemperature();
       char char_temp[10]; //Временная переменная для перевода Float в char
       char char_hum[10];
       dtostrf(h, 1, 0, char_temp);
       dtostrf(t, 1, 0, char_hum);
       client.publish("home/data/status/sensor/DHT_00001_t", char_temp);
       client.publish("home/data/status/sensor/DHT_00001_h", char_hum);  
    }
    lastMqtt = millis();
  }
}
Может нужно как то по другому передавать IP. проблема только в этом.
 
Последнее редактирование:

sivix

New member
Виталий приветствую! О EEPROM.begin(size) конечно знаю. Все остальные параметры у меня подгружаются. это не важно. Важно то что не работает. Сейчас попытаюсь объяснить. Тут я выкладываю код проблемы, а не свой скетч. Я накидал скетч он прошивается и подключается к WIFI и серверу MQTT. Как вы и говорили можно просто текст для IP адреса передать.
Но проблема осталось.
Начнем по порядку. Что-бы стартануть память нужно вызвать в setup() EEPROM.begin(512) ,до setup не получится . Тем самым переносим ниже setup PubSubClient client(wclient, ip);. Все память стартует записывает изменения в переменную IP, вроде как все должно работать но модуль конектится к адресу указному в месте объявления переменной IP. Далее тестовый код . Я не стал в тестовом коде реализовывать чтение из памяти. А просто создал переменную IP String . до setup. и в setup пытаюсь поменять текст. Но модуль подключается MQTT серверу прописному при объявлении переменной. Вывод в терминал такой. при старте выводит прописанный при создании переменной, после прохождения setup выводит измененный IP. В теории все должно работать. Но по факту берет IP который записан до Setup.
Дело даже не в чтении памяти. И не знаю как быть.

Вывод из терминала

Код:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "DHT.h"
#define DHTPIN D2
#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE,11);

const char *ssid =    ".......";        // cannot be longer than 32 characters!
const char *pass =    "......";        //

// Update these with values suitable for your network.

char* pubTopic = "home/data/#";
char* dev_top = "home/data/device";
char* statTopic = "home/data/status/";
String mqtt_user = "test";
String mqtt_pass = "test";
String mqtt_client_id = "00001";
String mqtt_client = "DHT_sensor";
unsigned long lastMqtt = 0;
boolean callback_set = true;
String ip = "IP сервера MQTT";




void setup() {
  // Setup console
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println(ip);
  dht.begin();
//  client.set_callback(callback);
  ip = "192.168.1.1";
  Serial.println(ip);
}
//IPAddress server(EEPROM.read(7), EEPROM.read(8), EEPROM.read(9), EEPROM.read(10));

WiFiClient wclient;
PubSubClient client(wclient, ip);

void callback(const MQTT::Publish& sub) {
  Serial.print("Get data from subscribed topic ");
  Serial.print(sub.topic());
  Serial.print(" => ");
  Serial.println(sub.payload_string());


  client.publish(statTopic, "test");
  Serial.println(statTopic);

  // echo
  MQTT::Publish newpub(pubTopic, sub.payload(), sub.payload_len());
  client.publish(newpub);
}
void loop() {

   if(callback_set){
     client.set_callback(callback);
     callback_set =false;

  }
  if (lastMqtt > millis()) lastMqtt = 0;
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);

    if (WiFi.waitForConnectResult() != WL_CONNECTED)
      return;
    Serial.println("WiFi connected");
  }

  if (WiFi.status() == WL_CONNECTED) {
    if (!client.connected()) {
      if (client.connect(mqtt_client)) {
        client.publish(dev_top, mqtt_client_id);
        float h = dht.readHumidity();
       float t = dht.readTemperature();
       char char_temp[10]; //Временная переменная для перевода Float в char
       char char_hum[10];
       dtostrf(h, 1, 0, char_temp);
       dtostrf(t, 1, 0, char_hum);
       client.publish("home/data/status/sensor/DHT_00001_t", char_temp);
       client.publish("home/data/status/sensor/DHT_00001_h", char_hum);
        client.subscribe("home/data/action/#");
      }
    }

    if (client.connected())
      client.loop();
  }
  if (millis() > (lastMqtt + 50000)) {
    if (!client.connected()) {
      if (client.connect("system_01V_eth")) client.subscribe("home/data/action/#");
    }
    if (client.connected()) {
       float h = dht.readHumidity();
       float t = dht.readTemperature();
       char char_temp[10]; //Временная переменная для перевода Float в char
       char char_hum[10];
       dtostrf(h, 1, 0, char_temp);
       dtostrf(t, 1, 0, char_hum);
       client.publish("home/data/status/sensor/DHT_00001_t", char_temp);
       client.publish("home/data/status/sensor/DHT_00001_h", char_hum); 
    }
    lastMqtt = millis();
  }
}
Может нужно как то по другому передавать IP. проблема только в этом.
Победа. Нужно делать так.
С начало иниц. клиента
WiFiClient wclient;
PubSubClient client(wclient);
У же потом в setup()
говорим ему IP.
client.set_server(ip,1883);
И все работает.

Все спасибо кто откликнулся.
 

Adney

New member
Дабы не плодить тему, набросал тоже простенькую заготовку сохранения параметров в eeprom. При первом запуске модуль ( у меня esp-01) включается в режиме открытой точки доступа. Далее, по адресу 192.168.4.1 открываем страницу настроек, в которой указываем SSID и пароль точки, к которой надо подключиться, жмем Save и перегружаемся. После перезагрузки модуль цепляется к точке доступа.
Вечер добрый.
Подскажите как переделать Ваш код, что бы запись ssid и пароля была во flesh, а не в eeprom?
 

espeshka

New member
Доброго времени суток, подскажите как добавить в Ваш код доп поля со статикой (ip,msk, gw) для STA?
 

Vitaly

Member
поля в настройку через веб, чтобы сохранялись и использовались при поднятии ста?

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

espeshka

New member
поля в настройку через веб, чтобы сохранялись и использовались при поднятии ста?

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

сделал следующее:
1) >processWeb
Код:
        else if (param.substring(0, addr_start) == "STAstatic")
        {
          param = param.substring(addr_start + 1);
          addr_end = param.indexOf('&');
          if (addr_end != -1)
          {
            lSTASTATIC = param.substring(0, addr_end);
            param = param.substring(addr_end + 1);
          }
          else
            lSTASTATIC = param.substring(0, addr_end);
        }

//--------------
        else if (param.substring(0, addr_start) == "ip0")
        {
          param = param.substring(addr_start + 1);
          addr_end = param.indexOf('&');
          if (addr_end != -1)
          {
            lDTIP0 = param.substring(0, addr_end);
            param = param.substring(addr_end + 1);
          }
          else
            lDTIP0 = param.substring(0, addr_end);
        }

Код:
      if (lSSID.length() > 0  && lHTTPUSER.length() > 0  && lHTTPPASS.length() > 0  &&
          (lSTAenabled == "true" || lSTAenabled == "false") && (lsenderEnabled == "true" || lsenderEnabled == "false")
          && (ldisableAP == "true" || ldisableAP == "false") && (lHTTPAuthEnabled == "true" || lHTTPAuthEnabled == "false")
          && (lSTASTATIC == "static" || lSTASTATIC == "dhcp"))

  if (lSTASTATIC == "static")
  eeprom_data.STASTATIC = true;
  else
  eeprom_data.STASTATIC = false;
в eeprom_data объявил переменные ipA, ipB,ipC,ipD тип byte

далее
String lDTIP0;
String lDTIP1;
String lDTIP2;
String lDTIP3;

lDTIP0.getBytes(eeprom_data.ipA,sizeof(eeprom_data.ipA));
lDTIP1.getBytes(eeprom_data.ipB,sizeof(eeprom_data.ipB));
lDTIP2.getBytes(eeprom_data.ipC,sizeof(eeprom_data.ipC));
lDTIP3.getBytes(eeprom_data.ipD,sizeof(eeprom_data.ipD));

write_settings();

затем веб-форма:
HTML:
    s += "<br>TYPE: <select name=\"STAstatic\">";
    if (eeprom_data.STASTATIC == true)
   {
      s += "<option value =\"true\" selected=\"selected\">static</option>";
      s += "<option value =\"false\">dhcp</option>";
    }
    else
    {
      s += "<option value =\"true\">static</option>";
      s += "<option value =\"false\" selected=\"selected\">dhcp</option>";
    }
s += "</select>";

        s += "<br>IP: <input type=text name=STAip size=16 maxlength=16 value='";
    s += (eeprom_data.ipA,DEC); 

    s += "' />";

далее
Код:
void STAinit() {

  WiFi.begin(eeprom_data.STAssid, eeprom_data.STApass);

  if (eeprom_data.STASTATIC == true)
{
Serial.println("STA network settings:");

union ArrayToInteger {
  byte array[4];
  uint32_t ipint;
};

ArrayToInteger converter;

converter.array[0] = eeprom_data.ipA;
converter.array[1] = eeprom_data.ipB;
converter.array[2] = eeprom_data.ipC;
converter.array[3] = eeprom_data.ipD;
WiFi.config(converter.ipint, IPAddress(192,168,10,1), IPAddress(255,255,255,0));
}

прошу помощи, бьюсь уже который день ни как не могу осилить
 
Последнее редактирование:

Vitaly

Member
немного непонятно - все парсится и сохраняется, но не применяется в момент настройки клиента?

я просто статик пока не пробовал, сложно так говорить
 

espeshka

New member
немного непонятно - все парсится и сохраняется, но не применяется в момент настройки клиента?

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

Vitaly

Member
в какой момент перестает работать? параметры парсит, сохраняет, загружает?

могу у себя скетч запустить глянуть
 

krepton85

Member
Бродил тут по интернету в поисках этой темы и первым делом наткнулся на отличный скетч на данную тематику - конфигуратор mqtt или web сервера через точку доступа + замечательная функция OTA (обновление прошивки по воздуху прямо с браузера).
Что бы скомпилировать этот мультискетч я потратил целый день, оказалось нужно подредактировать библиатеку pubsubclient. В итоге все собралось, все заработало как часы :) Но мне этого мало и я решил увеличить колличество подписок и пабликов mqtt до 4 шт, ну а потом еще и радиоприемник на 315 Мгц что бы с радиобрелков управлять тоже (но до их дело не дашло) в итоге так и не поборол mqtt, удалось только через web интерфейс размножить до 4 каналов.

Сцылка на гитхаб:
ESP_WiFiSwitch/ at master · biohazardxxx/ESP_WiFiSwitch · GitHub
Может кто допилит мне этот чудо скетчь. :)
 

Denis Karasiov

New member
Добрый день.

Возможно, вопрос окажется глупым, но пока мне так не кажется... И в теме не увидел на эту тему постов.

Вот часть кода:
Код:
...
#define EEPROM_START 0;
...
void readSettingsESP() {
  ...
  for (i = EEPROM_START; i < sizeof(eeprom_data); i++)
    { ... }
}
Если я правильно понял, то EEPROM_START - это начало блока памяти в EEPROM, откуда начинается чтение/запись наших данных. Тогда, если этот блок не в начале памяти, а где-то в середине, а блок данных, например, 4 байта. Он работать не будет. Если я правильно понимаю, то должно быть так:
Код:
for (i = EEPROM_START; i < EEPROM_START+sizeof(eeprom_data); i++)
Или я что-то не понял?
 
Последнее редактирование:
Сверху Снизу