Перейти к содержимому

← Web API - GET | Содержание | Далее: Калибровка датчиков →

9. Web API — POST-эндпоинты

Version: 1.0.0
Date: 2025-01-15

Детальная документация по REST API POST-эндпоинтам для управления и настройки системы ACRouter.




Содержание




9.1 Введение

POST-эндпоинты REST API ACRouter предназначены для:

  • Управления роутером — изменение режима работы, уровня диммера
  • Конфигурации — обновление системных параметров
  • Управления WiFi — подключение/отключение от сетей
  • Конфигурации железа — настройка GPIO, датчиков, диммеров
  • Управления системой — перезагрузка устройства

Все изменения применяются немедленно и сохраняются в NVS (энергонезависимая память).

Реализация: components/comm/src/WebServerManager.cpp




9.2 Формат запроса


9.2.1 Content-Type

Все POST-запросы должны использовать:

http
Content-Type: application/json


9.2.2 Структура запроса

http
POST /api/endpoint HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "parameter1": "value1",
  "parameter2": 123
}


9.2.3 Формат успешного ответа

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Operation completed successfully"
}


9.2.4 Формат ответа с ошибкой

HTTP-статус: 400, 500, 501

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



9.3 Эндпоинт: POST /api/config

Обновить параметры конфигурации системы. Можно обновить один или несколько параметров в одном запросе.


9.3.1 Запрос

http
POST /api/config HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "voltage_coef": 1.02,
  "current_coef": 30.0,
  "current_threshold": 0.12,
  "power_threshold": 12.0,
  "control_gain": 180.0,
  "balance_threshold": 40.0
}


9.3.2 Параметры (все необязательные)

Все параметры необязательны. Обновляются только указанные поля.

Параметр Тип Диапазон Описание
voltage_coef float 0.1 .. 10.0 Калибровочный коэффициент напряжения
current_coef float 0.1 .. 100.0 Коэффициент преобразования тока (А/В)
current_threshold float 0.01 .. 10.0 Порог обнаружения тока (А)
power_threshold float 1.0 .. 1000.0 Порог обнаружения мощности (Вт)
control_gain float 1.0 .. 1000.0 Коэффициент усиления контура управления
balance_threshold float 0.0 .. 100.0 Порог баланса для режима AUTO (Вт)


9.3.3 Ответ (успех)

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Configuration updated"
}

Если параметры не изменялись:

json
{
  "success": true,
  "message": "No changes"
}


9.3.4 Ответ (ошибка)

HTTP-статус: 400 Bad Request

json
{
  "error": "Missing request body"
}
json
{
  "error": "Invalid JSON"
}


9.3.5 Примеры использования

Обновить один параметр:

bash
curl -X POST http://192.168.4.1/api/config \
  -H "Content-Type: application/json" \
  -d '{"control_gain": 200.0}'

Обновить несколько параметров:

bash
curl -X POST http://192.168.4.1/api/config \
  -H "Content-Type: application/json" \
  -d '{
    "control_gain": 180.0,
    "balance_threshold": 40.0,
    "voltage_coef": 1.02
  }'

Python:

python
import requests

config = {
    "control_gain": 200.0,
    "balance_threshold": 35.0
}

response = requests.post(
    "http://192.168.4.1/api/config",
    json=config
)

print(response.json())
# {'success': True, 'message': 'Configuration updated'}

JavaScript:

javascript
const config = {
  control_gain: 200.0,
  balance_threshold: 35.0
};

fetch('http://192.168.4.1/api/config', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify(config)
})
  .then(r => r.json())
  .then(data => console.log(data));



9.4 Эндпоинт: POST /api/config/reset

Сбросить все параметры конфигурации до заводских значений.


9.4.1 Запрос

http
POST /api/config/reset HTTP/1.1
Host: 192.168.4.1

Тело запроса: не требуется


9.4.2 Заводские значения по умолчанию

cpp
control_gain        = 150.0
balance_threshold   = 50.0 W
voltage_coef        = 1.0
current_coef        = 30.0 A/V
current_threshold   = 0.1 A
power_threshold     = 10.0 W


9.4.3 Ответ (успех)

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Configuration reset to defaults"
}


9.4.4 Примеры использования

Bash:

bash
curl -X POST http://192.168.4.1/api/config/reset

Python:

python
import requests

response = requests.post("http://192.168.4.1/api/config/reset")
print(response.json())
# {'success': True, 'message': 'Configuration reset to defaults'}

⚠️ Предупреждение: операция необратима. Все пользовательские настройки будут потеряны.




