# Hatch — API

Устройство управляет приводом люка через 3 реле:
- **Силовое реле** (GPIO18, хардкод) — коммутирует +питание к приводу, включается при любом движении
- **Реле "открыть"** — канал 0, подаёт плюс на сигнальный провод открытия
- **Реле "закрыть"** — канал 1, подаёт плюс на сигнальный провод закрытия

Позиция люка отслеживается по времени (0.00 — 35.00 сек). Концевик "закрыто" подключён как feedback-пин канала 1.

---

### `GET /status`

#### Пример ответа

```json
{
  "status": "ok",
  "hatch": {
    "state": "open",
    "position_sec": 17.50,
    "position_pct": 50
  }
}
```

| Поле | Тип | Описание |
|---|---|---|
| `state` | string | Текущее состояние люка (см. таблицу ниже) |
| `position_sec` | float | Текущая позиция в секундах (0.00 — 35.00) |
| `position_pct` | int | Позиция в процентах от максимума (0 — 100) |

**Возможные значения `state`:**

| Значение | Описание |
|---|---|
| `closed` | Люк закрыт (position_sec == 0) |
| `open` | Люк открыт, привод не движется |
| `opening` | Люк открывается |
| `closing` | Люк закрывается |
| `calibrating` | Выполняется калибровка (поиск нулевой точки) |

---

### `POST /action`

#### Открыть люк

Можно передать либо `time`, либо `percent` — на выбор. Если переданы оба, приоритет у `percent`.

```json
{
  "action": "open",
  "params": {
    "time": 10.0
  }
}
```

```json
{
  "action": "open",
  "params": {
    "percent": 50
  }
}
```

| Параметр | Тип | Описание |
|---|---|---|
| `time` | float | Время движения в секундах (> 0) |
| `percent` | float | Желаемое приращение открытия в % от максимума (> 0, макс. 100) |

Итоговая позиция: `min(position_sec + time, 35.0)` — потолок 35 сек при любом раскладе.

**Логика перед открытием:**
- Если концевик активен → позиция сбрасывается в 0, люк открывается
- Если `position_sec == 0` и концевик не активен → выполняется калибровка (закрытие до концевика, макс. `position_sec + 0.1` сек). При неудаче — ошибка `CalibrationFailed`
- Если `position_sec > 0` → люк открывается сразу без калибровки

**Возможные ошибки:**

```json
{ "status": "error", "error": "IllegalActionOrParams", "message": "Hatch is already fully open" }
```
```json
{ "status": "error", "error": "CalibrationFailed", "message": "Limit switch did not trigger during calibration" }
```
```json
{ "status": "error", "error": "DeviceBusy", "message": "Hatch is already moving" }
```

---

#### Закрыть люк

```json
{
  "action": "close",
  "params": {
    "time": 10.0
  }
}
```

```json
{
  "action": "close",
  "params": {
    "percent": 50
  }
}
```

| Параметр | Тип | Описание |
|---|---|---|
| `time` | float | Время движения в секундах (> 0) |
| `percent` | float | Желаемое приращение закрытия в % от максимума (> 0, макс. 100) |

Итоговая позиция: `max(position_sec - time, 0.0)`. Если концевик срабатывает раньше — движение останавливается досрочно, позиция сбрасывается в 0.

**Возможные ошибки:**

```json
{ "status": "error", "error": "IllegalActionOrParams", "message": "Hatch is already closed" }
```
```json
{ "status": "error", "error": "DeviceBusy", "message": "Hatch is already moving" }
```

---

### События от устройства к серверу

Устройство отправляет события на `POST /events/new` сервера.

#### Концевик сработал

Отправляется при срабатывании концевика во время закрытия или калибровки.

```json
{
  "device_type": "hatch",
  "device_id": "0123456789ABCDEF",
  "event_name": "limit_switch_activated",
  "data": {}
}
```

#### Калибровка не удалась

Отправляется если концевик не сработал в отведённое время при попытке калибровки перед открытием.

```json
{
  "device_type": "hatch",
  "device_id": "0123456789ABCDEF",
  "event_name": "calibration_failed",
  "data": {}
}
```

---

### Карта каналов (channels schema)

Настраивается через `POST /set_channels_schema` (стандартный эндпоинт sh_core).

| Канал | Назначение | PIN | FEEDBACK |
|---|---|---|---|
| 0 | Открыть | GPIO пин реле "открыть" | — |
| 1 | Закрыть | GPIO пин реле "закрыть" | GPIO пин концевика "закрыто" |

Силовое реле хардкодится в `hatch.ino` константой `HATCH_POWER_RELAY_PIN` (GPIO18).