feat: Implement Homeassistant MQTT Gateway
This commit transforms the previous "Blinky" sample into a functional
Homeassistant MQTT Gateway application.
Key features and changes include:
- **Application Logic:** The core application logic is updated to function as a gateway between Modbus and MQTT.
- **Network Configuration:**
- Implemented persistent network settings using the Zephyr settings subsystem and NVS.
- Added robust Wi-Fi connection management with auto-reconnect.
- Centralized IP configuration to support both DHCP and static IP addresses.
- **Configuration:** Project and board configurations have been updated to enable necessary kernel features and network settings.
- **Documentation:** The README has been updated to reflect the new functionality and usage instructions.
- **Simulation:** The simulation script has been updated.
This commit is contained in:
parent
cbbd5f5fea
commit
6e669cfc4e
116
README.rst
116
README.rst
|
|
@ -1,97 +1,65 @@
|
|||
.. zephyr:code-sample:: blinky
|
||||
:name: Blinky
|
||||
:relevant-api: gpio_interface
|
||||
.. SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Blink an LED forever using the GPIO API.
|
||||
############################
|
||||
Modbus MQTT Gateway
|
||||
############################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
The Blinky sample blinks an LED forever using the :ref:`GPIO API <gpio_api>`.
|
||||
This Zephyr application serves as an MQTT gateway, primarily designed to bridge Modbus devices with a Home Assistant instance. It connects to a WiFi network, obtains an IP address, and communicates with an MQTT broker.
|
||||
|
||||
The source code shows how to:
|
||||
Features
|
||||
********
|
||||
|
||||
#. Get a pin specification from the :ref:`devicetree <dt-guide>` as a
|
||||
:c:struct:`gpio_dt_spec`
|
||||
#. Configure the GPIO pin as an output
|
||||
#. Toggle the pin forever
|
||||
- **WiFi Connectivity**: Connects to a specified WiFi network using credentials provided via Kconfig.
|
||||
- **Network Configuration**: Supports both DHCP and static IP addressing for flexible network integration.
|
||||
- **MQTT Integration**: Configured to communicate with an MQTT broker, with specific options for Home Assistant discovery.
|
||||
- **Configurability**: All major parameters, including WiFi, network, and MQTT settings, are configurable through Kconfig.
|
||||
- **Simulation Support**: Includes a script and configuration for running in a simulated environment (`native_sim`).
|
||||
|
||||
See :zephyr:code-sample:`pwm-blinky` for a similar sample that uses the PWM API instead.
|
||||
Configuration
|
||||
*************
|
||||
|
||||
.. _blinky-sample-requirements:
|
||||
The application is configured using Kconfig. Key options can be found in the "Home Assistant MQTT Options" menu.
|
||||
|
||||
Requirements
|
||||
************
|
||||
- **WiFi Settings**:
|
||||
- `CONFIG_WIFI_SSID`: The SSID of the WiFi network.
|
||||
- `CONFIG_WIFI_PASSWORD`: The password for the WiFi network.
|
||||
|
||||
Your board must:
|
||||
- **Network Settings**:
|
||||
- `CONFIG_NET_DHCP`: Enable or disable DHCP.
|
||||
- `CONFIG_NET_IP_ADDR`: Static IP address.
|
||||
- `CONFIG_NET_IP_MASK`: Static IP netmask.
|
||||
- `CONFIG_NET_IP_GATEWAY`: Static IP gateway.
|
||||
- `CONFIG_NET_DNS_SERVER`: Static DNS server.
|
||||
|
||||
#. Have an LED connected via a GPIO pin (these are called "User LEDs" on many of
|
||||
Zephyr's :ref:`boards`).
|
||||
#. Have the LED configured using the ``led0`` devicetree alias.
|
||||
- **MQTT Broker Settings**:
|
||||
- `CONFIG_HA_MQTT_BROKER_HOSTNAME`: Hostname or IP of the MQTT broker.
|
||||
- `CONFIG_HA_MQTT_BROKER_PORT`: Port of the MQTT broker.
|
||||
- `CONFIG_HA_MQTT_USERNAME`: Username for MQTT authentication.
|
||||
- `CONFIG_HA_MQTT_PASSWORD`: Password for MQTT authentication.
|
||||
|
||||
- **Home Assistant Device Info**:
|
||||
- `CONFIG_HA_MQTT_NAME`: Device name.
|
||||
- `CONFIG_HA_MQTT_MANUFACTURER`: Manufacturer name.
|
||||
- `CONFIG_HA_MQTT_MODEL`: Model name.
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
Build and flash Blinky as follows, changing ``reel_board`` for your board:
|
||||
**Building for Hardware (e.g., ESP32-C6)**
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/basic/blinky
|
||||
:board: reel_board
|
||||
:goals: build flash
|
||||
:compact:
|
||||
.. code-block:: shell
|
||||
|
||||
After flashing, the LED starts to blink and messages with the current LED state
|
||||
are printed on the console. If a runtime error occurs, the sample exits without
|
||||
printing to the console.
|
||||
west build -b esp32c6_devkitc_hpcore
|
||||
|
||||
Build errors
|
||||
************
|
||||
**Running in Simulation**
|
||||
|
||||
You will see a build error at the source code line defining the ``struct
|
||||
gpio_dt_spec led`` variable if you try to build Blinky for an unsupported
|
||||
board.
|
||||
A simulation can be run using the provided script:
|
||||
|
||||
On GCC-based toolchains, the error looks like this:
|
||||
.. code-block:: shell
|
||||
|
||||
.. code-block:: none
|
||||
./run_sim.sh
|
||||
|
||||
error: '__device_dts_ord_DT_N_ALIAS_led_P_gpios_IDX_0_PH_ORD' undeclared here (not in a function)
|
||||
|
||||
Adding board support
|
||||
********************
|
||||
|
||||
To add support for your board, add something like this to your devicetree:
|
||||
|
||||
.. code-block:: DTS
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
led0 = &myled0;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
myled0: led_0 {
|
||||
gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
The above sets your board's ``led0`` alias to use pin 13 on GPIO controller
|
||||
``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_HIGH` mean the LED is on when
|
||||
the pin is set to its high state, and off when the pin is in its low state.
|
||||
|
||||
Tips:
|
||||
|
||||
- See :dtcompatible:`gpio-leds` for more information on defining GPIO-based LEDs
|
||||
in devicetree.
|
||||
|
||||
- If you're not sure what to do, check the devicetrees for supported boards which
|
||||
use the same SoC as your target. See :ref:`get-devicetree-outputs` for details.
|
||||
|
||||
- See :zephyr_file:`include/zephyr/dt-bindings/gpio/gpio.h` for the flags you can use
|
||||
in devicetree.
|
||||
|
||||
- If the LED is built in to your board hardware, the alias should be defined in
|
||||
your :ref:`BOARD.dts file <devicetree-in-out-files>`. Otherwise, you can
|
||||
define one in a :ref:`devicetree overlay <set-devicetree-overlays>`.
|
||||
This will build and run the application for the `native_sim` target.
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
CONFIG_WIFI=y
|
||||
CONFIG_NET_L2_WIFI_SHELL=y
|
||||
CONFIG_WIFI_ESP32=y
|
||||
CONFIG_ESP32_WIFI_STA_RECONNECT=y
|
||||
21
prj.conf
21
prj.conf
|
|
@ -1,3 +1,23 @@
|
|||
# ---------------------------------------------------------------------------
|
||||
# APP SETTINGS
|
||||
# ---------------------------------------------------------------------------
|
||||
# See KConfig documentation for more details on these settings.
|
||||
# Most of them can also be set in the shell.
|
||||
CONFIG_NET_DHCP=n
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# GENERAL SETTINGS
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Settings subsystem
|
||||
CONFIG_SETTINGS=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
CONFIG_SETTINGS_NVS=y
|
||||
CONFIG_NVS=y
|
||||
CONFIG_SETTINGS_RUNTIME=y
|
||||
|
||||
# Networking core
|
||||
CONFIG_NETWORKING=y
|
||||
CONFIG_NET_IPV4=y
|
||||
|
|
@ -16,6 +36,7 @@ CONFIG_DNS_RESOLVER_MAX_SERVERS=2
|
|||
CONFIG_NET_LOG=y
|
||||
CONFIG_LOG=y
|
||||
CONFIG_NET_SHELL=y
|
||||
CONFIG_REBOOT=y
|
||||
|
||||
# Debugging and stack
|
||||
CONFIG_INIT_STACKS=y
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#!/bin/bash
|
||||
while true; do
|
||||
# build/zephyr/zephyr.exe --flash=flash.bin --uart_stdinout
|
||||
build/zephyr/zephyr.exe --uart_stdinout
|
||||
build/zephyr/zephyr.exe --flash=flash.bin --uart_stdinout
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(mqtt_gw, CONFIG_LOG_DEFAULT_LEVEL);
|
|||
* @return 0 on success, otherwise a negative error code.
|
||||
*/
|
||||
int main(void) {
|
||||
// k_sleep(K_SECONDS(1)); // Allow time for logging initialization
|
||||
k_sleep(K_MSEC(100)); // Allow time for logging initialization
|
||||
LOG_INF("MQTT Gateway. Board: %s", CONFIG_BOARD);
|
||||
net_init();
|
||||
return 0;
|
||||
|
|
|
|||
452
src/net.c
452
src/net.c
|
|
@ -12,14 +12,35 @@ LOG_MODULE_REGISTER(net, LOG_LEVEL_DBG);
|
|||
#include <zephyr/net/net_if.h>
|
||||
#include <zephyr/net/net_mgmt.h>
|
||||
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef CONFIG_WIFI
|
||||
#include <zephyr/net/wifi_mgmt.h>
|
||||
static struct net_mgmt_event_callback wifi_mgmt_cb;
|
||||
static K_SEM_DEFINE(wifi_connected_sem, 0, 1);
|
||||
|
||||
#define WIFI_RECONNECT_DELAY_S 10 // Wartezeit in Sekunden
|
||||
|
||||
static struct net_mgmt_event_callback wifi_connect_cb;
|
||||
static struct net_mgmt_event_callback wifi_disconnect_cb;
|
||||
|
||||
static void attempt_wifi_reconnect_work_handler(struct k_work *work);
|
||||
static struct k_timer wifi_reconnect_timer;
|
||||
static K_WORK_DEFINE(reconnect_work, attempt_wifi_reconnect_work_handler);
|
||||
|
||||
#endif // CONFIG_WIFI
|
||||
|
||||
static struct net_mgmt_event_callback net_mgmt_cb;
|
||||
|
||||
// Hooks for MQTT client control
|
||||
__weak void on_network_ready(struct net_if *iface)
|
||||
{
|
||||
LOG_INF("Network is ready for communication (default weak handler)");
|
||||
}
|
||||
|
||||
__weak void on_network_down(struct net_if *iface)
|
||||
{
|
||||
LOG_INF("Network is down (default weak handler)");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_DHCP
|
||||
static bool dhcp_enabled = true;
|
||||
|
|
@ -32,12 +53,72 @@ static char *static_netmask = CONFIG_NET_IP_MASK;
|
|||
static char *static_gateway = CONFIG_NET_IP_GATEWAY;
|
||||
static char *static_dns = CONFIG_NET_DNS_SERVER;
|
||||
|
||||
/**
|
||||
* @brief Starts the DHCPv4 client on the given network interface.
|
||||
*
|
||||
* @param iface The network interface.
|
||||
* @param user_data A pointer to user data (unused).
|
||||
*/
|
||||
static int net_settings_handle(
|
||||
const char *name, size_t len, settings_read_cb read_cb, void *cb_arg);
|
||||
|
||||
struct settings_handler net_settings = {
|
||||
.name = "net",
|
||||
.h_set = net_settings_handle,
|
||||
};
|
||||
|
||||
static int net_settings_handle(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
const char *next;
|
||||
int rc;
|
||||
|
||||
if (settings_name_steq(name, "dhcp", &next) && !next) {
|
||||
rc = read_cb(cb_arg, &dhcp_enabled, sizeof(dhcp_enabled));
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Error reading setting 'dhcp_enabled' (%d)", rc);
|
||||
} else {
|
||||
LOG_DBG("Loaded 'dhcp_enabled' from settings: %s",
|
||||
dhcp_enabled ? "ENABLED" : "DISABLED");
|
||||
}
|
||||
return rc > 0 ? 0 : rc;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int net_settings_init(void)
|
||||
{
|
||||
int rc;
|
||||
rc = settings_subsys_init();
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to initialize settings subsystem: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
rc = settings_register(&net_settings);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to register settings handler: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
rc = settings_load();
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to load settings: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void net_log_ip_settings(struct net_if *iface)
|
||||
{
|
||||
char buf[NET_IPV4_ADDR_LEN];
|
||||
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
||||
if (!ipv4) {
|
||||
LOG_INF("No IPv4 config on interface %s", net_if_get_device(iface)->name);
|
||||
return;
|
||||
}
|
||||
LOG_INF("IP settings for interface: %s", net_if_get_device(iface)->name);
|
||||
LOG_INF(" IP: %s",
|
||||
net_addr_ntop(AF_INET, &ipv4->unicast[0].ipv4.address.in_addr, buf, sizeof(buf)));
|
||||
LOG_INF(
|
||||
" Netmask: %s", net_addr_ntop(AF_INET, &ipv4->unicast[0].netmask, buf, sizeof(buf)));
|
||||
LOG_INF(" Gateway: %s", net_addr_ntop(AF_INET, &ipv4->gw, buf, sizeof(buf)));
|
||||
if (static_dns) {
|
||||
LOG_INF(" DNS: %s", static_dns);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_dhcpv4_client(struct net_if *iface, void *user_data)
|
||||
{
|
||||
ARG_UNUSED(user_data);
|
||||
|
|
@ -57,141 +138,35 @@ static void start_dhcpv4_client(struct net_if *iface, void *user_data)
|
|||
net_dhcpv4_start(iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Network management event handler.
|
||||
*
|
||||
* This function is called when a network management event occurs. It logs
|
||||
* information about the new IP address, subnet mask, router, and lease time
|
||||
* when an IPv4 address is added.
|
||||
*
|
||||
* @param cb The network management event callback structure.
|
||||
* @param mgmt_event The network management event.
|
||||
* @param iface The network interface.
|
||||
*/
|
||||
static void net_mgmt_event_handler(
|
||||
static void net_event_ipv4_addr_add_handler(
|
||||
struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface)
|
||||
{
|
||||
if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) {
|
||||
for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
||||
char buf[NET_IPV4_ADDR_LEN];
|
||||
|
||||
if (iface->config.ip.ipv4->unicast[i].ipv4.addr_type != NET_ADDR_DHCP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_INF(" Address[%d]: %s",
|
||||
net_if_get_by_iface(iface),
|
||||
net_addr_ntop(AF_INET,
|
||||
&iface->config.ip.ipv4->unicast[i].ipv4.address.in_addr,
|
||||
buf,
|
||||
sizeof(buf)));
|
||||
LOG_INF(" Subnet[%d]: %s",
|
||||
net_if_get_by_iface(iface),
|
||||
net_addr_ntop(AF_INET,
|
||||
&iface->config.ip.ipv4->unicast[i].netmask,
|
||||
buf,
|
||||
sizeof(buf)));
|
||||
LOG_INF(" Router[%d]: %s",
|
||||
net_if_get_by_iface(iface),
|
||||
net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, sizeof(buf)));
|
||||
LOG_INF("Lease time[%d]: %u seconds",
|
||||
net_if_get_by_iface(iface),
|
||||
iface->config.dhcpv4.lease_time);
|
||||
}
|
||||
}
|
||||
ARG_UNUSED(cb);
|
||||
ARG_UNUSED(mgmt_event);
|
||||
LOG_INF("#### IPV4 address assigned");
|
||||
net_log_ip_settings(iface);
|
||||
on_network_ready(iface);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIFI
|
||||
|
||||
/**
|
||||
* @brief Wi-Fi management event handler.
|
||||
*
|
||||
* This function is called when a Wi-Fi management event occurs. It gives the
|
||||
* `wifi_connected_sem` semaphore when the Wi-Fi is connected.
|
||||
*
|
||||
* @param cb The network management event callback structure.
|
||||
* @param mgmt_event The network management event.
|
||||
* @param iface The network interface.
|
||||
*/
|
||||
static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
|
||||
uint64_t mgmt_event, struct net_if *iface)
|
||||
static void net_event_if_up_handler(
|
||||
struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface)
|
||||
{
|
||||
if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) {
|
||||
LOG_INF("Wi-Fi connected!");
|
||||
k_sem_give(&wifi_connected_sem);
|
||||
}
|
||||
ARG_UNUSED(cb);
|
||||
ARG_UNUSED(mgmt_event);
|
||||
LOG_INF("#### Network interface %s is UP", net_if_get_device(iface)->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the Wi-Fi connection.
|
||||
*
|
||||
* This function sets up the Wi-Fi connection parameters and starts the
|
||||
* connection process. It registers an event handler to listen for connection
|
||||
* results.
|
||||
*/
|
||||
void init_wifi(void)
|
||||
static void net_event_if_down_handler(
|
||||
struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface)
|
||||
{
|
||||
// Netzwerk-Interface abrufen
|
||||
struct net_if *iface = net_if_get_default();
|
||||
if (!iface) {
|
||||
LOG_ERR("Could not get network interface");
|
||||
return;
|
||||
}
|
||||
|
||||
// Wi-Fi-Verbindungsparameter
|
||||
struct wifi_connect_req_params cnx_params = {
|
||||
.ssid = "ItenIOT", // Ersetzen Sie dies mit Ihrer SSID
|
||||
.ssid_length = sizeof("ItenIOT") - 1,
|
||||
.psk = "DasPferd", // Ersetzen Sie dies mit Ihrem Passwort
|
||||
.psk_length = sizeof("DasPferd") - 1,
|
||||
.security = WIFI_SECURITY_TYPE_PSK,
|
||||
.channel = WIFI_CHANNEL_ANY,
|
||||
};
|
||||
|
||||
// Event-Handler registrieren
|
||||
net_mgmt_init_event_callback(&wifi_mgmt_cb, wifi_mgmt_event_handler, NET_EVENT_WIFI_CONNECT_RESULT);
|
||||
net_mgmt_add_event_callback(&wifi_mgmt_cb);
|
||||
|
||||
LOG_INF("Connecting to Wi-Fi...");
|
||||
|
||||
// Verbindungsanfrage senden
|
||||
if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))) {
|
||||
LOG_ERR("Wi-Fi connection request failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// // Warten, bis die Verbindung hergestellt ist
|
||||
if (k_sem_take(&wifi_connected_sem, K_SECONDS(30)) != 0) {
|
||||
LOG_ERR("Wi-Fi connection timed out");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ab hier ist die Wi-Fi-Verbindung aufgebaut und Sie können Netzwerkoperationen durchführen.
|
||||
// Ein DHCP-Client wird automatisch gestartet, um eine IP-Adresse zu beziehen.
|
||||
LOG_INF("Wi-Fi setup complete.");
|
||||
ARG_UNUSED(cb);
|
||||
ARG_UNUSED(mgmt_event);
|
||||
LOG_INF("####Network interface %s is DOWN", net_if_get_device(iface)->name);
|
||||
on_network_down(iface);
|
||||
}
|
||||
#endif // CONFIG_WIFI
|
||||
|
||||
/**
|
||||
* @brief Initializes the network stack.
|
||||
*
|
||||
* This function initializes the network stack. It initializes and adds a
|
||||
* network management event callback to log network events. If Wi-Fi is
|
||||
* enabled, it initializes the Wi-Fi connection. If DHCP is enabled, it
|
||||
* starts the DHCP client on all interfaces. Otherwise, it sets a static IP
|
||||
* configuration.
|
||||
*
|
||||
* @return 0 on success, otherwise a negative error code.
|
||||
*/
|
||||
int net_init(void)
|
||||
{
|
||||
int net_set_ip(void) {
|
||||
int rc;
|
||||
net_mgmt_init_event_callback(&net_mgmt_cb, net_mgmt_event_handler, NET_EVENT_IPV4_ADDR_ADD);
|
||||
net_mgmt_add_event_callback(&net_mgmt_cb);
|
||||
|
||||
#ifdef CONFIG_WIFI
|
||||
init_wifi();
|
||||
#endif // CONFIG_WIFI
|
||||
|
||||
if (dhcp_enabled) {
|
||||
LOG_INF("DHCP is enabled, starting DHCP client on all interfaces");
|
||||
|
|
@ -204,18 +179,7 @@ int net_init(void)
|
|||
}
|
||||
LOG_INF("DHCP is disabled, setting static IP configuration on interface: %s",
|
||||
net_if_get_device(iface)->name);
|
||||
if (net_if_is_up(iface)) {
|
||||
LOG_INF("Bringing down network interface %s before setting static IP",
|
||||
net_if_get_device(iface)->name);
|
||||
// Ensure the interface is down before applying static configuration
|
||||
rc = net_if_down(iface);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to bring down network interface %s: %d",
|
||||
net_if_get_device(iface)->name,
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
struct in_addr ipaddr, netmask, gw;
|
||||
|
||||
if (net_addr_pton(AF_INET, static_ip, &ipaddr) < 0 ||
|
||||
|
|
@ -241,7 +205,7 @@ int net_init(void)
|
|||
|
||||
const char *dns_servers_str[] = {
|
||||
static_dns,
|
||||
NULL, // Terminate the list with NULL
|
||||
NULL,
|
||||
};
|
||||
struct sockaddr_in dns_server;
|
||||
dns_server.sin_family = AF_INET;
|
||||
|
|
@ -253,7 +217,7 @@ int net_init(void)
|
|||
}
|
||||
const struct sockaddr *dns_servers_sa[] = {
|
||||
(struct sockaddr *)&dns_server,
|
||||
NULL, // Terminate the list with NULL
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct dns_resolve_context dns_ctx;
|
||||
|
|
@ -263,6 +227,7 @@ int net_init(void)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (!net_if_is_up(iface)) {
|
||||
rc = net_if_up(iface);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to bring up network interface %s: %d",
|
||||
|
|
@ -271,10 +236,193 @@ int net_init(void)
|
|||
return rc;
|
||||
}
|
||||
LOG_INF("Static IP configuration set");
|
||||
LOG_INF(" IP: %s", static_ip);
|
||||
LOG_INF(" Netmask: %s", static_netmask);
|
||||
LOG_INF(" Gateway: %s", static_gateway);
|
||||
LOG_INF(" DNS: %s", static_dns);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WIFI
|
||||
static void schedule_reconnect(void)
|
||||
{
|
||||
LOG_INF("Scheduling Wi-Fi reconnect in %d seconds.", WIFI_RECONNECT_DELAY_S);
|
||||
k_timer_start(&wifi_reconnect_timer, K_SECONDS(WIFI_RECONNECT_DELAY_S), K_NO_WAIT);
|
||||
}
|
||||
|
||||
static void wifi_connect_handler(
|
||||
struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface)
|
||||
{
|
||||
ARG_UNUSED(mgmt_event);
|
||||
ARG_UNUSED(iface);
|
||||
|
||||
const int status = *(const int *)cb->info;
|
||||
|
||||
if (status != 0) {
|
||||
LOG_ERR("Wi-Fi connection attempt failed with status: %d", status);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INF("Wi-Fi connected successfully! Stopping reconnect timer.");
|
||||
k_timer_stop(&wifi_reconnect_timer);
|
||||
|
||||
net_set_ip();
|
||||
}
|
||||
|
||||
static void wifi_disconnect_handler(
|
||||
struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface)
|
||||
{
|
||||
ARG_UNUSED(cb);
|
||||
ARG_UNUSED(mgmt_event);
|
||||
|
||||
LOG_WRN("Wi-Fi disconnected!");
|
||||
net_dhcpv4_stop(iface);
|
||||
on_network_down(iface);
|
||||
schedule_reconnect();
|
||||
}
|
||||
|
||||
int net_wifi_connect(struct net_if *iface, struct wifi_connect_req_params *cnx_params)
|
||||
{
|
||||
int rc;
|
||||
LOG_INF("Connecting to Wi-Fi...");
|
||||
rc = net_mgmt(NET_REQUEST_WIFI_CONNECT,
|
||||
iface,
|
||||
cnx_params,
|
||||
sizeof(struct wifi_connect_req_params));
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Wi-Fi connection request failed with error: %d", rc);
|
||||
} else {
|
||||
LOG_INF("Wi-Fi connection request sent.");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int init_wifi(void)
|
||||
{
|
||||
struct net_if *iface = net_if_get_default();
|
||||
if (!iface) {
|
||||
LOG_ERR("Could not get network interface");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
struct wifi_connect_req_params cnx_params = {
|
||||
.ssid = "ItenIOT",
|
||||
.ssid_length = sizeof("ItenIOT") - 1,
|
||||
.psk = "DasPferd",
|
||||
.psk_length = sizeof("DasPferd") - 1,
|
||||
.security = WIFI_SECURITY_TYPE_PSK,
|
||||
.channel = WIFI_CHANNEL_ANY,
|
||||
};
|
||||
|
||||
static bool wifi_handlers_registered = false;
|
||||
if (!wifi_handlers_registered) {
|
||||
net_mgmt_init_event_callback(
|
||||
&wifi_connect_cb, wifi_connect_handler, NET_EVENT_WIFI_CONNECT_RESULT);
|
||||
net_mgmt_add_event_callback(&wifi_connect_cb);
|
||||
net_mgmt_init_event_callback(
|
||||
&wifi_disconnect_cb, wifi_disconnect_handler, NET_EVENT_WIFI_DISCONNECT_RESULT);
|
||||
net_mgmt_add_event_callback(&wifi_disconnect_cb);
|
||||
wifi_handlers_registered = true;
|
||||
}
|
||||
|
||||
return net_wifi_connect(iface, &cnx_params);
|
||||
}
|
||||
|
||||
static void attempt_wifi_reconnect_work_handler(struct k_work *work)
|
||||
{
|
||||
LOG_INF("Reconnect timer expired. Trying to connect...");
|
||||
if (init_wifi() != 0) {
|
||||
LOG_ERR("Failed to send Wi-Fi connection request, will try again.");
|
||||
schedule_reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_reconnect_timer_expiry(struct k_timer *timer_id)
|
||||
{
|
||||
k_work_submit(&reconnect_work);
|
||||
}
|
||||
|
||||
#endif // CONFIG_WIFI
|
||||
|
||||
int net_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = net_settings_init();
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to initialize network settings: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct net_mgmt_event_callback net_mgmt_cb_ipv4_addr_add;
|
||||
static struct net_mgmt_event_callback net_mgmt_cb_if_up;
|
||||
static struct net_mgmt_event_callback net_mgmt_cb_if_down;
|
||||
|
||||
net_mgmt_init_event_callback(
|
||||
&net_mgmt_cb_ipv4_addr_add, net_event_ipv4_addr_add_handler, NET_EVENT_IPV4_ADDR_ADD);
|
||||
net_mgmt_add_event_callback(&net_mgmt_cb_ipv4_addr_add);
|
||||
net_mgmt_init_event_callback(&net_mgmt_cb_if_up, net_event_if_up_handler, NET_EVENT_IF_UP);
|
||||
net_mgmt_add_event_callback(&net_mgmt_cb_if_up);
|
||||
net_mgmt_init_event_callback(
|
||||
&net_mgmt_cb_if_down, net_event_if_down_handler, NET_EVENT_IF_DOWN);
|
||||
net_mgmt_add_event_callback(&net_mgmt_cb_if_down);
|
||||
|
||||
#ifdef CONFIG_WIFI
|
||||
k_timer_init(&wifi_reconnect_timer, on_reconnect_timer_expiry, NULL);
|
||||
|
||||
rc = init_wifi();
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Initial Wi-Fi connection request failed: %d", rc);
|
||||
schedule_reconnect();
|
||||
}
|
||||
#else
|
||||
rc = net_set_ip();
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to set IP: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
#endif // CONFIG_WIFI
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_config_show(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
ARG_UNUSED(argc);
|
||||
ARG_UNUSED(argv);
|
||||
shell_print(shell, "DHCP: %s", dhcp_enabled ? "ENABLED" : "DISABLED");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_config_set_dhcp(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
shell_print(shell, "Usage: config set dhcp <0|1>");
|
||||
return -EINVAL;
|
||||
}
|
||||
int val = atoi(argv[1]);
|
||||
if (val != 0 && val != 1) {
|
||||
shell_print(shell, "Value must be 0 (false) or 1 (true)");
|
||||
return -EINVAL;
|
||||
}
|
||||
dhcp_enabled = (val != 0);
|
||||
int rc = settings_save_one("net/dhcp", &dhcp_enabled, sizeof(dhcp_enabled));
|
||||
if (rc < 0) {
|
||||
shell_error(shell, "Failed to save DHCP setting: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
shell_print(shell, "DHCP set to %s and saved", dhcp_enabled ? "ENABLED" : "DISABLED");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_config_set,
|
||||
SHELL_CMD(dhcp, NULL, "Set DHCP, 0=disabled, 1=enabled", cmd_config_set_dhcp),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_config,
|
||||
SHELL_CMD(show, NULL, "Show current config", cmd_config_show),
|
||||
SHELL_CMD(set, &sub_config_set, "Change config", NULL),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_CMD_REGISTER(config, &sub_config, "Configuration settings", NULL);
|
||||
|
|
|
|||
Loading…
Reference in New Issue