9.5 Эндпоинт: POST /api/mode

Установить режим работы роутера.


9.5.1 Запрос

http
POST /api/mode HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "mode": "auto"
}


9.5.2 Параметры

Параметр Тип Обязательный Допустимые значения
mode string Да "off", "auto", "eco", "offgrid", "manual", "boost"

Описание режимов:

Режим Описание
"off" Роутер отключён, диммер 0%
"auto" Солнечный роутер — минимизация импорта/экспорта
"eco" Экономный — защита от импорта, экспорт разрешён
"offgrid" Автономный — солнечные/аккумулятор, минимальное использование сети
"manual" Ручной — фиксированный уровень диммера
"boost" Максимальная мощность — диммер 100%


9.5.3 Ответ (успех)

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Mode set to AUTO"
}


9.5.4 Ответ (ошибка)

HTTP-статус: 400 Bad Request

json
{
  "error": "Missing 'mode' field"
}
json
{
  "error": "Invalid mode (use: off, auto, eco, offgrid, manual, boost)"
}


9.5.5 Примеры использования

Установить режим AUTO (солнечный роутер):

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

Установить режим ECO:

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

Python — переключение между режимами:

python
import requests
import time

def set_mode(mode):
    response = requests.post(
        "http://192.168.4.1/api/mode",
        json={"mode": mode}
    )
    return response.json()

# Set AUTO mode
print(set_mode("auto"))
time.sleep(60)

# Switch to MANUAL for testing
print(set_mode("manual"))
time.sleep(30)

# Return to AUTO
print(set_mode("auto"))



9.6 Эндпоинт: POST /api/dimmer

Установить уровень диммера. Автоматически переключает роутер в режим MANUAL.


9.6.1 Запрос

http
POST /api/dimmer HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "value": 75
}


9.6.2 Параметры

Параметр Тип Обязательный Диапазон Описание
value integer Да 0 .. 100 Уровень диммера в процентах


9.6.3 Ответ (успех)

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Dimmer value set"
}

⚠️ Важно: при установке уровня диммера роутер автоматически переключается в режим MANUAL.


9.6.4 Ответ (ошибка)

HTTP-статус: 400 Bad Request

json
{
  "error": "Missing 'value' field"
}
json
{
  "error": "Value must be 0-100"
}


9.6.5 Примеры использования

Установить диммер на 50%:

bash
curl -X POST http://192.168.4.1/api/dimmer \
  -H "Content-Type: application/json" \
  -d '{"value": 50}'

Python — плавное нарастание мощности:

python
import requests
import time

def set_dimmer(value):
    response = requests.post(
        "http://192.168.4.1/api/dimmer",
        json={"value": value}
    )
    return response.json()

# Gradually increase from 0% to 100%
for level in range(0, 101, 10):
    print(f"Setting dimmer to {level}%")
    set_dimmer(level)
    time.sleep(5)

# Gradually decrease back
for level in range(100, -1, -10):
    print(f"Setting dimmer to {level}%")
    set_dimmer(level)
    time.sleep(5)

JavaScript — управление ползунком:

javascript
// HTML: 

const slider = document.getElementById('dimmerSlider');

slider.addEventListener('change', (e) => {
  const value = parseInt(e.target.value);

  fetch('http://192.168.4.1/api/dimmer', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({value: value})
  })
    .then(r => r.json())
    .then(data => console.log(`Dimmer set to ${value}%`));
});



9.7 Эндпоинт: POST /api/manual

Альтернативный эндпоинт для установки ручного режима с заданным уровнем диммера. Эквивалентен POST /api/mode (mode=manual) + POST /api/dimmer.


9.7.1 Запрос

http
POST /api/manual HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "value": 60
}


9.7.2 Параметры

Параметр Тип Обязательный Диапазон Описание
value integer Да 0 .. 100 Уровень диммера в процентах


9.7.3 Поведение

  1. Переключает роутер в режим MANUAL
  2. Устанавливает уровень диммера на указанное значение


9.7.4 Ответ (успех)

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Manual control set"
}


9.7.5 Примеры использования

Bash:

bash
curl -X POST http://192.168.4.1/api/manual \
  -H "Content-Type: application/json" \
  -d '{"value": 60}'

Различие между /api/dimmer и /api/manual:

python
import requests

# Option 1: Use /api/dimmer
# Automatically switches to MANUAL
requests.post("http://192.168.4.1/api/dimmer", json={"value": 60})

# Option 2: Use /api/manual
# Explicitly switches to MANUAL and sets level
requests.post("http://192.168.4.1/api/manual", json={"value": 60})

