Add NVS support for relay channel config persistence

- Introduced NVS configuration options in Kconfig.
- Implemented NVS initialization and deinitialization in relay_chn_core.
- Added functions for storing and retrieving relay channel direction and tilt sensitivity in NVS.
- Updated relay_chn_tilt and relay_chn_output to utilize NVS for state management.
- Created relay_chn_nvs.c and relay_chn_nvs.h for NVS-related functionalities.

Closes #1074.
This commit is contained in:
2025-08-19 17:33:45 +03:00
parent f04632dc77
commit b19f0c553b
8 changed files with 490 additions and 23 deletions

View File

@@ -15,7 +15,12 @@ else()
list(APPEND srcs "src/relay_chn_ctl_single.c") list(APPEND srcs "src/relay_chn_ctl_single.c")
endif() endif()
if(CONFIG_RELAY_CHN_NVS)
list(APPEND srcs "src/relay_chn_nvs.c")
endif()
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include_dirs} INCLUDE_DIRS ${include_dirs}
PRIV_INCLUDE_DIRS ${priv_include_dirs} PRIV_INCLUDE_DIRS ${priv_include_dirs}
REQUIRES driver esp_timer esp_event) REQUIRES driver esp_timer esp_event nvs_flash)

35
Kconfig
View File

@@ -26,4 +26,39 @@ menu "Relay Channel Driver Configuration"
at a time. Tilting is specifically designed for controlling some at a time. Tilting is specifically designed for controlling some
types of curtains that need to be adjusted to let enter specific types of curtains that need to be adjusted to let enter specific
amount of day light. amount of day light.
config RELAY_CHN_ENABLE_NVS
bool "Enable persistent NVS storage for relay channel"
default n
help
If enabled, relay channel configuration will be stored in NVS.
endmenu
menu "Relay Channel NVS Storage Configuration"
depends on RELAY_CHN_ENABLE_NVS
config RELAY_CHN_NVS_NAMESPACE
string "NVS namespace for relay channel storage"
default "relay_chn"
help
The NVS namespace used for storing relay channel configuration.
This should be unique to avoid conflicts with other components.
config RELAY_CHN_NVS_CUSTOM_PARTITION
bool "Use custom NVS partition for relay channel storage"
default n
help
If enabled, a custom NVS partition will be used for storing
relay channel configuration. If disabled, the default NVS
partition will be used.
config RELAY_CHN_NVS_CUSTOM_PARTITION_NAME
string "Custom NVS partition name"
depends on RELAY_CHN_NVS_CUSTOM_PARTITION
default "app_data"
help
The name of the custom NVS partition used for storing relay channel
configuration. Make sure the name is exactly the same as label defined
in the relevant partition table.
endmenu endmenu

View File

