//------------Сеть
  extern "C" {
  #include "esp_wifi.h"
  }
  void InitWiFi(bool wifiAP){
    /*
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    cfg.rx_ba_win = 4;                    // Было 6
    cfg.cache_tx_buf_num = 2;             // МИНИМУМ: было 8-16  
    cfg.tx_buf_type = 0;                  // 0 = только динамические буферы
    cfg.static_tx_buf_num = 0;            // 0 = нет статических буферов
    cfg.dynamic_tx_buf_num = 4;           // Минимум динамических
    cfg.wifi_task_core_id = 1;            // Фиксировать ядро
    cfg.beacon_max_len = 100;             // Уменьшить макс. длину beacon
    esp_wifi_init(&cfg);
    */
      if (!wifiAP) {
    WiFi.mode(WIFI_STA);
    WiFi.persistent(true);
    WiFi.setSleep(WIFI_PS_NONE);
    WiFi.setHostname(host);
    WiFi.setAutoReconnect(true); 
    #if BOARD == ESP32S3
    WiFi.setTxPower(WIFI_POWER_17dBm); 
    #endif

    WiFi.begin(); 
    Serial.print("Подключение к предыдущей точке WiFi "); 
    #ifdef USE_DISPLAY
    LD.printString_6x8("Saved SSID          ", 1, 6);
    #endif
    uint32_t startTime = millis();
    while (WiFi.status() != WL_CONNECTED && millis() - startTime < 15000) {
      Serial.print(".");
      delay(500);
    }
      if (WiFi.status() != WL_CONNECTED && SamSetup.SavedSSID[0] != '\0') {
      Serial.println();  
      #ifdef USE_DISPLAY
      LD.printString_6x8(("EEPROM SSID " + String(SamSetup.SavedSSID)).c_str(), 1, 6);
      #endif
      #if BOARD == ESP32S3
      WiFi.setTxPower(WIFI_POWER_15dBm); 
      #endif
      WiFi.begin(SamSetup.SavedSSID, SamSetup.SavedPASS); 
      Serial.print("Подключение к точке WiFi из EEPROM "); 
      Serial.println(SamSetup.SavedSSID); 
      uint32_t startTime = millis();
      while (WiFi.status() != WL_CONNECTED && millis() - startTime < 15000) {
      Serial.print(".");
      delay(500);
      } 
    }
    if (WiFi.status() != WL_CONNECTED) {
      Serial.println();
      #ifdef USE_DISPLAY
      LD.printString_6x8(("Def.SSID " + String(defaultSSID)).c_str(), 1, 6); 
      #endif 
      WiFi.begin(defaultSSID, defaultPass); 
      Serial.print("Подключение к точке WiFi из INI "); 
      Serial.println(defaultSSID); 
      uint32_t startTime = millis();
      while (WiFi.status() != WL_CONNECTED && millis() - startTime < 15000) {
      Serial.print(".");
      delay(500);
      } 
    }
    Serial.println();    

    //if (WiFi.status() == WL_CONNECTED) 
    { 
      StIP = WiFi.localIP().toString();
      #ifdef USE_DISPLAY
      LD.printString_6x8((StIP + "    ").c_str(), 1, 7); 
      LD.printString_6x8("R    ", 1+16*6, 7);
      LD.printString_6x8("                    ", 1, 6);
      LD.printString_6x8((WiFi.SSID()).c_str(), 1, 6);
      #endif
      #ifdef USE_DISP_LC
        LQ.setCursor(0,1);LQ.print("Connected to " + WiFi.SSID());
        LQ.setCursor(0,2);LQ.print("IP: " + StIP);
      #endif
      Serial.println();
      Serial.print(F("Connected to ")); Serial.println(WiFi.SSID());    
      Serial.print(F("IP ")); Serial.println(StIP);   
    } 
    }
    #if BOARD == ESP32S3
    WiFi.setTxPower(WIFI_POWER_19dBm); 
    #endif
    if (WiFi.status() != WL_CONNECTED) {
      WiFi.setAutoReconnect(false); 
      WiFi.mode(WIFI_AP);
      WiFi.softAP("Samovar", WiFiAP_Pass);
      Serial.println();
      Serial.println(F("Started as WiFi AP"));
      Serial.print(F("Name: Samovar, Pass: ")); Serial.print(WiFiAP_Pass); Serial.println(F(",IP: 192.168.4.1"));
      StIP = "192.168.4.1";
      #ifdef USE_DISPLAY
      LD.printString_6x8(F("IP: 192.168.4.1     "), 1, 7);
      #endif
    }
  }
  void reset_wifi() {
    WiFi.disconnect(true);
    vTaskDelay(200/portTICK_PERIOD_MS);
    //Сбрасываем сохраненные настройки WiFi и переподключаемся
    InitWiFi(false);
  }
  void InitOTA() {
    #ifdef USE_UPDATE_OTA
        //Send OTA events to the browser
        ArduinoOTA.onStart([]() {
          String type;
          if (ArduinoOTA.getCommand() == U_FLASH)
            type = "Sketch";
          else {  // U_SPIFFS
            type = "Filesystem";
            SPIFFS.end();
          }
          type = type + " update start";
          events.send(type.c_str(), "ota");
        });
        ArduinoOTA.onEnd([]() {
          events.send(("Update End"), "ota");
        }); 
        ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
          //char p[32];
          //sprintf(p, "Progress: %u%%\n", (progress / (total / 100)));
          events.send(".", "ota");
        }); 
        ArduinoOTA.onError([](ota_error_t error) {
          if (error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota");
          else if (error == OTA_BEGIN_ERROR)
            events.send(("Begin Failed"), "ota");
          else if (error == OTA_CONNECT_ERROR)
            events.send(("Connect Failed"), "ota");
          else if (error == OTA_RECEIVE_ERROR)
            events.send(("Recieve Failed"), "ota");
          else if (error == OTA_END_ERROR)
            events.send(("End Failed"), "ota");
        });
        ArduinoOTA.setHostname(SAMOVAR_HOST);
        ArduinoOTA.begin(); DbgMsg("OTA started.",1);
    #endif
  }
  void InitTelegram(){
    if (SamSetup.UseTg) {
    if (WiFi.status() == WL_CONNECTED && SamSetup.tg_token[0] != 0 && SamSetup.tg_chat_id[0] != 0 && Ping.ping("212.237.16.93", 1)) {
      vTaskDelay(5 / portTICK_PERIOD_MS);
          if (xSemaphoreTake(xMsgSemaphore, (TickType_t)(50 / portTICK_RATE_MS)) == pdTRUE) {
            http_sync_request_get(String("http://212.237.16.93/bot") + SamSetup.tg_token + "/sendMessage?chat_id=" + SamSetup.tg_chat_id + "&text=" + urlEncode("Самоварыч готов к работе; IP=http://" + StIP));
            //DbgMsg("TG send.",1);
            xSemaphoreGive(xMsgSemaphore);
          }
    } else if (SamSetup.tg_chat_id[0] != 0) {
      Serial.println(F("Проблема с подключением к интернету."));
      }
    }
  }
  void InitBlynk(){
    //Blynk.disconnect();
    if (SamSetup.UseBlynk) {
    DbgMsg(F("Connecting to Blynk"),1);  
    if (SamSetup.blynkauth[0] != 0 && WiFi.status() == WL_CONNECTED) {
    if (SamSetup.BlynkUrl[0]!='/r')
      Blynk.config(SamSetup.blynkauth, SamSetup.BlynkUrl, 8080);
    else
        Blynk.config(SamSetup.blynkauth); //"blynk-cloud.com" 80
    } 
        Blynk.connect(BLYNK_TIMEOUT_MS);
      DbgMsg(F("Blynk started"),1);
    }
  }
