relay_chn - Relay Channel Controller

An ESP-IDF component for controlling relay channels, specifically designed for driving bipolar motors through relay pairs.

Features

  • Controls multiple relay channel pairs (up to 8 channels)
  • Built-in direction change inertia protection
  • Automatic command sequencing and timing
  • Event-driven architecture for reliable operation
  • Forward/Reverse direction control
  • Direction flipping capability
  • State monitoring and reporting
  • Optional sensitivty adjustable tilting feature
  • Optional NVS storage for persistent configuration
  • Optional configurable run limit protection

Description

Each relay channel consists of 2 output relays controlled by 2 GPIO pins. The component provides APIs to control these relay pairs while ensuring safe operation, particularly for driving bipolar motors. To prevent mechanical strain on the motor, the component automatically manages direction changes with a configurable inertia delay, protecting it from abrupt reversals. Hence, the component handles all the required timing between the movement transitions automatically to ensure reliable operation.

The run limit feature provides an additional layer of protection by automatically stopping channels after a configurable time period. This is particularly useful for motor-driven applications where continuous operation beyond a certain duration could cause damage or safety issues. Each channel can have its own run limit setting, and when enabled, the component will automatically stop the channel once it has been running for the specified duration.

It also provides an optional tilting interface per channel base. Tilting makes a channel move with a specific pattern moving with small steps at a time. Tilting is specifically designed for controlling some types of curtains that need to be adjusted to let enter specific amount of day light. Since it operates on relays, the switching frequency is limited to 10Hz which complies with the most of the general purpose relays' requirements. The minimum frequency is 2Hz and the duty cycle is about 10% in all ranges.

Another optional feature is NVS storage, which saves the configuration permanently across reboots of the device. These configurations are:

  • Direction
  • Run limit duration
  • Tilt sensitivity
  • Last tilt position

NVS Operation Details

When NVS storage is enabled (CONFIG_RELAY_CHN_ENABLE_NVS=y), the component creates a dedicated background task to manage all NVS write operations. This design has important implications for how you use the NVS-related functions:

  • Asynchronous Writes: All set operations (e.g., relay_chn_flip_direction(), relay_chn_set_run_limit()) are asynchronous. They add the write request to a queue and return immediately, preventing the calling task from being blocked.
  • Synchronous Reads: All get operations (e.g., relay_chn_get_direction()) are synchronous. They read the value directly from the NVS storage and will block the calling task until the read is complete.
  • Batched Commits: To optimize performance and minimize flash wear, the NVS task uses a batching mechanism for writes. It collects multiple write requests and commits them to the NVS flash in a single operation after a short period of inactivity (typically 200ms).

Important

Due to the asynchronous and batched nature of write operations, a call to a get function may not immediately reflect a value that was just written by a set function. Your application should account for this small delay.

Configuration

Configure the component through menuconfig under "Relay Channel Driver Configuration":

  • CONFIG_RELAY_CHN_OPPOSITE_INERTIA_MS: Time to wait before changing direction (200-1500ms, default: 800ms)
  • CONFIG_RELAY_CHN_COUNT: Number of relay channels (1-8, default: 1)
  • CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT: Enable run limit protection (default: n)
  • CONFIG_RELAY_CHN_ENABLE_TILTING: Enable tilting interface on all channels. (default: n)
  • CONFIG_RELAY_CHN_ENABLE_NVS: Enable persistent storage in NVS (default: n)

When run limit is enabled (CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT), the following configuration options become available:

  • CONFIG_RELAY_CHN_RUN_LIMIT_MIN_SEC: Minimum allowed run limit duration (1-60s, default: 10s)
  • CONFIG_RELAY_CHN_RUN_LIMIT_MAX_SEC: Maximum allowed run limit duration (60-3600s, default: 600s)
  • CONFIG_RELAY_CHN_RUN_LIMIT_DEFAULT_SEC: Default run limit duration for channels (10-3600s, default: 60s)

When NVS storage is enabled (CONFIG_RELAY_CHN_ENABLE_NVS), additional configuration options become available:

  • CONFIG_RELAY_CHN_NVS_NAMESPACE: NVS namespace for storing relay channel data (default: "relay_chn")
  • CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION: Use custom NVS partition instead of default (default: n)
  • CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME: Name of the custom partition if enabled (default "app_data")

NVS Storage Prerequisites

Warning

relay_chn component does not initialize the NVS flash.