@@ -14,6 +14,15 @@ extern "C" {
#define RELAY_CHN_OPPOSITE_INERTIA_MS CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS #define RELAY_CHN_OPPOSITE_INERTIA_MS CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS
#define RELAY_CHN_COUNT CONFIG_RELAY_CHN_COUNT #define RELAY_CHN_COUNT CONFIG_RELAY_CHN_COUNT
#define RELAY_CHN_ENABLE_TILTING CONFIG_RELAY_CHN_ENABLE_TILTING #define RELAY_CHN_ENABLE_TILTING CONFIG_RELAY_CHN_ENABLE_TILTING
#define RELAY_CHN_ENABLE_NVS CONFIG_RELAY_CHN_ENABLE_NVS
#if RELAY_CHN_ENABLE_NVS == 1
#define RELAY_CHN_NVS_NAMESPACE CONFIG_RELAY_CHN_NVS_NAMESPACE
#define RELAY_CHN_NVS_CUSTOM_PARTITION CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION
#if RELAY_CHN_NVS_CUSTOM_PARTITION == 1
#define RELAY_CHN_NVS_CUSTOM_PARTITION_NAME CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME
#endif
#endif
#if RELAY_CHN_COUNT > 1 #if RELAY_CHN_COUNT > 1
#define RELAY_CHN_ID_ALL RELAY_CHN_COUNT /*!< Special ID to address all channels */ #define RELAY_CHN_ID_ALL RELAY_CHN_COUNT /*!< Special ID to address all channels */

View File

@@ -0,0 +1,106 @@
/*
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "relay_chn_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize NVS storage for relay channels.
*
* @attention Before calling this function, make sure the NVS flash is initialised
* using either the nvs_flash_init() function for the default NVS partition or the
* nvs_flash_init_partition() function for a custom partition.
*
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_init(void);
/**
* @brief Store relay channel direction in NVS.
*
* @param[in] ch Channel number.
* @param[in] direction Direction to store.
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t direction);
/**
* @brief Retrieve relay channel direction from NVS.
*
* @param[in] ch Channel number.
* @param[out] direction Pointer to store retrieved direction.
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_get_direction(uint8_t ch, relay_chn_direction_t *direction);
#ifdef RELAY_CHN_ENABLE_TILTING
/**
* @brief Store tilt sensitivity in NVS.
*
* @param[in] ch Channel number.
* @param[in] sensitivity Sensitivity value to store.
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity);
/**
* @brief Retrieve tilt sensitivity from NVS.
*
* @param[in] ch Channel number.
* @param[out] sensitivity Pointer to store retrieved sensitivity.
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_get_tilt_sensitivity(uint8_t ch, uint8_t *sensitivity);
/**
* @brief Store tilt counters in NVS.
*
* @param[in] ch Channel number.
* @param[in] forward_count Forward tilt counter value.
* @param[in] reverse_count Reverse tilt counter value.
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint32_t forward_count, uint32_t reverse_count);
/**
* @brief Retrieve tilt counters from NVS.
*
* @param[in] ch Channel number.
* @param[out] forward_count Pointer to store forward tilt counter.
* @param[out] reverse_count Pointer to store reverse tilt counter.
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_get_tilt_count(uint8_t ch, uint32_t *forward_count, uint32_t *reverse_count);
#endif // RELAY_CHN_ENABLE_TILTING
/**
* @brief Erase all keys in the NVS namespace.
*
* This function will erase all key-value pairs in the NVS namespace used by relay channels.
*
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_erase_all(void);
/**
* @brief Deinitialize NVS storage for relay channels.
*
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t relay_chn_nvs_deinit(void);
#ifdef __cplusplus
}
#endif

View File

@@ -11,9 +11,15 @@
#include "relay_chn_output.h" #include "relay_chn_output.h"
#include "relay_chn_run_info.h" #include "relay_chn_run_info.h"
#include "relay_chn_ctl.h" #include "relay_chn_ctl.h"
#if RELAY_CHN_ENABLE_TILTING == 1 #if RELAY_CHN_ENABLE_TILTING == 1
#include "relay_chn_tilt.h" #include "relay_chn_tilt.h"
#endif #endif
#if RELAY_CHN_ENABLE_NVS == 1
#include "relay_chn_nvs.h"
#endif
#include "relay_chn_core.h" #include "relay_chn_core.h"
@@ -89,6 +95,11 @@ esp_err_t relay_chn_create(const uint8_t* gpio_map, uint8_t gpio_count)
ESP_RETURN_ON_FALSE(gpio_map != NULL, ESP_ERR_INVALID_ARG, TAG, "gpio_map cannot be NULL"); ESP_RETURN_ON_FALSE(gpio_map != NULL, ESP_ERR_INVALID_ARG, TAG, "gpio_map cannot be NULL");
esp_err_t ret; esp_err_t ret;
#if RELAY_CHN_ENABLE_NVS == 1
ret = relay_chn_nvs_init();
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize NVS for relay channel");
#endif
// Initialize the output // Initialize the output
ret = relay_chn_output_init(gpio_map, gpio_count); ret = relay_chn_output_init(gpio_map, gpio_count);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel outputs"); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel outputs");
@@ -137,6 +148,10 @@ void relay_chn_destroy(void)
relay_chn_ctl_deinit(); relay_chn_ctl_deinit();
relay_chn_output_deinit(); relay_chn_output_deinit();
#if RELAY_CHN_ENABLE_NVS == 1
relay_chn_nvs_deinit();
#endif
// Destroy the event loop // Destroy the event loop
esp_event_loop_delete(relay_chn_event_loop); esp_event_loop_delete(relay_chn_event_loop);
relay_chn_event_loop = NULL; relay_chn_event_loop = NULL;

125
src/relay_chn_nvs.c Normal file
View File

@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2025 Kozmotronik Tech
*
* SPDX-License-Identifier: MIT
*/
#include "esp_check.h"
#include "relay_chn_nvs.h"
#define RELAY_CHN_KEY_DIR "dir"
#ifdef RELAY_CHN_ENABLE_TILTING
#define RELAY_CHN_KEY_SENS(ch) "sens_%d"
#define RELAY_CHN_KEY_TFWD(ch) "tfwd_%d"
#define RELAY_CHN_KEY_TREV(ch) "trev_%d"
#endif
static const char *TAG = "RELAY_CHN_STORAGE_NVS";
static nvs_handle_t relay_chn_nvs;
esp_err_t relay_chn_nvs_init()
{
esp_err_t ret;
#if RELAY_CHN_NVS_CUSTOM_PARTITION == 1
ret = nvs_open_from_partition(RELAY_CHN_NVS_CUSTOM_PARTITION_NAME,
RELAY_CHN_NVS_NAMESPACE,
NVS_READWRITE,
&relay_chn_nvs);
ESP_RETURN_ON_ERROR(ret,
TAG,
"Failed to open NVS namespace '%s' from partition '%s' with error %s",
RELAY_CHN_NVS_NAMESPACE,
RELAY_CHN_NVS_CUSTOM_PARTITION_NAME,
esp_err_to_name(ret));
#else
ret = nvs_open(RELAY_CHN_NVS_NAMESPACE, NVS_READWRITE, &relay_chn_nvs);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to open NVS namespace '%s'", RELAY_CHN_NVS_NAMESPACE);
#endif // RELAY_CHN_NVS_CUSTOM_PARTITION
return ESP_OK;
}
esp_err_t relay_chn_nvs_set_direction(uint8_t ch, relay_chn_direction_t direction)
{
uint8_t direction_val;
esp_err_t ret = nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
if (ret == ESP_ERR_NVS_NOT_FOUND) {
// The key does not exist yet, set it to zero which is the default direction
direction_val = RELAY_CHN_DIRECTION_DEFAULT;
} else if (ret != ESP_OK) {
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to get direction from NVS with error: %s", esp_err_to_name(ret));
}
direction_val &= ~(1 << ch); // Clear the bit for the channel
direction_val |= (((uint8_t) direction) << ch); // Set the new direction bit
ret = nvs_set_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, direction_val);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set direction for channel %d", ch);
return nvs_commit(relay_chn_nvs);
}
esp_err_t relay_chn_nvs_get_direction(uint8_t ch, relay_chn_direction_t *direction)
{
ESP_RETURN_ON_FALSE(direction != NULL, ESP_ERR_INVALID_ARG, TAG, "Direction pointer is NULL");
uint8_t direction_val;
esp_err_t ret = nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_DIR, &direction_val);
if (ret != ESP_OK) {
return ret; // Return error if the key does not exist
}
*direction = (relay_chn_direction_t)((direction_val >> ch) & 0x01);
return ESP_OK;
}
#ifdef RELAY_CHN_ENABLE_TILTING
esp_err_t relay_chn_nvs_set_tilt_sensitivity(uint8_t ch, uint8_t sensitivity)
{
esp_err_t ret = nvs_set_u8(relay_chn_nvs, RELAY_CHN_KEY_SENS(ch), sensitivity);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to set tilt sensitivity for channel %d", ch);
return nvs_commit(relay_chn_nvs);
}
esp_err_t relay_chn_nvs_get_tilt_sensitivity(uint8_t ch, uint8_t *sensitivity)
{
ESP_RETURN_ON_FALSE(sensitivity != NULL, ESP_ERR_INVALID_ARG, TAG, "Sensitivity pointer is NULL");
return nvs_get_u8(relay_chn_nvs, RELAY_CHN_KEY_SENS(ch), sensitivity);
}
esp_err_t relay_chn_nvs_set_tilt_count(uint8_t ch, uint32_t forward_count, uint32_t reverse_count)
{
esp_err_t ret;
ret = nvs_set_u32(relay_chn_nvs, RELAY_CHN_KEY_TFWD(ch), forward_count);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to save forward_count tilt counter");
ret = nvs_set_u32(relay_chn_nvs, RELAY_CHN_KEY_TREV(ch), reverse_count);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to save reverse_count tilt counter");
return nvs_commit(relay_chn_nvs);
}
esp_err_t relay_chn_nvs_get_tilt_count(uint8_t ch, uint32_t *forward_count, uint32_t *reverse_count)
{
ESP_RETURN_ON_FALSE(forward_count != NULL && reverse_count != NULL,
ESP_ERR_INVALID_ARG, TAG, "Counter pointers are NULL");
esp_err_t ret = nvs_get_u32(relay_chn_nvs, RELAY_CHN_KEY_TFWD(ch), forward_count);
if (ret != ESP_OK) {
return ret; // Return error if the key does not exist
}
return nvs_get_u32(relay_chn_nvs, RELAY_CHN_KEY_TREV(ch), reverse_count);
}
#endif // RELAY_CHN_ENABLE_TILTING
esp_err_t relay_chn_nvs_erase_all()
{
// Erase all key-value pairs in the relay_chn NVS namespace
esp_err_t ret = nvs_erase_all(relay_chn_nvs);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to erase all keys in NVS namespace '%s'", RELAY_CHN_NVS_NAMESPACE);
// Commit the changes
return nvs_commit(relay_chn_nvs);
}
esp_err_t relay_chn_nvs_deinit()
{
nvs_close(relay_chn_nvs);
return ESP_OK;
}

