• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Как я "переползал" с Ардуйни 2.4.2 на Ардуюню 3.0.2

Mоnk

Member
Долго "сидел" на 2.4.2, потому что бинарники, скомпилированные в следующих за ядром 2.4.2 итерациях, через WebUpdate во флеш китайских "умных" розеток не влезали. Не лезет 483к в ESP8285, который к тому же 1Мх128К. Пользуюсь до сих пор IotManager версии 1.5.5, причем без json. Ну нравится мне, и все тут.

Однако все течет, все изменяется. Решил "прикрутить" ТелеграммБот, и понеслось... Бот от Гайвера с BearSSL заработал начиная с 2.5.0. Мелочится не стал, накатил 3.0.2. Бинарник на простом градуснике с часами по рассчета ArduinoIDE получился размером 54%, что и следовало ожидать.

Первое, что перестало работать, ESP8266 sketch data upload. Google изрядно потупел за последние годы, поэтому поиск решения занял немалое время с установкой Питона и другими ненужными танцами. Случайно наткнуля на ссылку https://github.com/esp8266/arduino-esp8266fs-plugin/releases, снес все лишнее, закинул папку ESP8266FS пятой версии сюда => C:\Program Files (x86)\Arduino\tools, и загрузка SPIFFS по кабелю заработала.

Дальше. Почему-то перестали прилетать push уведомления от onesignal.com. Понятно почему (теперь). Потому что теперь после "WiFiClientSecure push_client;" надо добавить "push_client.setInsecure();".
C++:
// ================================= Push notifications ==================================

void push(String push_msg)
{
  if (WiFi.status() == WL_CONNECTED)              // если подключились
  {
    WiFiClientSecure push_client;
    [B]push_client.setInsecure();[/B]
    if (!push_client.connect("onesignal.com", 443)) return;

    String push_data = F("{\"app_id\": \"8871958c-5f52-11e5-8f7a-c36f5770ade9\",\"include_player_ids\":[\"") + ids + F("\"],\"android_group\":\"IoT Manager\",\"contents\": {\"en\": \"") + push_msg + "\"}}";

    push_client.println("POST /api/v1/notifications HTTP/1.1");
    push_client.print("Host:");
    push_client.println("onesignal.com");
    push_client.println("User-Agent: esp8266.Arduino.IoTmanager");
    push_client.print("Content-Length: ");
    push_client.println(push_data.length());
    push_client.println("Content-Type: application/json");
    push_client.println("Connection: close");
    push_client.println();
    push_client.println(push_data);
  }
}

// ================================= End Push notifications ==================================
Самое обидное - при обращении к BME280 еспэшка уходила в ребут.
Пройдемся еще раз по тупому Гуглю. Задаём вопрос "esp8266 bme280 без библиотеки", и получаем список ответов типа "...необходимо две библиотеки", "...необходимо установить две специальных библиотеки", "...библиотека под bme280". "Точное соответствие" - по барабану. Тупая американская скотина, одним словом.
Не то, что бы я не любил чужие библиотеки. Просто когда пишешь код сам, понимаешь, как это работает.
Ларчик открывался просто. Накосячил с типом переменной. А Ардуйня все туже затягивает гайки в плане строгого соответствия спецификации языка.

Кабель конечно хорошо, но хочется как и раньше менять прошивки в гараже, в деревне, дома наконец с работы. Что я и делал, пока недобитые фашисты не отключили TeamViewer. Эту проблему я конечно решу. (Решил. Раскопал в недрах своей фалопомойки R-Admin. Конечно не настолько удобно теперь, но работает.) А пока хотя бы WebUpdate в пределах квартиры.
На просторах интернета увидел интересный вопрос возмущенного пользователя, дословно "почему сжатый gzip bin-SPIFFS разворачивается по воздуху пустым"? Та-ак! Идущий да обрящет! Специалисты в один голос утверждают, "должен быть #define ATOMIC_FS_UPDATE", собственно поиски которого приводят на https://arduino-esp8266.readthedocs.io/en/3.0.2/ota_updates/readme.html#compression. Бинго? Фиг вам!
Надо сначала чтобы в устройстве была прошивка с этим ATOMIC_FS_UPDATE! А появилась эта фича только в 2.6.0.

