Уже много лет пользуется большой популярностью микроконтроллер ESP8266 фирмы Espressif System, главная особенность которого встроенный интерфейс Wi-Fi. Так же на рынке присутствуют множество модулей на базе этого микроконтроллера, имеющих на борту различную периферию. Основной средой разработки является платформа Arduino.

Для микроконтроллера производителем разработано программное обеспечение модема сети Wi-Fi управляемого АТ-командами. К сожалению, использование ESP8266 как модема не снискало должной популярности. В данной работе предлагается программное обеспечение взаимодействия микроконтроллера с модемом через АТ-команды для реализации асинхронного многоканального ТСР-сервера. (Скачать исходник)

Работа с модемом через АТ-команды переставляют собой обмен текстовыми строками завершающимися символами возврат каретки и перевод строки (0x0D, 0x0A, они же CR, LF, они же /r, /n). Например, для команды проверки связи с модемом:

Запрос

Ответ модема

Комментарий

АТ/r/n

 

АТ-команда

 

/r/nАТ/r/n

Эхо команды

 

/r/nOK/r/n

Ответ

Стоит отметить, что некоторые ответные сообщения модема могут начинаться с символов возврата каретки и перевода строки, то есть модем выдает строки нулевой длины, а некоторые сообщения не содержат этих префиксных символов. Таким образом, на АТ-команду модем отвечает строкой (или несколькими строками) ненулевой длины, завершающейся символами возврат каретки и перевода строки. Установить закономерность появления строк нулевой длины не представляется возможным.

Отдельно стоят асинхронные сообщения модема. Эти сообщения модем выдает не как ответ на АТ-команды, а как реакцию на какие-то внешние события. Например, с помощью сообщение «+IPD …» - модем выдает принятые из сети данные, строками «0,CONNECT/r/n», «0,CLOSE/r/n» модем сообщает о подключении/отключении клиента к серверу TCP. Асинхронные сообщения не могут вклиниться в строку сообщений модема, однако могут перебить процесс получения ответов на АТ-команды. Например:

АТ/r/n

 

АТ-команда

 

/r/nАТ/r/n

Эхо команды

 

+IPD,0,1,192.168.0.101,49176:1

Асинхронное сообщение

 

/r/nOK/r/n

Ответ

Формат и наличие асинхронных сообщений зависят от режима работы модема: точка доступа или оконечная станция, режим множественного или единичного соединения, режим клиента или сервера и т. п. К сожалению, разработчики программного обеспечения не достаточно хорошо продумали форматы асинхронных сообщений, что несколько затрудняет их идентификацию.

После глубоко анализа системы АТ-команд модема ESP8266, разработан программный модуль для микроконтроллеров реализующий многоканальный ТСР-сервер. (Скачать исходник). Программное обеспечение предназначено для использования в шаблоне «Суперцикл» и состоит из функций инициализации ServerTCPInit() и главного метода ServerTCPMain() вызываемого в суперцикле (главном цикле).

Кратко опишем работу модуля. В суперцикле вызывается главный метод. В главном методе проходит конфигурирование модема в режиме многоканального ТСР-сервера, после успешной конфигурации программа переходит в режим считывания и передачи данных модему. Считанные данные помещаются в приемный буфер типа «первый вошел, первый вышел» (FIFO), интерфейсными функциями модуля можно считать принятые данные. Отправляемые данные, с помощью интерфейсных функций, записываются в передающий буфер, модуль по наличию данных в буфере автоматически начинается их передачу модему. При выполнении на процессоре Cortex-M0 с тактовой частоте 32 МГц, максимальное время выполнения кода главного метода не превышает 200мкс.