View File

@@ -10,6 +10,10 @@
#include "relay_chn_output.h" #include "relay_chn_output.h"
#include "relay_chn_core.h" #include "relay_chn_core.h"
#if RELAY_CHN_ENABLE_NVS == 1
#include "relay_chn_nvs.h"
#endif
static const char *TAG = "RELAY_CHN_OUTPUT"; static const char *TAG = "RELAY_CHN_OUTPUT";
@@ -38,7 +42,10 @@ static esp_err_t relay_chn_output_check_gpio_capabilities(uint8_t gpio_count)
return ESP_OK; return ESP_OK;
} }
static esp_err_t relay_chn_output_ctl_init(relay_chn_output_t *output, gpio_num_t forward_pin, gpio_num_t reverse_pin) static esp_err_t relay_chn_output_ctl_init(relay_chn_output_t *output,
gpio_num_t forward_pin,
gpio_num_t reverse_pin,
relay_chn_direction_t direction)
{ {
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(forward_pin), ESP_ERR_INVALID_ARG, TAG, ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(forward_pin), ESP_ERR_INVALID_ARG, TAG,
"Invalid GPIO pin number for forward_pin: %d", forward_pin); "Invalid GPIO pin number for forward_pin: %d", forward_pin);
@@ -60,12 +67,26 @@ static esp_err_t relay_chn_output_ctl_init(relay_chn_output_t *output, gpio_num_
// Initialize the GPIOs // Initialize the GPIOs
// Initialize the relay channel output // Initialize the relay channel output
output->forward_pin = forward_pin; output->forward_pin = direction == RELAY_CHN_DIRECTION_DEFAULT ? forward_pin : reverse_pin;
output->reverse_pin = reverse_pin; output->reverse_pin = direction == RELAY_CHN_DIRECTION_DEFAULT ? reverse_pin : forward_pin;
output->direction = RELAY_CHN_DIRECTION_DEFAULT; output->direction = direction;
return ESP_OK; return ESP_OK;
} }
#if RELAY_CHN_ENABLE_NVS == 1
static esp_err_t relay_chn_output_load_direction(uint8_t ch, relay_chn_direction_t *direction)
{
esp_err_t ret = relay_chn_nvs_get_direction(ch, direction);
if (ret == ESP_ERR_NVS_NOT_FOUND) {
// If the key does not exist, use the default direction
*direction = RELAY_CHN_DIRECTION_DEFAULT;
} else if (ret != ESP_OK) {
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to get direction from storage for channel %d: %s", ch, esp_err_to_name(ret));
}
return ESP_OK;
}
#endif
esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count) esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count)
{ {
esp_err_t ret; esp_err_t ret;
@@ -79,11 +100,23 @@ esp_err_t relay_chn_output_init(const uint8_t* gpio_map, uint8_t gpio_count)
gpio_num_t forward_pin = (gpio_num_t) gpio_map[gpio_index]; gpio_num_t forward_pin = (gpio_num_t) gpio_map[gpio_index];
gpio_num_t reverse_pin = (gpio_num_t) gpio_map[gpio_index + 1]; gpio_num_t reverse_pin = (gpio_num_t) gpio_map[gpio_index + 1];
ret = relay_chn_output_ctl_init(output, forward_pin, reverse_pin); relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT;
#if RELAY_CHN_ENABLE_NVS == 1
// If NVS storage is enabled, retrieve the direction from storage
ret = relay_chn_output_load_direction(i, &direction);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", i);
#endif
ret = relay_chn_output_ctl_init(output, forward_pin, reverse_pin, direction);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel %d", i); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel %d", i);
} }
#else #else
ret = relay_chn_output_ctl_init(&output, gpio_map[0], gpio_map[1]); relay_chn_direction_t direction = RELAY_CHN_DIRECTION_DEFAULT;
#if RELAY_CHN_ENABLE_NVS == 1
// If NVS storage is enabled, retrieve the direction from storage
ret = relay_chn_output_load_direction(0, &direction);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load direction from storage for channel %d", 0);
#endif
ret = relay_chn_output_ctl_init(&output, gpio_map[0], gpio_map[1], direction);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel"); ESP_RETURN_ON_ERROR(ret, TAG, "Failed to initialize relay channel");
#endif #endif
return ESP_OK; return ESP_OK;
@@ -160,6 +193,22 @@ void relay_chn_output_flip(relay_chn_output_t *output)
output->direction = (output->direction == RELAY_CHN_DIRECTION_DEFAULT) output->direction = (output->direction == RELAY_CHN_DIRECTION_DEFAULT)
? RELAY_CHN_DIRECTION_FLIPPED ? RELAY_CHN_DIRECTION_FLIPPED
: RELAY_CHN_DIRECTION_DEFAULT; : RELAY_CHN_DIRECTION_DEFAULT;
#if RELAY_CHN_ENABLE_NVS == 1
uint8_t ch = 0;
#if RELAY_CHN_COUNT > 1
for (uint8_t i = 0; i < RELAY_CHN_COUNT; i++) {
if (output == &outputs[i]) {
ch = i;
break;
}
}
#endif
esp_err_t ret = relay_chn_nvs_set_direction(ch, output->direction);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to save flipped direction for channel %d: %s", ch, esp_err_to_name(ret));
}
#endif
} }
relay_chn_direction_t relay_chn_output_get_direction(relay_chn_output_t *output) relay_chn_direction_t relay_chn_output_get_direction(relay_chn_output_t *output)

