Ir al contenido

← Estructura de la aplicación | Contenido | Siguiente: Referencia API →

4. Modos de operación del RouterController



4.1 Descripción general de los modos

RouterController soporta 6 modos de operación, cada uno optimizado para un escenario de uso específico.


Tabla de modos

Modo Enum Control del dimmer Control P_grid Sensores requeridos Aplicación
OFF 0 0% (fijo) ❌ No - Mantenimiento, apagado
AUTO 1 Automático ✅ P_grid → 0 Corriente de red Enrutador solar estándar
ECO 2 Semiautomático ⚠️ Solo importación Corriente de red Prevención de exportación
OFFGRID 3 Automático ❌ No Corriente solar Sistemas aislados
MANUAL 4 Fijo ❌ No - Tarifa nocturna, pruebas
BOOST 5 100% (fijo) ❌ No - Calentamiento forzado



4.2 Modo OFF (0) – Desactivado


Descripción

Apagado completo del control del dimmer. Se utiliza para mantenimiento, depuración o cuando no se requiere control de carga.


Algoritmo

cpp
void RouterController::processOffMode() {
    // Dimmer always 0%
    if (m_status.dimmer_percent != 0) {
        applyDimmerLevel(0);
    }
    m_status.state = RouterState::IDLE;
}


Parámetros

Sin parámetros configurables.


Sensores requeridos

No se requieren sensores (las mediciones continúan pero no se utilizan).


Comportamiento

  • Nivel del dimmer: 0% (constante)
  • P_grid: No controlado
  • Estado: IDLE
  • Mediciones: Continúan (PowerMeterADC funciona)
  • Interfaz web: Disponible
  • Comandos serie: Funcionan


Cuándo usar

  • ✅ Mantenimiento del dispositivo
  • ✅ Prueba de sensores sin control
  • ✅ Depuración del sistema
  • ✅ Desconexión temporal de la carga


Ejemplo de uso

cpp
// Via code
RouterController& router = RouterController::getInstance();
router.setMode(RouterMode::OFF);

// Via Serial
set-mode 0

// Via REST API
POST /api/mode
{"mode": 0}



4.3 Modo AUTO (1) – Enrutador solar automático


Descripción

Modo principal del enrutador solar. Equilibra automáticamente la potencia de red (P_grid) a cero, redirigiendo el exceso de energía solar a la carga en lugar de exportarlo a la red.


Algoritmo

cpp
void RouterController::processAutoMode(float power_grid) {
    // Goal: P_grid → 0
    // Proportional control with configurable gain

    float error = -power_grid;  // Invert: export = positive error

    // Check if within balance threshold
    if (fabs(power_grid) <= balance_threshold) {
        // Within threshold - hold current level
        return;
    }

    // Proportional control
    float delta = error / control_gain;
    m_target_level += delta;

    // Apply new level (clamped to 0-100%)
    applyDimmerLevel(m_target_level);
}


Comportamiento según el signo de P_grid

Situación P_grid Error Delta Acción
Exportación a la red < 0 (negativo) > 0 (positivo) > 0 Aumentar dimmer → más carga
Importación de la red > 0 (positivo) < 0 (negativo) < 0 Disminuir dimmer → menos carga
Equilibrio ≈ 0 (dentro del umbral) ≈ 0 0 Mantener nivel actual


Parámetros

control_gain (Kp)

Descripción: Coeficiente del controlador proporcional. Determina la velocidad de respuesta a los cambios de P_grid.

Fórmula: delta = error / control_gain

Rango: 10.0 - 1000.0

Predeterminado: 200.0

Impacto:

  • Kp menor (más rápido):
  • ✅ Respuesta rápida a los cambios
  • ❌ Posibles oscilaciones
  • Ejemplo: Kp = 50 → rápido, pero inestable

  • Kp mayor (más lento):

  • ✅ Control suave
  • ✅ Estabilidad
  • ❌ Respuesta lenta
  • Ejemplo: Kp = 500 → lento, pero estable

Recomendaciones:

python
System Type              | Recommended Kp | Comment
-------------------------|----------------|------------------------
Stable grid              | 150 - 250      | Optimal
Unstable grid            | 300 - 500      | Increase for stability
Fast clouds              | 100 - 150      | Decrease for responsiveness
High inertia heater      | 200 - 400      | Medium values

balance_threshold

Descripción: Umbral de equilibrio en Watts. Si |P_grid| < umbral, el sistema se considera equilibrado.

Rango: 0.0 - 100.0 W

Predeterminado: 10.0 W

Impacto:

  • Umbral menor:
  • ✅ Equilibrio más preciso (P_grid más cercano a 0)
  • ❌ Más ajustes (desgaste del TRIAC)

  • Umbral mayor:

  • ✅ Menos ciclos de conmutación
  • ❌ Equilibrio menos preciso