Модуль использует следующие функции:

  • Стандартная библиотека языка Си для работы со строками <string.h>,
    Функции memset(), strncpy(), strncmp(), strlen().

  • Функции для работы с таймером.
    void StartTimer(Timer_t* t, unsigned long pt); //запустить таймер t, на время pt
    unsigned char Timer(Timer_t* t); //Узнать состояние таймера t, если не 0, то таймер сработал

    Функции работают с системным миллисекундным таймером и позволяют гибко отмерять интервалы времени. Код функций работы с таймером можно изучить в примере проекта в файлах wait.c, wait.h.

  • Функции для работы с последовательным портом.
    void PutModem(unsigned char a); //передача байта в поток вывода
    void PutStrModemF(const char* s); //передача константной строки в поток вывода из ПЗУ
    void PutStrModemM(char* s); //передача неконстантной строки в поток вывода из ОЗУ
    unsigned short InkeyModem(void); //Прием байта из потока ввода, возвращает uint16, нет данных 0, есть 0x0100|data
    void ClearModem(void); //очистка приемного буфера потока ввода
    void GetTxModem(void); //узнать количество свободного места в буфере передачи
    Для удобства портировании модуля, функции определены через макросы.
    Работа с последовательным портом и на прием, и на передачу, осуществляется через буфер FIFO. Соответственно функции ввода/вывода являются неблокирующими. Функции PutStrModemF(), PutStrModemM() по сути, являются одинаковыми, но на некоторых платформах, например AVR, требуют различной реализации, поэтому они выделены в две различные функции.
    Функция GetTxModem() возвращает количество свободного места в буфере передачи и необходима для контроля переполнения буфера передачи последовательного порта. Если контроль переполнения не требуется, то в макросе определения функции необходимо поставить ненулевое значение.

Существуют два основных метода инициализации модуля: на этапе компиляции - через константы инициализации или в процессе выполнения программы - через функции установки параметров.

Основные константы инициализации:

#define ServerTCPStationAP (1) //Использовать режим станции !0 /точки доступа 0
#define ServerTCPDHCP (0) //Использовать DHCP
#define ServerTCPLocalPort "80" //локальный порт
#define ServerTCPIpLocal "192.168.0.105" //Локальный адрес
#define ServerTCPGateway "192.168.0.1" //Шлюз
#define ServerTCPNetmask "255.255.255.0" //Маска подсети
#define ServerTCPSSID "_INT" //Наименование точки доступа для подключения
#define ServerTCPParolAP "111111111" //пароль точки доступа для подключения
#define ServerTCPSSIDNew "IBAH" //наименование точки доступа для создания
#define ServerTCPParolAPNew "0123456789" //пароль точки доступа для
#define ServerTCPChanelAP (13) //Канал создаваемой точки доступа
#define ServerTCPNumStation (1) //Максимальное количество станций подключаемых к создаваемой точке доступа
#define ServerTCPSoket (2) //Максимальное количество подключений (сокетов) к ТСР-серверу 1-5
#define ServerTCPTimout (5) //Таймаут соединения ТСР-сервера, 1–7200 секунд, 0 без таймаута
#define ServerTCPTimoutSend (2999) //Таймаут отправки пакета, мс
#define ServerTCPBufferRX (512)  //размер приемного буфера сокета, допустимые значения 16,32,64,128,256,512,1024
#define ServerTCPBufferTX (2048) //размер буфера передачи сокета, допустимые значения 16,32,64,128,256,512,1024,2048-max

Стоит отметить что каждому сокету выделяется память на этапе компиляции, например при использовании двух сокетов, 512 байт приемного буфера сокета, 2048 буфера передачи, требуемый объем оперативной памяти (2048+512)*2=5120 байт. Чем больше размер буфера передачи (константа ServerTCPBufferTX), тем меньше «накладных расходов» при передаче данных большого объема, однако программное обеспечение модема ограничивает максимальный размер блока передаваемых данных 2048 байт. Размер буфера приема (ServerTCPBufferRX) должен быть больше максимального размера блока принимаемых данных. Константа ServerTCPTimoutSend таймаут отправки пакета, это время ожидания доставки блока данных клиенту, если за это время не блок данных не будет выставлен флаг ошибки.

Для настройки настроек модуля в процессе выполнения программы можно использовать функции установки, которые необходимо вызвать сразу после вызова функции инициализации ServerTCPInit(). В случае недопустимого вызова, функций установки возвращаемое значение ненулевое.

unsigned char SetStationAPServerTCP(unsigned char a); //Установить режим станции !0/ точки доступа 0
unsigned char SetDHCPServerTCP(unsigned char a); //Включить/выключить сервер DHCP !0/0
unsigned char SetLocalPortServerTCP(const char* s); //Установить локальный порт
unsigned char SetLocalIPServerTCP(const char* s); //Установить локальный адрес
unsigned char SetGetwayServerTCP(const char* s); //Установить шлюз
unsigned char SetNetmaskServerTCP(const char* s); //Установить маску подсети
unsigned char SetNameAPServerTCP(const char* s); //Установить наименование точки доступа
unsigned char SetParolAPServerTCP(const char* s); //Установить пароль точки доступа
unsigned char SetChanelAPServerTCP(unsigned char a); //Установить канал точки доступа
unsigned char SetNumStationServerTCP(unsigned char a); //Установить количество станций подключаемых к точке доступа

