Ir al contenido

← Comandos de terminal | Contenido | Siguiente: Web API - POST →

8. Web API – Puntos finales GET

Version: 1.0.0
Date: 2025-01-15

Documentación detallada de los puntos finales GET de la API REST para la supervisión y recuperación de información del sistema ACRouter.




Tabla de contenido




8.1 Introducción

La API REST de ACRouter proporciona un conjunto de puntos finales GET para:

  • Supervisión – obtener el estado actual del enrutador y las métricas de potencia
  • Configuración – leer los parámetros del sistema
  • Diagnósticos – información del sistema, estado WiFi, configuración de hardware

Todos los puntos finales devuelven datos en formato JSON.

Implementación: components/comm/src/WebServerManager.cpp

Inicio rápido: Consulte 07_COMMANDS_EN.md section "REST API Reference" for basic usage examples.




8.2 URL base y autenticación


8.2.1 URL base

Modo punto de acceso:

python
http://192.168.4.1/api/

Modo estación:

python
http:///api/

Use el comando serie wifi-status o GET /api/wifi/status para encontrar la dirección IP.


8.2.2 Autenticación

⚠️ Importante: La API REST no requiere autenticación. Todos los puntos finales son accesibles sin contraseña.

Security Recommendations:
- Use a separate WiFi network for IoT devices
- Configure firewall rules to restrict access
- Do not expose port 80 to external networks
- Basic authentication is planned for future versions


8.2.3 CORS

CORS (Cross-Origin Resource Sharing) está habilitado para todos los puntos finales.

Encabezado de respuesta:

python
Access-Control-Allow-Origin: *

Esto permite llamadas API desde aplicaciones web alojadas en otros dominios.




8.3 Formato de respuesta


8.3.1 Respuesta exitosa

Estado HTTP: 200 OK

Content-Type: application/json

Estructura:

json
{
  "field1": "value1",
  "field2": 123,
  "field3": true
}


8.3.2 Respuesta de error

Estado HTTP: 400, 404, 500, 501

Content-Type: application/json

Estructura:

json
{
  "error": "Error message description"
}

Ejemplo:

json
{
  "error": "Not Found"
}


8.3.3 Codificación

Todas las respuestas usan codificación UTF-8.




8.4 Punto final: GET /api/status

Obtener el estado completo del enrutador, incluyendo modo de operación, estado del controlador, potencia de red y nivel del dimmer.


8.4.1 Solicitud

http
GET /api/status HTTP/1.1
Host: 192.168.4.1

Parámetros: Ninguno


8.4.2 Respuesta

Estado HTTP: 200 OK

Esquema JSON:

json
{
  "mode": "string",              // Router operating mode
  "state": "string",             // Controller state
  "power_grid": 0.0,             // Grid power (W)
  "dimmer": 0,                   // Dimmer level (0-100%)
  "target_level": 0,             // Target level (0-100%)
  "control_gain": 0.0,           // Control gain
  "balance_threshold": 0.0,      // Balance threshold (W)
  "valid": true,                 // Data validity
  "uptime": 0,                   // Uptime (seconds)
  "free_heap": 0                 // Free memory (bytes)
}


8.4.3 Descripción de campos

Campo Tipo Descripción Valores posibles
mode string Modo de operación del enrutador "off", "auto", "eco", "offgrid", "manual", "boost", "unknown"
state string Estado del controlador "idle", "increasing", "decreasing", "at_max", "at_min", "error"
power_grid float Potencia de red en vatios. Positivo = importación desde la red (consumo), Negativo = exportación a la red (excedente) -∞ .. +∞
dimmer integer Nivel actual del dimmer en porcentaje 0 .. 100
target_level integer Nivel objetivo del dimmer (para modos AUTO, ECO, OFFGRID) 0 .. 100
control_gain float Ganancia del bucle de control 1.0 .. 1000.0
balance_threshold float Umbral de equilibrio en vatios (para modo AUTO) 0.0 .. 100.0
valid boolean Validez de los datos de medición. false = sensores no inicializados o error true / false
uptime integer Tiempo de actividad desde el arranque en segundos 0 ..
free_heap integer RAM libre en bytes 0 ..