# Result is identical



9.8 Эндпоинт: POST /api/hardware/voltage/calibrate

Автоматическая калибровка датчика напряжения (доступно начиная с версии 2.0).

Система автоматически измеряет выходное напряжение датчика (VDC RMS) и рассчитывает калибровочный коэффициент на основе измеренного напряжения сети.


9.8.1 Запрос

http
POST /api/hardware/voltage/calibrate HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "measured_vac": 232.5
}


9.8.2 Параметры

Параметр Тип Обязательный Описание
measured_vac float Да Напряжение сети, измеренное мультиметром (VAC RMS)

Диапазон: 100.0 .. 300.0 (в зависимости от стандарта электросети)


9.8.3 Процесс калибровки

  1. PowerMeterADC измеряет текущий выход датчика (VDC RMS)
  2. Рассчитывает коэффициент: multiplier = measured_vac / sensor_vdc
  3. Обновляет nominal_vdc до фактически измеренного значения
  4. Конфигурация сохраняется в NVS
  5. ⚠️ Для применения изменений требуется перезагрузка


9.8.4 Ответ (успех)

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Voltage sensor calibrated",
  "sensor_vdc": 0.72,
  "multiplier": 322.92,
  "sensor_type": "ZMPT107"
}

Поля ответа:

Поле Тип Описание
sensor_vdc float Измеренный выход датчика (VDC RMS)
multiplier float Рассчитанный коэффициент
sensor_type string Тип датчика (ZMPT107, ZMPT101B, CUSTOM)


9.8.5 Ответ (ошибка)

HTTP-статус: 400 Bad Request

json
{
  "error": "Missing 'measured_vac' field"
}
json
{
  "error": "PowerMeterADC is not running"
}
json
{
  "error": "No voltage sensor configured"
}

HTTP-статус: 500 Internal Server Error

json
{
  "error": "Failed to save calibration to NVS"
}


9.8.6 Примеры использования

Базовая калибровка:

bash
curl -X POST http://192.168.4.1/api/hardware/voltage/calibrate \
  -H "Content-Type: application/json" \
  -d '{"measured_vac": 232.5}'

Python — полная процедура калибровки:

json
{
  "success": true,
  "message": "Voltage sensor calibrated",
  "sensor_vdc": 0.72,
  "multiplier": 322.92,
  "sensor_type": "ZMPT107"
}

9.8.7 Важные замечания

python
import requests
import time

def calibrate_voltage_sensor(measured_vac, base_url="http://192.168.4.1"):
    """
    Automatic voltage sensor calibration

    Args:
        measured_vac: Grid voltage measured with multimeter (VAC)
        base_url: Router URL

    Returns:
        bool: True if calibration successful
    """

    print(f"Starting voltage sensor calibration...")
    print(f"Measured grid voltage: {measured_vac} VAC")

    # 1. Send calibration request
    response = requests.post(
        f"{base_url}/api/hardware/voltage/calibrate",
        json={"measured_vac": measured_vac},
        timeout=10
    )

    if response.status_code != 200:
        error = response.json().get('error', 'Unknown error')
        print(f"✗ Calibration failed: {error}")
        return False

    # 2. Get results
    result = response.json()

    if not result.get('success'):
        print(f"✗ Calibration failed")
        return False

    print(f"✓ Calibration successful:")
    print(f"  Sensor VDC: {result['sensor_vdc']:.3f} V")
    print(f"  Multiplier: {result['multiplier']:.2f}")
    print(f"  Sensor type: {result['sensor_type']}")

    # 3. Reboot device
    print("\nRebooting device to apply calibration...")
    requests.post(f"{base_url}/api/system/reboot")

    # 4. Wait for reboot
    time.sleep(15)

    # 5. Verify result
    print("Verifying calibration...")
    for attempt in range(10):
        try:
            status = requests.get(f"{base_url}/api/status", timeout=2).json()
            voltage = status.get('voltage', 0)

            # Check voltage is close to measured value
            if abs(voltage - measured_vac) < 5.0:
                print(f"✓ Calibration verified: {voltage:.1f} V")
                return True
            else:
                print(f"  Current reading: {voltage:.1f} V (expected {measured_vac:.1f} V)")
        except:
            pass

        time.sleep(2)

    print("⚠ Could not verify calibration (device may still be rebooting)")
    return False

# Usage
calibrate_voltage_sensor(232.5)

После калибровки требуется перезагрузка