//------------Blynk
  void pause_withdrawal(bool PauseOn);
  void set_current_power(float power);
  void set_pump_speed(float speed, bool msg);
  void set_body_temp();
  String get_Samovar_Status();
  float get_speed_from_rate(float rate, uint16_t s_per_l);

  #include <BlynkSimpleEsp32.h>
  #ifdef USE_LUA
    String run_lua_string(String lstr);
    WidgetTerminal terminal(V22);

    BLYNK_WRITE(V22) {
      String lstr = param.asStr();  // assigning incoming value from pin V22 to a variable
      terminal.println(lstr);
      lstr = run_lua_string(lstr);
      if (lstr.length() > 0) {
        terminal.println("ERR in lua: " + lstr);
      }
      else {
        terminal.println(F("Lua run complete"));
      }
      terminal.flush();
    }
  #endif
  BLYNK_READ(V0) {
    vTaskDelay(2 / portTICK_PERIOD_MS);
    Blynk.virtualWrite(V0, SteamSensor.avgTemp);
    vTaskDelay(2 / portTICK_PERIOD_MS);
    Blynk.virtualWrite(V4, PowerOn);
    int i;
    int k;
    if (startval > 0 && startval < 5)
      i = 1;
    else
      i = 0;
    Blynk.virtualWrite(V3, i);
    vTaskDelay(2 / portTICK_PERIOD_MS);
    if (PauseOn)
      k = 1;
    else
      k = 0;
    Blynk.virtualWrite(V13, k);
  }
  BLYNK_READ(V1) {
    Blynk.virtualWrite(V1, PipeSensor.avgTemp);
  }
  BLYNK_READ(V2) {
    Blynk.virtualWrite(V2, WthdrwlProgress);
  }
  BLYNK_READ(V5) {
    Blynk.virtualWrite(V5, bme_pressure);
  }
  BLYNK_READ(V6) {
    Blynk.virtualWrite(V6, WaterSensor.avgTemp);
  }
  BLYNK_READ(V7) {
    Blynk.virtualWrite(V7, TankSensor.avgTemp);
  }
  BLYNK_READ(V8) {
    Blynk.virtualWrite(V8, get_liquid_volume_by_step(stepper.getCurrent()));
  }
  BLYNK_READ(V9) {
    Blynk.virtualWrite(V9, ActualVolumePerHour);
  }
  BLYNK_READ(V10) {
    Blynk.virtualWrite(V10, WthdrwTimeS + "; " + WthdrwTimeAllS);
  }
  BLYNK_READ(V11) {
    Blynk.virtualWrite(V11, StrCrt);
  }
  BLYNK_READ(V14) {
    Blynk.virtualWrite(V14, get_Samovar_Status());
  }
  BLYNK_READ(V15) {
    Blynk.virtualWrite(V15, ipst);
  }
  BLYNK_READ(V19) {
    Blynk.virtualWrite(V19, SAMOVAR_VERSION);
  }
  #if defined(USE_PRESSURE_XGZ) || defined(USE_PRESSURE_MPX) || defined(USE_PRESSURE_1WIRE)
    BLYNK_READ(V22) {
      Blynk.virtualWrite(V22, pressure_value);
    }
  #endif
  BLYNK_READ(V21) {
      if (SamSetup.PwrType != NO_POVER_REG) {
      Blynk.virtualWrite(V21, "Тек:" + (String)current_power_volt + " Цель:" + (String) + target_power_volt);
    }
  }
  BLYNK_READ(V16) {
      if (SamSetup.PwrType != NO_POVER_REG) {
      Blynk.virtualWrite(V16, target_power_volt);
    }
  }
  BLYNK_WRITE(V16) {
      if (SamSetup.PwrType != NO_POVER_REG) {
      float Value16 = param.asFloat();  // assigning incoming value from pin V16 to a variable
      set_current_power(Value16);
    }
  }
  BLYNK_WRITE(V17) {
    float Value17 = param.asFloat();  // assigning incoming value from pin V17 to a variable
    set_pump_speed(get_speed_from_rate(Value17, Samovar_Mode == SAMOVAR_NBK_MODE ? SamSetup.NBK_StepperStepMl : SamSetup.StepperStepMl), true);
  }
  BLYNK_WRITE(V18) {
    set_body_temp();
  }
  BLYNK_WRITE(V12) {
    if (!PowerOn) return;
    int State = param.asInt();
    if (State == 1) {
      if (Samovar_Mode == SAMOVAR_BEER_MODE) {
        sam_command_sync = SAMOVAR_BEER_NEXT;
      } else if (Samovar_Mode == SAMOVAR_DISTILLATION_MODE) {
        sam_command_sync = SAMOVAR_DIST_NEXT;
      } else {
        sam_command_sync = SAMOVAR_START;
      }
    }
  }
  BLYNK_WRITE(V13) {
    pause_withdrawal(!PauseOn);
    t_min = 0;
    program_Wait = false;
  }
  BLYNK_WRITE(V3) {
    int Value3 = param.asInt();  // assigning incoming value from pin V3 to a variable
    if (Value3 == 1 && PowerOn) samovar_start();
    else
      sam_command_sync = SAMOVAR_RESET;
  }
  BLYNK_WRITE(V4) {
    //int Value4 = param.asInt();  // assigning incoming value from pin V4 to a variable
    if (Samovar_Mode == SAMOVAR_BEER_MODE && !PowerOn) {
      sam_command_sync = SAMOVAR_BEER;
    } else if (Samovar_Mode == SAMOVAR_BK_MODE && !PowerOn) {
      sam_command_sync = SAMOVAR_BK;
    } else if (Samovar_Mode == SAMOVAR_NBK_MODE && !PowerOn) {
      sam_command_sync = RUN_NBK;
    } else if (Samovar_Mode == SAMOVAR_DISTILLATION_MODE && !PowerOn) {
      sam_command_sync = SAMOVAR_DISTILLATION;
    } else
      sam_command_sync = SAMOVAR_POWER;
    //set_power(Value4);
  }