8.4.4 Ejemplo de respuesta

json
{
  "mode": "auto",
  "state": "increasing",
  "power_grid": 1250.3,
  "dimmer": 45,
  "target_level": 50,
  "control_gain": 150.0,
  "balance_threshold": 50.0,
  "valid": true,
  "uptime": 3625,
  "free_heap": 187456
}

Interpretation:
- Router in AUTO mode (Solar Router)
- State INCREASING (increasing power)
- Grid import: 1250.3 W (consumption exceeds generation)
- Current dimmer: 45%
- Target level: 50% (will increase to 50%)
- Uptime: 3625 sec (≈ 1 hour)
- Free memory: 187 KB


8.4.5 Uso

Supervisión en tiempo real:

bash
# Poll every 2 seconds
while true; do
  curl -s http://192.168.4.1/api/status | jq '.power_grid, .dimmer'
  sleep 2
done

Verificar modo de operación:

bash
curl -s http://192.168.4.1/api/status | jq -r '.mode'
# Output: auto

Python – supervisión del equilibrio:

python
import requests
import time

def monitor_balance():
    url = "http://192.168.4.1/api/status"
    while True:
        resp = requests.get(url).json()
        power = resp['power_grid']
        dimmer = resp['dimmer']

        if power > 0:
            print(f"IMPORT: {power:.1f}W | Dimmer: {dimmer}%")
        elif power < 0:
            print(f"EXPORT: {abs(power):.1f}W | Dimmer: {dimmer}%")
        else:
            print(f"BALANCE: 0W | Dimmer: {dimmer}%")

        time.sleep(2)

monitor_balance()



8.5 Punto final: GET /api/metrics

Obtener métricas de potencia ligeras para consultas frecuentes. Devuelve solo datos críticos para la supervisión, minimizando el tamaño de respuesta.


8.5.1 Solicitud

http
GET /api/metrics HTTP/1.1
Host: 192.168.4.1

Parámetros: Ninguno


8.5.2 Respuesta

Estado HTTP: 200 OK

Esquema JSON:

json
{
  "metrics": {
    "power_grid": 0.0,      // Grid power (W)
    "dimmer": 0,            // Dimmer level (0-100%)
    "target_level": 0       // Target level (0-100%)
  },
  "timestamp": 0            // Time (milliseconds since boot)
}


8.5.3 Descripción de campos

Campo Tipo Descripción
metrics.power_grid float Potencia de red (W). Positivo = importación, negativo = exportación
metrics.dimmer integer Nivel actual del dimmer (0–100 %)
metrics.target_level integer Nivel objetivo del dimmer (0–100 %)
timestamp integer Tiempo desde el arranque en milisegundos


8.5.4 Ejemplo de respuesta

json
{
  "metrics": {
    "power_grid": -125.7,
    "dimmer": 80,
    "target_level": 80
  },
  "timestamp": 3625482
}

Interpretation:
- Grid export: 125.7 W (generation exceeds consumption)
- Dimmer: 80% (routing surplus to load)
- Time: 3625 seconds since boot


8.5.5 Uso

Supervisión de alta frecuencia:

bash
# Poll every second (minimal traffic)
while true; do
  curl -s http://192.168.4.1/api/metrics | jq '.metrics'
  sleep 1
done

JavaScript – gráfico en tiempo real:

javascript
const baseUrl = "http://192.168.4.1/api";
const chartData = {
  labels: [],
  power: [],
  dimmer: []
};

function updateMetrics() {
  fetch(`${baseUrl}/metrics`)
    .then(r => r.json())
    .then(data => {
      const time = new Date().toLocaleTimeString();
      chartData.labels.push(time);
      chartData.power.push(data.metrics.power_grid);
      chartData.dimmer.push(data.metrics.dimmer);

      // Update chart (Chart.js, D3.js, etc.)
      updateChart(chartData);
    });
}

