# Configuring gain_lock_mode for ESP32-C3 in ESPectre

> Learn how to configure gain_lock_mode for ESP32 C3 in ESPectre firmware. Choose auto enabled or disabled settings for hardware gain lock or CV normalization.

- Repository: [Francesco Pace/espectre](https://github.com/francescopace/espectre)
- Tags: how-to-guide
- Published: 2026-06-10

---

**Configure the `GAIN_LOCK_MODE` setting in [`micro-espectre/src/config.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/config.py) to `"auto"`, `"enabled"`, or `"disabled"` to control whether the ESPectre firmware attempts hardware gain lock during boot or falls back to CV normalization.**

The ESP32-C3 features hardware AGC (Automatic Gain Control) lock support, unlike the ESP32-C6. In the francescopace/espectre repository, the gain-lock mode determines how the motion-detection pipeline calibrates itself during initialization. Proper configuration ensures stable turbulence metrics without manual intervention.

## Understanding Gain-Lock Modes on ESP32-C3

ESPectre provides three configurable modes for gain management. Because the ESP32-C3 supports hardware gain lock, all three modes are functional and produce different behaviors:

- **`auto`** (default): Attempts gain lock only if the AGC value is at or above `GAIN_LOCK_MIN_SAFE_AGC` (30). If the signal is too weak, it skips the lock phase and enables CV normalization automatically.
- **`enabled`**: Forces a gain-lock attempt on every boot. On ESP32-C3 this succeeds under normal conditions, providing hardware-stabilized gain for CSI measurements.
- **`disabled`**: Bypasses the gain-lock phase entirely. The system immediately uses **CV normalization** (standard deviation/mean) for gain-invariant turbulence metrics, reducing boot time.

## Configuration File Location

The primary configuration resides in [`micro-espectre/src/config.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/config.py). Edit these constants to change the behavior:

```python

# Gain Lock Configuration

# Modes: "auto" (skip if signal too strong), "enabled" (always lock), "disabled" (never lock)

GAIN_LOCK_MODE = "auto"       # Recommended: "auto" - skips gain lock if AGC < 30

GAIN_LOCK_MIN_SAFE_AGC = 30   # Minimum safe AGC value (below this, gain lock is skipped in auto mode)

```

*Source: [config.py](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/config.py)*

## Boot-Time Handling

The main entry point in [`micro-espectre/src/main.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/main.py) reads the mode and initializes the chip-specific logic. For ESP32-C3, the firmware attempts the lock sequence when the mode is `"enabled"` or `"auto"` (with sufficient AGC):

```python
if chip == 'ESP32-C3':
    # Hardware gain lock available

    needs_cv_normalization = False  # Will use hardware lock unless mode forces otherwise

```

If the lock fails or the mode is set to `"disabled"`, the code sets `needs_cv_normalization = True` to ensure the segmentation pipeline uses the software fallback.

*Source: [main.py](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/main.py)*

## Segmentation Pipeline Integration

The `SegmentationContext` class in [`micro-espectre/src/segmentation.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/segmentation.py) receives the normalization flag via the `use_cv_normalization` attribute:

```python

# Default False for chips with gain lock support

# Set to True if gain lock is disabled or unavailable

self.use_cv_normalization = False

```

When the calibration code detects a missing lock (or the user forces `disabled`), it flips the flag to `True`, ensuring the motion detection algorithm uses CV-normalized turbulence metrics.

*Source: [segmentation.py](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/segmentation.py)*

## Practical Configuration Examples

### Forcing Hardware Gain Lock on ESP32-C3

To ensure the firmware always attempts hardware gain lock (useful in stable RF environments):

```python

# micro-espectre/src/config.py

GAIN_LOCK_MODE = "enabled"

```

Re-build and flash (`pio run`). The boot log will indicate:

```

🔒 Gain lock mode: enabled → Attempting hardware lock...
🔒 Gain lock acquired successfully

```

### Disabling Gain Lock for Faster Boot

If you prefer deterministic CV normalization or need faster initialization:

```python

# micro-espectre/src/config.py

GAIN_LOCK_MODE = "disabled"

```

This bypasses the AGC negotiation entirely, setting `use_cv_normalization = True` immediately.

### Runtime Override via CLI

The Micro-ESPectre CLI accepts command-line arguments to override the config file for a single execution:

```bash
python -m src.main --gain-lock-mode enabled

```

### ESPHome YAML Configuration

For production ESPectre deployments using ESPHome, ensure the underlying firmware constants are set before compilation:

```yaml
esphome:
  name: espectre_c3
  platform: ESP32
  board: esp32-c3

# The gain_lock_mode is set at firmware compile time via config.py

# Ensure GAIN_LOCK_MODE is set to your desired mode before flashing

```

After flashing, verify in the Home Assistant logs:

```

[DEBUG] Gain lock enabled – Hardware AGC lock active (ESP32‑C3)

```

## Verification and CSI Packet Flags

Each CSI packet carries a gain-locked bit in [`micro-espectre/tools/csi_utils.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/tools/csi_utils.py). For ESP32-C3 with successful hardware lock, this bit is set to `1`:

```python
description = f'HT20 {self.label}, gain locked (AGC stable)'

```

If the lock fails or is disabled, the bit remains `0` and the description notes the fallback method.

*Source: [csi_utils.py](https://github.com/francescopace/espectre/blob/main/micro-espectre/tools/csi_utils.py)*

## Summary

- **ESP32-C3 supports hardware gain lock**, unlike the ESP32-C6, allowing use of the `"enabled"` mode for hardware-stabilized measurements.
- **Configure via `GAIN_LOCK_MODE`** in [`micro-espectre/src/config.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/config.py) using `"auto"`, `"enabled"`, or `"disabled"`.
- **The segmentation pipeline** respects this setting through `SegmentationContext.use_cv_normalization`, automatically switching between hardware gain control and CV normalization.
- **Verify behavior** through boot logs and the gain-locked bit in CSI packets parsed by [`csi_utils.py`](https://github.com/francescopace/espectre/blob/main/csi_utils.py).

## Frequently Asked Questions

### What is the recommended gain_lock_mode for ESP32-C3?

Use `"auto"` for most deployments. This attempts hardware gain lock when the AGC value is healthy (≥30) but falls back to CV normalization automatically if the signal is too weak, providing the best balance of accuracy and reliability.

### Can I use gain lock mode "enabled" on ESP32-C3?

Yes. The ESP32-C3 supports hardware AGC gain lock, so `"enabled"` mode will attempt to acquire a lock on every boot. This is safe and appropriate for environments with consistent RF conditions where you want guaranteed hardware-stabilized gain.

### Why would I disable gain lock on a chip that supports it?

Setting `GAIN_LOCK_MODE = "disabled"` speeds up boot time by skipping the AGC negotiation phase. It also provides deterministic behavior in testing environments where you want consistent CV-normalized metrics regardless of hardware state.

### How do I verify that gain lock is actually working on my ESP32-C3?

Check the serial boot logs for the message `Gain lock acquired successfully`. Additionally, inspect the CSI packets using [`csi_utils.py`](https://github.com/francescopace/espectre/blob/main/csi_utils.py); the gain-locked bit (bit 0) will be set to `1` when hardware lock is active, and the packet description will indicate "gain locked" rather than "no gain lock".