Ну что-же, поехали...
Идея проста. Делаем чистую WebUpdate прошивку с ATOMIC_FS_UPDATE в 3.0.2, заливаем бинарник (смешные 301к) "по воздуху" в устройство, компилим нормальную прошивку для устройства в 3.0.2, сжимаем в gzip 9-м уровнем (максимально), заливаем архив "по воздуху" в устройство.
C++:
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>

#define ATOMIC_FS_UPDATE          //---------- Возможность прошить сжатым бинарником

const char* ssid = "Роутер";
const char* password = "Пароль_ВиФи";
const char* ssidAP = "WebUpdate";
const char* passwordAP = "Пароль_ТочкиДоступа_есп";

ESP8266WebServer server(80);
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
IPAddress ip(192,168,1,96); IPAddress gateway(192,168,1,1); IPAddress subnet(255,255,255,0); // ориентируясь на свой роутер

void setup(void)
{
  WiFi.mode(WIFI_AP_STA);
    WiFi.setAutoConnect(false);
    WiFi.setAutoReconnect(true);
    WiFi.config(ip, gateway, subnet, ip);
    WiFi.begin(ssid, password);
    int ii = 80;
    while (WiFi.status() != WL_CONNECTED && ii){delay(100); ii--;}
    if (WiFi.status() != WL_CONNECTED) WiFi.mode(WIFI_AP);  // если не подключились
    WiFi.softAP(ssidAP, passwordAP);

    server.on("/", HTTP_GET, [](){
      server.sendHeader("Connection", "close");
      server.sendHeader("Access-Control-Allow-Origin", "*");
      server.send(200, "text/html", serverIndex);
    });
    server.on("/update", HTTP_POST, [](){
      server.sendHeader("Connection", "close");
      server.sendHeader("Access-Control-Allow-Origin", "*");
      server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
    delay(1000);
      ESP.restart();
    },[](){
      HTTPUpload& upload = server.upload();
      if(upload.status == UPLOAD_FILE_START)
      {
        WiFiUDP::stopAll();
        uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
        if(!Update.begin(maxSketchSpace)) //start with max available size
        {Update.printError(Serial);}
      }
      else if(upload.status == UPLOAD_FILE_WRITE)
      {
        if(Update.write(upload.buf, upload.currentSize) != upload.currentSize)
        {Update.printError(Serial);}
      }
      else if(upload.status == UPLOAD_FILE_END)
      {
        if(Update.end(true)) //true to set the size to the current progress
        {  }
        else
        {Update.printError(Serial);}
      }
      yield();
    });
    server.begin();
}
 
void loop(void)
{
  server.handleClient();
  delay(1);
}
Ура? Не-а! "Толстый слой шоколада" в виде огромного количества Стрингов (надо же было так назвать "много букв"!) кушает весьма много "оперативки". И несколько проектов даже имея 21К свободного heap отказались посылать push, и уходили в ребут. Чертов SSL!

Лезем опять в Гугль, смотрим, как народ борется с нехваткой памяти. Находим чудесные вещи с лаконичным названием PSTR() и F(), и начинаем их применять.
C++:
     //------- Обновлялка. Грузилка. Запасной вариант. -------------
  server.on("/refit", HTTP_GET, [](){
  server.sendHeader("Connection", "close");
  server.sendHeader("Access-Control-Allow-Origin", "*");
  const char * serverIndex = PSTR("<html><head><meta charset=utf-8><title>Обновлялка</title>\
  <style>body {background-color: #cccccc; font-size: 16pt; Color: #ff0000;}</style></head><body>\
  <P>Обновлялка.</P><form method='POST' action='/update' enctype='multipart/form-data'>\
  <input type='file' name='update'><input type='submit' value='Прошить'></form>\
  <P>SPIFFS Upload</P><form method='POST' action='/edit' enctype='multipart/form-data'>\
  <input type='file' name='data'><input class='button' type='submit' value='Upload'></form></body></html>");
  server.send(200, "text/html", serverIndex);
  });