// Update every 2 seconds
setInterval(updateMetrics, 2000);

Comparación con /api/status:

Criterio /api/status /api/metrics
Tamaño de respuesta ~250 bytes ~80 bytes
Campos 10 campos 3 campos + marca temporal
Caso de uso Información completa Supervisión en tiempo real
Frecuencia de consulta 5–10 segundos 1–2 segundos



8.6 Punto final: GET /api/config

Obtener todos los parámetros de configuración del sistema guardados en NVS.


8.6.1 Solicitud

http
GET /api/config HTTP/1.1
Host: 192.168.4.1

Parámetros: Ninguno


8.6.2 Respuesta

Estado HTTP: 200 OK

Esquema JSON:

json
{
  "control_gain": 0.0,          // Control gain
  "balance_threshold": 0.0,     // Balance threshold (W)
  "voltage_coef": 0.0,          // Voltage coefficient
  "current_coef": 0.0,          // Current coefficient (A/V)
  "current_threshold": 0.0,     // Current detection threshold (A)
  "power_threshold": 0.0,       // Power detection threshold (W)
  "router_mode": 0,             // Router mode (number)
  "manual_level": 0             // Manual mode level (0-100%)
}


8.6.3 Descripción de campos

Campo Tipo Rango Predeterminado Descripción
control_gain float 1.0 .. 1000.0 150.0 Ganancia del bucle de control
balance_threshold float 0.0 .. 100.0 50.0 Umbral de equilibrio para modo AUTO (W)
voltage_coef float 0.1 .. 10.0 1.0 Coeficiente de calibración de voltaje
current_coef float 0.1 .. 100.0 30.0 Coeficiente de conversión de corriente (A/V)
current_threshold float 0.01 .. 10.0 0.1 Umbral de detección de corriente (A)
power_threshold float 1.0 .. 1000.0 10.0 Umbral de detección de potencia activa (W)
router_mode integer 0 .. 5 1 Modo del enrutador: 0=OFF, 1=AUTO, 2=ECO, 3=OFFGRID, 4=MANUAL, 5=BOOST
manual_level integer 0 .. 100 0 Nivel del dimmer para modo manual (%)


8.6.4 Ejemplo de respuesta

json
{
  "control_gain": 180.0,
  "balance_threshold": 40.0,
  "voltage_coef": 1.02,
  "current_coef": 30.0,
  "current_threshold": 0.12,
  "power_threshold": 12.0,
  "router_mode": 1,
  "manual_level": 50
}

Interpretation:
- Gain increased to 180 (faster response)
- Balance threshold reduced to ±40 W (tighter balancing)
- Voltage corrected by +2% (sensor calibration)
- Mode: 1 (AUTO - Solar Router)
- Manual level: 50% (when switching to MANUAL)


8.6.5 Uso

Copia de seguridad de configuración:

bash
# Save configuration to file
curl -s http://192.168.4.1/api/config > acrouter_config_backup.json

# Restore later via POST /api/config
curl -X POST http://192.168.4.1/api/config \
  -H "Content-Type: application/json" \
  -d @acrouter_config_backup.json

Python – comparar configuraciones:

python
import requests
import json

def compare_configs(url1, url2):
    config1 = requests.get(f"{url1}/api/config").json()
    config2 = requests.get(f"{url2}/api/config").json()

    differences = {}
    for key in config1:
        if config1[key] != config2.get(key):
            differences[key] = {
                'device1': config1[key],
                'device2': config2.get(key)
            }

    return differences

# Compare two routers
diffs = compare_configs("http://192.168.4.1", "http://192.168.4.2")
print(json.dumps(diffs, indent=2))



8.7 Punto final: GET /api/info

Obtener información del sistema: versión del firmware, tipo de chip, tamaño del flash, memoria libre, tiempo de actividad.


8.7.1 Solicitud

http
GET /api/info HTTP/1.1
Host: 192.168.4.1