Recomendaciones:

python
Load Power               | Recommended Threshold
-------------------------|----------------------
< 500 W                  | 5 - 10 W
500 - 1500 W             | 10 - 20 W
> 1500 W                 | 20 - 50 W


Sensores requeridos

Mínimo:

  • Current Grid (requerido) – para la determinación de P_grid
  • Voltage (recomendado) – para el cálculo de potencia

Opcional:

  • ⚪ Current Load – para monitoreo de consumo
  • ⚪ Current Solar – para monitoreo de generación


Ejemplos de operación

Ejemplo 1: Excedente solar

python
Initial state:
  P_solar = 3000 W
  P_house = 800 W
  P_grid = -2200 W (export!)
  Dimmer = 0%

After 10 seconds (Kp=200):
  error = -(-2200) = +2200
  delta = 2200 / 200 = +11% per iteration
  → Dimmer gradually increases

After 30 seconds:
  Dimmer ≈ 70% (~1400 W to heater)
  P_grid ≈ -800 W (still exporting)
  → Continues to increase

After 60 seconds (stabilization):
  Dimmer = 95% (~1900 W)
  P_grid ≈ -5 W (within 10W threshold)
  → Balance achieved ✅

Ejemplo 2: Una nube cubre el sol

python
Stable state:
  P_solar = 2500 W
  P_grid = 0 W (balance)
  Dimmer = 80% (~1600 W)

Cloud:
  P_solar = 500 W (sharp drop)
  P_grid = +1100 W (import!)

  error = -1100
  delta = -1100 / 200 = -5.5%
  → Dimmer decreases by 5.5%

After 5 seconds:
  Dimmer ≈ 50% (~1000 W)
  P_grid ≈ +100 W (close to balance)

After 10 seconds:
  Dimmer = 30% (~600 W)
  P_grid ≈ +5 W (within threshold)
  → New balance achieved ✅


Configuración a través de interfaces

cpp
// Via code
router.setMode(RouterMode::AUTO);
router.setControlGain(200.0f);
router.setBalanceThreshold(10.0f);

// Via Serial
set-mode 1
set-kp 200
set-threshold 10

// Via REST API
POST /api/mode
{"mode": 1}

POST /api/config
{"control_gain": 200.0, "balance_threshold": 10.0}



4.4 Modo ECO (2) – Economía (Anti-Exportación)


Descripción

Modo de prevención de exportación. Evita exportar electricidad a la red, pero permite la importación. Se utiliza cuando la exportación no es rentable o está prohibida.


Algoritmo

cpp
void RouterController::processEcoMode(float power_grid) {
    // Goal: P_grid >= 0 (avoid export, allow import)

    if (power_grid > balance_threshold) {
        // IMPORTING from grid - reduce load
        float error = -power_grid;

        // Slower response: increase gain by 1.5x
        float delta = error / (control_gain * 1.5f);
        m_target_level += delta;

        applyDimmerLevel(m_target_level);
    } else {
        // EXPORTING or BALANCED - hold current level
        // Do not increase load aggressively
    }
}


Diferencias con AUTO

Aspecto AUTO ECO
Exportación Impedida (dimmer aumenta) Permitida (dimmer no aumenta)
Importación Impedida (dimmer disminuye) Permitida (dimmer disminuye lentamente)
Velocidad de respuesta Rápida (Kp) Más lenta (Kp × 1,5)
Objetivo P_grid = 0 P_grid ≥ 0


Comportamiento

  • P_grid > umbral (importación):
  • Disminuir lentamente el dimmer
  • Velocidad: Kp × 1,5 (más lento que AUTO)

  • P_grid < 0 (exportación):

  • NO aumentar el dimmer
  • Mantener el nivel actual

  • P_grid ≈ 0:

  • Mantener el nivel actual


Parámetros

Iguales que AUTO:

  • control_gain – afecta la velocidad de disminución durante la importación
  • balance_threshold – umbral para la determinación del equilibrio


Sensores requeridos

  • Current Grid (requerido)
  • Voltage (recomendado)


Cuándo usar

  • ✅ Sin contrato de exportación a la red
  • ✅ Tarifa de exportación desfavorable (< costo de importación)
  • ✅ Restricción técnica de exportación
  • ✅ Protección contra exportación con red inestable


Ejemplo de operación

python
Initial state:
  P_solar = 2000 W
  P_house = 1000 W
  P_grid = -1000 W (export 1 kW)
  Dimmer = 0%

In ECO mode:
  → Dimmer does NOT increase
  → P_grid remains -1000 W (export continues)

  Result: Excess goes to grid (acceptable in ECO)

After 1 hour (cloud):
  P_solar = 500 W
  P_house = 1000 W
  P_grid = +500 W (import!)

  → Dimmer slowly decreases (if it was enabled)
  → After some time P_grid ≈ 0