//------------MQTT
  char mqttstr[100] = "SMV/\0";
  char mqttstr1[100];
  void DbgMsg(const String& Msg, bool ln);
  void SendMsg(const String& m, MESSAGE_TYPE msg_type);
  void onMqttConnect(bool sessionPresent);
  void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
  void onMqttPublish(uint16_t packetId);
  void connectToMqtt();

  void initMqtt() {
    //if (mqttClient.connected()) mqttClient.disconnect();
    if (SamSetup.UseMQTT) {
      char buf[10];
      itoa(chipId, buf, 10);
      mqttClient.onConnect(onMqttConnect);
      mqttClient.onDisconnect(onMqttDisconnect);
      mqttClient.onPublish(onMqttPublish);
      mqttClient.setClientId(buf);
      //mqttClient.setClientId("1234");
      mqttClient.setMaxTopicLength(PAYLOADSIZE);
      mqttClient.setCredentials(SamSetup.MQTT_User, SamSetup.MQTT_Pass);
      mqttClient.setServer(SamSetup.MQTT_Serv, SamSetup.MQTT_Port);
      strcat(mqttstr, SamSetup.blynkauth);
      strcat(mqttstr, "/");

      if (strlen(SamSetup.blynkauth) < 30) send_mqtt = false; else send_mqtt = true;

      //  mqttClient.onSubscribe(onMqttSubscribe);
      //  mqttClient.onUnsubscribe(onMqttUnsubscribe);
      //  mqttClient.onMessage(onMqttMessage);

      connectToMqtt();
      vTaskDelay(500);
    }
  }
  void connectToMqtt() {
    DbgMsg("Connecting to MQTT...",1);
    //  uint8_t i;
    //  i = 0;
    mqttClient.connect();
    //  while (!mqttClient.connected()){
    //    delay(50);
    //    i++;
    //    if (i > 25) break;
    //  }
  }
  void onMqttConnect(bool sessionPresent) {
  DbgMsg("MQQT connected.",1);
  }
  void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  DbgMsg("Disconnected from MQTT: " + String(static_cast<std::underlying_type<AsyncMqttClientDisconnectReason>::type>(reason)),1);
  }
  void onMqttPublish(uint16_t packetId) {
    //  Serial.println("Publish acknowledged.");
    //  Serial.print("  packetId: ");
    //  Serial.println(packetId);
  }
  void MqttSendMsg(const String &Str, const char *chart ) {
    if (!send_mqtt) return;
    strcpy(mqttstr1, mqttstr);
    strcat(mqttstr1, chart);
    static char payload[PAYLOADSIZE];

    //Версия сообщения
    strcat(mqttstr1, "/3");
    Str.toCharArray(payload, PAYLOADSIZE);
    uint16_t packetIdPub1 = mqttClient.publish(mqttstr1, 2, true, payload);
    if (packetIdPub1 == 0) {
      if (!mqttClient.connected()){
        mqttClient.connect();
      }
      packetIdPub1 = mqttClient.publish(mqttstr1, 2, true, payload);
    }
  }
//