Parámetros: Ninguno


8.7.2 Respuesta

Estado HTTP: 200 OK

Esquema JSON:

json
{
  "version": "string",          // Firmware version
  "chip": "string",             // Chip type
  "flash_size": 0,              // Flash size (bytes)
  "free_heap": 0,               // Free memory (bytes)
  "uptime": 0,                  // [DEPRECATED] Uptime (sec)
  "uptime_sec": 0               // Uptime (seconds)
}


8.7.3 Descripción de campos

Campo Tipo Descripción
version string ACRouter firmware version (format: "X.Y.Z")
chip string Microcontroller type (typically "ESP32")
flash_size integer Tamaño de la memoria flash en bytes
free_heap integer RAM libre en bytes
uptime integer [OBSOLETO] Tiempo de actividad en segundos (use uptime_sec)
uptime_sec integer Tiempo de actividad desde el arranque en segundos


8.7.4 Ejemplo de respuesta

json
{
  "version": "1.0.0",
  "chip": "ESP32",
  "flash_size": 4194304,
  "free_heap": 189328,
  "uptime": 7234,
  "uptime_sec": 7234
}

Interpretation:
- Firmware version: 1.0.0
- Chip: ESP32
- Flash: 4 MB (4194304 bytes)
- Free RAM: 184 KB (189328 bytes)
- Uptime: 7234 sec (≈ 2 hours 34 seconds)


8.7.5 Uso

Supervisión de memoria:

