Билли-Релешка: ESP32/ESP8266 "на пальцах"

Всем привет.

Давно хотел сделать что-то вроде “ESP101”, то есть Arduino-проект на базе модулей ESP32/ESP8266, к которому прикручены максимальное количество простых каналов коммуникации (с возможностью их настройки) и возможность управлять простой (ВКЛ./ВЫКЛ.) нагрузкой.

Билли-Релешка это:
простая передача команд по UART, “голому” TCP, HTTP и Bluetooth Classic (там, где он есть);
унифицированная обработка команд, поступающих по различным каналам коммуникации;
наличие базовой веб-морды;
возможность управления через сервер в локальной сети или в Интернете (правда, этот сервер придётся развернуть, но в описании Билли есть ссылка на подходящий проект для Linux);
подробные и структурированные комментарии;
модульная структура кода, благодаря чему скетч удобно модифицировать и дополнять;
совместимость с любой (вроде бы) платой ESP32/ESP8266, поддерживаемой в соответствующем ядре Arduino;
простая пред-compile-time настройка в одном заголовочном config-файле;
простая runtime-настройка каналов коммуникаций с помощью AT-команд;
подробный вывод статуса устройства через UART и другие каналы коммуникации.

Надеюсь, ссылки на GitHub достаточно для корректного оформления поста, поскольку файлов многовато, чтобы выкладывать сюда код из каждого. Но на всякий случай выкладываю код из основного файла (.ino):

/******************* ОПИСАНИЕ *******************/

/**
 * Имя файла: Billy_the_Relay.ino
 * ----------------------------------------------------------------------------|---------------------------------------|
 * Назначение: Ардуино-проект на базе модуля ESP32 или ESP8266.
 * Дистанционное управление простой (ВКЛ./ВЫКЛ.) нагрузкой.
 * ----------------------------------------------------------------------------|---------------------------------------|
 * Примечания:
 */


/************ ДИРЕКТИВЫ ПРЕПРОЦЕССОРА ***********/

/*--- Включения ---*/

// Настройки проекта.
#include "config_general.h"            // Помимо файла .ino включается в заголовочные файлы ряда локальных модулей.

#include "config_ASCII_cmd_handler.h"  /* Помимо файла .ino включается в заголовочный файл модуля ESP_HTTP,
                                        * поскольку тому необходимо "знать" тексты команд.
                                        */

#include "config_inbuilt_storage.h"    /* Помимо файла .ino включается в заголовочный файл модуля inbuilt_storage,
                                        * поскольку тому необходимо "знать", что он имеет дело с ESP32/ESP8266.
                                        */

// Локальные модули.
#include "utilities.h"
#include "ASCII_cmd_handler.h"
#include "inbuilt_storage.h"
#include "HW_UART.h"
#include "ESP_WiFi.h"
#include "ESP_TCP.h"
#include "ESP_HTTP.h"

#if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
    #include "ESP32_Bluetooth.h"
#endif

// Дополнительные библиотеки для Arduino IDE включаются в локальных модулях.


/****************** ТИПЫ ДАННЫХ *****************/

/* Структура, в которую записываются значения настроек,
 * считываемые со встроенного накопителя устройства.
 */
typedef struct strd_vals_t {
    char SSID[STR_MAX_LEN + 1];
    char pswd[STR_MAX_LEN + 1];
    uint32_t local_server_port;
    bool IoT_flag;
    char IoT_server_IP[STR_MAX_LEN + 1];
    uint32_t IoT_server_port;
    char IoT_req_msg[STR_MAX_LEN + 1];
    uint32_t IoT_req_period;
    bool BT_flag;
    char BT_dev_name[STR_MAX_LEN + 1];
    bool RSSI_print_flag;
} strd_vals_t;


/*************** ПРОТОТИПЫ ФУНКЦИЙ **************/

/*--- Функции-обработчики ---*/

/* Функции, вызываемые в ответ на поступившие команды и на ошибки обработки
 * команд. Ниже указано, при каких условиях вызывается та или иная функция.
 */

// Отсутствует корректный префикс команды.
void handle_cmd_err_prefix();

// После корректного префикса команды отсутствует корректная команда.
void handle_cmd_err_cmd();

/* После корректной команды, требующей ввода значения,
 * отсутствует корректное значение.
 */
void handle_cmd_err_val();

// Длина команды превышает установленный лимит.
void handle_cmd_err_len();

/* Введена команда #0:
 * включение или выключение нагрузки. Основная "рабочая лошадка".
 */
void handle_cmd_set_load(char *cmd);

/* Введена команда #1:
 * изменение SSID точки доступа локальной сети Wi-Fi, хранящегося
 * во встроенном накопителе устройства.
 */
void handle_cmd_set_local_SSID(char *cmd);

/* Введена команда #2:
 * вывод SSID точки доступа локальной сети Wi-Fi, хранящегося
 * во встроенном накопителе устройства.
 */
void handle_cmd_print_local_SSID();

/* Введена команда #3:
 * изменение пароля точки доступа локальной сети Wi-Fi, хранящегося
 * во встроенном накопителе устройства.
 */
void handle_cmd_set_local_pswd(char *cmd);

/* Введена команда #4:
 * изменение номера порта, используемого устройством как локальным TCP-сервером,
 * хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_set_local_port(char *cmd);

/* Введена команда #5:
 * вывод номера порта, используемого устройством как локальным TCP-сервером,
 * хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_print_local_port();

/* Введена команда #6:
 * вывод локального IP-адреса, присвоенного устройству в текущей сети Wi-Fi.
 */
void handle_cmd_print_local_IP();

/* Введена команда #7:
 * перезапуск локальных соединений.
 */
void handle_cmd_rst_local_conn();

/* Введена команда #8:
 * включение или выключение связи с удалённым сервером (сервером IoT).
 */
void handle_cmd_set_IoT_flag(char *cmd);

/* Введена команда #9:
 * изменение IP-адреса удалённого сервера, хранящегося
 * во встроенном накопителе устройства.
 */
void handle_cmd_set_IoT_server_IP(char *cmd);

/* Введена команда #10:
 * вывод IP-адреса удалённого сервера, хранящегося
 * во встроенном накопителе устройства.
 */
void handle_cmd_print_IoT_server_IP();