javascript
async function calibrateVoltageSensor(measuredVAC) {
    try {
        // 1. Send calibration request
        const response = await fetch('http://192.168.4.1/api/hardware/voltage/calibrate', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({measured_vac: measuredVAC})
        });

        const result = await response.json();

        if (!result.success) {
            alert(`Calibration failed: ${result.error || 'Unknown error'}`);
            return false;
        }

        // 2. Show results
        alert(`Calibration successful!\n` +
              `Sensor VDC: ${result.sensor_vdc.toFixed(3)} V\n` +
              `Multiplier: ${result.multiplier.toFixed(2)}\n` +
              `Sensor: ${result.sensor_type}\n\n` +
              `Device will reboot now...`);

        // 3. Reboot device
        await fetch('http://192.168.4.1/api/system/reboot', {method: 'POST'});

        return true;
    } catch (error) {
        alert(`Error: ${error.message}`);
        return false;
    }
}

// Usage in HTML form
// 
// 


Автоматически обновляет nominal_vdc до фактически измеренного значения

Более точная и быстрая калибровка

  • 9.9 Эндпоинт: POST /api/wifi/connect
  • Подключиться к WiFi-сети. При успешном подключении учётные данные автоматически сохраняются в NVS.
  • 9.9.1 Запрос

http

  • 📋 Copy
  • POST /api/wifi/connect HTTP/1.1 Host: 192.168.4.1 Content-Type: application/json { "ssid": "MyHomeNetwork", "password": "MySecurePassword123" }
  • 9.9.2 Параметры
  • Параметр

Тип




9.9 Эндпоинт: POST /api/wifi/connect

Имя WiFi-сети (максимум 32 символа)


password

http
POST /api/wifi/connect HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "ssid": "MyHomeNetwork",
  "password": "MySecurePassword123"
}


9.9.3 Поведение

Параметр Тип Обязательный Описание
Получает IP-адрес через DHCP string Да При следующей загрузке роутер автоматически подключится к этой сети
9.9.4 Ответ (успех) string json 📋 Copy


{ "success": true, "message": "Connecting to WiFi... Credentials will be saved on success", "ssid": "MyHomeNetwork" }

  1. ⚠️ Важно: ответ отправляется сразу после инициирования подключения. Фактическое подключение занимает 5–10 секунд.
  2. 9.9.5 Ответ (ошибка)
  3. HTTP-статус: 400 Bad Request
  4. json
  5. 📋 Copy
  6. { "error": "Missing 'ssid' field" }
  7. HTTP-статус: 500 Internal Server Error
  8. json


📋 Copy

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Connecting to WiFi... Credentials will be saved on success",
  "ssid": "MyHomeNetwork"
}

📋 Copy


curl -s http://192.168.4.1/api/wifi/status | jq '.sta_connected, .sta_ip'

HTTP-статус: 400 Bad Request

json
{
  "error": "Missing 'ssid' field"
}

HTTP-статус: 500 Internal Server Error

json
{
  "error": "Failed to initiate WiFi connection"
}


curl -X POST http://192.168.4.1/api/wifi/connect \ -H "Content-Type: application/json" \ -d '{"ssid": "PublicWiFi"}'

Python — подключение с проверкой:

bash
curl -s http://192.168.4.1/api/wifi/status | jq '.sta_connected, .sta_ip'


⚠️ Безопасность: пароль передаётся в открытом виде. Используйте только через прямое AP-подключение.

9.10 Эндпоинт: POST /api/wifi/disconnect

bash
curl -X POST http://192.168.4.1/api/wifi/connect \
  -H "Content-Type: application/json" \
  -d '{
    "ssid": "MyHomeNetwork",
    "password": "SecurePass2024"
  }'

📋 Copy

bash
curl -X POST http://192.168.4.1/api/wifi/connect \
  -H "Content-Type: application/json" \
  -d '{"ssid": "PublicWiFi"}'

Отключается от STA-сети

python
import requests
import time

def connect_wifi(ssid, password=None):
    """Connect to WiFi and wait for result"""

    # Send connection request
    payload = {"ssid": ssid}
    if password:
        payload["password"] = password

    response = requests.post(
        "http://192.168.4.1/api/wifi/connect",
        json=payload
    )

    if response.status_code != 200:
        print(f"Failed to initiate connection: {response.json()}")
        return False

    print(f"Connecting to {ssid}...")

    # Wait 10 seconds
    time.sleep(10)

    # Check result
    status = requests.get("http://192.168.4.1/api/wifi/status").json()

    if status['sta_connected'] and status['sta_ssid'] == ssid:
        print(f"✓ Connected to {ssid}")
        print(f"  IP: {status['sta_ip']}")
        print(f"  RSSI: {status['rssi']} dBm")
        return True
    else:
        print(f"✗ Failed to connect to {ssid}")
        return False

