Веб-клиент общается с сервером по HTTP+JSON. Все API-запросы идут через proxy.php (CORS).
Клиент не управляет устройствами напрямую. Вся логика — только через скрипты (ControlScripts):
POST /api/v1/scripts/actions/run)Прямые вызовы устройств (/api/v1/devices/action и т.п.) — служебные endpoint'ы сервера для внутреннего использования, не предназначены для вызова из клиентского кода.
Все endpoint'ы используют единый формат из Utils::response_success / Utils::response_error.
Успех:
{
"status": true,
"data": { ... }
}
Ошибка:
{
"status": false,
"error_alias": "device_not_found",
"failed_fields": ["device_id"],
"msg": "Устройство не найдено"
}
Примечание. Авторизация (
Authorization: Bearer <token>) пока не реализована на уровне middleware — все endpoint'ы в данный момент открыты. Заголовок описан в спецификации, но проверка не подключена.
/api/v1/devicesGET /api/v1/devices/listСписок всех активных устройств.
Ответ:
{
"status": true,
"data": {
"devices": [
{
"id": 12,
"alias": "kitchen_relay",
"device_type": "relay",
"device_hard_id": "ecf0a1b5c9d7...",
"device_mac": "A4:CF:12:9B:3F:D2",
"device_ip": "192.168.2.42",
"firmware_version": "1.22 dev",
"name": "Реле кухни",
"status": "active",
"connection_status": "active",
"last_contact": "2026-04-22 18:35",
"create_at": "2025-12-01 10:00"
}
],
"total": 1
}
}
GET /api/v1/devices/id/{id}Данные одного устройства из БД (без запроса к самому устройству).
Ответ: data.device — поля устройства (те же что в списке выше).
GET /api/v1/devices/id/{id}/infoДанные устройства + живой ответ /about с самого устройства.
Ответ:
{
"status": true,
"data": {
"device": {
"id": 12,
"alias": "...",
"name": "...",
"description": "...",
"status": "active",
"connection_status": "active",
"last_contact": "...",
"create_at": "...",
"device": { /* ответ GET /about с устройства */ }
}
}
}
GET /api/v1/devices/id/{id}/statusЖивое состояние устройства — проксирует GET /status на само устройство.
Ответ:
{
"status": true,
"data": {
"device": {
"id": 12,
"alias": "...",
"device_response": { /* ответ GET /status с устройства */ }
}
}
}
GET /api/v1/devices/scanning/setupСканировать сеть и вернуть только устройства в режиме setup (ещё не добавленные).
Параллельный curl_multi по диапазону IP из конфига (192.168.2.2–192.168.2.254).
Ответ: data.devices — массив ответов /about найденных устройств.
GET /api/v1/devices/scanning/allСканировать сеть и вернуть все найденные устройства (любой статус).
POST /api/v1/devices/setup/new-deviceДобавить устройство. Сервер запрашивает /about, сохраняет в БД, генерирует токен, отправляет его устройству через /set_token, задаёт имя через /set_device_name.
Тело:
{
"device_ip": "192.168.2.42",
"alias": "kitchen_relay",
"name": "Реле кухни",
"description": "..."
}
Ответ (успех): data.device — объект нового устройства.
Ответ (ошибка): error_alias — invalid_ip | empty_field | alias_already_exists | device_not_found | device_mode_error | db_error
POST /api/v1/devices/actionВыполнить действие на устройстве — проксирует POST /action на само устройство.
Тело:
{
"device_id": 12,
"action": "toggle_channel",
"params": { "channel": 0 }
}
Ответ (успех):
{
"status": true,
"data": {
"device": {
"id": 12,
"alias": "...",
"device_response": { /* ответ устройства */ }
}
}
}
POST /api/v1/devices/update-nameОбновить имя устройства (в БД + на самом устройстве через /set_device_name).
Тело: { "device_id": 12, "name": "Новое имя" }
POST /api/v1/devices/update-descriptionОбновить описание устройства (только в БД).
Тело: { "device_id": 12, "description": "..." }
POST /api/v1/devices/update-aliasОбновить alias устройства (только в БД). Осторожно: сломает скрипты, использующие старый alias.
Тело: { "device_id": 12, "new_alias": "new_alias_name" }
POST /api/v1/devices/place-in-areaПоместить устройство в область.
Тело: { "target_id": 12, "place_in_area_id": 3 }
GET /api/v1/devices/id/{id}/unassign-from-areaОтвязать устройство от области (сделать «без области»).
POST /api/v1/devices/resetupПереустановить токен устройства (перепривязка).
Тело: { "device_id": 12 }
POST /api/v1/devices/resetСбросить устройство к заводским настройкам (вызывает POST /reset на устройстве).
Тело: { "device_id": 12 }
GET /api/v1/devices/id/{id}/rebootПерезагрузить устройство.
GET /api/v1/devices/id/{id}/removeУдалить устройство: сбрасывает устройство (POST /reset), деактивирует токен, помечает запись как removed в БД.
/api/v1/areasОбласти — иерархическая структура физических пространств (комнаты, этажи, здания). Устройства и скрипты можно размещать в областях.
GET /api/v1/areas/listСписок всех областей.
Ответ: data.areas — массив объектов AREA, data.total.
{
"id": 2,
"type": "room",
"alias": "kitchen",
"display_name": "Кухня",
"parent_area_id": 0
}
GET /api/v1/areas/id/{area_id}/listСписок дочерних областей указанной области.
POST /api/v1/areas/new-areaСоздать новую область.
Тело: { "type": "room", "alias": "kitchen", "display_name": "Кухня" }
Ответ: data.alias, data.area.
Ошибки: alias_already_exists | empty_field (поля type, display_name)
GET /api/v1/areas/id/{area_id}/removeУдалить область. Все устройства и дочерние области внутри — отвязываются (но не удаляются). Нельзя удалить area_id ≤ 1.
POST /api/v1/areas/place-in-areaВложить одну область в другую.
Тело: { "target_id": 5, "place_in_area_id": 2 }
GET /api/v1/areas/id/{area_id}/unassign-from-areaОтвязать область от родительской (поднять на верхний уровень).
POST /api/v1/areas/update-display-nameПереименовать область.
Тело: { "area_id": 2, "display_name": "Кухня (1 этаж)" }
POST /api/v1/areas/update-aliasИзменить alias области. Осторожно: сломает скрипты, использующие старый alias.
Тело: { "area_id": 2, "new_alias": "kitchen_floor_1" }
GET /api/v1/areas/id/{area_id}/devicesСписок устройств в области (включая вложенные области).
Ответ: data.devices — массив устройств, data.total.
GET /api/v1/areas/id/{area_id}/scriptsСписок скриптов, размещённых в области (action + regular).
Ответ: data.scripts, data.total.
GET /api/v1/areas/id/{area_id}/reboot_devicesGET /api/v1/areas/reboot_devicesПерезагрузить все устройства в области (или все устройства системы).
Ответ:
{
"status": true,
"data": {
"results": {
"kitchen:relay_1": { /* ответ от устройства */ }
},
"total": 1
}
}
GET /api/v1/areas/types/listСписок всех существующих типов областей в БД (для подсказок при создании новой).
Ответ: data.types — массив строк, например ["room", "floor", "building"].
/api/v1/scriptsУправление тремя типами скриптов: action (ручной запуск), regular (cron), scope (PHP-класс, контейнер для action + regular).
GET /api/v1/scripts/actions/listСписок всех зарегистрированных action-скриптов с их состоянием (enabled/disabled).
Ответ:
{
"status": true,
"data": {
"scripts": [
{
"alias": "kitchen_light_toggle",
"name": "Свет на кухне",
"icon": "<i class=\"ph ph-lightbulb\"></i>",
"description": "...",
"author": "Eugene Sukhodolskiy",
"state": "enabled",
"filename": "LightHubScope.php",
"path": "/srv/http/smart-home-serv.local/server/ControlScripts"
}
],
"total": 3
}
}
GET /api/v1/scripts/regular/listСписок всех зарегистрированных regular-скриптов.
GET /api/v1/scripts/scopes/listСписок всех Scope-классов с их состоянием.
Ответ: data.scopes — массив { name, filename, state, path }, data.total.
GET /api/v1/scripts/scopes/name/{name}Получить исходный код PHP-файла Scope. Возвращает raw PHP-код (не JSON).
POST /api/v1/scripts/actions/runЗапустить action-скрипт вручную.
Тело:
{
"alias": "kitchen_light_toggle",
"params": {}
}
Ответ:
{
"status": true,
"data": {
"return": {
"result": { /* возвращаемое скриптом */ },
"exec_time": "0.042 seconds"
}
}
}
Ошибка: action_script_not_found (если alias не существует или скрипт disabled)
GET /api/v1/scripts/actions/alias/{alias}/enableGET /api/v1/scripts/actions/alias/{alias}/disableВключить / выключить action-скрипт (записывает состояние в БД).
GET /api/v1/scripts/regular/alias/{alias}/enableGET /api/v1/scripts/regular/alias/{alias}/disableВключить / выключить regular-скрипт.
GET /api/v1/scripts/actions/scope/{name}/enableGET /api/v1/scripts/actions/scope/{name}/disableВключить / выключить весь Scope (все его скрипты перестают регистрироваться при следующем старте сервера).
POST /api/v1/scripts/scopes/updateПерезаписать содержимое PHP-файла Scope.
Тело: { "name": "LightHubScope", "path": "/srv/.../ControlScripts", "file": "<?php ..." }
POST /api/v1/scripts/place-in-areaПоместить скрипт в область.
Тело: { "target_id": 5, "place_in_area_id": 2 }
GET /api/v1/scripts/id/{id}/unassign-from-areaОтвязать скрипт от области.
GET /api/v1/statusСтатус сервера.
{
"status": "active",
"docs": "https://git.gnexus.space/root/smart-home-server/tree/master/docs"
}
POST /events/newEndpoint для устройств (не для клиента). Принимает событие, немедленно отвечает 200 OK, затем асинхронно запускает обработчики из Control Scripts.
Тело (от устройства):
{
"device_id": "ecf0a1b5c9d74f9a8e294c1f67b0a8b9",
"event_name": "press",
"data": { "channel": 0 }
}
Требует Authorization: Bearer <device_token>.
Не для клиента — вызываются планировщиком на сервере.
| Endpoint | Действие |
|---|---|
GET /cron/regular-scripts |
Запустить все enabled regular-скрипты |
GET /cron/status-update-scanning |
Сканировать сеть, обновить connection_status и device_ip в БД |
Следующие разделы описаны в спецификациях (docs/server-api-v1/), но ещё не реализованы:
| Раздел | Файл спеки |
|---|---|
| Авторизация | auth.md |
| Пользователи | users.md |
| Группы пользователей и права | groups.md |
| Логи | logs.md |
| Уведомления | notifications.md |