bash
# Check for memory leaks
while true; do
  free_heap=$(curl -s http://192.168.4.1/api/info | jq '.free_heap')
  echo "$(date +%T) Free heap: $free_heap bytes"
  sleep 60
done

Python – alerta de memoria baja:

python
import requests
import time

def monitor_memory(url, threshold_kb=100):
    while True:
        info = requests.get(f"{url}/api/info").json()
        free_kb = info['free_heap'] / 1024

        if free_kb < threshold_kb:
            print(f"⚠️ WARNING: Low memory! {free_kb:.1f} KB free")
            # Send notification (email, Telegram, etc.)
        else:
            print(f"✓ Memory OK: {free_kb:.1f} KB free")

        time.sleep(300)  # Check every 5 minutes

monitor_memory("http://192.168.4.1", threshold_kb=150)

Formatear tiempo de actividad:

python
def format_uptime(seconds):
    days = seconds // 86400
    hours = (seconds % 86400) // 3600
    minutes = (seconds % 3600) // 60
    secs = seconds % 60

    return f"{days}d {hours}h {minutes}m {secs}s"

info = requests.get("http://192.168.4.1/api/info").json()
print(f"Uptime: {format_uptime(info['uptime_sec'])}")
# Output: Uptime: 0d 2h 34m 18s



8.8 Punto final: GET /api/wifi/status

Obtener el estado detallado de la conexión WiFi: modo AP/STA, direcciones IP, SSID, intensidad de señal, dirección MAC, credenciales guardadas.


8.8.1 Solicitud

http
GET /api/wifi/status HTTP/1.1
Host: 192.168.4.1

Parámetros: Ninguno


8.8.2 Respuesta

Estado HTTP: 200 OK

Esquema JSON:

json
{
  "state": "string",              // WiFi state
  "ap_active": false,             // AP active
  "ap_ssid": "string",            // AP SSID
  "ap_ip": "string",              // AP IP address
  "ap_clients": 0,                // Connected clients
  "sta_connected": false,         // STA connected
  "sta_ssid": "string",           // STA SSID
  "sta_ip": "string",             // STA IP address
  "rssi": 0,                      // Signal strength (dBm)
  "has_saved_credentials": false, // Credentials saved in NVS
  "mac": "string",                // MAC address
  "hostname": "string"            // Hostname
}


8.8.3 Descripción de campos

Campo Tipo Descripción Valores posibles
state string Estado del WiFi "IDLE", "AP_ONLY", "STA_CONNECTING", "STA_CONNECTED", "AP_STA", "STA_FAILED"
ap_active boolean Punto de acceso activo true / false
ap_ssid string Nombre del AP (formato: ACRouter_XXXXXX) -
ap_ip string Dirección IP del AP (normalmente 192.168.4.1) -
ap_clients integer Número de clientes conectados al AP 0 .. 4
sta_connected boolean Conectado a red WiFi como cliente true / false
sta_ssid string Nombre de la red WiFi -
sta_ip string Dirección IP obtenida por DHCP -
rssi integer Intensidad de señal WiFi en dBm -100 .. -30
has_saved_credentials boolean Credenciales guardadas en NVS true / false
mac string Dirección MAC del dispositivo (formato: XX:XX:XX:XX:XX:XX) -
hostname string Nombre de host del dispositivo -

Evaluación de la intensidad de señal (RSSI):

RSSI (dBm) Calidad Descripción
-30 a -50 Excelente Señal muy fuerte
-51 a -70 Buena Conexión estable
-71 a -85 Regular Posibles caídas ocasionales
-86 a -100 Deficiente Conexión inestable


8.8.4 Ejemplo de respuesta (AP + STA activos)

json
{
  "state": "AP_STA",
  "ap_active": true,
  "ap_ssid": "ACRouter_A1B2C3",
  "ap_ip": "192.168.4.1",
  "ap_clients": 2,
  "sta_connected": true,
  "sta_ssid": "MyHomeNetwork",
  "sta_ip": "192.168.1.150",
  "rssi": -58,
  "has_saved_credentials": true,
  "mac": "24:6F:28:A1:B2:C3",
  "hostname": "acrouter"
}

Interpretation:
- Mode: AP_STA (simultaneous access point and client)
- AP active: ACRouter_A1B2C3 at 192.168.4.1
- 2 clients connected to AP
- STA connected to MyHomeNetwork with IP 192.168.1.150
- Signal strength: -58 dBm (good quality)
- Credentials saved in NVS


8.8.5 Ejemplo de respuesta (solo AP)

json
{
  "state": "AP_ONLY",
  "ap_active": true,
  "ap_ssid": "ACRouter_A1B2C3",
  "ap_ip": "192.168.4.1",
  "ap_clients": 1,
  "sta_connected": false,
  "has_saved_credentials": false,
  "mac": "24:6F:28:A1:B2:C3",
  "hostname": "acrouter"
}


8.8.6 Uso

Verificar conexión de red:

bash
sta_connected=$(curl -s http://192.168.4.1/api/wifi/status | jq -r '.sta_connected')

if [ "$sta_connected" = "true" ]; then
  echo "✓ Connected to WiFi"
else
  echo "✗ Not connected to WiFi"
fi

Python – supervisión de la intensidad de señal:

python
import requests
import time

def monitor_wifi_signal(url):
    while True:
        status = requests.get(f"{url}/api/wifi/status").json()

        if not status['sta_connected']:
            print("⚠️ Not connected to WiFi")
            time.sleep(10)
            continue

        rssi = status['rssi']
        ssid = status['sta_ssid']

        if rssi >= -50:
            quality = "Excellent"
        elif rssi >= -70:
            quality = "Good"
        elif rssi >= -85:
            quality = "Fair"
        else:
            quality = "Poor"

        print(f"{ssid}: {rssi} dBm ({quality})")
        time.sleep(30)

monitor_wifi_signal("http://192.168.4.1")



8.9 Punto final: GET /api/wifi/scan

Escanear redes WiFi disponibles en el alcance.


8.9.1 Solicitud

http
GET /api/wifi/scan HTTP/1.1
Host: 192.168.4.1

Parámetros: Ninguno

⚠️ Advertencia: El escaneo tarda 2–3 segundos. La conexión STA puede desconectarse brevemente durante el escaneo.


8.9.2 Respuesta

Estado HTTP: 200 OK

Esquema JSON:

json
{
  "networks": [
    {
      "ssid": "string",         // Network name
      "rssi": 0,                // Signal strength (dBm)
      "encryption": "string",   // Encryption type
      "channel": 0              // Channel number
    }
  ],
  "count": 0                    // Number of networks found
}


8.9.3 Descripción de campos

Campo Tipo Descripción
networks array Array de redes encontradas
networks[].ssid string Nombre de la red WiFi
networks[].rssi integer Intensidad de señal en dBm
networks[].encryption string Tipo de cifrado: "open" o "secured"
networks[].channel integer Número de canal WiFi (1–14)
count integer Número total de redes encontradas


8.9.4 Ejemplo de respuesta

json
{
  "networks": [
    {
      "ssid": "MyHomeNetwork",
      "rssi": -45,
      "encryption": "secured",
      "channel": 6
    },
    {
      "ssid": "GuestNetwork",
      "rssi": -62,
      "encryption": "open",
      "channel": 11
    },
    {
      "ssid": "Neighbor_WiFi",
      "rssi": -78,
      "encryption": "secured",
      "channel": 1
    }
  ],
  "count": 3
}


8.9.5 Ejemplo de respuesta (sin redes)

json
{
  "networks": [],
  "count": 0
}


8.9.6 Uso

Bash – listar redes disponibles:

bash
curl -s http://192.168.4.1/api/wifi/scan | jq -r '.networks[] | "\(.ssid): \(.rssi) dBm (\(.encryption))"'

Salida:

python
MyHomeNetwork: -45 dBm (secured)
GuestNetwork: -62 dBm (open)
Neighbor_WiFi: -78 dBm (secured)

Python – encontrar la mejor red:

python
import requests

def find_best_network(url, preferred_ssids):
    """Find best network from preferred list"""
    scan_result = requests.get(f"{url}/api/wifi/scan").json()

    best_network = None
    best_rssi = -100

    for network in scan_result['networks']:
        if network['ssid'] in preferred_ssids:
            if network['rssi'] > best_rssi:
                best_rssi = network['rssi']
                best_network = network

    return best_network

# Usage
preferred = ["HomeNetwork_2.4GHz", "HomeNetwork_5GHz", "GuestNetwork"]
best = find_best_network("http://192.168.4.1", preferred)

if best:
    print(f"Best network: {best['ssid']} ({best['rssi']} dBm)")
else:
    print("No preferred networks found")

JavaScript – mostrar lista de redes:

javascript
fetch('http://192.168.4.1/api/wifi/scan')
  .then(r => r.json())
  .then(data => {
    const networkList = data.networks.map(net => {
      const signal = net.rssi >= -50 ? '▂▄▆█' :
                     net.rssi >= -70 ? '▂▄▆_' :
                     net.rssi >= -85 ? '▂▄__' : '▂___';

      const lock = net.encryption === 'secured' ? '🔒' : '🔓';

      return `${lock} ${net.ssid} ${signal} (Channel ${net.channel})`;
    });

    console.log(`Found ${data.count} networks:\n${networkList.join('\n')}`);
  });



8.10 Punto final: GET /api/hardware/config

Obtener la configuración de componentes de hardware: canales ADC, dimmers, cruce por cero, relés, LEDs.


8.10.1 Solicitud

http
GET /api/hardware/config HTTP/1.1
Host: 192.168.4.1

Parámetros: Ninguno


8.10.2 Respuesta

Estado HTTP: 200 OK

Esquema JSON:

json
{
  "adc_channels": [
    {
      "gpio": 0,                // GPIO pin
      "type": 0,                // Sensor type (number)
      "type_name": "string",    // Sensor type name
      "multiplier": 0.0,        // Multiplier
      "offset": 0.0,            // Offset
      "enabled": false          // Enabled
    }
  ],
  "dimmer_ch1": {
    "gpio": 0,                  // GPIO pin
    "enabled": false            // Enabled
  },
  "dimmer_ch2": {
    "gpio": 0,
    "enabled": false
  },
  "zerocross_gpio": 0,          // Zero-cross detector GPIO
  "zerocross_enabled": false,   // Zero-cross enabled
  "relay_ch1": {
    "gpio": 0,
    "active_high": false,       // Logic: true=HIGH active
    "enabled": false
  },
  "relay_ch2": {
    "gpio": 0,
    "active_high": false,
    "enabled": false
  },
  "led_status_gpio": 0,         // Status LED GPIO
  "led_load_gpio": 0            // Load LED GPIO
}


8.10.3 Tipos de sensor (SensorType)

Código Nombre Descripción
0 NONE No utilizado
1 ZMPT107 Sensor de voltaje ZMPT107
2 SCT013 Sensor de corriente SCT-013 (transformador)
3 ACS712 Sensor de corriente ACS712 (efecto Hall)


8.10.4 Ejemplo de respuesta

json
{
  "adc_channels": [
    {
      "gpio": 34,
      "type": 1,
      "type_name": "ZMPT107",
      "multiplier": 320.0,
      "offset": 0.0,
      "enabled": true
    },
    {
      "gpio": 35,
      "type": 2,
      "type_name": "SCT013",
      "multiplier": 30.0,
      "offset": 0.0,
      "enabled": true
    },
    {
      "gpio": 32,
      "type": 3,
      "type_name": "ACS712",
      "multiplier": 30.0,
      "offset": 0.0,
      "enabled": true
    },
    {
      "gpio": 33,
      "type": 0,
      "type_name": "NONE",
      "multiplier": 1.0,
      "offset": 0.0,
      "enabled": false
    }
  ],
  "dimmer_ch1": {
    "gpio": 19,
    "enabled": true
  },
  "dimmer_ch2": {
    "gpio": 23,
    "enabled": false
  },
  "zerocross_gpio": 18,
  "zerocross_enabled": true,
  "relay_ch1": {
    "gpio": 15,
    "active_high": true,
    "enabled": false
  },
  "relay_ch2": {
    "gpio": 2,
    "active_high": true,
    "enabled": false
  },
  "led_status_gpio": 17,
  "led_load_gpio": 5
}

Interpretation:
- ADC channel 0: GPIO 34, ZMPT107 voltage sensor
- ADC channel 1: GPIO 35, SCT013 current sensor
- ADC channel 2: GPIO 32, ACS712 current sensor
- ADC channel 3: Not used
- Dimmer 1: GPIO 19 (active)
- Dimmer 2: GPIO 23 (disabled)
- Zero-cross: GPIO 18 (active)
- Relays 1-2: Disabled
- Status LED: GPIO 17
- Load LED: GPIO 5


8.10.5 Uso

Diagnóstico de configuración de hardware:

bash
curl -s http://192.168.4.1/api/hardware/config | jq '.'

Python – verificar conflictos de GPIO:

python
import requests

def check_gpio_conflicts(url):
    config = requests.get(f"{url}/api/hardware/config").json()

    gpio_usage = {}
    conflicts = []

    # Collect all used GPIOs
    for i, ch in enumerate(config['adc_channels']):
        if ch['enabled']:
            gpio = ch['gpio']
            if gpio in gpio_usage:
                conflicts.append(f"GPIO {gpio}: {gpio_usage[gpio]} and ADC channel {i}")
            else:
                gpio_usage[gpio] = f"ADC channel {i}"

    if config['dimmer_ch1']['enabled']:
        gpio = config['dimmer_ch1']['gpio']
        if gpio in gpio_usage:
            conflicts.append(f"GPIO {gpio}: {gpio_usage[gpio]} and Dimmer 1")
        else:
            gpio_usage[gpio] = "Dimmer 1"

    # ... check all other GPIOs

    if conflicts:
        print("⚠️ GPIO conflicts detected:")
        for conflict in conflicts:
            print(f"  - {conflict}")
    else:
        print("✓ No GPIO conflicts")

check_gpio_conflicts("http://192.168.4.1")



8.11 Códigos de error HTTP

Código Estado Descripción Ejemplo
200 OK Solicitud exitosa Todos los puntos finales GET en caso de éxito
400 Bad Request Formato de solicitud inválido Parámetro inválido
404 Not Found Punto final no encontrado GET /api/unknown
500 Internal Server Error Error interno del servidor Error al leer NVS
501 Not Implemented Funcionalidad no implementada GET /api/calibrate

Formato de error:

json
{
  "error": "Error message description"
}

Ejemplos:

json
{
  "error": "Not Found"
}
json
{
  "error": "Failed to read configuration from NVS"
}



8.12 Ejemplos de uso


8.12.1 Supervisión de estado (Python)

python
import requests
import time
from datetime import datetime

class ACRouterMonitor:
    def __init__(self, base_url):
        self.base_url = base_url

    def get_status(self):
        return requests.get(f"{self.base_url}/api/status").json()

    def get_metrics(self):
        return requests.get(f"{self.base_url}/api/metrics").json()

    def get_config(self):
        return requests.get(f"{self.base_url}/api/config").json()

    def monitor_loop(self, interval=2):
        print("ACRouter Monitor - Press Ctrl+C to stop")
        print("-" * 60)

        try:
            while True:
                status = self.get_status()

                timestamp = datetime.now().strftime("%H:%M:%S")
                mode = status['mode'].upper()
                state = status['state']
                power = status['power_grid']
                dimmer = status['dimmer']

                # Format output
                power_str = f"{power:+7.1f}W"
                if power > 0:
                    direction = "IMPORT"
                elif power < 0:
                    direction = "EXPORT"
                else:
                    direction = "BALANCE"

                print(f"[{timestamp}] {mode:8} | {state:11} | {power_str} {direction:7} | Dimmer: {dimmer:3}%")

                time.sleep(interval)

        except KeyboardInterrupt:
            print("\nMonitoring stopped")

# Usage
monitor = ACRouterMonitor("http://192.168.4.1")
monitor.monitor_loop(interval=2)


8.12.2 Panel de control (JavaScript + HTML)

html



    ACRouter Dashboard
    


    

ACRouter Dashboard

Mode
-
Grid Power
-
Dimmer
-
State
-


8.12.3 Exportar a CSV (Bash)

bash
#!/bin/bash

API_URL="http://192.168.4.1/api"
CSV_FILE="acrouter_metrics_$(date +%Y%m%d_%H%M%S).csv"

# CSV header
echo "timestamp,mode,state,power_grid,dimmer,target_level,free_heap" > "$CSV_FILE"

echo "Logging metrics to $CSV_FILE (Press Ctrl+C to stop)"

while true; do
    # Get data
    status=$(curl -s "$API_URL/status")

    # Extract fields
    timestamp=$(date +"%Y-%m-%d %H:%M:%S")
    mode=$(echo "$status" | jq -r '.mode')
    state=$(echo "$status" | jq -r '.state')
    power=$(echo "$status" | jq -r '.power_grid')
    dimmer=$(echo "$status" | jq -r '.dimmer')
    target=$(echo "$status" | jq -r '.target_level')
    heap=$(echo "$status" | jq -r '.free_heap')

    # Write to CSV
    echo "$timestamp,$mode,$state,$power,$dimmer,$target,$heap" >> "$CSV_FILE"

    # Display
    echo "[$(date +%H:%M:%S)] Logged: Power=${power}W, Dimmer=${dimmer}%"

    sleep 5
done



  • 01_OVERVIEW.md – Descripción general del proyecto
  • 03_STRUCTURE.md – Arquitectura de la aplicación
  • 07_COMMANDS.md – Referencia de comandos (RU)
  • 07_COMMANDS_EN.md – Referencia de comandos (EN)
  • 09_WEB_API_POST.md – Puntos finales POST de la API Web (siguiente sección)

Firmware Version: 1.0.0
Last Updated: 2025-01-15

← Comandos de terminal | Contenido | Siguiente: Web API - POST →