# Usage
connect_wifi("MyHomeNetwork", "MyPassword123")

HTTP-статус: 200 OK




9.10 Эндпоинт: POST /api/wifi/disconnect

📋 Copy


{ "success": true, "message": "Disconnected from WiFi network" }

http
POST /api/wifi/disconnect HTTP/1.1
Host: 192.168.4.1

Тело запроса: не требуется


curl -X POST http://192.168.4.1/api/wifi/disconnect

  • Python:
  • python
  • 📋 Copy


import requests response = requests.post("http://192.168.4.1/api/wifi/disconnect") print(response.json()) status = requests.get("http://192.168.4.1/api/wifi/status").json() print(f"Состояние: {status['state']}") # AP_ONLY print(f"Сохранены учётные данные: {status['has_saved_credentials']}") # True

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Disconnected from WiFi network"
}


📋 Copy

Bash:

bash
curl -X POST http://192.168.4.1/api/wifi/disconnect

Python:

python
import requests

response = requests.post("http://192.168.4.1/api/wifi/disconnect")
print(response.json())
# {'success': True, 'message': 'Disconnected from WiFi network'}

# Check status
status = requests.get("http://192.168.4.1/api/wifi/status").json()
print(f"State: {status['state']}")  # AP_ONLY
print(f"Saved credentials: {status['has_saved_credentials']}")  # True (remain in NVS)



9.11 Эндпоинт: POST /api/wifi/forget

json


📋 Copy

http
POST /api/wifi/forget HTTP/1.1
Host: 192.168.4.1

Тело запроса: не требуется


📋 Copy

  • { "error": "Failed to clear WiFi credentials" }
  • 9.11.5 Примеры использования
  • Bash:
  • bash


📋 Copy

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "WiFi credentials cleared from NVS"
}


import requests def reset_wifi(): """Полный сброс WiFi""" print("Отключение от WiFi...") requests.post("http://192.168.4.1/api/wifi/disconnect") print("Удаление сохранённых учётных данных...") response = requests.post("http://192.168.4.1/api/wifi/forget") if response.json()['success']: print("✓ WiFi сброшен") print(" После перезагрузки роутер будет только в режиме AP") else: print("✗ Не удалось удалить учётные данные") reset_wifi()

HTTP-статус: 500 Internal Server Error

json
{
  "error": "Failed to clear WiFi credentials"
}


9.12 Эндпоинт: POST /api/hardware/config

Bash:

bash
curl -X POST http://192.168.4.1/api/wifi/forget

📋 Copy

python
import requests

def reset_wifi():
    """Complete WiFi reset"""

    # 1. Disconnect from network
    print("Disconnecting from WiFi...")
    requests.post("http://192.168.4.1/api/wifi/disconnect")

    # 2. Clear saved credentials
    print("Clearing saved credentials...")
    response = requests.post("http://192.168.4.1/api/wifi/forget")

    if response.json()['success']:
        print("✓ WiFi reset complete")
        print("  Router will be in AP-only mode after reboot")
    else:
        print("✗ Failed to clear credentials")

reset_wifi()

Параметр

python
# Change WiFi network

# 1. Clear old credentials
requests.post("http://192.168.4.1/api/wifi/forget")

# 2. Connect to new network
requests.post("http://192.168.4.1/api/wifi/connect", json={
    "ssid": "NewNetwork",
    "password": "NewPassword"
})



9.12 Эндпоинт: POST /api/hardware/config

gpio

integer


Да

http
POST /api/hardware/config HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "adc_channels": [
    {
      "gpio": 34,
      "type": 1,
      "multiplier": 320.0,
      "offset": 0.0,
      "enabled": true
    },
    ...
  ],
  "dimmer_ch1": {
    "gpio": 19,
    "enabled": true
  },
  "zerocross_gpio": 18,
  "zerocross_enabled": true,
  ...
}


integer

Да

Параметр Тип Обязательный Описание Нет
Калибровочный коэффициент integer Да float Нет
Смещение калибровки integer Да boolean Да
multiplier float json GPIO: только ADC1 (32–39). ADC2 не поддерживается в режиме непрерывного считывания! Multiplier: если не указан, выбирается автоматически по типу датчика:
VOLTAGE_AC → 230.0 (ZMPT107) float json Диммеры: Параметр
Тип Описание Да integer GPIO-пин диммера 1

dimmer_ch1.enabled

  • boolean
  • Диммер 1 включён
  • dimmer_ch2.gpio
  • integer
  • GPIO-пин диммера 2