Функции имеют различный смысл в зависимости от конфигураций модема, например в режиме точки функция SetDHCPServerTCP() управляет DHCP-сервером, а в режиме оконечной станции DHCP-клиентом. Функции SetNameAPServerTCP(), SetParolAPServerTCP() устанавливают либо наименование/пароль создаваемой точки доступа, либо наименование/пароль точки доступа к которой осуществляется подключение.

Обмен данными с через ТСР-сервер осуществляется посредством буферов типа FIFO через интерфейсные функции. Размер буферов указывается в константах настройки модуля. Каждая интерфейсная функция принимает в качестве аргумента номер сокета (NumSoket), к которому она обращается. Константой

#define UseCheckSoket (0)//Использовать проверку номера сокета

можно отключить проверку номера сокета.
Функции являются неблокирующими.
Функции записи в буфер передачи сокета имеют две реализации, одна записывает данные в буфер и инициирует передачу, другая только записывает данные в буфер передачи.

Функции чтения из буфера приема сокета:

unsigned short Inkey16ServerTCP(unsigned char NumSoket); //Прочитать из приемного буфера, нет данных возвращает 0, есть данные 0x0100|data
unsigned char  InkeyServerTCP(unsigned char NumSoket); //Прочитать из приемного буфера, нет данных возвращает 0

Функция Inkey16ServerTCP() предназначена для чтения бинарных данных, Функция InkeyServerTCP() для чтения текстовых данных.

Функции передачи данных:

void PutServerTCP(unsigned char a, unsigned char NumSoket); //Передать байт, сразу инициируется передача
void PutDelayServerTCP(unsigned char a, unsigned char NumSoket); //Положить в буфер передачи, передача не инициируется
void StartPutServerTCP(unsigned char NumSoket); //Инициировать передачу из буфера
unsigned char GetStartPutServerTCP(unsigned char NumSoket); //Узнать состояние передачи

Функции работы с буферами приема-передачи:

void ClearRxServerTCP(unsigned char NumSoket); //очистка буфера приема сокета
void ClearTxServerTCP(unsigned char NumSoket); //очистка буфера передачи сокета
unsigned short GetTxFreeServerTCP(unsigned char NumSoket); //Узнать количество свободного места в буфере передачи
unsigned short GetTxBusyServerTCP(unsigned char NumSoket); //Узнать количество байт в буфере передачи

Функции форматного вывода данных:

void PutStrServerTCP(const char* a, unsigned char NumSoket); //Передать строку
void PutStrDelayServerTCP(const char* a, unsigned char NumSoket); //Записать строку в буфер передачи

Вывод в десятичном виде без знака и значащих нулей:

void PutDec16uServerTCP(unsigned short a, unsigned char NumSoket);
void PutDec32uServerTCP(unsigned long a, unsigned char NumSoket);
void PutDec16uDelayServerTCP(unsigned short a, unsigned char NumSoket);
void PutDec32uDelayServerTCP(unsigned long a, unsigned char NumSoket);

Вывод в шестнадцатеричном виде

void PutHex8ServerTCP(unsigned char a, unsigned char NumSoket);
void PutHex16ServerTCP(unsigned short a, unsigned char NumSoket);
void PutHex32ServerTCP(unsigned long a, unsigned char NumSoket);
void PutHex8DelayServerTCP(unsigned char a, unsigned char NumSoket);
void PutHex16DelayServerTCP(unsigned short a, unsigned char NumSoket);
void PutHex32DelayServerTCP(unsigned long a, unsigned char NumSoket);

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

extern const volatile unsigned char InitServerTCP; //Инициализация модема
extern const volatile unsigned char ReadyServerTCP; //Готов к подключению клиента
extern const volatile unsigned char ConnectServerTCP; //Подключен клиент
extern const volatile unsigned char ErrorServerTCP; //Ошибка инициализации модема

С помощью этих переменных можно определить состояние модуля и ошибки инициализации модема.

