Разместите VPN за модулем Wi-Fi UART, а не внутри него
Модулю Wi-Fi UART нужен TCP-сокет, а туннелем владеет шлюз. Назовите его адрес, держите обратный путь открытым и знайте, где начинается шифрование.
Микроконтроллеру с модулем Wi-Fi UART не нужно реализовывать VPN, чтобы добраться до сервиса за ним. Модуль уже выполняет стек TCP/IP и предоставляет сокеты через последовательный порт, а шлюз в той же локальной сети может провести этот трафик через туннель. Схема работает только тогда, когда вы можете по порядку ответить на четыре вопроса, поэтому относитесь к ней как к контрольному списку: адрес, сокет, маршрут, граница. Остановитесь на первых воротах, которые не проходят, потому что последующие не могут это компенсировать.
Дайте каждому уровню одну задачу
Канал UART переносит AT-команды и полезную нагрузку между микроконтроллером и модулем. Модуль подключается к сети Wi-Fi и владеет IP-соединением, включая свой адрес источника. Шлюз владеет туннелем, учётными данными и политикой пересылки. Именно разделение этих задач делает схему отлаживаемой на каждом этапе.
Разделение меняет и то, как вы пишете политику шлюза. Правило источника должно называть адрес модуля в локальной сети, а не выдуманный адрес микроконтроллера за последовательным каналом. У микроконтроллера в этой схеме нет собственной идентичности IP, а попытка сделать вид, что она есть, порождает правило, которое никогда не совпадает.
Дайте модулю стабильный адрес любым механизмом резервирования, который поддерживает сеть, или поместите устройства в отдельный сегмент и позвольте шлюзу сопоставлять по интерфейсу. Адрес из пула, который меняется после перезагрузки, рано или поздно сломает политику, которая была верной, когда вы её писали.
Может ли шлюз назвать адрес модуля?
Прежде чем откроется любой сокет, убедитесь, что модуль подключён, имеет адрес и шлюз видит его на ожидаемом интерфейсе. Это ворота, которые чаще всего отказывают молча, потому что модуль охотно сообщит о попытке соединения, которая так и не покинула локальную сеть.
AT+CWMODE=1 AT+CWJAP="lab-wifi","passphrase" AT+CIPSTA? AT+CIPMUX=0
Режим одного соединения сохраняет последовательность команд простой, и это правильная отправная точка для одного датчика, который разговаривает с одним сервисом. Режим нескольких соединений меняет синтаксис каждой следующей команды, поэтому определите, в каком режиме вы находитесь, прежде чем копировать пример из другой версии прошивки.
Откройте сокет с модуля
Когда адрес и режим определены, модуль может открыть TCP-соединение с частным сервисом. Адрес ниже — пример из документационного диапазона; подставьте свой и сохраните ту же форму.
AT+CIPSTART="TCP","10.90.0.20",9000
AT+CIPSEND=18
{"t":21.4,"rh":48}
Эта AT-команда открывает обычный TCP-сокет, а сокет не является туннелем: ничто в нём не создаёт VPN и ничто не шифрует полезную нагрузку. Режим TLS в прошивке — отдельная функция со своей командой и своей работой с сертификатами, и произвольный модуль UART может не поддерживать ни одну из них. Сверьтесь со справочником AT-команд TCP/IP для своей прошивки, а не предполагайте, что приведённый синтаксис к ней применим.
Длина полезной нагрузки в AT+CIPSEND должна соответствовать тому, что вы действительно отправляете, иначе модуль будет ждать байты, которые никогда не придут, и соединение будет выглядеть зависшим. Эта ошибка похожа на сетевую проблему и почти всегда является ошибкой на единицу в длине.
Направьте соединение через шлюз
Шлюзу нужен маршрут к частному назначению, разрешение пересылать из сети устройств в туннель и обратный путь, который доходит до модуля. Если удалённая сторона не маршрутизирует обратно в подсеть устройств, схеме нужно осознанное правило трансляции, и это правило меняет идентичность источника, которую видит сервис.
ip route get 10.90.0.20 sudo tcpdump -ni wg0 'host 10.90.0.20 and port 9000' sudo conntrack -L | grep 9000
Сначала наблюдайте за обратным путём. Пересланный пакет, который доходит до сервиса и никогда не возвращается, даёт тайм-аут на модуле без какой-либо ошибки на шлюзе, и люди часами смотрят на канал Wi-Fi. Запись в conntrack говорит, видел ли шлюз ответ вообще.
Решите, где туннель действительно заканчивается
Туннель начинается на шлюзе. Он не шифрует канал UART и не делает сегмент локальной сети между модулем и шлюзом частью туннеля. Всё, что нуждается в защите на этом сегменте, нуждается в собственном механизме, а обычный TCP в этом примере — не TLS.
Решите и то, что происходит при падении туннеля. Если доставка должна идти только через VPN, политика пересылки не должна разрешать то же назначение по альтернативному пути, потому что резервный маршрут тихо отменяет требование. Ограничьте поведение при переподключении, чтобы отключённый модуль не затопил последовательный канал или удалённый сервис повторами.
Запишите четыре ответа вместе: адрес модуля, цель сокета, маршрут шлюза и место, где начинается шифрование. Следующему человеку, который будет отлаживать это устройство, понадобятся все четыре, и ни один из них нельзя вывести только из прошивки.