/* Введена команда #11:
 * изменение номера порта, в который устройство будет стучаться
 * к удалённому серверу, хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_set_IoT_server_port(char *cmd);

/* Введена команда #12:
 * вывод номера порта, в который устройство будет стучаться
 * к удалённому серверу, хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_print_IoT_server_port();

/* Введена команда #13:
 * изменение текста запроса, направляемого устройством удалённому серверу,
 * хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_set_IoT_req_msg(char *cmd);

/* Введена команда #14:
 * вывод текста запроса, направляемого устройством удалённому серверу,
 * хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_print_IoT_req_msg();

/* Введена команда #15:
 * изменение периодичности (в миллисекундах) направления запросов
 * удалённому серверу, хранящейся во встроенном накопителе устройства.
 */
void handle_cmd_set_IoT_req_period(char *cmd);

/* Введена команда #16:
 * включение или выключение Bluetooth.
 */
void handle_cmd_set_BT_flag(char *cmd);

/* Введена команда #17:
 * изменение имени устройства как ведомого устройства Bluetooth,
 * хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_set_BT_dev_name(char *cmd);

/* Введена команда #18:
 * вывод имени устройства как ведомого устройства Bluetooth,
 * хранящегося во встроенном накопителе устройства.
 */
void handle_cmd_print_BT_dev_name();

/* Введена команда #19:
 * включение или выключение периодического вывода текущего значения RSSI.
 */
void handle_cmd_set_RSSI_print_flag(char *cmd);


/*--- Помощники функций-обработчиков ---*/

// Вспомогательная функция для set-обработчиков.
void handle_cmd_helper_set(char *cmd, const char *topic, int32_t addr, bool echo);

// Вспомогательная функция для print-обработчиков.
void handle_cmd_helper_print(const char *topic, int32_t addr);

// Вспомогательная функция для отправки сообщений обработчиками.
void handle_cmd_helper_send(char *msg);


/*--- Прочие функции ---*/

// Чтение настроек со встроенного накопителя устройства в структуру.
void strd_vals_read(strd_vals_t *_strd_vals);


/******************** ФУНКЦИИ *******************/

/*--- Основные функции ---*/