Индикация приема/передачи данных через ТСР-сервер

extern const volatile unsigned char IndikRxServerTCP; //Индикатор Прием
extern const volatile unsigned char IndikTxServerTCP; //Индикатор Передача

Данные переменные устанавливаются в ненулевое состояние в начале процесса передачи и при приеме данных. Время индикации, время нахождения в ненулевом состоянии, определяется константами:

#define TimeRxIndik (100) //Время индикации Прием, мс
#define TimeTxIndik (100) //Время индикации Передача, мс

Считать параметры настройки модема можно с помощью следующих глобальных переменных доступных только для чтения:

extern const volatile unsigned char StationAPServerTCP; //Режим станции !0 / режим точки доступа 0
extern const volatile unsigned char OnDHCPServerTCP; //Включен DHCP
extern const volatile unsigned char ChanelAPServerTCP; //Канал точки доступа extern const volatile unsigned char NumStationServerTCP; //Количество станций подключаемых к точке доступа
extern const char IpLocalServerTCP[ServerTCPRazmerBufferIP]; //Локальный адрес
extern const char IpGatewayServerTCP[ServerTCPRazmerBufferIP]; //Шлюз
extern const char IpNetmaskServerTCP[ServerTCPRazmerBufferIP]; //Маска подсети
extern const char SSIDServerTCP[ServerTCPRazmerBufferAP]; //наименование Точки доступа
extern const char ParolAPServerTCP[ServerTCPRazmerBufferAP]; //пароль Точки доступа

Эти переменные имеют различное поведение при работе модема в режиме станции, режиме точки доступа, при включенном или выключенном клиенте/сервере DHCP.

Следующая группа переменных позволяет считать информацию о подключениях к ТСР-серверу.

extern const char IpRemovServerTCP[ServerTCPSoket][ServerTCPRazmerBufferIP]; //Удаленный адрес
extern const char PortRemovServerTCP[ServerTCPSoket][ServerTCPRazmerBufferPort]; //Удаленный порт

Следует отметить, что данные переменные являются массивом строк, количество строк в массиве определяется константой

#define ServerTCPSoket (2) //Максимальное количество подключений ТСР-сервера 1-5 

Последняя группа переменных позволяет получить информацию о работе точки доступа и сервера DHCP.

extern const char MACLocalServerTCP[ServerTCPRazmerBufferMAC]; //локальный MAC адрес. Обновляется при подключении в режиме станции к DHCP-серверу
extern const char ConMACAdressServerTCP[ServerTCPRazmerBufferMAC]; //Последний подключившийся MAC к точке доступа. Обновляется в режиме Точки доступа
extern const char DisMACAdressServerTCP[ServerTCPRazmerBufferMAC]; //Последний отключившийся MAC от точки доступа. Обновляется в режиме Точки доступа
extern const char DHCPIPAdressServerTCP[ServerTCPRazmerBufferIP]; //Последний выданный DHCP-сервером IP-адрес. Обновляется в режиме Точки доступа и DHCP-сервера
extern const char DHCPMACAdressServerTCP[ServerTCPRazmerBufferMAC];//Последний MAC которому DHCP-сервер выдавал IP-адрес. Обновляется в режиме Точки доступа и DHCP-сервера

Эти переменные, также имеют различное поведение при работе модема в режиме станции, режиме точки доступа, при включенном или выключенном клиенте/сервере DHCP, что отражено в комментариях.

Пример проекта собран в среде разработки IAR7, для микроконтроллера STM32L072. Протестирован с версией ПО модема 3.0.5 (от 08.2021).

Пример получен урезанием всего лишнего из работающего устройства. Данный проект предназначен для изучения приемов работы с ТСР-сервером. В примере реализован простейший асинхронный Web-сервер, выдающий страничку с основными параметрами устройства. Сервер поддерживает два подключения. Настройки и состояние ТСР-сервера доступны по интерфейсу Modbus