If NVS storage is enabled, you must initialize NVS flash before calling relay_chn_create() in your application code. The relay_chn component can use either the default or a custom NVS partition from your application, depending on the configuration settings.

Initialize for Default Partition

  1. Enable NVS, but keep the custom partition option disabled in menuconfig:
CONFIG_RELAY_CHN_ENABLE_NVS=y
CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=n
  1. Initialize the default NVS flash:
// Initialize default NVS partition
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
    ESP_ERROR_CHECK(nvs_flash_erase());
    ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);

// Now you can create relay channels
ret = relay_chn_create(gpio_map, gpio_count);

Initialize for Custom Partition

  1. Enable both NVS and custom partition, also set the custom partition name in menuconfig.
CONFIG_RELAY_CHN_ENABLE_NVS=y
CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION=n
CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME=my_custom_partition

Important

The CONFIG_RELAY_CHN_NVS_CUSTOM_PARTITION_NAME must match exactly the label defined for the custom NVS partition in the partition table. Otherwise the component initialisation will fail due to the ESP_ERR_NVS_PART_NOT_FOUND error.

  1. Initialize the custom NVS partition:
esp_err_t ret = nvs_flash_init_partition(YOUR_CUSTOM_PARTITION_NAME);
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
    ESP_ERROR_CHECK(nvs_flash_erase_partition(YOUR_CUSTOM_PARTITION_NAME));
    ret = nvs_flash_init_partition(YOUR_CUSTOM_PARTITION_NAME);
}
ESP_ERROR_CHECK(ret);

// Now you can create relay channels
ret = relay_chn_create(gpio_map, gpio_count);

Installation

Just add it as a custom dependency to your project's idf_component.yml:

dependencies:
  # Add as a custom component from git repository
  relay_chn:
    git: https://git.kozmotronik.com.tr/KozmotronikTech/relay_chn.git
    version: '>=1.0.0'

Usage

The relay_chn component can be used in two different modes, which are determined by the 'CONFIG_RELAY_CHN_COUNT' configuration:

  • Single channel mode (CONFIG_RELAY_CHN_COUNT == 1)
  • Multi channel mode (CONFIG_RELAY_CHN_COUNT > 1)

Depending on the mode, the component will be built selectively, so the signatures of some available API functions may vary, either including or excluding a channel ID parameter:

relay_chn_run_forward(); // No channel ID parameter for single channel mode
// or
relay_chn_run_forward(2); // Channel ID parameters will be needed in multi channel mode

See the examples for further reference

1. Initialize relay channels

// Define GPIO pins for relay channels
const uint8_t gpio_map[] = {4, 5};  // One channel example
/*------------------------------------------------------------------------*/
const uint8_t gpio_map[] = {4, 5, 9, 10, 18, 19};  // Or a 3 channel example
const uint8_t gpio_count = sizeof(gpio_map) / sizeof(gpio_map[0]);

// Create and initialize relay channels
esp_err_t ret = relay_chn_create(gpio_map, gpio_count);
if (ret != ESP_OK) {
    // Handle error
}

2. Control relay channels

For single mode:

// Run the channel forward
relay_chn_run_forward();

// Run the channel reverse
relay_chn_run_reverse();

// Stop the channel
relay_chn_stop();

// Flip the direction of the channel
relay_chn_flip_direction();

For multi mode

// Run channel #0 forward
relay_chn_run_forward(0);
// Run all channels forward
relay_chn_run_forward_all();

// Run channel #1 reverse
relay_chn_run_reverse(1);
// Run all channels reverse
relay_chn_run_reverse_all();

// Stop channel #1
relay_chn_stop(1);
// Stop all channels
relay_chn_stop_all();

// Flip direction of channel #0
relay_chn_flip_direction(0);
// Flip direction of all channels
relay_chn_flip_direction_all();

3. Monitor channel state

Warning

Listener callbacks are executed from the context of the notification dispatcher task. To ensure system responsiveness and prevent event loss, callbacks must be lightweight and non-blocking. Avoid any long-running operations or functions that may block, such as vTaskDelay() or semaphore takes with long timeouts, inside the callback.

For single mode:

// Get channel state
relay_chn_state_t state = relay_chn_get_state();
// Get the string representation of the state of the channel
char *state_str = relay_chn_get_state_str();

// Get channel direction
relay_chn_direction_t direction = relay_chn_get_direction();