или

void Tun_ing()
{
  server.sendHeader("Connection", "close");
  server.sendHeader("Access-Control-Allow-Origin", "*");
  String tHTML = F("<!DOCTYPE html><html lang=ru><head><meta charset=\"utf-8\"><title>Tuning.</title><style>body {background-color: #cccccc; font-size: 16pt; font-family: arial;}</style></head><body><form method=\"post\" action=\"/tunsave\"><input required id=\"pI\" name=\"_pageId\" maxlength=\"2\" placeholder=\"порядковый номер\" value=\"");
  tHTML += String(pageId);
  tHTML += F("\"><br><input required id=\"dN\" name=\"_devName\" maxlength=\"10\" placeholder=\"имя в IoTmanager\" value=\"") + devName;
  tHTML += F("\"><br><input required id=\"dI\" name=\"_deviceId\" maxlength=\"24\" placeholder=\"идентификатор устройства\" value=\"") + deviceId;
  tHTML += F("\"><br><input required id=\"pg\" name=\"_page\" maxlength=\"10\" placeholder=\"закладка в IoTmanager\" value=\"") + page;
...
...
Память резко освобождается до 32К+. Push начинает работать. Можно продолжать развлекаться.
 

enjoynering

Well-known member
просто оставлю это здесь:

const char [] PROGMEM - тут.

еще одна магия R"=EOF=(текст тут)=EOF=":
- R"=EOF=()=EOF=" or R"=====()=====":
- R means treat everything between "=====(" & ")=====" as a raw string.
- "=====" can be anything you like (within certain bounds) as long as it's the
same at both the start & end of the string. You could use R"-=(This is "text")=-"
which would assign the string 'This is "text"'. The important thing to remember
is that ")=====" must not appear in your text anywhere, so make sure it's
something really obscure.
пример использования всего что выше:
Код:
const char indexHTML[] PROGMEM = R"=EOF=(
ваша страница htlm тут
)=EOF=";
остальное коментировать не буду, но вам опреленно надо почитать книги по C и C++
 

Mоnk

Member
остальное коментировать не буду
Жаль. Возможно это помогло бы Вам научиться выражать свои мысли четко и ясно для других. А другим Буржуинам было бы интересно узнать "страшную военную тайну, которую скрывает Мальчиш-Кибальчиш". И горько заплакать над своим криво написанным кодом.
 
  • Like
Реакции: PAV

enjoynering

Well-known member
Если "разжуёте", что это, и как работает, буду признателен.
Ели я ещё буду жевать за вас, то зачем вы в этом уравнении?

Ловить рыбу за вас нет ни малейшего желания. Извините, что потратил свое время на вас. Больше этого не повторится. Тысяча извинений.
 
  • Angry
Реакции: PAV

Atom

Member
Да, пасибо. На "R" натыкался, но кроме того, что это "необработанный Стринг", ничего толком не нашел. Если "разжуёте", что это, и как работает, буду признателен.
Это возможность указать компилятору, что текст из несколько линий ниже будет входить в значение константы. Точно не помню какие там правила, но нужно быть осторожным с пробелами в конце терминационной строки и вроде как в каждой линии приписать \n.
 

Atom

Member
Что за версия
Ардуюню 3.0.2

Если речь о Arduino IDE, то новая это 2.0.0.

Но не в этом цимис. К нему цепляется Esp Exception decoder?
 

PAV

Member
Ох, чую зря я вчера обновился ;)))


Пока, из того, что нашел - для BME сходу заработала библиотека Seeed_BME280.h Остальные отправляли контроллер в ребут.
 

Mоnk

Member
для BME сходу заработала библиотека
C++:
#define D3  0
#define D4  2

#include <Wire.h>                 //---------- I2C
#define BME280                    //---------- Используется датчик si7021 AM2302 BME280

