feat(gateway): enhance UART configuration validation for Modbus and KNX
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -31,6 +32,7 @@ struct GatewayBridgeServiceConfig {
|
||||
UBaseType_t modbus_task_priority{4};
|
||||
std::optional<GatewayModbusConfig> default_modbus_config;
|
||||
bool allow_modbus_uart0{false};
|
||||
bool allow_knx_uart0{false};
|
||||
std::vector<int> reserved_uart_ports;
|
||||
uint32_t bacnet_task_stack_size{8192};
|
||||
UBaseType_t bacnet_task_priority{5};
|
||||
@@ -63,6 +65,10 @@ class GatewayBridgeService {
|
||||
|
||||
ChannelRuntime* findRuntime(uint8_t gateway_id);
|
||||
const ChannelRuntime* findRuntime(uint8_t gateway_id) const;
|
||||
void collectUsedRuntimeResources(uint8_t except_gateway_id,
|
||||
std::set<uint16_t>* modbus_tcp_ports,
|
||||
std::set<uint16_t>* knx_udp_ports,
|
||||
std::set<int>* serial_uarts) const;
|
||||
|
||||
DaliDomainService& dali_domain_;
|
||||
GatewayCache& cache_;
|
||||
|
||||
@@ -1186,6 +1186,7 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
int modbus_client_sock{-1};
|
||||
int modbus_uart_port{-1};
|
||||
std::string modbus_last_error;
|
||||
std::string knx_last_error;
|
||||
|
||||
struct DiagnosticSnapshotCacheEntry {
|
||||
DaliDomainSnapshot snapshot;
|
||||
@@ -1460,6 +1461,13 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
if (!parsed.has_value()) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
{
|
||||
LockGuard guard(lock);
|
||||
const esp_err_t validation_err = validateStoredBridgeConfigLocked(parsed.value());
|
||||
if (validation_err != ESP_OK) {
|
||||
return validation_err;
|
||||
}
|
||||
}
|
||||
BridgeProvisioningStore store(bridgeNamespace());
|
||||
const esp_err_t err = store.saveObject(
|
||||
kBridgeConfigKey,
|
||||
@@ -1832,7 +1840,8 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t startKnx() {
|
||||
esp_err_t startKnx(std::set<uint16_t>* used_ports = nullptr,
|
||||
std::set<int>* used_uarts = nullptr) {
|
||||
LockGuard guard(lock);
|
||||
if (!service_config.knx_enabled) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
@@ -1844,15 +1853,44 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
if (!config.has_value()) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
std::string validation_error;
|
||||
const esp_err_t validation_err = validateKnxConfigLocked(
|
||||
config.value(), activeModbusConfigLocked(), &validation_error);
|
||||
if (validation_err != ESP_OK) {
|
||||
knx_last_error = validation_error;
|
||||
return validation_err;
|
||||
}
|
||||
if (config->ip_router_enabled && used_ports != nullptr) {
|
||||
if (used_ports->find(config->udp_port) != used_ports->end()) {
|
||||
knx_last_error = "duplicate KNXnet/IP UDP port " + std::to_string(config->udp_port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
used_ports->insert(config->udp_port);
|
||||
}
|
||||
if (config->ip_router_enabled && used_uarts != nullptr) {
|
||||
const int uart_port = config->tp_uart.uart_port;
|
||||
if (used_uarts->find(uart_port) != used_uarts->end()) {
|
||||
knx_last_error = "KNX TP-UART UART" + std::to_string(uart_port) +
|
||||
" is already used by another runtime";
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
used_uarts->insert(uart_port);
|
||||
}
|
||||
knx->setConfig(config.value());
|
||||
knx_router->setConfig(config.value());
|
||||
if (!config->ip_router_enabled) {
|
||||
knx_started = false;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
knx_last_error.clear();
|
||||
const esp_err_t err = knx_router->start(service_config.knx_task_stack_size,
|
||||
service_config.knx_task_priority);
|
||||
knx_started = err == ESP_OK;
|
||||
if (err != ESP_OK) {
|
||||
knx_last_error = knx_router->lastError().empty()
|
||||
? "failed to start KNX TP-UART router"
|
||||
: knx_router->lastError();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1961,9 +1999,10 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
cJSON_AddBoolToObject(knx_json, "startupEnabled", service_config.knx_startup_enabled);
|
||||
cJSON_AddBoolToObject(knx_json, "started", knx_started);
|
||||
cJSON_AddBoolToObject(knx_json, "routerReady", knx_router != nullptr && knx_router->started());
|
||||
if (knx_router != nullptr) {
|
||||
cJSON_AddStringToObject(knx_json, "lastError", knx_router->lastError().c_str());
|
||||
}
|
||||
const std::string router_error = knx_router == nullptr ? "" : knx_router->lastError();
|
||||
cJSON_AddStringToObject(knx_json, "lastError",
|
||||
knx_last_error.empty() ? router_error.c_str()
|
||||
: knx_last_error.c_str());
|
||||
if (effective_knx.has_value()) {
|
||||
cJSON_AddBoolToObject(knx_json, "daliRouterEnabled",
|
||||
effective_knx->dali_router_enabled);
|
||||
@@ -2713,22 +2752,120 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
service_config.reserved_uart_ports.end();
|
||||
}
|
||||
|
||||
esp_err_t validateSerialModbusConfigLocked(const GatewayModbusConfig& config) const {
|
||||
esp_err_t validateSerialModbusConfigLocked(
|
||||
const GatewayModbusConfig& config,
|
||||
const std::optional<GatewayKnxConfig>& candidate_knx,
|
||||
std::string* error_message = nullptr) const {
|
||||
const int uart_port = config.serial.uart_port;
|
||||
if (uart_port < 0 || uart_port > 2) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "Modbus serial UART port must be 0, 1, or 2";
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (uart_port == 0 && !service_config.allow_modbus_uart0) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message =
|
||||
"Modbus serial on UART0 requires moving the ESP-IDF console and UART0 control off UART0";
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (isReservedUartLocked(uart_port)) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "Modbus serial UART" + std::to_string(uart_port) +
|
||||
" is already reserved by a DALI serial PHY";
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (service_config.knx_enabled && candidate_knx.has_value() &&
|
||||
candidate_knx->ip_router_enabled && candidate_knx->tp_uart.uart_port == uart_port) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "Modbus serial UART" + std::to_string(uart_port) +
|
||||
" conflicts with KNX TP-UART; choose another free UART for RS485";
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t validateKnxConfigLocked(const GatewayKnxConfig& config,
|
||||
const std::optional<GatewayModbusConfig>& candidate_modbus,
|
||||
std::string* error_message = nullptr) const {
|
||||
if (!config.ip_router_enabled) {
|
||||
return ESP_OK;
|
||||
}
|
||||
const int uart_port = config.tp_uart.uart_port;
|
||||
if (uart_port < 0 || uart_port > 2) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "KNX TP-UART port must be 0, 1, or 2";
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (uart_port == 0 && !service_config.allow_knx_uart0) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message =
|
||||
"KNX TP-UART on UART0 requires moving the ESP-IDF console and UART0 control off UART0";
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (isReservedUartLocked(uart_port)) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "KNX TP-UART UART" + std::to_string(uart_port) +
|
||||
" is already reserved by a DALI serial PHY";
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (service_config.modbus_enabled && candidate_modbus.has_value() &&
|
||||
GatewayModbusTransportIsSerial(candidate_modbus->transport) &&
|
||||
candidate_modbus->serial.uart_port == uart_port) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "KNX TP-UART UART" + std::to_string(uart_port) +
|
||||
" conflicts with Modbus serial UART";
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t validateStoredBridgeConfigLocked(const GatewayBridgeStoredConfig& config) {
|
||||
const auto candidate_modbus = config.modbus.has_value() ? config.modbus
|
||||
: service_config.default_modbus_config;
|
||||
const auto candidate_knx = config.knx.has_value() ? config.knx
|
||||
: service_config.default_knx_config;
|
||||
std::string validation_error;
|
||||
if (candidate_modbus.has_value() &&
|
||||
GatewayModbusTransportIsSerial(candidate_modbus->transport)) {
|
||||
const esp_err_t err = validateSerialModbusConfigLocked(
|
||||
candidate_modbus.value(), candidate_knx, &validation_error);
|
||||
if (err != ESP_OK) {
|
||||
modbus_last_error = validation_error;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (candidate_knx.has_value()) {
|
||||
const esp_err_t err = validateKnxConfigLocked(candidate_knx.value(), candidate_modbus,
|
||||
&validation_error);
|
||||
if (err != ESP_OK) {
|
||||
knx_last_error = validation_error;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
modbus_last_error.clear();
|
||||
knx_last_error.clear();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t saveModbusConfig(const GatewayModbusConfig& config) {
|
||||
LockGuard guard(lock);
|
||||
if (GatewayModbusTransportIsSerial(config.transport)) {
|
||||
std::string validation_error;
|
||||
const esp_err_t validation_err = validateSerialModbusConfigLocked(
|
||||
config, activeKnxConfigLocked(), &validation_error);
|
||||
if (validation_err != ESP_OK) {
|
||||
modbus_last_error = validation_error;
|
||||
return validation_err;
|
||||
}
|
||||
}
|
||||
BridgeProvisioningStore store(bridgeNamespace());
|
||||
const esp_err_t err = store.saveObject(
|
||||
kBridgeConfigKey,
|
||||
@@ -2742,6 +2879,7 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
if (modbus != nullptr) {
|
||||
modbus->setConfig(config);
|
||||
}
|
||||
modbus_last_error.clear();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -2752,8 +2890,33 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
return service_config.default_knx_config;
|
||||
}
|
||||
|
||||
esp_err_t saveKnxConfig(const GatewayKnxConfig& config) {
|
||||
esp_err_t saveKnxConfig(const GatewayKnxConfig& config,
|
||||
std::set<uint16_t>* used_ports = nullptr,
|
||||
std::set<int>* used_uarts = nullptr) {
|
||||
LockGuard guard(lock);
|
||||
std::string validation_error;
|
||||
const esp_err_t validation_err = validateKnxConfigLocked(
|
||||
config, activeModbusConfigLocked(), &validation_error);
|
||||
if (validation_err != ESP_OK) {
|
||||
knx_last_error = validation_error;
|
||||
return validation_err;
|
||||
}
|
||||
const bool restart_router = knx_started || (knx_router != nullptr && knx_router->started());
|
||||
if (restart_router && config.ip_router_enabled && used_ports != nullptr &&
|
||||
used_ports->find(config.udp_port) != used_ports->end()) {
|
||||
knx_last_error = "duplicate KNXnet/IP UDP port " + std::to_string(config.udp_port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (restart_router && config.ip_router_enabled && used_uarts != nullptr &&
|
||||
used_uarts->find(config.tp_uart.uart_port) != used_uarts->end()) {
|
||||
knx_last_error = "KNX TP-UART UART" + std::to_string(config.tp_uart.uart_port) +
|
||||
" is already used by another runtime";
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (restart_router && knx_router != nullptr) {
|
||||
knx_router->stop();
|
||||
knx_started = false;
|
||||
}
|
||||
BridgeProvisioningStore store(bridgeNamespace());
|
||||
const esp_err_t err = store.saveObject(
|
||||
kBridgeConfigKey,
|
||||
@@ -2770,6 +2933,10 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
if (knx_router != nullptr) {
|
||||
knx_router->setConfig(config);
|
||||
}
|
||||
if (restart_router) {
|
||||
return startKnx(used_ports, used_uarts);
|
||||
}
|
||||
knx_last_error.clear();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -2920,14 +3087,18 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
if (GatewayModbusTransportIsSerial(config->transport)) {
|
||||
const esp_err_t serial_err = validateSerialModbusConfigLocked(config.value());
|
||||
std::string validation_error;
|
||||
const esp_err_t serial_err = validateSerialModbusConfigLocked(
|
||||
config.value(), activeKnxConfigLocked(), &validation_error);
|
||||
if (serial_err != ESP_OK) {
|
||||
modbus_last_error = "invalid or reserved Modbus serial UART";
|
||||
modbus_last_error = validation_error;
|
||||
return serial_err;
|
||||
}
|
||||
if (used_uarts != nullptr) {
|
||||
const int uart_port = config->serial.uart_port;
|
||||
if (used_uarts->find(uart_port) != used_uarts->end()) {
|
||||
modbus_last_error = "Modbus serial UART" + std::to_string(uart_port) +
|
||||
" is already used by another runtime";
|
||||
ESP_LOGW(kTag, "gateway=%u skips duplicate Modbus serial UART%d", channel.gateway_id,
|
||||
uart_port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
@@ -2938,6 +3109,7 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
const uint16_t port = config->port == 0 ? kGatewayModbusDefaultTcpPort : config->port;
|
||||
if (GatewayModbusTransportIsTcp(config->transport) && used_ports != nullptr) {
|
||||
if (used_ports->find(port) != used_ports->end()) {
|
||||
modbus_last_error = "duplicate Modbus TCP port " + std::to_string(port);
|
||||
ESP_LOGW(kTag, "gateway=%u skips duplicate Modbus TCP port %u", channel.gateway_id, port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
@@ -3289,7 +3461,9 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
const esp_err_t err = saveModbusConfig(parsed.value());
|
||||
cJSON_Delete(root);
|
||||
if (err != ESP_OK) {
|
||||
writeModbusManagementResponse(uart_port, false, action.c_str(), esp_err_to_name(err));
|
||||
writeModbusManagementResponse(
|
||||
uart_port, false, action.c_str(),
|
||||
modbus_last_error.empty() ? esp_err_to_name(err) : modbus_last_error.c_str());
|
||||
return;
|
||||
}
|
||||
writeModbusManagementResponse(uart_port, true, action.c_str(), nullptr);
|
||||
@@ -3367,11 +3541,11 @@ esp_err_t GatewayBridgeService::start() {
|
||||
runtimes_.push_back(std::move(runtime));
|
||||
}
|
||||
|
||||
std::set<int> used_serial_uarts;
|
||||
if (config_.modbus_enabled && config_.modbus_startup_enabled) {
|
||||
std::set<uint16_t> used_ports;
|
||||
std::set<int> used_uarts;
|
||||
std::set<uint16_t> used_modbus_ports;
|
||||
for (const auto& runtime : runtimes_) {
|
||||
const esp_err_t err = runtime->startModbus(&used_ports, &used_uarts);
|
||||
const esp_err_t err = runtime->startModbus(&used_modbus_ports, &used_serial_uarts);
|
||||
if (err != ESP_OK && err != ESP_ERR_NOT_FOUND && err != ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGW(kTag, "gateway=%u Modbus startup skipped: %s", runtime->channel.gateway_id,
|
||||
esp_err_to_name(err));
|
||||
@@ -3380,8 +3554,9 @@ esp_err_t GatewayBridgeService::start() {
|
||||
}
|
||||
|
||||
if (config_.knx_enabled && config_.knx_startup_enabled) {
|
||||
std::set<uint16_t> used_knx_ports;
|
||||
for (const auto& runtime : runtimes_) {
|
||||
const esp_err_t err = runtime->startKnx();
|
||||
const esp_err_t err = runtime->startKnx(&used_knx_ports, &used_serial_uarts);
|
||||
if (err != ESP_OK && err != ESP_ERR_NOT_FOUND && err != ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGW(kTag, "gateway=%u KNX/IP startup skipped: %s", runtime->channel.gateway_id,
|
||||
esp_err_to_name(err));
|
||||
@@ -3422,6 +3597,44 @@ const GatewayBridgeService::ChannelRuntime* GatewayBridgeService::findRuntime(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GatewayBridgeService::collectUsedRuntimeResources(
|
||||
uint8_t except_gateway_id,
|
||||
std::set<uint16_t>* modbus_tcp_ports,
|
||||
std::set<uint16_t>* knx_udp_ports,
|
||||
std::set<int>* serial_uarts) const {
|
||||
for (const auto& runtime : runtimes_) {
|
||||
if (runtime->channel.gateway_id == except_gateway_id) {
|
||||
continue;
|
||||
}
|
||||
LockGuard guard(runtime->lock);
|
||||
if (runtime->modbus_started) {
|
||||
const auto modbus_config = runtime->activeModbusConfigLocked();
|
||||
if (modbus_config.has_value()) {
|
||||
if (GatewayModbusTransportIsSerial(modbus_config->transport) && serial_uarts != nullptr) {
|
||||
serial_uarts->insert(modbus_config->serial.uart_port);
|
||||
} else if (GatewayModbusTransportIsTcp(modbus_config->transport) &&
|
||||
modbus_tcp_ports != nullptr) {
|
||||
const uint16_t port = modbus_config->port == 0 ? kGatewayModbusDefaultTcpPort
|
||||
: modbus_config->port;
|
||||
modbus_tcp_ports->insert(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (runtime->knx_started ||
|
||||
(runtime->knx_router != nullptr && runtime->knx_router->started())) {
|
||||
const auto knx_config = runtime->activeKnxConfigLocked();
|
||||
if (knx_config.has_value() && knx_config->ip_router_enabled) {
|
||||
if (knx_udp_ports != nullptr) {
|
||||
knx_udp_ports->insert(knx_config->udp_port);
|
||||
}
|
||||
if (serial_uarts != nullptr) {
|
||||
serial_uarts->insert(knx_config->tp_uart.uart_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GatewayBridgeHttpResponse GatewayBridgeService::handleGet(
|
||||
const std::string& action_arg, int gateway_id_arg, const std::string& query_arg) {
|
||||
if (!config_.bridge_enabled) {
|
||||
@@ -3626,7 +3839,12 @@ GatewayBridgeHttpResponse GatewayBridgeService::handlePost(
|
||||
if (action == "config" || action == "save_config") {
|
||||
const esp_err_t err = runtime->saveBridgeConfig(body);
|
||||
if (err != ESP_OK) {
|
||||
return ErrorResponse(err, "failed to save bridge config");
|
||||
const char* message = !runtime->knx_last_error.empty()
|
||||
? runtime->knx_last_error.c_str()
|
||||
: (!runtime->modbus_last_error.empty()
|
||||
? runtime->modbus_last_error.c_str()
|
||||
: "failed to save bridge config");
|
||||
return ErrorResponse(err, message);
|
||||
}
|
||||
return handleGet("config", gateway_id.value());
|
||||
}
|
||||
@@ -3666,9 +3884,15 @@ GatewayBridgeHttpResponse GatewayBridgeService::handlePost(
|
||||
return handleGet("cloud", gateway_id.value());
|
||||
}
|
||||
if (action == "modbus_start") {
|
||||
const esp_err_t err = runtime->startModbus();
|
||||
std::set<uint16_t> used_modbus_ports;
|
||||
std::set<int> used_serial_uarts;
|
||||
collectUsedRuntimeResources(gateway_id.value(), &used_modbus_ports, nullptr,
|
||||
&used_serial_uarts);
|
||||
const esp_err_t err = runtime->startModbus(&used_modbus_ports, &used_serial_uarts);
|
||||
if (err != ESP_OK) {
|
||||
return ErrorResponse(err, "failed to start Modbus bridge");
|
||||
return ErrorResponse(err, runtime->modbus_last_error.empty()
|
||||
? "failed to start Modbus bridge"
|
||||
: runtime->modbus_last_error.c_str());
|
||||
}
|
||||
return handleGet("modbus", gateway_id.value());
|
||||
}
|
||||
@@ -3694,16 +3918,29 @@ GatewayBridgeHttpResponse GatewayBridgeService::handlePost(
|
||||
if (!parsed.has_value()) {
|
||||
return ErrorResponse(ESP_ERR_INVALID_ARG, "invalid KNX config");
|
||||
}
|
||||
const esp_err_t err = runtime->saveKnxConfig(parsed.value());
|
||||
std::set<uint16_t> used_knx_ports;
|
||||
std::set<int> used_serial_uarts;
|
||||
collectUsedRuntimeResources(gateway_id.value(), nullptr, &used_knx_ports,
|
||||
&used_serial_uarts);
|
||||
const esp_err_t err = runtime->saveKnxConfig(parsed.value(), &used_knx_ports,
|
||||
&used_serial_uarts);
|
||||
if (err != ESP_OK) {
|
||||
return ErrorResponse(err, "failed to save KNX bridge config");
|
||||
return ErrorResponse(err, runtime->knx_last_error.empty()
|
||||
? "failed to save KNX bridge config"
|
||||
: runtime->knx_last_error.c_str());
|
||||
}
|
||||
return handleGet("knx", gateway_id.value());
|
||||
}
|
||||
if (action == "knx_start") {
|
||||
const esp_err_t err = runtime->startKnx();
|
||||
std::set<uint16_t> used_knx_ports;
|
||||
std::set<int> used_serial_uarts;
|
||||
collectUsedRuntimeResources(gateway_id.value(), nullptr, &used_knx_ports,
|
||||
&used_serial_uarts);
|
||||
const esp_err_t err = runtime->startKnx(&used_knx_ports, &used_serial_uarts);
|
||||
if (err != ESP_OK) {
|
||||
return ErrorResponse(err, "failed to start KNX/IP bridge");
|
||||
return ErrorResponse(err, runtime->knx_last_error.empty()
|
||||
? "failed to start KNX/IP bridge"
|
||||
: runtime->knx_last_error.c_str());
|
||||
}
|
||||
return handleGet("knx", gateway_id.value());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user