View File

@@ -10,6 +10,12 @@
#include "relay_chn_run_info.h" #include "relay_chn_run_info.h"
#include "relay_chn_tilt.h" #include "relay_chn_tilt.h"
#if RELAY_CHN_ENABLE_NVS == 1
#include "relay_chn_nvs.h"
#define RELAY_CHN_TILT_FLUSH_DEBOUNCE_MS 3000
#endif
static const char *TAG = "RELAY_CHN_TILT"; static const char *TAG = "RELAY_CHN_TILT";
@@ -65,6 +71,9 @@ typedef struct relay_chn_tilt_ctl {
relay_chn_tilt_timing_t tilt_timing; /*!< Tilt timing structure */ relay_chn_tilt_timing_t tilt_timing; /*!< Tilt timing structure */
relay_chn_tilt_counter_t tilt_counter; /*!< Tilt counter structure */ relay_chn_tilt_counter_t tilt_counter; /*!< Tilt counter structure */
esp_timer_handle_t tilt_timer; /*!< Tilt timer handle */ esp_timer_handle_t tilt_timer; /*!< Tilt timer handle */
#if RELAY_CHN_ENABLE_NVS == 1
esp_timer_handle_t flush_timer; /*!< Flush timer to avoid frequent write of tilt counters */
#endif
} relay_chn_tilt_ctl_t; } relay_chn_tilt_ctl_t;
@@ -295,7 +304,7 @@ static void relay_chn_tilt_set_timing_values(relay_chn_tilt_timing_t *tilt_timin
tilt_timing->pause_time_ms = pause_time_ms; tilt_timing->pause_time_ms = pause_time_ms;
} }
static void _relay_chn_tilt_sensitivity_set(relay_chn_tilt_ctl_t *tilt_ctl, uint8_t sensitivity) static void relay_chn_tilt_compute_set_sensitivity(relay_chn_tilt_ctl_t *tilt_ctl, uint8_t sensitivity)
{ {
if (sensitivity >= 100) { if (sensitivity >= 100) {
relay_chn_tilt_set_timing_values(&tilt_ctl->tilt_timing, relay_chn_tilt_set_timing_values(&tilt_ctl->tilt_timing,
@@ -309,6 +318,12 @@ static void _relay_chn_tilt_sensitivity_set(relay_chn_tilt_ctl_t *tilt_ctl, uint
RELAY_CHN_TILT_RUN_MIN_MS, RELAY_CHN_TILT_RUN_MIN_MS,
RELAY_CHN_TILT_PAUSE_MIN_MS); RELAY_CHN_TILT_PAUSE_MIN_MS);
} }
else if (sensitivity == RELAY_CHN_TILT_DEFAULT_SENSITIVITY) {
relay_chn_tilt_set_timing_values(&tilt_ctl->tilt_timing,
sensitivity,
RELAY_CHN_TILT_DEFAULT_RUN_MS,
RELAY_CHN_TILT_DEFAULT_PAUSE_MS);
}
else { else {
// Compute the new timing values from the sensitivity percent value by using linear interpolation // Compute the new timing values from the sensitivity percent value by using linear interpolation
uint32_t tilt_run_time_ms = 0, tilt_pause_time_ms = 0; uint32_t tilt_run_time_ms = 0, tilt_pause_time_ms = 0;
@@ -331,12 +346,16 @@ void relay_chn_tilt_set_sensitivity(uint8_t chn_id, uint8_t sensitivity)
if (chn_id == RELAY_CHN_ID_ALL) { if (chn_id == RELAY_CHN_ID_ALL) {
for (int i = 0; i < RELAY_CHN_COUNT; i++) { for (int i = 0; i < RELAY_CHN_COUNT; i++) {
_relay_chn_tilt_sensitivity_set(&tilt_ctls[i], sensitivity); relay_chn_tilt_compute_set_sensitivity(&tilt_ctls[i], sensitivity);
} }
} }
else { else {
_relay_chn_tilt_sensitivity_set(&tilt_ctls[chn_id], sensitivity); relay_chn_tilt_compute_set_sensitivity(&tilt_ctls[chn_id], sensitivity);
} }
#if RELAY_CHN_ENABLE_NVS == 1
relay_chn_nvs_set_tilt_sensitivity(chn_id, sensitivity);
#endif // RELAY_CHN_ENABLE_NVS
} }
esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, size_t length) esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, size_t length)
@@ -367,7 +386,11 @@ esp_err_t relay_chn_tilt_get_sensitivity(uint8_t chn_id, uint8_t *sensitivity, s
void relay_chn_tilt_set_sensitivity(uint8_t sensitivity) void relay_chn_tilt_set_sensitivity(uint8_t sensitivity)
{ {
_relay_chn_tilt_sensitivity_set(&tilt_ctl, sensitivity); relay_chn_tilt_compute_set_sensitivity(&tilt_ctl, sensitivity);
#if RELAY_CHN_ENABLE_NVS == 1
relay_chn_nvs_set_tilt_sensitivity(0, sensitivity);
#endif // RELAY_CHN_ENABLE_NVS
} }
uint8_t relay_chn_tilt_get_sensitivity() uint8_t relay_chn_tilt_get_sensitivity()
@@ -380,6 +403,10 @@ void relay_chn_tilt_reset_count(relay_chn_tilt_ctl_t *tilt_ctl)
{ {
tilt_ctl->tilt_counter.tilt_forward_count = 0; tilt_ctl->tilt_counter.tilt_forward_count = 0;
tilt_ctl->tilt_counter.tilt_reverse_count = 0; tilt_ctl->tilt_counter.tilt_reverse_count = 0;
#if RELAY_CHN_ENABLE_NVS == 1
esp_timer_stop(tilt_ctl->flush_timer);
#endif
} }
/** /**
@@ -449,6 +476,31 @@ static uint32_t relay_chn_tilt_count_update(relay_chn_tilt_ctl_t *tilt_ctl)
return 0; return 0;
} }
#if RELAY_CHN_ENABLE_NVS == 1
static esp_err_t relay_chn_tilt_save_tilt_counter(relay_chn_tilt_ctl_t *tilt_ctl)
{
// Save the tilt count to NVS storage
esp_err_t ret = relay_chn_nvs_set_tilt_count(tilt_ctl->chn_ctl->id,
tilt_ctl->tilt_counter.tilt_forward_count,
tilt_ctl->tilt_counter.tilt_reverse_count);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "relay_chn_tilt_execute_stop: Failed to save tilt count for channel #%d: %s", tilt_ctl->chn_ctl->id, esp_err_to_name(ret));
}
return ESP_OK;
}
static void relay_chn_tilt_flush_timer_cb(void *arg)
{
relay_chn_tilt_ctl_t* tilt_ctl = (relay_chn_tilt_ctl_t*) arg;
ESP_RETURN_VOID_ON_FALSE(tilt_ctl != NULL, TAG, "relay_chn_tilt_flush_timer_cb: timer arg is NULL");
// Save the tilt count to storage
esp_err_t ret = relay_chn_tilt_save_tilt_counter(tilt_ctl);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "relay_chn_tilt_execute_stop: Failed to save tilt count for channel #%d: %s", tilt_ctl->chn_ctl->id, esp_err_to_name(ret));
}
}
#endif
static void relay_chn_tilt_execute_stop(relay_chn_tilt_ctl_t *tilt_ctl) static void relay_chn_tilt_execute_stop(relay_chn_tilt_ctl_t *tilt_ctl)
{ {
// Stop the channel's timer if active // Stop the channel's timer if active
@@ -461,6 +513,11 @@ static void relay_chn_tilt_execute_stop(relay_chn_tilt_ctl_t *tilt_ctl)
ESP_LOGE(TAG, "relay_chn_tilt_execute_stop: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id); ESP_LOGE(TAG, "relay_chn_tilt_execute_stop: Failed to output stop for relay channel #%d!", tilt_ctl->chn_ctl->id);
} }
relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP); relay_chn_dispatch_cmd(tilt_ctl->chn_ctl, RELAY_CHN_CMD_STOP);
#if RELAY_CHN_ENABLE_NVS == 1
// Start the flush debounce timer
relay_chn_start_esp_timer_once(tilt_ctl->flush_timer, RELAY_CHN_TILT_FLUSH_DEBOUNCE_MS);
#endif
} }
static void relay_chn_tilt_execute_forward(relay_chn_tilt_ctl_t *tilt_ctl) static void relay_chn_tilt_execute_forward(relay_chn_tilt_ctl_t *tilt_ctl)
@@ -544,7 +601,7 @@ static void relay_chn_tilt_event_handler(void *handler_arg, esp_event_base_t eve
static void relay_chn_tilt_timer_cb(void *arg) static void relay_chn_tilt_timer_cb(void *arg)
{ {
relay_chn_tilt_ctl_t* tilt_ctl = (relay_chn_tilt_ctl_t*) arg; relay_chn_tilt_ctl_t* tilt_ctl = (relay_chn_tilt_ctl_t*) arg;
ESP_RETURN_VOID_ON_FALSE(tilt_ctl != NULL, TAG, "relay_chn_tilt_timer_cb: event_data is NULL"); ESP_RETURN_VOID_ON_FALSE(tilt_ctl != NULL, TAG, "relay_chn_tilt_timer_cb: timer arg is NULL");
switch (tilt_ctl->step) switch (tilt_ctl->step)
{ {
@@ -571,17 +628,44 @@ static void relay_chn_tilt_timer_cb(void *arg)
} }
} }
esp_err_t relay_chn_tilt_ctl_init(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_ctl_t *chn_ctl) #if RELAY_CHN_ENABLE_NVS == 1
static esp_err_t relay_chn_tilt_load_sensitivity(uint8_t ch, uint8_t *sensitivity)
{
esp_err_t ret = relay_chn_nvs_get_tilt_sensitivity(ch, sensitivity);
if (ret == ESP_ERR_NVS_NOT_FOUND) {
*sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
return ESP_OK;
}
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", ch);
return ESP_OK;
}
static esp_err_t relay_chn_tilt_load_tilt_counter(uint8_t ch, relay_chn_tilt_counter_t *tilt_counter)
{
esp_err_t ret = relay_chn_nvs_get_tilt_count(ch, &tilt_counter->tilt_forward_count, &tilt_counter->tilt_reverse_count);
if (ret == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGD(TAG, "relay_chn_tilt_load_tilt_counter: No tilt counters found in NVS for channel %d, initializing to zero", ch);
tilt_counter->tilt_forward_count = 0;
tilt_counter->tilt_reverse_count = 0;
return ESP_OK;
}
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt counters for channel %d", ch);
return ESP_OK;
}
#endif // RELAY_CHN_ENABLE_NVS
static esp_err_t relay_chn_tilt_ctl_init(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_ctl_t *chn_ctl,
relay_chn_tilt_counter_t *tilt_counter, uint8_t sensitivity)
{ {
tilt_ctl->cmd = RELAY_CHN_TILT_CMD_NONE; tilt_ctl->cmd = RELAY_CHN_TILT_CMD_NONE;
tilt_ctl->step = RELAY_CHN_TILT_STEP_NONE; tilt_ctl->step = RELAY_CHN_TILT_STEP_NONE;
tilt_ctl->tilt_timing.sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY; relay_chn_tilt_compute_set_sensitivity(tilt_ctl, sensitivity);
tilt_ctl->tilt_timing.move_time_ms = RELAY_CHN_TILT_DEFAULT_RUN_MS; // Init tilt counters
tilt_ctl->tilt_timing.pause_time_ms = RELAY_CHN_TILT_DEFAULT_PAUSE_MS; tilt_ctl->tilt_counter.tilt_forward_count = tilt_counter->tilt_forward_count;
relay_chn_tilt_reset_count(tilt_ctl); tilt_ctl->tilt_counter.tilt_reverse_count = tilt_counter->tilt_reverse_count;
tilt_ctl->chn_ctl = chn_ctl; tilt_ctl->chn_ctl = chn_ctl;
tilt_ctl->chn_ctl->tilt_ctl = tilt_ctl; // tilt_ctl->chn_ctl->tilt_ctl = tilt_ctl;
// Create tilt timer for the channel // Create tilt timer for the channel
char timer_name[32]; char timer_name[32];
@@ -591,17 +675,50 @@ esp_err_t relay_chn_tilt_ctl_init(relay_chn_tilt_ctl_t *tilt_ctl, relay_chn_ctl_
.arg = tilt_ctl, .arg = tilt_ctl,
.name = timer_name .name = timer_name
}; };
return esp_timer_create(&timer_args, &tilt_ctl->tilt_timer); esp_err_t ret = esp_timer_create(&timer_args, &tilt_ctl->tilt_timer);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create tilt timer for channel %d", chn_ctl->id);
#if RELAY_CHN_ENABLE_NVS == 1
// Create flush timer for the tilt counters
snprintf(timer_name, sizeof(timer_name), "relay_chn_%2d_tilt_flush_timer", chn_ctl->id);
timer_args.callback = relay_chn_tilt_flush_timer_cb;
timer_args.name = timer_name;
ret = esp_timer_create(&timer_args, &tilt_ctl->flush_timer);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to create tilt flush timer for channel %d", chn_ctl->id);
#endif
return ESP_OK;
} }
esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls) esp_err_t relay_chn_tilt_init(relay_chn_ctl_t *chn_ctls)
{ {
uint8_t sensitivity;
relay_chn_tilt_counter_t tilt_counter;
#if RELAY_CHN_COUNT > 1 #if RELAY_CHN_COUNT > 1
for (int i = 0; i < RELAY_CHN_COUNT; i++) { for (int i = 0; i < RELAY_CHN_COUNT; i++) {
relay_chn_tilt_ctl_init(&tilt_ctls[i], &chn_ctls[i]); #if RELAY_CHN_ENABLE_NVS == 1
} esp_err_t ret = relay_chn_tilt_load_sensitivity(i, &sensitivity);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", i);
ret = relay_chn_tilt_load_tilt_counter(i, &tilt_counter);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt counters for channel %d", i);
#else #else
relay_chn_tilt_ctl_init(&tilt_ctl, chn_ctls); sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
tilt_counter.tilt_forward_count = 0;
tilt_counter.tilt_reverse_count = 0;
#endif // RELAY_CHN_ENABLE_NVS == 1
relay_chn_tilt_ctl_init(&tilt_ctls[i], &chn_ctls[i], &tilt_counter, sensitivity);
}
#else
sensitivity = RELAY_CHN_TILT_DEFAULT_SENSITIVITY;
tilt_counter.tilt_forward_count = 0;
tilt_counter.tilt_reverse_count = 0;
#if RELAY_CHN_ENABLE_NVS == 1
esp_err_t ret = relay_chn_tilt_load_sensitivity(0, &sensitivity);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt sensitivity for channel %d", 0);
ret = relay_chn_tilt_load_tilt_counter(0, &tilt_counter);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to load tilt counters for channel %d", 0);
#endif // RELAY_CHN_ENABLE_NVS == 1
relay_chn_tilt_ctl_init(&tilt_ctl, chn_ctls, &tilt_counter, sensitivity);
#endif // RELAY_CHN_COUNT > 1 #endif // RELAY_CHN_COUNT > 1
return esp_event_handler_register_with(relay_chn_event_loop, return esp_event_handler_register_with(relay_chn_event_loop,
@@ -616,6 +733,12 @@ void relay_chn_tilt_ctl_deinit(relay_chn_tilt_ctl_t *tilt_ctl)
esp_timer_delete(tilt_ctl->tilt_timer); esp_timer_delete(tilt_ctl->tilt_timer);
tilt_ctl->tilt_timer = NULL; tilt_ctl->tilt_timer = NULL;
} }
#if RELAY_CHN_ENABLE_NVS == 1
if (tilt_ctl->flush_timer != NULL) {
esp_timer_delete(tilt_ctl->flush_timer);
tilt_ctl->flush_timer = NULL;
}
#endif // RELAY_CHN_ENABLE_NVS == 1
} }
void relay_chn_tilt_deinit() void relay_chn_tilt_deinit()