231 lines
8.1 KiB
PHP
Executable File
231 lines
8.1 KiB
PHP
Executable File
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/lib/bootstrap.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
function api_json(array $payload, int $status = 200): never
|
|
{
|
|
http_response_code($status);
|
|
echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
exit;
|
|
}
|
|
|
|
function api_input(): array
|
|
{
|
|
$raw = file_get_contents('php://input');
|
|
if ($raw === false || trim($raw) === '') {
|
|
return $_POST ?: [];
|
|
}
|
|
|
|
$decoded = json_decode($raw, true);
|
|
if (is_array($decoded)) {
|
|
return $decoded;
|
|
}
|
|
|
|
return $_POST ?: [];
|
|
}
|
|
|
|
try {
|
|
$config = app_load_config();
|
|
$client = new HomeAssistantClient($config);
|
|
$action = strtolower((string)($_GET['action'] ?? 'snapshot'));
|
|
|
|
if ($action === 'bootstrap') {
|
|
api_json(app_build_snapshot($config, $client, 'main'));
|
|
}
|
|
|
|
if ($action === 'snapshot') {
|
|
$spaceId = (string)($_GET['space_id'] ?? ($_GET['room_id'] ?? 'main'));
|
|
api_json(app_build_snapshot($config, $client, $spaceId));
|
|
}
|
|
|
|
if ($action === 'history') {
|
|
$entityId = trim((string)($_GET['entity_id'] ?? ''));
|
|
$hours = max(1, (int)($_GET['hours'] ?? 24));
|
|
|
|
if ($entityId === '') {
|
|
api_json(['ok' => false, 'error' => 'entity_id is required'], 400);
|
|
}
|
|
|
|
api_json([
|
|
'ok' => true,
|
|
'entity_id' => $entityId,
|
|
'hours' => $hours,
|
|
'history' => $client->fetchEntityHistory($entityId, $hours),
|
|
]);
|
|
}
|
|
|
|
if ($action === 'service') {
|
|
$payload = api_input();
|
|
$entityId = trim((string)($payload['entity_id'] ?? ''));
|
|
$command = trim((string)($payload['command'] ?? 'toggle'));
|
|
$value = $payload['value'] ?? null;
|
|
|
|
if ($entityId === '') {
|
|
api_json(['ok' => false, 'error' => 'entity_id is required'], 400);
|
|
}
|
|
|
|
[$domain, $service, $serviceData] = app_service_for_entity($entityId, $command);
|
|
if ($command === 'set_temperature' && $value !== null) {
|
|
$serviceData['temperature'] = $value;
|
|
}
|
|
if ($command === 'set_hvac_mode' && $value !== null) {
|
|
$serviceData['hvac_mode'] = $value;
|
|
}
|
|
if ($command === 'set_fan_mode' && $value !== null) {
|
|
$serviceData['fan_mode'] = $value;
|
|
}
|
|
if ($command === 'set_swing_mode' && $value !== null) {
|
|
$serviceData['swing_mode'] = $value;
|
|
}
|
|
if ($command === 'set_preset_mode' && $value !== null) {
|
|
$serviceData['preset_mode'] = $value;
|
|
}
|
|
if ($command === 'set_position' && $value !== null) {
|
|
$serviceData['position'] = $value;
|
|
}
|
|
|
|
$result = $client->callService($domain, $service, $serviceData);
|
|
api_json(['ok' => true, 'result' => $result]);
|
|
}
|
|
|
|
if ($action === 'save-entity-override') {
|
|
$payload = api_input();
|
|
$roomId = trim((string)($payload['room_id'] ?? ''));
|
|
$entityId = trim((string)($payload['entity_id'] ?? ''));
|
|
|
|
if ($roomId === '' || $entityId === '') {
|
|
api_json(['ok' => false, 'error' => 'room_id and entity_id are required'], 400);
|
|
}
|
|
|
|
$patch = [
|
|
'visible' => array_key_exists('visible', $payload) ? (bool)$payload['visible'] : null,
|
|
'order' => array_key_exists('order', $payload) ? (int)$payload['order'] : null,
|
|
'card_type' => array_key_exists('card_type', $payload) ? (string)$payload['card_type'] : null,
|
|
'title' => array_key_exists('title', $payload) ? (string)$payload['title'] : null,
|
|
'icon' => array_key_exists('icon', $payload) ? (string)$payload['icon'] : null,
|
|
];
|
|
|
|
$config = app_update_entity_override($config, $roomId, $entityId, $patch);
|
|
api_json(['ok' => true, 'config' => ['rooms' => $config['rooms']]]);
|
|
}
|
|
|
|
if ($action === 'save-space-override') {
|
|
$payload = api_input();
|
|
$roomId = trim((string)($payload['room_id'] ?? ''));
|
|
|
|
if ($roomId === '') {
|
|
api_json(['ok' => false, 'error' => 'room_id is required'], 400);
|
|
}
|
|
|
|
$patch = [
|
|
'visible' => array_key_exists('visible', $payload) ? (bool)$payload['visible'] : null,
|
|
'order' => array_key_exists('order', $payload) ? (int)$payload['order'] : null,
|
|
'name' => array_key_exists('name', $payload) ? (string)$payload['name'] : null,
|
|
'icon' => array_key_exists('icon', $payload) ? (string)$payload['icon'] : null,
|
|
];
|
|
|
|
if (array_key_exists('temperature_sensor_entity_id', $payload)) {
|
|
$patch['temperature_sensor_entity_id'] = (string)$payload['temperature_sensor_entity_id'];
|
|
}
|
|
|
|
$config = app_update_room_override($config, $roomId, $patch);
|
|
api_json(['ok' => true, 'config' => ['rooms' => $config['rooms']]]);
|
|
}
|
|
|
|
if ($action === 'create-room-layout-item') {
|
|
$payload = api_input();
|
|
$roomId = trim((string)($payload['room_id'] ?? ''));
|
|
|
|
if ($roomId === '') {
|
|
api_json(['ok' => false, 'error' => 'room_id is required'], 400);
|
|
}
|
|
|
|
$layoutItemId = trim((string)($payload['layout_item_id'] ?? ''));
|
|
if ($layoutItemId === '') {
|
|
$layoutItemId = 'slot_' . str_replace('.', '', uniqid('', true));
|
|
}
|
|
|
|
$order = array_key_exists('order', $payload) ? (int)$payload['order'] : null;
|
|
$config = app_update_room_layout_item($config, $roomId, $layoutItemId, [
|
|
'order' => $order,
|
|
]);
|
|
|
|
api_json([
|
|
'ok' => true,
|
|
'layout_item_id' => $layoutItemId,
|
|
'config' => ['rooms' => $config['rooms']],
|
|
]);
|
|
}
|
|
|
|
if ($action === 'save-room-layout-item') {
|
|
$payload = api_input();
|
|
$roomId = trim((string)($payload['room_id'] ?? ''));
|
|
$layoutItemId = trim((string)($payload['layout_item_id'] ?? ''));
|
|
|
|
if ($roomId === '' || $layoutItemId === '') {
|
|
api_json(['ok' => false, 'error' => 'room_id and layout_item_id are required'], 400);
|
|
}
|
|
|
|
$patch = [
|
|
'order' => array_key_exists('order', $payload) ? (int)$payload['order'] : null,
|
|
];
|
|
|
|
$config = app_update_room_layout_item($config, $roomId, $layoutItemId, $patch);
|
|
api_json(['ok' => true, 'config' => ['rooms' => $config['rooms']]]);
|
|
}
|
|
|
|
if ($action === 'delete-room-layout-item') {
|
|
$payload = api_input();
|
|
$roomId = trim((string)($payload['room_id'] ?? ''));
|
|
$layoutItemId = trim((string)($payload['layout_item_id'] ?? ''));
|
|
|
|
if ($roomId === '' || $layoutItemId === '') {
|
|
api_json(['ok' => false, 'error' => 'room_id and layout_item_id are required'], 400);
|
|
}
|
|
|
|
$config = app_delete_room_layout_item($config, $roomId, $layoutItemId);
|
|
api_json(['ok' => true, 'config' => ['rooms' => $config['rooms']]]);
|
|
}
|
|
|
|
if ($action === 'reorder-room-grid') {
|
|
$payload = api_input();
|
|
$roomId = trim((string)($payload['room_id'] ?? ''));
|
|
$entries = $payload['entries'] ?? [];
|
|
|
|
if ($roomId === '' || !is_array($entries)) {
|
|
api_json(['ok' => false, 'error' => 'room_id and entries are required'], 400);
|
|
}
|
|
|
|
$config = app_reorder_room_grid($config, $roomId, $entries);
|
|
api_json(['ok' => true, 'config' => ['rooms' => $config['rooms']]]);
|
|
}
|
|
|
|
if ($action === 'save-settings') {
|
|
$payload = api_input();
|
|
if (array_key_exists('edit_mode', $payload)) {
|
|
$config['app']['edit_mode'] = (bool)$payload['edit_mode'];
|
|
}
|
|
if (array_key_exists('title', $payload) && trim((string)$payload['title']) !== '') {
|
|
$config['app']['title'] = trim((string)$payload['title']);
|
|
}
|
|
app_save_config($config);
|
|
api_json(['ok' => true, 'settings' => $config['app']]);
|
|
}
|
|
|
|
if ($action === 'popup') {
|
|
$payload = api_input();
|
|
$popup = app_handle_popup_event($config, $payload);
|
|
api_json(['ok' => true, 'popup' => $popup]);
|
|
}
|
|
|
|
api_json(['ok' => false, 'error' => 'Unknown action'], 404);
|
|
} catch (Throwable $e) {
|
|
api_json([
|
|
'ok' => false,
|
|
'error' => $e->getMessage(),
|
|
], 500);
|
|
}
|