Control WOL 프록시 전환
This commit is contained in:
@@ -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` 전용 토큰으로 서버 간 호출합니다.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user