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); $config = api_mirror_config_change($config, $action, $payload); app_save_config($config); 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); $config = api_mirror_config_change($config, $action, $payload); app_save_config($config); 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, ]); $config = api_mirror_config_change($config, $action, $payload); app_save_config($config); 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); $config = api_mirror_config_change($config, $action, $payload); app_save_config($config); 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); $config = api_mirror_config_change($config, $action, $payload); app_save_config($config); 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); $config = api_mirror_config_change($config, $action, $payload); app_save_config($config); 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']); } $config = api_mirror_config_change($config, $action, $payload); 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); }