void setup()
{
    /*--- Установка режима работы задействованных выводов устройства ---*/

    pinMode(LOAD_PIN, OUTPUT);
    pinMode(WIFI_INDICATOR_LED_PIN, OUTPUT);


    /*--- Взаимодействие со встроенным накопителем ---*/

    /* У ESP32 и ESP8266, в отличие от устройств на базе микроконтроллеров AVR,
     * встроенный накопитель перед использованием необходимо инициализировать.
     */
    inbuilt_storage_init(INBUILT_STORAGE_SIZE);

    // Чтение настроек со встроенного накопителя устройства в структуру.
    strd_vals_t strd_vals;
    strd_vals_read(&strd_vals);

    /* При необходимости любую настройку можно первоначально сохранить
     * во встроенном накопителе устройства, указав её прямо в коде перед
     * компиляцией. Для этого требуется раскомментировать соответствующие
     * директивы #define и указать желаемые значения среди параметров
     * функции, после чего загрузить скетч в устройство и запустить его.
     * После этого следует вновь закомментировать директивы и повторно
     * загрузить скетч в устройство, поскольку иначе настройки будут
     * сбрасываться к исходным значениям при каждом запуске устройства.
     */

    //#define SET_SSID_AT_UPLOAD
    #ifdef SET_SSID_AT_UPLOAD
        inbuilt_storage_write("NEWSSID",
                              strlen("NEWSSID"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_SSID);
    #endif

    //#define SET_PSWD_AT_UPLOAD
    #ifdef SET_PSWD_AT_UPLOAD
        inbuilt_storage_write("123456",
                              strlen("123456"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_PSWD);
    #endif

    //#define SET_LOCAL_SERVER_PORT_AT_UPLOAD
    #ifdef SET_LOCAL_SERVER_PORT_AT_UPLOAD
        inbuilt_storage_write("451",
                              strlen("451"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_LOCAL_SERVER_PORT);
    #endif

    //#define SET_IOT_FLAG_AT_UPLOAD
    #ifdef SET_IOT_FLAG_AT_UPLOAD
        inbuilt_storage_write("OFF",
                              strlen("OFF"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_IOT_FLAG);
    #endif

    //#define SET_IOT_SERVER_IP_AT_UPLOAD
    #ifdef SET_IOT_SERVER_IP_AT_UPLOAD
        inbuilt_storage_write("111.111.111.111",
                              strlen("111.111.111.111"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_IOT_SERVER_IP);
    #endif

    //#define SET_IOT_SERVER_PORT_AT_UPLOAD
    #ifdef SET_IOT_SERVER_PORT_AT_UPLOAD
        inbuilt_storage_write("451",
                              strlen("451"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_IOT_SERVER_PORT);
    #endif

    //#define SET_IOT_REQ_MSG_AT_UPLOAD
    #ifdef SET_IOT_REQ_MSG_AT_UPLOAD
        inbuilt_storage_write("UPD_REQ",
                              strlen("UPD_REQ"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_IOT_REQ_MSG);
    #endif

    //#define SET_IOT_REQ_PERIOD_AT_UPLOAD
    #ifdef SET_IOT_REQ_PERIOD_AT_UPLOAD
        inbuilt_storage_write("500",
                              strlen("500"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_IOT_REQ_PERIOD);
    #endif

    //#define SET_BT_FLAG_AT_UPLOAD
    #ifdef SET_BT_FLAG_AT_UPLOAD
        inbuilt_storage_write("OFF",
                              strlen("OFF"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_BT_FLAG);
    #endif

    //#define SET_BT_DEV_NAME_AT_UPLOAD
    #ifdef SET_BT_DEV_NAME_AT_UPLOAD
        inbuilt_storage_write("NEW_BT_DEV_NAME",
                              strlen("NEW_BT_DEV_NAME"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_BT_DEV_NAME);
    #endif

    //#define SET_RSSI_PRINT_FLAG_AT_UPLOAD
    #ifdef SET_RSSI_PRINT_FLAG_AT_UPLOAD
        inbuilt_storage_write("OFF",
                              strlen("OFF"),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_RSSI_PRINT_FLAG);
    #endif


    /*--- Запуск коммуникаций ---*/

    // Запуск аппаратного интерфейса UART.
    Serial.begin(HW_UART_BAUD_RATE);
    delay(HW_UART_STARTUP_PAUSE);    // Небольшая пауза, дающая устройству время на запуск интерфейса.

    Serial.println("");
    Serial.println("*** HELLO, HUMAN! ***");

    /* Для инициализации некоторых объектов требуется указать их настройки
     * до компиляции, поскольку те передаются в конструктор в качестве
     * параметров. Чтобы инициализировать такие глобальные объекты в файлах
     * модулей и не тащить их в файл .ino, указываем в качестве параметров
     * конструктора заглушку, а затем уже при выполнении setup() передаём
     * в эти объекты нужные нам значения, считанные со встроенного накопителя.
     */
    ESP_TCP_server_port_update(strd_vals.local_server_port);

    // Подключение к сети Wi-Fi.
    bool WiFi_connected = ESP_WiFi_set_connection(strd_vals.SSID,
                                                  strd_vals.pswd,
                                                  CONN_TIMEOUT);

    if (WiFi_connected) {
        ESP_WiFi_indicate_connection(WIFI_INDICATOR_LED_PIN,
                                     WIFI_INDICATE_CONNECTION_CYCLES,
                                     WIFI_INDICATE_CONNECTION_PERIOD);

        Serial.print("Current local IP address is: ");
        Serial.println(ESP_WiFi_get_current_IP());

        ESP_TCP_server_start();
        Serial.print("Local TCP server started at port ");
        Serial.println(strd_vals.local_server_port);

        ESP_HTTP_server_start();
        ESP_HTTP_set_handlers();
        Serial.print("Local HTTP server started at port ");
        Serial.println(HTTP_PORT);
    }
    Serial.println("");

    // Запуск Bluetooth.
    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        if (strd_vals.BT_flag) {
            ESP32_BT_start(strd_vals.BT_dev_name);
        }
    #endif


    /*--- Вывод значений соответствующих настроек ---*/

    // Проверка флага связи с удалённым сервером (сервером IoT).
    Serial.print("Requests to IoT server: ");
    if (strd_vals.IoT_flag) {
        Serial.println("ON");
        Serial.print("Target IoT server IP address: ");
        Serial.println(strd_vals.IoT_server_IP);
        Serial.print("Target IoT server port: ");
        Serial.println(strd_vals.IoT_server_port);
        Serial.print("Request text: ");
        Serial.println(strd_vals.IoT_req_msg);
        Serial.print("Request period (once per ms): ");
        Serial.println(strd_vals.IoT_req_period);
    } else {
        Serial.println("OFF");
    }

    // Проверка флага работы Bluetooth.
    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        Serial.print("Bluetooth: ");
        if (strd_vals.BT_flag) {
            Serial.println("ON");
            Serial.print("Bluetooth device name: ");
            Serial.println(strd_vals.BT_dev_name);
        } else {
            Serial.println("OFF");
        }
    #endif

    // Проверка флага периодического вывода текущего значения RSSI через UART.
    Serial.print("Print RSSI: ");
    if (strd_vals.RSSI_print_flag) {
        Serial.println("ON");
    } else {
        Serial.println("OFF");
    }
    Serial.println("");
}

void loop()
{
    // Чтение данных со встроенного накопителя в структуру.
    strd_vals_t strd_vals;
    strd_vals_read(&strd_vals);

    // Массив строк с командами.
    static const char *cmd_list[] = {
        CMD_0,
        CMD_1,
        CMD_2,
        CMD_3,
        CMD_4,
        CMD_5,
        CMD_6,
        CMD_7,
        CMD_8,
        CMD_9,
        CMD_10,
        CMD_11,
        CMD_12,
        CMD_13,
        CMD_14,
        CMD_15,
        CMD_16,
        CMD_17,
        CMD_18,
        CMD_19
    };


    /*--- Вывод текущего значения RSSI ---*/
    
    uint32_t WiFi_RSSI_print_period = WIFI_RSSI_PRINT_PERIOD;
    if (WiFi_RSSI_print_period == 0) {
        WiFi_RSSI_print_period = DEFAULT_WIFI_RSSI_PRINT_PERIOD;  // Защита от деления на ноль.
    }

    static bool RSSI_print_loaded = 0;
    if (millis() % WiFi_RSSI_print_period != 0) {
        RSSI_print_loaded = 1;
    }

    if (strd_vals.RSSI_print_flag && millis() % WiFi_RSSI_print_period == 0 && RSSI_print_loaded) {
        ESP_WiFi_RSSI_print();
        RSSI_print_loaded = 0;
    }


    /*--- Приём команд ---*/

    // Буфер для записи команд.
    char terminal_input[STR_MAX_LEN + 1] = {0};

    // Приём данных через аппаратный UART.
    uint32_t HW_UART_bytes_read = HW_UART_read_line(terminal_input,
                                                    STR_MAX_LEN,
                                                    CONN_TIMEOUT,
                                                    HW_UART_READ_SLOWDOWN);
    if (HW_UART_bytes_read > STR_MAX_LEN) {
        terminal_input[0] = '\0';
        handle_cmd_err_len();
    }

    // Приём локальным сервером данных по TCP.
    if (ESP_TCP_server_get_client()) {
        uint32_t TCP_server_bytes_read = ESP_TCP_server_read_line(terminal_input,
                                                                  STR_MAX_LEN,
                                                                  CONN_TIMEOUT);
        if (TCP_server_bytes_read > STR_MAX_LEN) {
            terminal_input[0] = '\0';
            handle_cmd_err_len();
        }
    }

    // Обработка HTTP-запросов и запись значения из тела запроса в буфер.
    ESP_HTTP_handle_client_in_loop();
    ESP_HTTP_copy_value(terminal_input, STR_MAX_LEN);

    /* Направление локальным TCP-клиентом запроса
     * удалённому серверу и приём ответа.
     */
    if (strd_vals.IoT_req_period == 0) {
        strd_vals.IoT_req_period = DEFAULT_IOT_REQ_PERIOD;  // Защита от деления на ноль.
    }

    if (strd_vals.IoT_flag && millis() % strd_vals.IoT_req_period == 0) {
        Serial.print ("Sending request to an IoT server, target IP: ");
        Serial.print(strd_vals.IoT_server_IP);
        Serial.print(", target port: ");
        Serial.println(strd_vals.IoT_server_port);

        if (ESP_TCP_client_get_server(strd_vals.IoT_server_IP, strd_vals.IoT_server_port)) {
            Serial.println("Remote server reached.");
            ESP_TCP_client_send_msg(strd_vals.IoT_req_msg);

            uint32_t TCP_client_bytes_read = ESP_TCP_client_read_line(terminal_input,
                                                                      STR_MAX_LEN,
                                                                      CONN_TIMEOUT);
            if (TCP_client_bytes_read > STR_MAX_LEN) {
                terminal_input[0] = '\0';
                handle_cmd_err_len();
            }
        } else {
            Serial.println("Remote server unavailable.");
        }
    }

    // Приём данных через Bluetooth.
    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        bool BT_was_connected = 0;
        if (strd_vals.BT_flag && ESP32_BT_check_connection()) {
            BT_was_connected = 1;
            uint32_t BT_bytes_read = 0;
            BT_bytes_read = ESP32_BT_read_line(terminal_input, STR_MAX_LEN, CONN_TIMEOUT);
            
            if (BT_bytes_read > STR_MAX_LEN) {
                terminal_input[0] = '\0';
                handle_cmd_err_len();
            }
        }
    #endif


    /*--- Обработка записанных в буфер ASCII-команд ---*/
    
    // По сути это центральный узел всего скетча.

    // Проверка заполненности буфера и наличия префикса в буфере.
    if (terminal_input[0] != '\0' && ASCII_cmd_handler_check_prefix(terminal_input, CMD_PREFIX)) {
        utilities_remove_CR_and_LF(terminal_input);

        // Проверка наличия команд в буфере.
        int32_t func_to_call = ASCII_cmd_handler_check_cmd(terminal_input, cmd_list, CMD_LIST_LEN);
        switch (func_to_call) {
            case -1:
                handle_cmd_err_cmd();
                break;

            case 0:
                handle_cmd_set_load(terminal_input);
                break;

            case 1:
                handle_cmd_set_local_SSID(terminal_input);
                break;

            case 2:
                handle_cmd_print_local_SSID();
                break;

            case 3:
                handle_cmd_set_local_pswd(terminal_input);
                break;

            case 4:
                handle_cmd_set_local_port(terminal_input);
                break;

            case 5:
                handle_cmd_print_local_port();
                break;

            case 6:
                handle_cmd_print_local_IP();
                break;

            case 7:
                handle_cmd_rst_local_conn();
                break;

            case 8:
                handle_cmd_set_IoT_flag(terminal_input);
                break;

            case 9:
                handle_cmd_set_IoT_server_IP(terminal_input);
                break;

            case 10:
                handle_cmd_print_IoT_server_IP();
                break;

            case 11:
                handle_cmd_set_IoT_server_port(terminal_input);
                break;

            case 12:
                handle_cmd_print_IoT_server_port();
                break;

            case 13:
                handle_cmd_set_IoT_req_msg(terminal_input);
                break;

            case 14:
                handle_cmd_print_IoT_req_msg();
                break;

            case 15:
                handle_cmd_set_IoT_req_period(terminal_input);
                break;

            case 16:
                handle_cmd_set_BT_flag(terminal_input);
                break;

            case 17:
                handle_cmd_set_BT_dev_name(terminal_input);
                break;

            case 18:
                handle_cmd_print_BT_dev_name();
                break;

            case 19:
                handle_cmd_set_RSSI_print_flag(terminal_input);
                break;

            default:
                break;  // Ничего не делаем, отдаём дань MISRA.
        }
    } else if (terminal_input[0] != '\0') {
        handle_cmd_err_prefix();
        ESP_TCP_clients_disconnect(CONN_SHUTDOWN_DOWNTIME);
    }
    
    
    /*--- Завершение коммуникации ---*/

    // Отключение TCP-клиентов.
    ESP_TCP_clients_disconnect(CONN_SHUTDOWN_DOWNTIME);

    // Отключение Bluetooth-соединения.
    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        if (BT_was_connected) {  /* Если повторно вызывать метод connected(),
                                  * то крашится RTOS. Поэтому пришлось ввести
                                  * дополнительный флаг.
                                  */
            ESP32_BT_disconnect(CONN_SHUTDOWN_DOWNTIME);
        }
    #endif
}


/*--- Функции-обработчики ---*/

void handle_cmd_err_prefix()
{
    handle_cmd_helper_send("Invalid prefix for a command.");
}

void handle_cmd_err_cmd()
{
    handle_cmd_helper_send("No valid command entered.");
}

void handle_cmd_err_val()
{
    handle_cmd_helper_send("No valid value submitted.");
}

void handle_cmd_err_len()
{
    handle_cmd_helper_send("Command buffer overflow.");
}

// Команда #0
void handle_cmd_set_load(char *cmd)
{
    char *cmd_val = strstr(cmd, "=") + 1;

    if (!strcmp(cmd_val, "TOGGLE")) {
        if (digitalRead(LOAD_PIN) == LOAD_ON) {
            strcpy(cmd_val, "OFF");
        } else {
            strcpy(cmd_val, "ON");
        }
    }

    if (!strcmp(cmd_val, "ON")) {
        digitalWrite(LOAD_PIN, LOAD_ON);
        handle_cmd_helper_send("LOAD ON");

        return;
    }

    if (!strcmp(cmd_val, "OFF")) {
        digitalWrite(LOAD_PIN, LOAD_OFF);
        handle_cmd_helper_send("LOAD OFF");

        return;
    }

    handle_cmd_err_val();
}

/* Выводить или не выводить новое значение изменённой настройки.
 * Для пароля не выводим, для всего остального выводим.
 */
#define ECHO_ON 1
#define ECHO_OFF 0

// Команда #1
void handle_cmd_set_local_SSID(char *cmd)
{
    handle_cmd_helper_set(cmd,
                          "SSID changed successfully! New SSID is: ",
                          INBUILT_STORAGE_ADDR_SSID,
                          ECHO_ON);
}

// Команда #2
void handle_cmd_print_local_SSID()
{
    handle_cmd_helper_print("Current SSID is: ",
                            INBUILT_STORAGE_ADDR_SSID);
}

// Команда #3
void handle_cmd_set_local_pswd(char *cmd)
{
    handle_cmd_helper_set(cmd,
                          "Password changed successfully!",
                          INBUILT_STORAGE_ADDR_PSWD,
                          ECHO_OFF);
}

// Команда #4
void handle_cmd_set_local_port(char *cmd)
{
    handle_cmd_helper_set(cmd,
                          "Local server port changed successfully! New port is: ",
                          INBUILT_STORAGE_ADDR_LOCAL_SERVER_PORT,
                          ECHO_ON);

    handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
}

// Команда #5
void handle_cmd_print_local_port()
{
    handle_cmd_helper_print("Current local server port is: ",
                            INBUILT_STORAGE_ADDR_LOCAL_SERVER_PORT);
}

// Команда #6
void handle_cmd_print_local_IP()
{
    char msg[STR_MAX_LEN * 2 + 1] = {0};
    String current_IP = ESP_WiFi_get_current_IP();
    strcpy(msg, "Current IP address is: ");
    strcat(msg, current_IP.c_str());
    handle_cmd_helper_send(msg);
}

// Команда #7
void handle_cmd_rst_local_conn()
{
    handle_cmd_helper_send("Resetting local connections...");
    ESP_TCP_clients_disconnect(CONN_SHUTDOWN_DOWNTIME);
    ESP_TCP_server_stop(CONN_SHUTDOWN_DOWNTIME);

    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        ESP32_BT_stop(CONN_SHUTDOWN_DOWNTIME);
    #endif

    setup();
}

// Команда #8
void handle_cmd_set_IoT_flag(char *cmd)
{
    char *cmd_val = strstr(cmd, "=") + 1;

    if (!strcmp(cmd_val, "ON")) {
        inbuilt_storage_write(cmd_val,
                              strlen(cmd_val),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_IOT_FLAG);

        handle_cmd_helper_send("Requests to an IoT server are enabled (ON).");
    } else if (!strcmp(cmd_val, "OFF")) {
        inbuilt_storage_write(cmd_val,
                              strlen(cmd_val),
                              INBUILT_STORAGE_STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_IOT_FLAG);

        handle_cmd_helper_send("Requests to an IoT server are disabled (OFF).");
    } else {
        handle_cmd_err_val();
    }
}

// Команда #9
void handle_cmd_set_IoT_server_IP(char *cmd)
{
    handle_cmd_helper_set(cmd,
                          "IoT server target IP changed successfully! New IP is: ",
                          INBUILT_STORAGE_ADDR_IOT_SERVER_IP,
                          ECHO_ON);
}

// Команда #10
void handle_cmd_print_IoT_server_IP()
{
    handle_cmd_helper_print("Current IoT server target IP is: ",
                            INBUILT_STORAGE_ADDR_IOT_SERVER_IP);
}

// Команда #11
void handle_cmd_set_IoT_server_port(char *cmd)
{
    handle_cmd_helper_set(cmd,
                          "IoT server target port changed successfully! New port is: ",
                          INBUILT_STORAGE_ADDR_IOT_SERVER_PORT,
                          ECHO_ON);
}

// Команда #12
void handle_cmd_print_IoT_server_port()
{
    handle_cmd_helper_print("Current IoT server target port is: ",
                            INBUILT_STORAGE_ADDR_IOT_SERVER_PORT);
}

// Команда #13
void handle_cmd_set_IoT_req_msg(char *cmd)
{
    handle_cmd_helper_set(cmd,
                          "IoT server request text changed successfully! New text is: ",
                          INBUILT_STORAGE_ADDR_IOT_REQ_MSG,
                          ECHO_ON);
}

// Команда #14
void handle_cmd_print_IoT_req_msg()
{
    handle_cmd_helper_print("Current IoT server request text is: ",
                            INBUILT_STORAGE_ADDR_IOT_REQ_MSG);
}

// Команда #15
void handle_cmd_set_IoT_req_period(char *cmd)
{
    handle_cmd_helper_set(cmd,
                          "IoT server request period changed successfully! New period (ms) is: ",
                          INBUILT_STORAGE_ADDR_IOT_REQ_PERIOD,
                          ECHO_ON);
}

// Команда #16
void handle_cmd_set_BT_flag(char *cmd)
{
    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        char *cmd_val = strstr(cmd, "=") + 1;

        if (!strcmp(cmd_val, "ON")) {
            inbuilt_storage_write(cmd_val,
                                  strlen(cmd_val),
                                  STR_MAX_LEN,
                                  INBUILT_STORAGE_ADDR_BT_FLAG);

            handle_cmd_helper_send("Bluetooth enabled (ON).");
            handle_cmd_rst_local_conn();
        } else if (!strcmp(cmd_val, "OFF")) {
            inbuilt_storage_write(cmd_val,
                                  strlen(cmd_val),
                                  STR_MAX_LEN,
                                  INBUILT_STORAGE_ADDR_BT_FLAG);

            handle_cmd_helper_send("Bluetooth disabled (OFF).");
            handle_cmd_rst_local_conn();
        } else {
            handle_cmd_err_val();
        }
    #endif
}

// Команда #17
void handle_cmd_set_BT_dev_name(char *cmd)
{
    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        handle_cmd_helper_set(cmd,
                              "Bluetooth device name changed successfully! New name is: ",
                              INBUILT_STORAGE_ADDR_BT_DEV_NAME,
                              ECHO_ON);

        handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
    #endif
}

// Команда #18
void handle_cmd_print_BT_dev_name()
{
    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        handle_cmd_helper_print("Current Bluetooth device name is: ",
                                INBUILT_STORAGE_ADDR_BT_DEV_NAME);
    #endif
}

// Команда #19
void handle_cmd_set_RSSI_print_flag(char *cmd)
{
    char *cmd_val = strstr(cmd, "=") + 1;

    if (!strcmp(cmd_val, "ON")) {
        inbuilt_storage_write(cmd_val,
                              strlen(cmd_val),
                              STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_RSSI_PRINT_FLAG);

        handle_cmd_helper_send("RSSI print enabled (ON).");
    } else if (!strcmp(cmd_val, "OFF")) {
        inbuilt_storage_write(cmd_val,
                              strlen(cmd_val),
                              STR_MAX_LEN,
                              INBUILT_STORAGE_ADDR_RSSI_PRINT_FLAG);

        handle_cmd_helper_send("RSSI print disabled (OFF).");
    } else {
        handle_cmd_err_val();
    }
}


/*--- Помощники функций-обработчиков ---*/

// Вспомогательная функция для set-обработчиков.
void handle_cmd_helper_set(char *cmd, const char *topic, int32_t addr, bool echo)
{
    char *cmd_val = strstr(cmd, "=") + 1;

    inbuilt_storage_write(cmd_val,
                          strlen(cmd_val),
                          STR_MAX_LEN,
                          addr);

    char msg[STR_MAX_LEN * 2 + 1] = {0};
    strcpy(msg, topic);

    if (echo) {
        strcat(msg, cmd_val);
    }

    handle_cmd_helper_send(msg);
}

// Вспомогательная функция для print-обработчиков.
void handle_cmd_helper_print(const char *topic, int32_t addr)
{
    char msg[STR_MAX_LEN * 2 + 1] = {0};
    strcpy(msg, topic);

    char val[INBUILT_STORAGE_STR_MAX_LEN + 1] = {0};
    inbuilt_storage_read(val,
                         sizeof(val),
                         STR_MAX_LEN,
                         addr);
    strcat(msg, val);
    handle_cmd_helper_send(msg);
}

// Вспомогательная функция для отправки сообщений обработчиками.
void handle_cmd_helper_send(char *msg)
{
    Serial.println(msg);
    ESP_TCP_server_send_msg(msg);

    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        char val[INBUILT_STORAGE_STR_MAX_LEN + 1] = {0};
        inbuilt_storage_read(val,
                             sizeof(val),
                             STR_MAX_LEN,
                             INBUILT_STORAGE_ADDR_BT_FLAG);

        if (!strcmp(val, "ON")) {
            ESP32_BT_send_msg(msg);
        }
    #endif
}


/*--- Прочие функции ---*/

// Чтение настроек со встроенного накопителя устройства в структуру.
void strd_vals_read(strd_vals_t *_strd_vals)
{
    // Индексы в массиве строк, считываемых со встроенного накопителя.
    #define INDEX_SSID               0
    #define INDEX_PSWD               1
    #define INDEX_LOCAL_SERVER_PORT  2
    #define INDEX_IOT_FLAG           3
    #define INDEX_IOT_SERVER_IP      4
    #define INDEX_IOT_SERVER_PORT    5
    #define INDEX_IOT_REQ_MSG        6
    #define INDEX_IOT_REQ_PERIOD     7
    #define INDEX_BT_FLAG            8
    #define INDEX_BT_DEV_NAME        9
    #define INDEX_RSSI_PRINT_FLAG    10


    /*--- Чтение строк со встроенного накопителя ---*/
    
    char strd_vals_str[INBUILT_STORAGE_ITEM_LIST_LEN][INBUILT_STORAGE_STR_MAX_LEN + 1] = {0};
    uint32_t strd_vals_addr[] = {
        INBUILT_STORAGE_ADDR_SSID,
        INBUILT_STORAGE_ADDR_PSWD,
        INBUILT_STORAGE_ADDR_LOCAL_SERVER_PORT,
        INBUILT_STORAGE_ADDR_IOT_FLAG,
        INBUILT_STORAGE_ADDR_IOT_SERVER_IP,
        INBUILT_STORAGE_ADDR_IOT_SERVER_PORT,
        INBUILT_STORAGE_ADDR_IOT_REQ_MSG,
        INBUILT_STORAGE_ADDR_IOT_REQ_PERIOD,
        INBUILT_STORAGE_ADDR_BT_FLAG,
        INBUILT_STORAGE_ADDR_BT_DEV_NAME,
        INBUILT_STORAGE_ADDR_RSSI_PRINT_FLAG
    };

    uint32_t strd_vals_addr_list_len = sizeof(strd_vals_addr) / sizeof(uint32_t);
    if (INBUILT_STORAGE_ITEM_LIST_LEN != strd_vals_addr_list_len) {
        Serial.println("");
        Serial.println("Error reading from inbuilt storage: function strd_vals_read().");

        return;
    }

    for (uint32_t i = 0; i < INBUILT_STORAGE_ITEM_LIST_LEN; ++i) {
        inbuilt_storage_read(strd_vals_str[i],
                             sizeof(strd_vals_str[i]),
                             INBUILT_STORAGE_STR_MAX_LEN,
                             strd_vals_addr[i]);
    }


    /*--- Запись строк и извлечённых целочисленных значений в структуру ---*/
    
    // SSID.
    strcpy(_strd_vals->SSID, strd_vals_str[INDEX_SSID]);
    
    // Пароль.
    strcpy(_strd_vals->pswd, strd_vals_str[INDEX_PSWD]);
    
    // Порт локального TCP-сервера.
    _strd_vals->local_server_port = strtol(strd_vals_str[INDEX_LOCAL_SERVER_PORT], NULL, 10);

    // Флаг связи с удалённым сервером (сервером IoT).
    if (!strcmp(strd_vals_str[INDEX_IOT_FLAG], "ON")) {
        _strd_vals->IoT_flag = 1;
    } else {
        _strd_vals->IoT_flag = 0;
    }

    // IP удалённого сервера.
    strcpy(_strd_vals->IoT_server_IP, strd_vals_str[INDEX_IOT_SERVER_IP]);
    
    // Порт удалённого сервера.
    _strd_vals->IoT_server_port = strtol(strd_vals_str[INDEX_IOT_SERVER_PORT], NULL, 10);
    
    // Текст запроса, направляемого удалённому серверу.
    strcpy(_strd_vals->IoT_req_msg, strd_vals_str[INDEX_IOT_REQ_MSG]);
    
    // Периодичность отправки запросов удалённому серверу.
    _strd_vals->IoT_req_period = strtol(strd_vals_str[INDEX_IOT_REQ_PERIOD], NULL, 10);

    #if defined THIS_IS_ESP32 && defined BLUETOOTH_PROVIDED
        // Флаг Bluetooth.
        if (!strcmp(strd_vals_str[INDEX_BT_FLAG], "ON")) {
            _strd_vals->BT_flag = 1;
        } else {
            _strd_vals->BT_flag = 0;
        }

        // Имя устройства как ведомого устройства Bluetooth.
        strcpy(_strd_vals->BT_dev_name, strd_vals_str[INDEX_BT_DEV_NAME]);
    #endif

    // Флаг вывода текущего значения RSSI.
    if (!strcmp(strd_vals_str[INDEX_RSSI_PRINT_FLAG], "ON")) {
        _strd_vals->RSSI_print_flag = 1;
    } else {
        _strd_vals->RSSI_print_flag = 0;
    }
}

Не все роутеры отдают RSSI. Более 1000 строк чтобы релюшкой пощёлкать, капец. Видно такие же гении писали ПО для станции Луна, и как ей было не разбиться.

Вообще, в таких случаях пишут откуда брать библиотеки. Например, вот с этой программа просто не компилируется. И где мне искать “правильную”? Так что, скомпилировать я её, к сожалению, не смог :frowning:

Но, даже если не смотреть на библиотеки, а посмотреть на собственный текст, то … более 1000 строк файла .ino в котором встречаются функции по 100 строк - это такой стиль программирования, чтобы было

?

И, наконец, Вы считаете, что вот на это можно забивать?

Пачка предупреждений
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_prefix()':
D:\temp\BR\BR.ino:680:59: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Invalid prefix for a command.");
                                                           ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_cmd()':
D:\temp\BR\BR.ino:685:55: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("No valid command entered.");
                                                       ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_val()':
D:\temp\BR\BR.ino:690:55: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("No valid value submitted.");
                                                       ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_len()':
D:\temp\BR\BR.ino:695:54: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Command buffer overflow.");
                                                      ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_load(char*)':
D:\temp\BR\BR.ino:713:41: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("LOAD ON");
                                         ^
D:\temp\BR\BR.ino:720:42: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("LOAD OFF");
                                          ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_local_port(char*)':
D:\temp\BR\BR.ino:767:109: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
                                                                                                             ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_rst_local_conn()':
D:\temp\BR\BR.ino:790:60: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Resetting local connections...");
                                                            ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_IoT_flag(char*)':
D:\temp\BR\BR.ino:812:77: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Requests to an IoT server are enabled (ON).");
                                                                             ^
D:\temp\BR\BR.ino:819:79: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Requests to an IoT server are disabled (OFF).");
                                                                               ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_BT_flag(char*)':
D:\temp\BR\BR.ino:894:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
             handle_cmd_helper_send("Bluetooth enabled (ON).");
                                                             ^
D:\temp\BR\BR.ino:902:63: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
             handle_cmd_helper_send("Bluetooth disabled (OFF).");
                                                               ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_BT_dev_name(char*)':
D:\temp\BR\BR.ino:919:113: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
                                                                                                                 ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_RSSI_print_flag(char*)':
D:\temp\BR\BR.ino:943:58: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("RSSI print enabled (ON).");
                                                          ^
D:\temp\BR\BR.ino:950:60: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("RSSI print disabled (OFF).");
                                                            ^

У вас не ESP8266, случаем? Просто у меня эти ворнинги вылезают только на ESP8266, но не на ESP32.

На GitHub я в сноске упомянул этот нюанс и рекомендовал его игнорировать. Да, для меня не очень важно несоответствие скетча ISO :slightly_smiling_face:

Библиотека BluetoothSerial.h стандартно поставляется вместе с “ядром” для ESP32, которое устанавливается через прописывание json в настройках Arduino IDE. Так что её нет необходимости искать и устанавливать отдельно.

Ну а если у вас вдруг ESP8266, то откуда там Bluetooth? :wink:

Учитывая, что все специфически относящиеся к конкретным коммуникациям узлы разнесены по модулям - да, я так считаю :slightly_smiling_face: Когда я дополнял проект функционалом отправки сообщений по SMTP, это потребовало минимума усилий.

Я поставил ядро из IDE, библиотеки не было. IDE 2.2.1

Эти предупреждения не имеют никакого отношения к аппаратуре. Они вылезают или не вылезают в зависимости от опций компилятора. У меня стоит “всегда выводить всё”. Вот они у меня всегда и лезут.

Здесь уже была тема, где человек игнорил именно эти варнинги, а потом с вытаращенными глазами спрашивал что у него не так и почему ничего не работает.

Видимо, поэтому я предпочитаю 1.8.19. Но досадно слышать, да.

Разумеется, просто для разных “ядер” в Arduino IDE эти опции установлены по-разному. У меня почему-то при выборе ESP32 ворнинги не вылезают, как ни крути.

А у меня всё работает :slightly_smiling_face:

Рад за Вас.

Но убедиться в этом мне не удалось :frowning:

А можете скинуть скрины из интерфейса Arduino IDE? Я правда хотел бы разобраться.

Странно, что BluetoothSerial, которая уже давным-давно поставляется вместе с ядром, не подтягивается в новую версию IDE.

Ядро

Библиотеку я уже сказал откуда взял

Вот полный

лог сообщений
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_prefix()':
D:\temp\BR\BR.ino:680:59: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Invalid prefix for a command.");
                                                           ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_cmd()':
D:\temp\BR\BR.ino:685:55: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("No valid command entered.");
                                                       ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_val()':
D:\temp\BR\BR.ino:690:55: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("No valid value submitted.");
                                                       ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_len()':
D:\temp\BR\BR.ino:695:54: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Command buffer overflow.");
                                                      ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_load(char*)':
D:\temp\BR\BR.ino:713:41: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("LOAD ON");
                                         ^
D:\temp\BR\BR.ino:720:42: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("LOAD OFF");
                                          ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_local_port(char*)':
D:\temp\BR\BR.ino:767:109: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
                                                                                                             ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_rst_local_conn()':
D:\temp\BR\BR.ino:790:60: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Resetting local connections...");
                                                            ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_IoT_flag(char*)':
D:\temp\BR\BR.ino:812:77: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Requests to an IoT server are enabled (ON).");
                                                                             ^
D:\temp\BR\BR.ino:819:79: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Requests to an IoT server are disabled (OFF).");
                                                                               ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_BT_flag(char*)':
D:\temp\BR\BR.ino:894:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
             handle_cmd_helper_send("Bluetooth enabled (ON).");
                                                             ^
D:\temp\BR\BR.ino:902:63: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
             handle_cmd_helper_send("Bluetooth disabled (OFF).");
                                                               ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_BT_dev_name(char*)':
D:\temp\BR\BR.ino:919:113: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
                                                                                                                 ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_RSSI_print_flag(char*)':
D:\temp\BR\BR.ino:943:58: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("RSSI print enabled (ON).");
                                                          ^
D:\temp\BR\BR.ino:950:60: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("RSSI print disabled (OFF).");
                                                            ^
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BTAdvertisedDeviceSet.cpp: In member function 'virtual std::__cxx11::string BTAdvertisedDeviceSet::toString()':
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BTAdvertisedDeviceSet.cpp:45:30: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'uint32_t' {aka 'unsigned int'} [-Werror=format=]
   snprintf(val, sizeof(val), "%06lx", getCOD() & 0xFFFFFF);
                              ^~~~~~~  ~~~~~~~~~~~~~~~~~~~
cc1plus.exe: some warnings being treated as errors
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:629:46: error: 'bt_mode' has not been declared
 static bool _init_bt(const char *deviceName, bt_mode mode)
                                              ^~~~~~~
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp: In function 'bool _init_bt(const char*, int)':
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:681:26: error: 'btStartMode' was not declared in this scope
     if (!btStarted() && !btStartMode(mode)){
                          ^~~~~~~~~~~
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:681:26: note: suggested alternative: 'btStarted'
     if (!btStarted() && !btStartMode(mode)){
                          ^~~~~~~~~~~
                          btStarted
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:711:5: error: 'esp_spp_cfg_t' was not declared in this scope
     esp_spp_cfg_t cfg = BT_SPP_DEFAULT_CONFIG();
     ^~~~~~~~~~~~~
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:711:5: note: suggested alternative: 'esp_spp_cb_t'
     esp_spp_cfg_t cfg = BT_SPP_DEFAULT_CONFIG();
     ^~~~~~~~~~~~~
     esp_spp_cb_t
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:712:5: error: 'cfg' was not declared in this scope
     cfg.mode = ESP_SPP_MODE_CB;
     ^~~
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:713:9: error: 'esp_spp_enhanced_init' was not declared in this scope
     if (esp_spp_enhanced_init(&cfg) != ESP_OK){
         ^~~~~~~~~~~~~~~~~~~~~
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:713:9: note: suggested alternative: 'esp_spp_deinit'
     if (esp_spp_enhanced_init(&cfg) != ESP_OK){
         ^~~~~~~~~~~~~~~~~~~~~
         esp_spp_deinit
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp: In member function 'bool BluetoothSerial::begin(String, bool, bool)':
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:842:54: error: 'BT_MODE_CLASSIC_BT' was not declared in this scope
     return _init_bt(local_name.c_str(), disableBLE ? BT_MODE_CLASSIC_BT : BT_MODE_BTDM);
                                                      ^~~~~~~~~~~~~~~~~~
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:842:54: note: suggested alternative: 'ESP_BT_MODE_CLASSIC_BT'
     return _init_bt(local_name.c_str(), disableBLE ? BT_MODE_CLASSIC_BT : BT_MODE_BTDM);
                                                      ^~~~~~~~~~~~~~~~~~
                                                      ESP_BT_MODE_CLASSIC_BT
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:842:75: error: 'BT_MODE_BTDM' was not declared in this scope
     return _init_bt(local_name.c_str(), disableBLE ? BT_MODE_CLASSIC_BT : BT_MODE_BTDM);
                                                                           ^~~~~~~~~~~~
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:842:75: note: suggested alternative: 'ESP_BT_MODE_BTDM'
     return _init_bt(local_name.c_str(), disableBLE ? BT_MODE_CLASSIC_BT : BT_MODE_BTDM);
                                                                           ^~~~~~~~~~~~
                                                                           ESP_BT_MODE_BTDM
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp: At global scope:
d:\GoogleD\Soft\libraries\BluetoothSerial\src\BluetoothSerial.cpp:629:13: error: 'bool _init_bt(const char*, int)' defined but not used [-Werror=unused-function]
 static bool _init_bt(const char *deviceName, bt_mode mode)
             ^~~~~~~~
cc1plus.exe: some warnings being treated as errors

exit status 1

Compilation error: exit status 1

Мне кажется (и я изначально это подозревал), что у вас установлено ядро от компании Arduino (для их же плат). А нужно от Espressif.

https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html

Что значит, кажется, если я Вам скрин выложил. Да, так и есть.

Почему об этом не написано в документации проекта? Ладно, попробуем.

Потому что я не предполагал, что кто-то перепутает ядро для популярных Али-плат ESP32 с ядром официальных плат для Arduino :slightly_smiling_face: Там же даже списки плат указаны (на вашем скрине ниже виден заголовок нужного ядра от ESP32).

Я без наезда, если что. Просто это действительно очень труднопредсказуемая сложность.

Супер!

Какую плату выбирать в том ядре?

Зависит от того, какой у вас модуль/плата. Если самый обычный “китаец” с чёрной паяльной маской (и на нём обычный прямоугольный серебристик без индекса после ESP32), то выбирайте ESP32 Dev Module. Если у нас, например, сиреневая Mini S2 без крышки модуля, то выбирайте LOLIN S2 Mini. Если у вас какой-то поздний вариант типа ESP32-WROVER или ESP32-C3, то ищите соответствующую опцию.

Partition scheme лучше сразу выбирать Huge App (я об этом писал в документации).

Ну, слава те Господи, хоть скомпилировалось.

Лог
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_prefix()':
D:\temp\BR\BR.ino:680:59: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Invalid prefix for a command.");
                                                           ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_cmd()':
D:\temp\BR\BR.ino:685:55: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("No valid command entered.");
                                                       ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_val()':
D:\temp\BR\BR.ino:690:55: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("No valid value submitted.");
                                                       ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_err_len()':
D:\temp\BR\BR.ino:695:54: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Command buffer overflow.");
                                                      ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_load(char*)':
D:\temp\BR\BR.ino:713:41: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("LOAD ON");
                                         ^
D:\temp\BR\BR.ino:720:42: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("LOAD OFF");
                                          ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_local_port(char*)':
D:\temp\BR\BR.ino:767:109: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
                                                                                                             ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_rst_local_conn()':
D:\temp\BR\BR.ino:790:60: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     handle_cmd_helper_send("Resetting local connections...");
                                                            ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_IoT_flag(char*)':
D:\temp\BR\BR.ino:812:77: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Requests to an IoT server are enabled (ON).");
                                                                             ^
D:\temp\BR\BR.ino:819:79: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Requests to an IoT server are disabled (OFF).");
                                                                               ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_BT_flag(char*)':
D:\temp\BR\BR.ino:894:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
             handle_cmd_helper_send("Bluetooth enabled (ON).");
                                                             ^
D:\temp\BR\BR.ino:902:63: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
             handle_cmd_helper_send("Bluetooth disabled (OFF).");
                                                               ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_BT_dev_name(char*)':
D:\temp\BR\BR.ino:919:113: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("Please reboot your device or reset local connection to put changes into effect.");
                                                                                                                 ^
D:\temp\BR\BR.ino: In function 'void handle_cmd_set_RSSI_print_flag(char*)':
D:\temp\BR\BR.ino:943:58: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("RSSI print enabled (ON).");
                                                          ^
D:\temp\BR\BR.ino:950:60: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
         handle_cmd_helper_send("RSSI print disabled (OFF).");
                                                            ^
Скетч использует 1487057 байт (47%) памяти устройства. Всего доступно 3145728 байт.
Глобальные переменные используют 57460 байт (17%) динамической памяти, оставляя 270220 байт для локальных переменных. Максимум: 327680 байт.
1 лайк

Теперь ещё и заработает, инфа сотка :slightly_smiling_face:

А можно методологический вопрос?

Вот Вы ведь не забили на эти предупреждения, а даже чего-то там про них в гитхабе написали (сразу продемонстрировав, что Ваш код написан небрежно). Не проще ли было просто правильно описать параметры функций, чтобы этих сообщений вовсе не было? Ведь по трудоёмкости правильно описать параметры, сравнимо с написанием текста на гитхабе. Так почему? Это бравада такая, типа мол “я крутой, мне закон не писан” или что?

Нужно же было оставить хоть какие-то объективные поводы для токсичности (ой, то есть для справедливой критики) :grinning:

А ворнинги я уберу. git push, выбираю тебя!