feat: Add DALI raw frame handling and USB setup bridge
- Introduced DaliRawFrame structure to encapsulate raw frame data. - Enhanced DaliDomainService to manage raw frame sinks and processing. - Implemented raw frame task for asynchronous handling of incoming DALI frames. - Integrated raw frame handling in GatewayBleBridge and GatewayNetworkService. - Added GatewayUsbSetupBridge to facilitate USB Serial/JTAG communication with DALI. - Configured ESP-NOW for wireless communication and setup management. - Updated GatewayRuntime to support clearing wireless credentials on boot button long press. - Enhanced CMakeLists to include new components and dependencies. Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "gateway_network.hpp"
|
||||
|
||||
#include "dali_domain.hpp"
|
||||
#include "gateway_controller.hpp"
|
||||
#include "gateway_runtime.hpp"
|
||||
|
||||
@@ -9,6 +10,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_ip_addr.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
@@ -26,6 +28,9 @@ namespace {
|
||||
constexpr const char* kTag = "gateway_network";
|
||||
constexpr const char* kSetupApSsid = "LAMMIN_Gateway";
|
||||
constexpr size_t kUdpBufferSize = 256;
|
||||
constexpr uint8_t kEspNowBroadcastMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
GatewayNetworkService* s_espnow_service = nullptr;
|
||||
|
||||
class LockGuard {
|
||||
public:
|
||||
@@ -86,6 +91,43 @@ std::string MacToHex(const uint8_t mac[6]) {
|
||||
return std::string(out);
|
||||
}
|
||||
|
||||
std::string LocalMacHex(wifi_interface_t interface) {
|
||||
uint8_t mac[6] = {};
|
||||
if (esp_wifi_get_mac(interface, mac) != ESP_OK) {
|
||||
return {};
|
||||
}
|
||||
return MacToHex(mac);
|
||||
}
|
||||
|
||||
const char* JsonString(cJSON* parent, const char* name) {
|
||||
cJSON* item = cJSON_GetObjectItem(parent, name);
|
||||
return cJSON_IsString(item) ? item->valuestring : nullptr;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> BytesFromJsonString(const char* value) {
|
||||
if (value == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string_view text(value);
|
||||
auto decoded = DecodeHex(text);
|
||||
if (!decoded.empty() || text.empty()) {
|
||||
return decoded;
|
||||
}
|
||||
return std::vector<uint8_t>(text.begin(), text.end());
|
||||
}
|
||||
|
||||
std::string BytesToHex(const std::vector<uint8_t>& bytes) {
|
||||
static constexpr char kHex[] = "0123456789ABCDEF";
|
||||
std::string out;
|
||||
out.reserve(bytes.size() * 2);
|
||||
for (uint8_t byte : bytes) {
|
||||
out.push_back(kHex[(byte >> 4) & 0x0F]);
|
||||
out.push_back(kHex[byte & 0x0F]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string PrintJson(cJSON* node) {
|
||||
if (node == nullptr) {
|
||||
return {};
|
||||
@@ -132,8 +174,9 @@ esp_err_t RegisterUri(httpd_handle_t server, const char* uri, httpd_method_t met
|
||||
|
||||
GatewayNetworkService::GatewayNetworkService(GatewayController& controller,
|
||||
GatewayRuntime& runtime,
|
||||
DaliDomainService& dali_domain,
|
||||
GatewayNetworkServiceConfig config)
|
||||
: controller_(controller), runtime_(runtime), config_(config),
|
||||
: controller_(controller), runtime_(runtime), dali_domain_(dali_domain), config_(config),
|
||||
udp_lock_(xSemaphoreCreateMutex()) {}
|
||||
|
||||
esp_err_t GatewayNetworkService::start() {
|
||||
@@ -146,7 +189,12 @@ esp_err_t GatewayNetworkService::start() {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (config_.wifi_enabled) {
|
||||
if (config_.espnow_setup_startup_enabled) {
|
||||
err = startSetupAp();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
} else if (config_.wifi_enabled) {
|
||||
err = startWifi();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
@@ -158,9 +206,15 @@ esp_err_t GatewayNetworkService::start() {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = configureBootButton();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
controller_.addNotificationSink(
|
||||
[this](const std::vector<uint8_t>& frame) { handleGatewayNotification(frame); });
|
||||
controller_.addWifiStateSink([this](uint8_t mode) { handleWifiControl(mode); });
|
||||
dali_domain_.addRawFrameSink([this](const DaliRawFrame& frame) { handleDaliRawFrame(frame); });
|
||||
|
||||
if (config_.http_enabled) {
|
||||
err = startHttpServer();
|
||||
@@ -176,6 +230,11 @@ esp_err_t GatewayNetworkService::start() {
|
||||
}
|
||||
}
|
||||
|
||||
err = startBootButtonTask();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
started_ = true;
|
||||
ESP_LOGI(kTag, "network service started http=%d udp=%d", config_.http_enabled,
|
||||
config_.udp_enabled);
|
||||
@@ -202,6 +261,7 @@ esp_err_t GatewayNetworkService::startWifi() {
|
||||
if (wifi_started_) {
|
||||
return ESP_OK;
|
||||
}
|
||||
stopEspNow();
|
||||
setup_ap_started_ = false;
|
||||
|
||||
if (wifi_sta_netif_ == nullptr) {
|
||||
@@ -299,6 +359,7 @@ esp_err_t GatewayNetworkService::startSetupAp() {
|
||||
}
|
||||
|
||||
if (wifi_started_) {
|
||||
stopEspNow();
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_disconnect());
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_stop());
|
||||
}
|
||||
@@ -327,12 +388,106 @@ esp_err_t GatewayNetworkService::startSetupAp() {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (config_.espnow_setup_enabled) {
|
||||
err = startEspNow();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(kTag, "setup AP started without ESP-NOW: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
wifi_started_ = true;
|
||||
setup_ap_started_ = true;
|
||||
ESP_LOGI(kTag, "setup AP started ssid=%s ip=192.168.3.1", kSetupApSsid);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t GatewayNetworkService::startEspNow() {
|
||||
if (espnow_started_) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_now_init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(kTag, "failed to init ESP-NOW: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
s_espnow_service = this;
|
||||
err = esp_now_register_recv_cb(&GatewayNetworkService::HandleEspNowReceive);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(kTag, "failed to register ESP-NOW RX callback: %s", esp_err_to_name(err));
|
||||
esp_now_deinit();
|
||||
s_espnow_service = nullptr;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = addEspNowPeer(kEspNowBroadcastMac, true);
|
||||
if (err != ESP_OK) {
|
||||
esp_now_unregister_recv_cb();
|
||||
esp_now_deinit();
|
||||
s_espnow_service = nullptr;
|
||||
return err;
|
||||
}
|
||||
|
||||
espnow_connected_ = false;
|
||||
espnow_peer_.fill(0);
|
||||
espnow_started_ = true;
|
||||
ESP_LOGI(kTag, "ESP-NOW setup ingress started local_mac=%s", LocalMacHex(WIFI_IF_AP).c_str());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void GatewayNetworkService::stopEspNow() {
|
||||
if (!espnow_started_) {
|
||||
return;
|
||||
}
|
||||
|
||||
esp_now_unregister_recv_cb();
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_now_deinit());
|
||||
if (s_espnow_service == this) {
|
||||
s_espnow_service = nullptr;
|
||||
}
|
||||
espnow_connected_ = false;
|
||||
espnow_started_ = false;
|
||||
espnow_peer_.fill(0);
|
||||
}
|
||||
|
||||
esp_err_t GatewayNetworkService::addEspNowPeer(const uint8_t* mac, bool broadcast) {
|
||||
if (mac == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (esp_now_is_peer_exist(mac)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_now_peer_info_t peer = {};
|
||||
std::memcpy(peer.peer_addr, mac, sizeof(peer.peer_addr));
|
||||
peer.channel = 0;
|
||||
peer.ifidx = setup_ap_started_ || broadcast ? WIFI_IF_AP : WIFI_IF_STA;
|
||||
peer.encrypt = false;
|
||||
esp_err_t err = esp_now_add_peer(&peer);
|
||||
if (err == ESP_ERR_ESPNOW_EXIST) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(kTag, "failed to add ESP-NOW peer %s: %s", MacToHex(mac).c_str(),
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t GatewayNetworkService::sendEspNowJson(const uint8_t* mac, const std::string& payload) {
|
||||
if (mac == nullptr || payload.empty()) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = addEspNowPeer(mac, std::memcmp(mac, kEspNowBroadcastMac, 6) == 0);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return esp_now_send(mac, reinterpret_cast<const uint8_t*>(payload.data()), payload.size());
|
||||
}
|
||||
|
||||
esp_err_t GatewayNetworkService::configureStatusLed() {
|
||||
if (config_.status_led_gpio < 0) {
|
||||
return ESP_OK;
|
||||
@@ -354,6 +509,25 @@ esp_err_t GatewayNetworkService::configureStatusLed() {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t GatewayNetworkService::configureBootButton() {
|
||||
if (config_.boot_button_gpio < 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
gpio_config_t io_config = {};
|
||||
io_config.pin_bit_mask = 1ULL << static_cast<uint32_t>(config_.boot_button_gpio);
|
||||
io_config.mode = GPIO_MODE_INPUT;
|
||||
io_config.pull_up_en = config_.boot_button_active_low ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
|
||||
io_config.pull_down_en = config_.boot_button_active_low ? GPIO_PULLDOWN_DISABLE : GPIO_PULLDOWN_ENABLE;
|
||||
io_config.intr_type = GPIO_INTR_DISABLE;
|
||||
const esp_err_t err = gpio_config(&io_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(kTag, "failed to configure boot button GPIO%d: %s", config_.boot_button_gpio,
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t GatewayNetworkService::startHttpServer() {
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.server_port = config_.http_port;
|
||||
@@ -409,10 +583,31 @@ esp_err_t GatewayNetworkService::startUdpTask() {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t GatewayNetworkService::startBootButtonTask() {
|
||||
if (config_.boot_button_gpio < 0 || boot_button_task_handle_ != nullptr) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const BaseType_t created =
|
||||
xTaskCreate(&GatewayNetworkService::BootButtonTaskEntry, "gateway_boot_btn",
|
||||
config_.boot_button_task_stack_size, this, config_.boot_button_task_priority,
|
||||
&boot_button_task_handle_);
|
||||
if (created != pdPASS) {
|
||||
boot_button_task_handle_ = nullptr;
|
||||
ESP_LOGE(kTag, "failed to create boot button task");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void GatewayNetworkService::UdpTaskEntry(void* arg) {
|
||||
static_cast<GatewayNetworkService*>(arg)->udpTaskLoop();
|
||||
}
|
||||
|
||||
void GatewayNetworkService::BootButtonTaskEntry(void* arg) {
|
||||
static_cast<GatewayNetworkService*>(arg)->bootButtonTaskLoop();
|
||||
}
|
||||
|
||||
void GatewayNetworkService::HandleWifiEvent(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data) {
|
||||
auto* service = static_cast<GatewayNetworkService*>(arg);
|
||||
@@ -421,6 +616,13 @@ void GatewayNetworkService::HandleWifiEvent(void* arg, esp_event_base_t event_ba
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayNetworkService::HandleEspNowReceive(const esp_now_recv_info_t* info,
|
||||
const uint8_t* data, int data_len) {
|
||||
if (s_espnow_service != nullptr) {
|
||||
s_espnow_service->handleEspNowReceive(info, data, data_len);
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayNetworkService::handleWifiEvent(esp_event_base_t event_base, int32_t event_id,
|
||||
void* event_data) {
|
||||
if (!config_.wifi_enabled) {
|
||||
@@ -459,6 +661,139 @@ void GatewayNetworkService::handleWifiEvent(esp_event_base_t event_base, int32_t
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayNetworkService::handleEspNowReceive(const esp_now_recv_info_t* info,
|
||||
const uint8_t* data, int data_len) {
|
||||
if (!espnow_started_ || info == nullptr || info->src_addr == nullptr || data == nullptr ||
|
||||
data_len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string payload(reinterpret_cast<const char*>(data),
|
||||
static_cast<size_t>(data_len));
|
||||
cJSON* root = cJSON_Parse(payload.c_str());
|
||||
if (root == nullptr) {
|
||||
ESP_LOGW(kTag, "ignored non-JSON ESP-NOW setup packet len=%d", data_len);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* type = JsonString(root, "type");
|
||||
if (type == nullptr) {
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
|
||||
addEspNowPeer(info->src_addr);
|
||||
const std::string local_mac = LocalMacHex(WIFI_IF_AP);
|
||||
|
||||
if (std::strcmp(type, "connReq") == 0) {
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
if (response != nullptr) {
|
||||
cJSON_AddStringToObject(response, "type", "connRsp");
|
||||
cJSON_AddStringToObject(response, "data", "");
|
||||
cJSON_AddStringToObject(response, "dst", MacToHex(info->src_addr).c_str());
|
||||
cJSON_AddStringToObject(response, "src", local_mac.c_str());
|
||||
cJSON_AddStringToObject(response, "pmk", "");
|
||||
const std::string rendered = PrintJson(response);
|
||||
sendEspNowJson(kEspNowBroadcastMac, rendered);
|
||||
cJSON_Delete(response);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::strcmp(type, "connAck") == 0) {
|
||||
if (!espnow_connected_) {
|
||||
std::memcpy(espnow_peer_.data(), info->src_addr, espnow_peer_.size());
|
||||
espnow_connected_ = true;
|
||||
ESP_LOGI(kTag, "ESP-NOW setup peer connected mac=%s", MacToHex(info->src_addr).c_str());
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::strcmp(type, "echo") == 0) {
|
||||
if (espnow_connected_) {
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
if (response != nullptr) {
|
||||
cJSON_AddStringToObject(response, "type", "echoRsp");
|
||||
cJSON_AddStringToObject(response, "data", "");
|
||||
const std::string rendered = PrintJson(response);
|
||||
sendEspNowJson(info->src_addr, rendered);
|
||||
cJSON_Delete(response);
|
||||
}
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::strcmp(type, "cmd") == 0 || std::strcmp(type, "data") == 0) {
|
||||
const auto frame = BytesFromJsonString(JsonString(root, "data"));
|
||||
if (!frame.empty()) {
|
||||
controller_.enqueueCommandFrame(frame);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::strcmp(type, "uart") == 0) {
|
||||
cJSON* num = cJSON_GetObjectItem(root, "num");
|
||||
const auto frame = BytesFromJsonString(JsonString(root, "data"));
|
||||
if (cJSON_IsNumber(num) && !frame.empty()) {
|
||||
handleSetupUartFrame(num->valueint, frame);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
void GatewayNetworkService::handleSetupUartFrame(int setup_id,
|
||||
const std::vector<uint8_t>& frame) {
|
||||
if (frame.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame.size() >= 7) {
|
||||
controller_.enqueueCommandFrame(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t channel_index = static_cast<uint8_t>(setup_id - 3);
|
||||
for (const auto& channel : dali_domain_.channelInfo()) {
|
||||
if (channel.channel_index == channel_index) {
|
||||
if (!dali_domain_.writeBridgeFrame(channel.gateway_id, frame.data(), frame.size())) {
|
||||
ESP_LOGW(kTag, "failed to forward ESP-NOW setup UART%d frame to gateway=%u", setup_id,
|
||||
channel.gateway_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGW(kTag, "ignored setup UART%d frame for unbound DALI channel", setup_id);
|
||||
}
|
||||
|
||||
void GatewayNetworkService::handleDaliRawFrame(const DaliRawFrame& frame) {
|
||||
if (!espnow_started_ || !espnow_connected_ || frame.data.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON* payload = cJSON_CreateObject();
|
||||
if (payload == nullptr) {
|
||||
return;
|
||||
}
|
||||
cJSON_AddStringToObject(payload, "type", "uart");
|
||||
cJSON_AddNumberToObject(payload, "num", static_cast<double>(frame.channel_index + 3));
|
||||
const std::string data_hex = BytesToHex(frame.data);
|
||||
cJSON_AddStringToObject(payload, "data", data_hex.c_str());
|
||||
|
||||
const std::string rendered = PrintJson(payload);
|
||||
cJSON_Delete(payload);
|
||||
if (!rendered.empty()) {
|
||||
sendEspNowJson(espnow_peer_.data(), rendered);
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayNetworkService::udpTaskLoop() {
|
||||
udp_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (udp_socket_ < 0) {
|
||||
@@ -504,6 +839,47 @@ void GatewayNetworkService::udpTaskLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayNetworkService::bootButtonTaskLoop() {
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
const TickType_t poll_ticks = pdMS_TO_TICKS(100);
|
||||
const uint32_t long_press_ms = std::max<uint32_t>(config_.boot_button_long_press_ms, 100);
|
||||
|
||||
auto is_pressed = [this]() {
|
||||
const int level = gpio_get_level(static_cast<gpio_num_t>(config_.boot_button_gpio));
|
||||
return config_.boot_button_active_low ? level == 0 : level != 0;
|
||||
};
|
||||
|
||||
while (true) {
|
||||
if (!is_pressed()) {
|
||||
vTaskDelay(poll_ticks);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t pressed_ms = 0;
|
||||
while (is_pressed()) {
|
||||
vTaskDelay(poll_ticks);
|
||||
pressed_ms += 100;
|
||||
}
|
||||
|
||||
if (pressed_ms >= long_press_ms) {
|
||||
ESP_LOGW(kTag, "BOOT long press clears Wi-Fi credentials and restarts");
|
||||
runtime_.clearWirelessInfo();
|
||||
stopEspNow();
|
||||
if (wifi_started_) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_disconnect());
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_stop());
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
esp_restart();
|
||||
} else {
|
||||
ESP_LOGI(kTag, "BOOT short press enters setup AP mode");
|
||||
handleWifiControl(101);
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayNetworkService::handleGatewayNotification(const std::vector<uint8_t>& frame) {
|
||||
if (!config_.udp_enabled || udp_socket_ < 0 || frame.empty()) {
|
||||
return;
|
||||
@@ -527,6 +903,7 @@ void GatewayNetworkService::handleGatewayNotification(const std::vector<uint8_t>
|
||||
void GatewayNetworkService::handleWifiControl(uint8_t mode) {
|
||||
if (mode == 0) {
|
||||
config_.wifi_enabled = false;
|
||||
stopEspNow();
|
||||
if (wifi_started_) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_disconnect());
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_stop());
|
||||
@@ -549,6 +926,7 @@ void GatewayNetworkService::handleWifiControl(uint8_t mode) {
|
||||
if (mode == 1) {
|
||||
config_.wifi_enabled = true;
|
||||
if (setup_ap_started_) {
|
||||
stopEspNow();
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_stop());
|
||||
wifi_started_ = false;
|
||||
setup_ap_started_ = false;
|
||||
|
||||
Reference in New Issue
Block a user