dimmer_ch2.enabled

Параметр Тип Описание
Параметр integer Описание
zerocross_gpio Описание GPIO-пин
zerocross_enabled integer Включён
Реле: Описание Тип

Описание

Параметр Тип Описание
relay_ch1.active_high integer float
relay_ch1.enabled Описание integer

relay_ch2.*

Параметр Тип Описание
Параметр integer Описание
led_status_gpio Описание GPIO статусного LED
led_load_gpio Описание GPIO LED нагрузки
9.12.3 Валидация Перед сохранением конфигурация автоматически проверяется: Проверка конфликтов GPIO (один GPIO не может использоваться дважды)

Проверка корректности GPIO-пинов (0–39)

Параметр Тип Описание
json integer { "success": true, "message": "Configuration saved to NVS (reboot required)" }
⚠️ Важно: для применения изменений требуется перезагрузка! integer HTTP-статус: 400 Bad Request


json

📋 Copy

  • { "success": false, "error": "GPIO 19 conflict: used by Dimmer 1 and ADC channel 0" }
  • 9.12.6 Примеры использования
  • Обновить ADC-каналы:


bash

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Configuration saved to NVS (reboot required)"
}

📋 Copy


import requests config = { "dimmer_ch1": { "gpio": 21, # Изменить с 19 на 21 "enabled": True } } response = requests.post( "http://192.168.4.1/api/hardware/config", json=config ) if response.json()['success']: print("Конфигурация сохранена. Перезагрузка...") requests.post("http://192.168.4.1/api/system/reboot")

HTTP-статус: 400 Bad Request

json
{
  "success": false,
  "error": "GPIO 19 conflict: used by Dimmer 1 and ADC channel 0"
}


📋 Copy

POST /api/hardware/validate HTTP/1.1 Host: 192.168.4.1 Content-Type: application/json { "dimmer_ch1": { "gpio": 34, "enabled": true } }

bash
curl -X POST http://192.168.4.1/api/hardware/config \
  -H "Content-Type: application/json" \
  -d '{
    "adc_channels": [
      {
        "gpio": 34,
        "type": 1,
        "multiplier": 320.0,
        "offset": 0.0,
        "enabled": true
      },
      {
        "gpio": 35,
        "type": 2,
        "multiplier": 30.0,
        "offset": 0.0,
        "enabled": true
      }
    ]
  }'

📋 Copy

python
import requests

config = {
    "dimmer_ch1": {
        "gpio": 21,  # Change from 19 to 21
        "enabled": True
    }
}

response = requests.post(
    "http://192.168.4.1/api/hardware/config",
    json=config
)

if response.json()['success']:
    print("Configuration saved. Rebooting device...")
    # Reboot device
    requests.post("http://192.168.4.1/api/system/reboot")



9.13 Эндпоинт: POST /api/hardware/validate

📋 Copy


{ "valid": false, "error": "GPIO 34 conflict: already used by ADC channel 0" }

http
POST /api/hardware/validate HTTP/1.1
Host: 192.168.4.1
Content-Type: application/json

{
  "dimmer_ch1": {
    "gpio": 34,
    "enabled": true
  }
}


📋 Copy

HTTP-статус: 200 OK

json
{
  "valid": true
}


http

HTTP-статус: 200 OK

json
{
  "valid": false,
  "error": "GPIO 34 conflict: already used by ADC channel 0"
}


Отправляет ответ клиенту

Ждёт 500 мс (для передачи ответа)

python
import requests

new_config = {
    "dimmer_ch1": {"gpio": 21, "enabled": True},
    "zerocross_gpio": 18
}

# 1. Validate first
validate_response = requests.post(
    "http://192.168.4.1/api/hardware/validate",
    json=new_config
)

if validate_response.json()['valid']:
    print("✓ Configuration valid, applying...")

    # 2. Apply configuration
    apply_response = requests.post(
        "http://192.168.4.1/api/hardware/config",
        json=new_config
    )

    if apply_response.json()['success']:
        print("✓ Configuration saved, rebooting...")
        requests.post("http://192.168.4.1/api/system/reboot")
else:
    print(f"✗ Invalid configuration: {validate_response.json()['error']}")



9.14 Эндпоинт: POST /api/system/reboot

HTTP-статус: 200 OK


json

http
POST /api/system/reboot HTTP/1.1
Host: 192.168.4.1

Тело запроса: не требуется


bash

  1. 📋 Copy
  2. curl -X POST http://192.168.4.1/api/system/reboot
  3. Python — перезагрузить и дождаться:
  4. python

📋 Copy


import requests import time def reboot_and_wait(url="http://192.168.4.1"): """Перезагрузить устройство и дождаться его появления в сети""" print("Перезагрузка устройства...") try: requests.post(f"{url}/api/system/reboot", timeout=5) except requests.exceptions.RequestException: pass # Соединение может прерваться print("Ожидание перезагрузки...") time.sleep(10) for attempt in range(30): try: response = requests.get(f"{url}/api/info", timeout=2) if response.status_code == 200: info = response.json() print(f"✓ Устройство онлайн (время работы: {info['uptime_sec']} с)") return True except requests.exceptions.RequestException: pass print(f" Попытка {attempt + 1}/30...") time.sleep(2) print("✗ Устройство не вышло в сеть") return False # Использование reboot_and_wait()

HTTP-статус: 200 OK

json
{
  "success": true,
  "message": "Rebooting in 3 seconds..."
}


Описание

Bash:

bash
curl -X POST http://192.168.4.1/api/system/reboot

Internal Server Error

python
import requests
import time

def reboot_and_wait(url="http://192.168.4.1"):
    """Reboot device and wait for it to come back online"""

    print("Rebooting device...")
    try:
        requests.post(f"{url}/api/system/reboot", timeout=5)
    except requests.exceptions.RequestException:
        pass  # Connection may be dropped

    print("Waiting for device to reboot...")
    time.sleep(10)  # Wait 10 seconds

    # Wait until device comes back online
    for attempt in range(30):
        try:
            response = requests.get(f"{url}/api/info", timeout=2)
            if response.status_code == 200:
                info = response.json()
                print(f"✓ Device online (uptime: {info['uptime_sec']}s)")
                return True
        except requests.exceptions.RequestException:
            pass

        print(f"  Attempt {attempt + 1}/30...")
        time.sleep(2)

    print("✗ Device did not come back online")
    return False

# Usage
reboot_and_wait()



9.15 Обработка ошибок


9.15.2 Примеры ошибок

Отсутствует тело запроса: json Описание
{ "error": "Missing request body" } Некорректный JSON: json
📋 Copy { "error": "Invalid JSON" } Отсутствует обязательное поле:
json 📋 Copy { "error": "Missing 'mode' field" }


Недопустимое значение:

json

json
{
  "error": "Missing request body"
}

json

json
{
  "error": "Invalid JSON"
}

Python:

json
{
  "error": "Missing 'mode' field"
}

9.16 Примеры использования

json
{
  "error": "Value must be 0-100"
}

import requests import time class ACRouterConfig: def __init__(self, base_url="http://192.168.4.1"): self.base_url = base_url def set_mode(self, mode): """Установить режим работы""" return requests.post( f"{self.base_url}/api/mode", json={"mode": mode} ).json() def set_dimmer(self, value): """Установить уровень диммера""" return requests.post( f"{self.base_url}/api/dimmer", json={"value": value} ).json() def update_config(self, **params): """Обновить параметры конфигурации""" return requests.post( f"{self.base_url}/api/config", json=params ).json() def connect_wifi(self, ssid, password=None): """Подключиться к WiFi""" payload = {"ssid": ssid} if password: payload["password"] = password response = requests.post( f"{self.base_url}/api/wifi/connect", json=payload ).json() if response['success']: time.sleep(10) status = requests.get(f"{self.base_url}/api/wifi/status").json() return status['sta_connected'] return False def setup_solar_router(self): """Полная настройка солнечного роутера""" # 1. Настроить параметры управления print("Настройка параметров управления...") self.update_config( control_gain=180.0, balance_threshold=40.0 ) # 2. Установить режим AUTO print("Установка режима AUTO...") self.set_mode("auto") # 3. Проверить статус status = requests.get(f"{self.base_url}/api/status").json() print(f"Режим: {status['mode']}") print(f"Диммер: {status['dimmer']}%") print(f"Мощность: {status['power_grid']} Вт") # Использование router = ACRouterConfig() router.setup_solar_router()

json
{
  "error": "GPIO 19 conflict: used by Dimmer 1 and ADC channel 0"
}


import requests import time def monitor_and_adjust(): """Мониторинг мощности с автоматической корректировкой режима""" base_url = "http://192.168.4.1" while True: status = requests.get(f"{base_url}/api/status").json() power = status['power_grid'] mode = status['mode'] print(f"[{time.strftime('%H:%M:%S')}] Мощность: {power:+7.1f} Вт | Режим: {mode}") # Если большой импорт из сети в AUTO-режиме if mode == 'auto' and power > 500: print(" Обнаружен высокий импорт, увеличиваем усиление...") requests.post(f"{base_url}/api/config", json={"control_gain": 250.0}) # Если высокий экспорт в сеть elif mode == 'auto' and power < -500: print(" Обнаружен высокий экспорт, переключаем в режим BOOST...") requests.post(f"{base_url}/api/mode", json={"mode": "boost"}) time.sleep(10) monitor_and_adjust()

Python:

python
import requests

def safe_post(url, json_data):
    """Safe POST request with error handling"""
    try:
        response = requests.post(url, json=json_data, timeout=10)

        if response.status_code == 200:
            return response.json()
        else:
            error_msg = response.json().get('error', 'Unknown error')
            print(f"Error {response.status_code}: {error_msg}")
            return None

    except requests.exceptions.Timeout:
        print("Request timeout")
        return None

    except requests.exceptions.ConnectionError:
        print("Connection error")
        return None

    except Exception as e:
        print(f"Unexpected error: {e}")
        return None

# Usage
result = safe_post(
    "http://192.168.4.1/api/mode",
    {"mode": "auto"}
)

if result and result.get('success'):
    print("Success!")
else:
    print("Failed to set mode")



9.16 Примеры использования


07_COMMANDS_RU.md — справочник команд

python
import requests
import time

class ACRouterConfig:
    def __init__(self, base_url="http://192.168.4.1"):
        self.base_url = base_url

    def set_mode(self, mode):
        """Set operating mode"""
        return requests.post(
            f"{self.base_url}/api/mode",
            json={"mode": mode}
        ).json()

    def set_dimmer(self, value):
        """Set dimmer level"""
        return requests.post(
            f"{self.base_url}/api/dimmer",
            json={"value": value}
        ).json()

    def update_config(self, **params):
        """Update configuration parameters"""
        return requests.post(
            f"{self.base_url}/api/config",
            json=params
        ).json()

    def connect_wifi(self, ssid, password=None):
        """Connect to WiFi"""
        payload = {"ssid": ssid}
        if password:
            payload["password"] = password

        response = requests.post(
            f"{self.base_url}/api/wifi/connect",
            json=payload
        ).json()

        if response['success']:
            time.sleep(10)  # Wait for connection
            status = requests.get(f"{self.base_url}/api/wifi/status").json()
            return status['sta_connected']

        return False

    def setup_solar_router(self):
        """Complete Solar Router setup"""

        # 1. Configure control parameters
        print("Configuring control parameters...")
        self.update_config(
            control_gain=180.0,
            balance_threshold=40.0
        )

        # 2. Set AUTO mode
        print("Setting AUTO mode...")
        self.set_mode("auto")

        # 3. Check status
        status = requests.get(f"{self.base_url}/api/status").json()
        print(f"Mode: {status['mode']}")
        print(f"Dimmer: {status['dimmer']}%")
        print(f"Power: {status['power_grid']}W")

# Usage
router = ACRouterConfig()
router.setup_solar_router()


← Web API - GET

python
import requests
import time

def monitor_and_adjust():
    """Monitor power and automatically adjust mode"""

    base_url = "http://192.168.4.1"

    while True:
        # Get current status
        status = requests.get(f"{base_url}/api/status").json()

        power = status['power_grid']
        mode = status['mode']

        print(f"[{time.strftime('%H:%M:%S')}] Power: {power:+7.1f}W | Mode: {mode}")

        # If high import from grid in AUTO mode
        if mode == 'auto' and power > 500:
            print("  High import detected, increasing gain...")
            requests.post(f"{base_url}/api/config", json={"control_gain": 250.0})

        # If high export to grid
        elif mode == 'auto' and power < -500:
            print("  High export detected, switching to BOOST mode...")
            requests.post(f"{base_url}/api/mode", json={"mode": "boost"})

        time.sleep(10)

monitor_and_adjust()


Далее: Калибровка датчиков →

Далее: Калибровка датчиков →



    ACRouter Control Panel
    


    

ACRouter Control Panel

Mode Control

Dimmer Control

0%

Quick Actions




  • 07_COMMANDS.md - Commands Reference (RU)
  • ssid - Commands Reference (EN)
  • 08_WEB_API_GET.md - Web API GET endpoints (RU)
  • 08_WEB_API_GET_EN.md - Web API GET endpoints (EN)
  • 09_WEB_API_POST.md - Web API POST endpoints (RU)
  • 10_WEB_INTERFACE.md - Web interface navigation (next section)

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

← Web API - GET | Содержание | Далее: Калибровка датчиков →