4.5 Modo OFFGRID (3) – Aislado de la red


Descripción

Modo para sistemas autónomos con paneles solares y baterías, sin conexión a la red. Utiliza el exceso de energía solar para la carga.


Algoritmo

cpp
void RouterController::processOffgridMode(const Measurements& meas) {
    float power_solar = meas.power_active[CURRENT_SOLAR];
    float power_load = meas.power_active[CURRENT_LOAD];

    if (power_solar > balance_threshold) {
        // Solar generation available
        float available_power = power_solar * 0.8f;  // 80% safety margin

        if (available_power > power_load + balance_threshold) {
            // Can increase load
            float delta = (available_power - power_load) / (control_gain * 2.0f);
            m_target_level += delta;
        } else if (available_power < power_load - balance_threshold) {
            // Need to reduce load
            m_target_level -= 5.0f;  // Gradual decrease
        }

        applyDimmerLevel(m_target_level);
    } else {
        // No solar generation - reduce load to minimum
        m_target_level -= 10.0f;  // Faster decrease
        applyDimmerLevel(m_target_level);
    }
}


Características

  • NO utiliza P_grid (el sensor de red puede estar ausente)
  • Utiliza P_solar para determinar la potencia disponible
  • Conservador: 80% de la potencia disponible (protección de batería)
  • Prioridad: Carga principal → Baterías → Calentador


Parámetros

  • control_gain – afecta la velocidad de aumento de carga
  • balance_threshold – potencia solar mínima para la activación
  • Margen de seguridad: 0,8 (80%) – codificado fijo


Sensores requeridos

Mínimo:

  • Current Solar (requerido) – para la determinación de generación
  • Voltage (recomendado)

Opcional:

  • ⚪ Current Load – para un control más preciso
  • ❌ Current Grid – NO requerido (puede estar ausente)


Cuándo usar

  • ✅ Sistemas aislados de la red
  • ✅ Paneles solares + baterías
  • ✅ Sin conexión a la red
  • ✅ Maximizar el uso de energía solar


Ejemplo de operación

python
Daytime (sunny):
  P_solar = 1500 W
  P_house = 800 W (from battery/solar)
  P_load (dimmer) = 0 W

  available_power = 1500 * 0.8 = 1200 W

  → Can turn on heater
  → Dimmer gradually increases to ~60% (1200 W)
  → Battery is not discharging (enough solar)

Evening (sunset):
  P_solar = 200 W (dropping)
  available_power = 200 * 0.8 = 160 W
  P_load = 800 W (heater was on)

  → Too little solar
  → Dimmer quickly decreases (10% per iteration)
  → After several iterations: Dimmer = 0%
  → Battery is saved for main load

Night:
  P_solar = 0 W
  → Dimmer = 0%
  → Heater is off



4.6 Modo MANUAL (4) – Manual


Descripción

Nivel fijo del dimmer establecido por el usuario. Sin control automático.


Algoritmo

cpp
void RouterController::processManualMode() {
    // Fixed level set by user
    if (m_status.dimmer_percent != m_manual_level) {
        applyDimmerLevel(m_manual_level);
    }
    m_status.state = RouterState::IDLE;
}


Parámetros

  • manual_level – nivel del dimmer (0-100%)


Sensores requeridos

No se requieren sensores (las mediciones continúan para monitoreo).


Cuándo usar

  • ✅ Tarifa nocturna (establecer 100% para la noche)
  • ✅ Pruebas de carga
  • ✅ Mantenimiento de temperatura (establecer 50%)
  • ✅ Depuración del sistema


Ejemplo de uso

cpp
// Set 75%
router.setMode(RouterMode::MANUAL);
router.setManualLevel(75);

// Via Serial
set-mode 4
set-manual 75

// Via REST API
POST /api/mode
{"mode": 4}

POST /api/manual
{"level": 75}


Escenario: Tarifa nocturna

bash
# 23:00 - night tariff starts (cheap)
set-mode 4
set-manual 100  # Full power

# 07:00 - night tariff ends
set-mode 1      # Switch to AUTO



4.7 Modo BOOST (5) – Calentamiento forzado


Descripción

Dimmer fijo al 100%. Potencia máxima a la carga.


Algoritmo

cpp
void RouterController::processBoostMode() {
    // Always 100%
    if (m_status.dimmer_percent != 100) {
        applyDimmerLevel(100);
    }
    m_status.state = RouterState::AT_MAXIMUM;
}


Parámetros

Sin parámetros configurables (siempre 100%).


Sensores requeridos

No requeridos.


Cuándo usar

  • ✅ Calentamiento rápido del calentador de agua
  • ✅ Aprovechamiento de tarifa económica
  • ✅ Modo de emergencia


Advertencias

⚠️ ADVERTENCIA:

  • Alto consumo de red
  • Posible sobrecalentamiento de la carga
  • Monitorear la temperatura manualmente
  • No dejar sin supervisión