#define SCL_pin     D3            //---------- I2C SCL 0
#define SDA_pin     D4            //---------- I2C SDA 2

#ifdef BME280
  #define BME280_ADDRESS  0x76
  float   Weather_p;
  String  Weather_pS    = "#";
  bool    BME280present = false;  // ===== BME280 найден?
  // Calibration data
  uint16_t dig_T1; int16_t dig_T2; int16_t dig_T3;
  uint16_t dig_P1; int16_t dig_P2; int16_t dig_P3;
  int16_t dig_P4;  int16_t dig_P5; int16_t dig_P6;
  int16_t dig_P7;  int16_t dig_P8; int16_t dig_P9;
  uint8_t dig_H1;  int16_t dig_H2; uint8_t dig_H3;
  int16_t dig_H4;  int16_t dig_H5; int8_t  dig_H6;
  int32_t t_fine;
#endif

  String  Weather_tS      = "#";
  String  Weather_hS      = "#";
  float   Weather_t, Weather_h;
  int     timer10s        = 0;      // ===== 10 sec
  unsigned long timeNow   = 0;

void setup()
{
  Wire.begin(SDA_pin, SCL_pin);       //---------- I2C
}

void loop()
{
  timeNow = millis();
  if ((timeNow - timer10s) > 10000)  //---------- 10 секунд
  {
  getWeather();
  timer10s = timeNow;
  }
}

#if defined(BME280)
//=====================================================
void getWeather()
{
  if (BME280Read8(0xD0) == 0x60)
  {
    if (!BME280present)
    {
      dig_T1 = BME280Read16LE(0x88);
      dig_T2 = BME280ReadS16LE(0x8A);
      dig_T3 = BME280ReadS16LE(0x8C);

      dig_P1 = BME280Read16LE(0x8E);
      dig_P2 = BME280ReadS16LE(0x90);
      dig_P3 = BME280ReadS16LE(0x92);
      dig_P4 = BME280ReadS16LE(0x94);
      dig_P5 = BME280ReadS16LE(0x96);
      dig_P6 = BME280ReadS16LE(0x98);
      dig_P7 = BME280ReadS16LE(0x9A);
      dig_P8 = BME280ReadS16LE(0x9C);
      dig_P9 = BME280ReadS16LE(0x9E);

      dig_H1 = BME280Read8(0xA1);
      dig_H2 = BME280Read16LE(0xE1);
      dig_H3 = BME280Read8(0xE3);
      dig_H4 = (BME280Read8(0xE4) << 4) | (0x0F & BME280Read8(0xE4 + 1));
      dig_H5 = (BME280Read8(0xE5 + 1) << 4) | (0x0F & BME280Read8(0xE5) >> 4);
      dig_H6 = (int8_t)BME280Read8(0xE7);

      writeRegister(0xF2, 0x05);  //Choose 16X oversampling
      writeRegister(0xF4, 0xB7);  //Choose 16X oversampling

      BME280present = true;
    }
    getTemperature();
      Weather_tS = Weather_t < 0 ? String(Weather_t) : "+" + String(Weather_t);
    getHumidity();
      Weather_hS = String(Weather_h);
    getPressure();
      Weather_pS = String(Weather_p);
/*
    if (hide[CLIMATE])     // Здесь собственно вывод данных куда надо (датчик доступен)
    {
      hide[CLIMATE] = false;
      pubConfigX(CLIMATE);
    }
*/
  }
  else
  {
    BME280present = false;
    Weather_tS = "#";
    Weather_hS = "#";
    Weather_pS = "#";
/*
    if (!hide[CLIMATE])     // Здесь собственно вывод данных куда надо (датчик не доступен)
    {
      hide[CLIMATE] = true;
      pubConfigX(CLIMATE);
    }
*/
  }
}