Из периферии микроконтроллера используются:

  • Системный таймер (файлы wait.h, wait.c), на котором реализованы функции измерения интервалов времени.

  • LPUART (файлы uart0.h, uart0DMATx.c), непосредственно в проекте не используется, однако на это порт можно выводить отладочную информацию о работе модуля. Вывод отладочной инфор мации определяется константами:
    #define OTLADKA (0) //включить режим отладки при инициализации модема
    #define OTLADKA_IPD (0) //включить режим отладки при приеме данных
    #define OTLADKA_IPD_ERR (0) //включить режим выдачи сообщений об ошибках при приеме
    #define OTLADKA_IPD_DATA (0) //включить режим отображения принимаемых данных
    #define OTLADKA_TX (0) //включить режим отладки при передаче данных
    #define OTLADKA_TX_DATA (0) //включить режим отображения передаваемых данных

  • USART1 (файлы uart1.h, uart1DMATx.c) используется для обмена по протоколу Modbus RTU со скадой.

  • USART2 (файлы uart2.h, uart2InteruptTx.c) используется для обмена данными с модемом ESP8266.

Для сохранения настроек модема используется микросхема FRAM памяти FM25l256. Интерфейс памяти в файлах FM25L256.h, FM25L256.c. Описание энергонезависимых данных и функции автоматического сохранения/восстановления данных в файлах SaveRestore.h, SaveRestore.c.

В файле main.h определен битовый регистр состояния устройства. Из регистра удалены флаги, не имеющие отношения к работе ТСР и Web серверов.

Кратко опишем работу программы. После старта микроконтроллера происходит инициализация всех периферийных модулей. А так же инициализация ТСР-сервера и Web-сервера. В главном цикле последовательно вызываются функции  ТСР-сервера, Web-сервера, интерфейса Modbus RTU и интерфейса автоматического сохранения энергонезависимых данных.

Состояние, настройки, а также служебные переменные модема выводятся и загружаются по интерфейсу Modbus RTU. Описание и адреса тегов для чтения можно посмотреть в файле функции Prg2ModBusOutReg(), а тегов для записи в функции ModBus2PrgOutReg() (файл ModBus2Prg.c). Стоит отметить, что заполнение регистров Modbus происходит различными значениями при разных настройках модема, режим точки доступа или режим оконечной станции, включенном выключенном клиенте или сервере DHCP. Например, в режиме оконечной станции при включенном DHCP-клиенте в регистры Modbus записывается значение строки параметров ТСР-сервера, а при выключенном DHCP-клиенте значение настроек из энергонезависимой памяти. Это позволяет через интерфейс Modbus гибко конфигурировать модем, используя минимальное количество регистров.

С помощью интерфейсных функций ТСР-сервера данные HTTP запроса считываются Web-сервером. Сервер формирует страничку в соответствии с запросом браузера. Описание файловой системы Web-сайта можно посмотреть в файле WebSite.h.

В завершении несколько фотографий.

Электрический шкаф с платой контроллера, на которой установлен модуль ESP-01S
Электрический шкаф с платой контроллера, на которой установлен модуль ESP-01S
Страница скады с настройками модема ESP8266
Страница скады с настройками модема ESP8266

В заключении хочется отметить, что модем на базе ESP8266, хоть и не отличается высоким быстродействием и не предназначен для передачи больших объемов данных, но является вполне адекватным устройством при своей стоимости. Тестирование в режиме приема-передачи в сети Wi-Fi совместно с Modbus-клиентом показало, что пропадает один блок данных на 40-50 тысяч запросов с интервалом 100мс. Возможно, это не является ошибкой, просто был превышен таймаут отправки блока данных, если таймаут установить большим значением количество ошибок существенно уменьшится.

Скачать исходные файлы ТСР-сервера

Скачать пример проекта