Ejemplo de uso

cpp
// Enable BOOST
router.setMode(RouterMode::BOOST);

// Return to AUTO after 2 hours
delay(2 * 60 * 60 * 1000);
router.setMode(RouterMode::AUTO);



4.8 Cambio entre modos


Cambio seguro

Al cambiar de modo, RouterController:

  1. Registra el cambio de modo
  2. Reinicia el estado interno
  3. Aplica el nuevo algoritmo
cpp
void RouterController::setMode(RouterMode mode) {
    if (m_status.mode == mode) {
        return;  // No change
    }

    RouterMode old_mode = m_status.mode;
    m_status.mode = mode;

    ESP_LOGI(TAG, "Mode changed: %d -> %d",
             static_cast(old_mode),
             static_cast(mode));

    // Reset state for new mode
    m_status.state = RouterState::IDLE;
}


Recomendaciones de cambio

Transiciones seguras:

python
OFF ↔ AUTO      ✅ Safe
OFF ↔ MANUAL    ✅ Safe
AUTO ↔ ECO      ✅ Safe (similar algorithms)
MANUAL ↔ BOOST  ✅ Safe

Precaución:

python
AUTO → BOOST    ⚠️ Sharp power spike
OFFGRID → AUTO  ⚠️ Different sensors


Secuencias de comandos

bash
# Example 1: Morning transition
set-mode 0        # OFF - pause
# ... system check ...
set-mode 1        # AUTO - start operation

# Example 2: Testing
set-mode 4        # MANUAL
set-manual 25     # 25% for test
# ... observation ...
set-manual 50     # 50%
# ... observation ...
set-mode 1        # Return to AUTO



4.9 Configuraciones mínimas de sensores


Para cada modo

Modo Sensores requeridos Opcional Nota
OFF - - Sensores no utilizados
AUTO Voltage, Current Grid Current Load, Current Solar Grid necesario para P_grid
ECO Voltage, Current Grid Current Load, Current Solar Grid necesario para P_grid
OFFGRID Voltage, Current Solar Current Load Grid NO requerido
MANUAL - Voltage, Current Grid Solo para monitoreo
BOOST - Voltage, Current Grid Solo para monitoreo


Configuración mínima (enrutador solar)

Para los modos AUTO/ECO:

python
ADC0: GPIO35, VOLTAGE_AC,    enabled=true   ← Required
ADC1: GPIO36, CURRENT_GRID,  enabled=true   ← Required
ADC2: -,      NONE,           enabled=false
ADC3: -,      NONE,           enabled=false

Dimmer1: GPIO19, enabled=true               ← Required
ZeroCross: GPIO18, enabled=true             ← Required

Resultado:

  • ✅ Medición de P_grid (para equilibrio)
  • ✅ Control del dimmer
  • ❌ Sin monitoreo solar/carga


Configuración completa

python
ADC0: GPIO35, VOLTAGE_AC,     enabled=true
ADC1: GPIO39, CURRENT_LOAD,   enabled=true
ADC2: GPIO36, CURRENT_GRID,   enabled=true
ADC3: GPIO34, CURRENT_SOLAR,  enabled=true

Dimmer1: GPIO19, enabled=true
Dimmer2: GPIO23, enabled=true (optional)
ZeroCross: GPIO18, enabled=true

Resultado:

  • ✅ Monitoreo completo del sistema
  • ✅ Todos los modos soportados
  • ✅ Análisis detallado



4.10 Configuración de parámetros a través de interfaces


Por comandos serie

bash
# Mode switching
set-mode 0          # OFF
set-mode 1          # AUTO
set-mode 2          # ECO
set-mode 3          # OFFGRID
set-mode 4          # MANUAL
set-mode 5          # BOOST

# AUTO/ECO parameters
set-kp 200          # Set Kp = 200
set-threshold 10    # Balance threshold 10 W

# MANUAL parameters
set-manual 75       # Set 75%

# Save
config-save         # Save to NVS


Por REST API

bash
# Set mode
curl -X POST http://192.168.4.1/api/mode \
  -H "Content-Type: application/json" \
  -d '{"mode": 1}'

# Set parameters
curl -X POST http://192.168.4.1/api/config \
  -H "Content-Type: application/json" \
  -d '{
    "control_gain": 200.0,
    "balance_threshold": 10.0
  }'

# Set MANUAL level
curl -X POST http://192.168.4.1/api/manual \
  -H "Content-Type: application/json" \
  -d '{"level": 75}'


Por interfaz web

  1. Abrir el panel de control: http://192.168.4.1/
  2. Seleccionar modo (6 botones)
  3. Para MANUAL: mover el deslizador
  4. Click "Apply"

← Estructura de la aplicación | Contenido | Siguiente: Referencia API →