void getTemperature()
{
  int32_t var1, var2;
  int32_t adc_T = BME280Read24(0xFA);

  adc_T >>= 4;
  var1 = (((adc_T >> 3) - ((int32_t)(dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11;
  var2 = (((((adc_T >> 4) - ((int32_t)dig_T1)) * ((adc_T >> 4) - ((int32_t)dig_T1))) >> 12) * ((int32_t)dig_T3)) >> 14;
  t_fine = var1 + var2;

  Weather_t = ((t_fine * 5 + 128) >> 8)/100.0;
}

void getHumidity()
{
  int32_t v_x1_u32r;
  int32_t adc_H = BME280Read16(0xFD);

  v_x1_u32r = (t_fine - ((int32_t)76800));
  v_x1_u32r = (((((adc_H << 14) - (((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * v_x1_u32r)) + ((
    int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)dig_H6)) >> 10) * (((v_x1_u32r * ((int32_t)dig_H3)) >> 11) + ((
      int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)dig_H2) + 8192) >> 14));
  v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)dig_H1)) >> 4));
  v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
  v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
    
  Weather_h = (uint32_t)(v_x1_u32r >> 12) / 1024.0;
}

void getPressure()
{
  int64_t var1, var2, p;
  int32_t adc_P = BME280Read24(0xF7);

  adc_P >>= 4;
  var1 = ((int64_t)t_fine) - 128000;
  var2 = var1 * var1 * (int64_t)dig_P6;
  var2 = var2 + ((var1 * (int64_t)dig_P5) << 17);
  var2 = var2 + (((int64_t)dig_P4) << 35);
  var1 = ((var1 * var1 * (int64_t)dig_P3) >> 8) + ((var1 * (int64_t)dig_P2) << 12);
  var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)dig_P1) >> 33;
  if (var1 == 0) { return; }    // избежать исключения, вызванного делением на ноль
  p = 1048576 - adc_P;
  p = (((p << 31) - var2) * 3125) / var1;
  var1 = (((int64_t)dig_P9) * (p >> 13) * (p >> 13)) >> 25;
  var2 = (((int64_t)dig_P8) * p) >> 19;
  p = ((p + var1 + var2) >> 8) + (((int64_t)dig_P7) << 4);
    
  Weather_p = ((uint32_t)p / 256) / 133.32239F;
}

uint8_t BME280Read8(uint8_t reg)
{
  Wire.beginTransmission(BME280_ADDRESS);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(BME280_ADDRESS, 1);  // return 0 if slave didn't response
    
  if (Wire.available() < 1)
  {
    BME280present = false; return 0;
  }

  return Wire.read();
}

uint16_t BME280Read16(uint8_t reg)
{
  uint8_t msb, lsb;

  Wire.beginTransmission(BME280_ADDRESS);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(BME280_ADDRESS, 2);  // return 0 if slave didn't response

  if (Wire.available() < 2)
  {
    BME280present = false; return 0;
  }
  msb = Wire.read();
  lsb = Wire.read();

  return (uint16_t) msb << 8 | lsb;
}

uint16_t BME280Read16LE(uint8_t reg)
{
  uint16_t data = BME280Read16(reg);
  return (data >> 8) | (data << 8);
}

int16_t BME280ReadS16(uint8_t reg) {return (int16_t)BME280Read16(reg);}

int16_t BME280ReadS16LE(uint8_t reg) {return (int16_t)BME280Read16LE(reg);}

uint32_t BME280Read24(uint8_t reg)
{
  uint32_t data;

  Wire.beginTransmission(BME280_ADDRESS);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(BME280_ADDRESS, 3);  // return 0 if slave didn't response

  if (Wire.available() < 3)
  {
    BME280present = false; return 0;
  }
  data = Wire.read();
  data <<= 8;
  data |= Wire.read();
  data <<= 8;
  data |= Wire.read();

  return data;
}

void writeRegister(uint8_t reg, uint8_t val)
{
  Wire.beginTransmission(BME280_ADDRESS); // start transmission to device
  Wire.write(reg);                        // send register address
  Wire.write(val);                        // send value to write
  Wire.endTransmission();                 // end transmission
}

//=====================================================
#endif
 
Сверху Снизу