// Listen to relay channel state changes
static void relay_chn_listener(uint8_t chn_id, relay_chn_state_t old_state, relay_chn_state_t new_state) {
    /* The channel id can be ignored in single mode */
    /* Handle state changes */
}
// Register the listener callback
relay_chn_register_listener(relay_chn_listener);
// Unregister the listener when it is not needed anymore
relay_chn_unregister_listener(relay_chn_listener);

For multi mode:

// Get channel #0 state
relay_chn_state_t state = relay_chn_get_state(0);

// Get states for all channels
relay_chn_state_t states[CONFIG_RELAY_CHN_COUNT];
relay_chn_get_states(states);

// Get the string representation of the state of the channel #0
char *state_str = relay_chn_get_state_str(0);

// Get channel #0 direction
relay_chn_direction_t direction = relay_chn_get_direction(0);

// Get directions for all channels
relay_chn_direction_t directions[CONFIG_RELAY_CHN_COUNT];
relay_chn_get_directions(directions);

/* The listener is same for multi mode */

4. Run Limit Control (if enabled)

For single mode:

// Assuming CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT is enabled

// Get current run limit (in seconds)
uint16_t limit = relay_chn_get_run_limit();

// Set new run limit (in seconds)
relay_chn_set_run_limit(120); // Set to 120 seconds

For multi mode:

// Assuming CONFIG_RELAY_CHN_ENABLE_RUN_LIMIT is enabled

// Get run limit for channel #0 (in seconds)
uint16_t limit = relay_chn_get_run_limit(0);

// Set new run limit for specific channels (in seconds)
relay_chn_set_run_limit(0, 120);          // Set channel #0 to 120 seconds
relay_chn_set_run_limit(1, 180);          // Set channel #1 to 180 seconds
relay_chn_set_run_limit_all_with(90);     // Set all channels to 90 seconds

// Assuming the CONFIG_RELAY_CHN_COUNT is 4
uint16_t limits_sec[CONFIG_RELAY_CHN_COUNT] = { 30, 35, 40, 45 };
relay_chn_set_run_limit_all(limits_sec);   // Set all channels according to the array

Note

When a channel reaches its run limit, it will automatically stop. The run limit timer is reset whenever the channel starts running in either direction.

5. Tilting Interface (if enabled)

For single mode:

// Assuming CONFIG_RELAY_CHN_ENABLE_TILTING is enabled

// Start tilting automatically
relay_chn_tilt_auto();

// Tilt forward
relay_chn_tilt_forward();

// Tilt reverse
relay_chn_tilt_reverse();

// Stop tilting
relay_chn_tilt_stop();

// Set tilting sensitivity (sensitivity as percentage)
relay_chn_tilt_set_sensitivity(90);

// Get tilting sensitivity (sensitivty as percentage)
uint8_t sensitivity = relay_chn_tilt_get_sensitivity();

For multi mode:

// Assuming CONFIG_RELAY_CHN_ENABLE_TILTING is enabled

// Start tilting automatically on channel #0
relay_chn_tilt_auto(0);
relay_chn_tilt_auto_all(); // on all channels

// Tilt forward on channel #1
relay_chn_tilt_forward(1);
relay_chn_tilt_forward_all();

// Tilt reverse on channel #2
relay_chn_tilt_reverse(2);
relay_chn_tilt_reverse_all();

// Stop tilting on channel #0
relay_chn_tilt_stop(0);
relay_chn_tilt_stop_all();

// Set tilting sensitivity (sensitivity as percentage) for channel #0
relay_chn_tilt_set_sensitivity(0, 90);
relay_chn_tilt_set_sensitivity_all_with(90);

// Assuming the CONFIG_RELAY_CHN_COUNT is 4
uint8_t sensitivities[CONFIG_RELAY_CHN_COUNT] = { 90, 85, 80, 75 };
relay_chn_tilt_set_sensitivity_all(sensitivity);   // Set all channels according to the array

// Get tilt sensitivity for channel #0
uint8_t sensitivity = relay_chn_tilt_get_sensitivity(0);

// Get tilting sensitivity (sensitivty as percentage)
uint8_t sensitivities[CONFIG_RELAY_CHN_COUNT];
relay_chn_tilt_get_sensitivity_all(sensitivities);

License

MIT License - Copyright (c) 2025 kozmotronik.

Description
A custom ESP-IDF component for controlling up to 8 relay channels.
Readme MIT 1.7 MiB
1.0.0 Latest
2025-09-13 12:00:56 +03:00
Languages
C 96.8%
Shell 2.2%
CMake 1%