Control WOL 프록시 전환

This commit is contained in:
seo
2026-07-22 01:17:58 +09:00
parent 8016ca69db
commit 299478d2ad
2 changed files with 97 additions and 13 deletions
+5 -5
View File
@@ -1,11 +1,11 @@
# Wake On LAN Proxy # Wake On LAN Proxy
Home Assistant의 PC 전원 스위치 엔티티를 켜는 얇은 프록시 API입니다. Control의 WOL API를 호출해 PC를 켜는 얇은 프록시 API입니다.
## 기능 ## 기능
- 현재 PC 전원 스위치 상태 조회 - 현재 LAN 클라이언트 상태 조회
- POST 요청 시 Home Assistant `switch.turn_on` 호출 - POST 요청 시 `https://seo.chaegeon.com/api.php?action=wake_lan` 호출
- 공통 인증 쿠키 확인 - 공통 인증 쿠키 확인
## 구조 ## 구조
@@ -14,10 +14,10 @@ Home Assistant의 PC 전원 스위치 엔티티를 켜는 얇은 프록시 API
## 공통 모듈 연동 ## 공통 모듈 연동
Home Assistant 주소, 토큰, 엔티티명, 인증 확인은 `/custom/common` 모듈을 사용합니다. Control API 주소, WOL 전용 토큰, 대상 MAC, 인증 확인은 `/custom/common` 모듈을 사용합니다.
`/custom/common/asset-version.php``wakeonlan` 서비스 버전 계산에는 `api.php`와 공통 인증/설정 파일이 포함됩니다. 이 프로젝트는 단독 브라우저 화면이 없는 API라서 자동 새로고침 스크립트는 직접 불러오지 않습니다. 런처 같은 호출 화면은 자기 서비스 기준으로 파일 변경을 감시합니다. `/custom/common/asset-version.php``wakeonlan` 서비스 버전 계산에는 `api.php`와 공통 인증/설정 파일이 포함됩니다. 이 프로젝트는 단독 브라우저 화면이 없는 API라서 자동 새로고침 스크립트는 직접 불러오지 않습니다. 런처 같은 호출 화면은 자기 서비스 기준으로 파일 변경을 감시합니다.
## 운영 메모 ## 운영 메모
직접 접근 가능한 전원 제어 API이므로 인증 없이 공개하면 안 됩니다. 현재는 공통 인증 쿠키가 있어야 호출니다. 직접 접근 가능한 전원 제어 API이므로 인증 없이 공개하면 안 됩니다. 현재는 공통 인증 쿠키가 있어야 호출되며, 실제 WOL 전송은 Control의 `wake_lan` 전용 토큰으로 서버 간 호출합니다.
+92 -8
View File
@@ -1,7 +1,6 @@
<?php <?php
require_once __DIR__ . '/../common/auth.php'; require_once __DIR__ . '/../common/auth.php';
require_once __DIR__ . '/../common/ha.php';
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store'); header('Cache-Control: no-store');
@@ -9,26 +8,111 @@ header('Cache-Control: no-store');
custom_require_auth(); custom_require_auth();
$config = custom_config(); $config = custom_config();
$entity = $config['entities']['wake_switch']; $wakeConfig = $config['control']['wake_lan'] ?? [];
$controlBase = rtrim((string)($wakeConfig['base'] ?? ''), '/');
$controlToken = (string)($wakeConfig['token'] ?? '');
$targetMac = strtolower((string)($wakeConfig['mac'] ?? ''));
$timeout = max(2, (int)($wakeConfig['timeout'] ?? 8));
function wake_control_request(string $method, string $action, array $params): ?array
{
global $controlBase, $controlToken, $timeout;
if ($controlBase === '' || $controlToken === '') {
return null;
}
$url = $controlBase . '/api.php?action=' . rawurlencode($action);
$body = http_build_query($params, '', '&');
if ($method === 'GET' && $body !== '') {
$url .= '&' . $body;
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'X-Control-API-Token: ' . $controlToken,
],
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Accept: application/json',
'Content-Type: application/x-www-form-urlencoded',
'X-Control-API-Token: ' . $controlToken,
]);
}
$raw = curl_exec($ch);
$status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if (!is_string($raw) || $raw === '') {
return null;
}
$decoded = json_decode($raw, true);
if (!is_array($decoded)) {
return null;
}
$decoded['_http_status'] = $status;
return $decoded;
}
if (isset($_GET['status'])) { if (isset($_GET['status'])) {
$state = custom_ha_state('seoul_wol', $entity); $res = wake_control_request('GET', 'wake_lan_status', [
if (!$state || !isset($state['state'])) { 'mac' => $targetMac,
]);
if (!$res || empty($res['ok'])) {
custom_json(['result' => 'error'], 502); custom_json(['result' => 'error'], 502);
} }
$wake = $res['data']['wake'] ?? [];
custom_json([ custom_json([
'result' => 'ok', 'result' => 'ok',
'state' => $state['state'], 'state' => (string)($wake['state'] ?? 'unknown'),
'wake' => $wake,
]); ]);
} }
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$res = custom_ha_request('seoul_wol', 'POST', '/services/switch/turn_on', [ $res = wake_control_request('POST', 'wake_lan', [
'entity_id' => $entity, 'mac' => $targetMac,
]); ]);
custom_json(['result' => $res === null ? 'error' : 'sent'], $res === null ? 502 : 200); if (!$res) {
custom_json(['result' => 'error'], 502);
}
if (!empty($res['ok'])) {
custom_json([
'result' => 'sent',
'wake' => $res['data']['wake'] ?? null,
]);
}
if (($res['message'] ?? '') === 'device_already_online') {
custom_json([
'result' => 'already',
'state' => 'on',
]);
}
custom_json([
'result' => 'error',
'message' => $res['message'] ?? $res['error'] ?? 'control_wake_failed',
], 502);
} }
custom_json(['result' => 'invalid_request'], 400); custom_json(['result' => 'invalid_request'], 400);