Комментарии (48)


  1. wigneddoom
    21.12.2024 17:13

    Я видел такое, что вам, людям, и не снилось. Атакующие корабли, пылающие над Орионом; Лучи Си, разрезающие мрак у ворот Тангейзера. Все эти мгновения затеряются во времени, как... слёзы в дожде... Пришло время умирать.

    Восемь лет назад, чтобы не "зашквариться" об Ардуино, я собирал под линуксом компилятор GGC с патчами для Tensilica Xtensa. Оптимизировал нашу прошивку, чтобы она полностью из RAM выполнялась, а не с флешки. Воевал с WiFi стеком, который цельнотянут с BSD. Эх, были времена...


  1. tigreavecdesailes
    21.12.2024 17:13

    Как поднять Wi-Fi на ESP8266 и не зашквариться об Arduino

    Использовать замечательный родной SDK на бвзе FreeRTOS

    https://github.com/espressif/ESP8266_RTOS_SDK


    1. IBAH_II Автор
      21.12.2024 17:13

      Если АТ-команду существуют, должен же ими кто-то пользоваться


      1. Moog_Prodigy
        21.12.2024 17:13

        Обычно ими пользуются те, кто работает с такими железками как SIM900 и иже с ними. Ну или с железными диалап-модемами.


        1. VirtualVoid
          21.12.2024 17:13

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


        1. vrangel
          21.12.2024 17:13

          Это если зашквариться об Ардуино. Шутка. Для модемов типа sim800 есть замечательный компонент в esp-idf, который реализует PPP over serial. В Arduino ide, вроде, тоже можно использовать.


          1. Moog_Prodigy
            21.12.2024 17:13

            Понятно, что под ESP нашлось, но есп относительно молодая платформа, в то же время можно спаять простейший преобразователь уровня и воткнуть sim900 в com-порт 80486 компа и пообщаться в консоли. Даже смски отправлять. Или с AVR-а \PIC условного. Большинство сигнализаций (для зданий и помещений) именно так и устроены (те, которые ставят ЧОПы всякие).


  1. randomsimplenumber
    21.12.2024 17:13

    не зашквариться об Arduino

    Как говорится, вечер в хату, господа программисты. Кофе-брейк в радость, печенька в сладость.


    1. IBAH_II Автор
      21.12.2024 17:13

      Тогда "не оскоромиться". Аминь.

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


  1. Equity184
    21.12.2024 17:13

    а что не так с arduino ?


    1. Dark_Purple
      21.12.2024 17:13

      Зашквар для профи))


      1. Denev
        21.12.2024 17:13

        Подозреваю, что в средние века переписчики книг в таком же духе о печатном станке отзывались. "Это что же теперь все кто хочешь книги читать смогу и грамоте учиться. Действительно, что же это делается!"


        1. Moog_Prodigy
          21.12.2024 17:13

          Мне нравится ваша аналогия. Действительно. Рукописные книги это - крутые иллюстрации (или нет, но все же), это - занятие для многих монахов, занятие прибыльное условному монастырю, опять же переписчика надо учить, и на выходе получаем каллиграфиста и художника в одном лице (или двух) - кроме переписи книг эти люди становятся грамотными специалистами. А станок - херак и в продакшн.

          Но аналогия эта ложная. Ардуино - это как представьте дать людям из средневековья возможности самых навороченных сегодняшних или даже будущих LLM. Все, и картинки, сюжет и тексты будет генерировать она. А тебе достаточно скормить ей нужный промт. Возможно "заклинания" - это прообраз промта мечтателей того времени. "Эх, был бы я писателем, написал бы вот такую книгу, там вот это и вот то, а потом вот так, ух!". И вот заклинания такие люди ищут, собирают в сборники, пишут с их помощью книги...А потом удивляются, почему даже при самом навороченном промте их книги совершенно не хотят читать.

          ---передал вышенаписанное локальной нейронке "как ты видишь развитие этой истории дальше?"----

          Затем нашелся упоротый чел, который настолько хотел стать писателем и написать книгу своей мечты, что писал промт 2 года. Но когда он его дописал, он не стал его отправлять LLM, а просто оформил в виде книги. И это стало бестселлером!


  1. 4chemist
    21.12.2024 17:13

    Лапша из if не читаема. Воспользовались бы switch-case вариантом.

    Велосипедов полон код. Особенно доставило ваше "!0".

    С комментариями переборщили, следует писать код так чтобы он был понятен с минимумом комментариев.

    "Магических" констант в коде не должно быть, ваша переменная SostWiFi постоянно сравнивается с этими "магическими" константами.


    1. IBAH_II Автор
      21.12.2024 17:13

      Лапша из if не читаема. Воспользовались бы switch-case вариантом.

      Не читаема? ну и не читайте! Я бы воспользовался switch-case, но мне нужен if.

      Велосипедов полон код. Особенно доставило ваше "!0".

      Некоторые пишут false-true, я предпочитаю 0 и !0, Меньше букв, больше смысла. В первом стандарте Си они и были так определены, привычка.

      С комментариями переборщили, следует писать код так чтобы он был понятен с минимумом комментариев.

      Кому следует? Последствия многократного код ревью и рефакторинга

      "Магических" констант в коде не должно быть, ваша переменная SostWiFi постоянно сравнивается с этими "магическими" константами.

      Это вы программистам на бейсике скажите, там в каждой строке магическая константа.


      1. 4chemist
        21.12.2024 17:13

        Вы очень болезненно отреагировали на мой комментарий. Я тоже на критику болезненно реагировал сразу после вуза.)

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

        Касательно комментирования кода. Многие имена переменных совершенно ни о чем не говорят при первом взгляде, когда в голове еще нет контекста. Я бы даже предложил провести минификацию исходного кода, и меньше объема занимать будет, и читаемость не ухудшится.)

        О магических константах - 42. Вы сразу же должны понять что это за константа такая.)


        1. Qlavrt
          21.12.2024 17:13

          Кто понял, ставим лайк )


  1. Kononvaler
    21.12.2024 17:13

    Ничего не понял. А что, с тойже wifi.h , не жизнь? Для чего этот модем?


    1. randomsimplenumber
      21.12.2024 17:13

      если бы у рыбы была шерсть..

      Если есть устройство, умеющее в команды модема..


      1. Kononvaler
        21.12.2024 17:13

        В примере у автора вроде был modbus. Он умеет в tcp.
        Если есть устройство умеющее в AT, то лучше наверно модемную связь и использовать, поболе чем 150 метров будет. RS485 иже.
        Практическог применения что-то не пойму. Ради упоминаемого зашквара ежели?

        А, уже не один я этим вопросом задался... Свежие коменты почитал.


    1. IBAH_II Автор
      21.12.2024 17:13

      в заголовке же сказано, чтоб не зашкварится.

      Зачем мне осваивать Ардуино?

      У меня в стеке освоенные МК, с кучей наработок.

      Лепить на ардуино сервер, лепить какой-то протокол для обмена данными между основным МК и ESP... Плодить слои абстракций, привязанных к конкретному устройству...

      Уж лучше возьму готовое устройство WiFi-модем, напишу универсальную библиотеку и подключу к своей системе, в последствии и к другим системам. И буду счастлив.


  1. Hexlight
    21.12.2024 17:13

    Имхо, паять на плату модуль питания с Aliexpres это кратно больший "зашквар", чем Arduino.


    1. kenomimi
      21.12.2024 17:13

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

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


  1. EvilTeacher
    21.12.2024 17:13

    Прекрасно. Мы увидели возможности ESP-шки. Но у меня остался один вопрос: ЗАЧЕМ?... Вот я сейчас достану из коробки одну из кучки 8266, подключу ее к своей рабочей системе... Чтобы ЧТО? Я, конечно, могу вспомнить AT-команды, которыми мучал свой старенький Zyxel, но этот Зухель уже давным давно в своем кремниевом раю...
    А давайте на базе ESP-шки соберем Спектрум и будем в него шпилить с осознанием высоты своего величия... Или вернемся к DOS, телефонным модемам на 2400 и FIDO. Развернем эволюцию вспять и посрамим дедушку Дарвина!
    Извините. Вырвалось прямо на клавиатуру.


    1. MaFrance351
      21.12.2024 17:13

      А давайте на базе ESP-шки соберем Спектрум

      Было уже, кстати:


  1. yakBober
    21.12.2024 17:13

    Только из названия возникает вопрос .Почему именно ESP8266?


    1. IBAH_II Автор
      21.12.2024 17:13

      Потому что на ESP8266 есть недорогой доступный WiFi-модем.


  1. JIexa21
    21.12.2024 17:13

    Когда возился с этим ESP, то насколько помню, то там была куча примеров с помощью которых запустил все что мне надо минут за 5...
    Зачем эта портянка тут? Кто-то будет это использовать? Не думаю...


    1. randomsimplenumber
      21.12.2024 17:13

      Емнип esp01 искаропки прошита как модем. т.е. если нужен модем с АТ командами - можно просто взять готовый. Где должен запускаться предложенный автором веб-сервер - на модеме, или на внешнем контроллере, я что-то не очень понял.


      1. a3296282
        21.12.2024 17:13

        У автора веб-сервер крутится на внешнем контроллере, ESP используется как WiFi модуль, управляется АТ командами.

        Мной таким же образом сделан MQTT клиент, с двумя вариантами беспроводной сети GSM или WiFi


        1. IBAH_II Автор
          21.12.2024 17:13

          Спасибо. Хоть кто-то прочитал статью.


        1. SmartTherm
          21.12.2024 17:13

          это примерно как в анекдоте про того чудо-хирурга, который удалял гланды через анус... Чего б не сделать веб сервер на ESP и общаться с ним по уарту


  1. StrawberryPie
    21.12.2024 17:13

    Зашкварился AT командами


  1. Nyptus
    21.12.2024 17:13

    2024 год - уже как 11 лет "професионналы" продложают хоронить Arduino.
    ...to be continued


  1. RolexStrider
    21.12.2024 17:13

    Почему писать в Arduino IDE - зашквар (сам в свое время поднабравшись опыта перешел на AVR Studio и чистый C) - но это же просто набор макросов, а под капотом тот же avr-gcc? И что, всех кто пытается делать минимальные реализации Python/JS делать для AVR - сразу "под шконку и в петушиную масть"?


  1. kenomimi
    21.12.2024 17:13

    Ардуино это не зашквар. Это суперклей и синяя изолента мира железа/программирования. Вот прямо сейчас парой килобайт своего кода я завел связку ESP32 + EINK 7' - оно подписывается на mqtt топики устройств умного дома и показывает результат. Что-то считает. Сколько я такое делал бы без ардуино и модулей? Полгода? А с ардуино два вечера вместе с печатью корпуса. Да, бинарь весит полтора метра, а не пять килобайт, как хотелось бы гуру - но модули ESP32 настолько дешевые и мощные, что как бы пофиг на эту неоптимальность. Стабильность? Собрал весь умный дом на этих самых модулях - на многих аптайм уже по полгода... Разве что никаких болтающихся проводков, все паяю, прикручиваю, или заливаю пластиком, если нельзя закрепить нормально.

    Так что всему свое место. Иногда нужно делать что-то дендрофекальным способом, и ничего плохого в этом нет. Лишь бы было понимание, где так можно, а где нет.


    1. Kononvaler
      21.12.2024 17:13

      e-lnk 7 цветов или 7 дюймов? Чет дорогие штуки результат показывать, дешевле старый планшет в режим киоска загнать и mqtt в нодеред и в дашбоард послать.
      По потреблению эл.энегрии правда наверно через полгода окупится...


      1. Borz
        21.12.2024 17:13

        Чет дорогие штуки

        на алике за 9k рублей за 7 цветов в 7 дюймов и драйвером в комплекте - дорого?


        1. Kononvaler
          21.12.2024 17:13

          думаю не дешево сто баксов только за экран.


      1. randomsimplenumber
        21.12.2024 17:13

        Главное чтобы старый планшет прожил эти полгода ;) Как у него с деградацией батареи и дисплея?

        А хобби-:проект и не должен окупаться.


        1. kenomimi
          21.12.2024 17:13

          Висит леново и самсунг, уже больше года - полет нормальный. Брал их уже столетними б\у, смотрел только на внешний вид и версию андроида. Самсунг олед, но ничего за год не выгорело... Батарею вообще можно снять, заменив подходящим ионистором, чтобы при мигании света планшет не вырубался.


        1. Kononvaler
          21.12.2024 17:13

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


      1. kenomimi
        21.12.2024 17:13

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

        Старые планшеты 2 штуки использую как пульты управления, тоже взял по тыще каждый, перешил на AOSP, сделал лончером openhab и повесил на стену - уже год как идеально. Но в спальню, например, вешать планшет плохая идея - он светит сильно очень. Там для показометра eink идеально подходит.


        1. Kononvaler
          21.12.2024 17:13

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


  1. dexterhtcone
    21.12.2024 17:13

    Спасибо за статью и за код.


    1. IBAH_II Автор
      21.12.2024 17:13

      Харбрардунинодетект дает отрицательные результаты. Не все потеряно!


  1. SmartTherm
    21.12.2024 17:13

    Грешен. Занимался такой же херью. Чтобы не связываться с ардуиной.

    Изгалялся с AT командами и отловом состояния неонки внутре родной прошивки от Экспресиф. Исплевался.

    А потом перешел на framework = arduino в platformio. И забыл как страшный сон и AT гемморой, и заморочки Arduino ide


    1. randomsimplenumber
      21.12.2024 17:13

      platformio ништяк. В нем и Arduino core не зашкварно трогать за хидеры.