Return full findmydevice history paths
This commit is contained in:
@@ -42,9 +42,9 @@ Home Assistant에 기록된 Galaxy Z Fold7의 위치, 배터리, 활동 상태,
|
||||
|
||||
## 히스토리와 지도
|
||||
|
||||
실시간 화면은 현재 위치와 상태를 조회하고, 기본 기간 입력값에 해당하는 최근 하루 이동 기록도 지도에 함께 표시합니다. 기간 입력을 변경하면 해당 범위의 이동 기록을 `history=1` 옵션으로 다시 요청합니다. 서버는 Home Assistant 위치 기록을 5m 미만 미세 이동 기준으로 정리한 뒤 최대 800개 지점으로 샘플링합니다.
|
||||
실시간 화면은 현재 위치와 상태를 조회하고, 기본 기간 입력값에 해당하는 최근 하루 이동 기록도 지도에 함께 표시합니다. 기간 입력을 변경하면 해당 범위의 이동 기록을 `history=1` 옵션으로 다시 요청합니다. 서버는 기간이 길어도 Home Assistant 히스토리 API를 실행하고, 반환된 위치 기록을 샘플링하거나 최대 개수로 자르지 않고 응답합니다.
|
||||
|
||||
Naver Map에는 전체 경로선을 먼저 그리고 시작/종료 마커와 최대 180개의 중간 포인트를 표시합니다. 기록 조회 시 지도는 경로 전체가 보이도록 자동으로 범위를 맞추며, 종료 지점 정보창을 먼저 열어 최근 위치를 바로 확인할 수 있게 합니다.
|
||||
Naver Map에는 응답받은 전체 경로선을 먼저 그리고 시작/종료 마커와 중간 포인트를 표시합니다. 기록 조회 시 지도는 경로 전체가 보이도록 자동으로 범위를 맞추며, 종료 지점 정보창을 먼저 열어 최근 위치를 바로 확인할 수 있게 합니다.
|
||||
|
||||
지도 기능은 NAVER 지도 API v3의 기본 컨트롤, 지도 유형, `TrafficLayer`, `StreetLayer`, `Polyline`, `PointingIcon`, `Circle`, `fitBounds`를 활용합니다. 지도 아래 도구 패널에서 일반/위성 지도 전환, 교통 레이어, 거리뷰 가능 구역 레이어, 경로 전체 보기, 경로 재생, GPS 튐 보정, Naver 지도 열기를 제어합니다.
|
||||
|
||||
@@ -68,4 +68,6 @@ Android Companion App의 실제 상태값은 API에서 한국어/영어 표시
|
||||
|
||||
## 운영 메모
|
||||
|
||||
긴 기간 히스토리 조회는 Home Assistant recorder 데이터량과 웹서버/프록시 timeout 영향을 받을 수 있습니다. findmydevice API는 자체 포인트 수 제한과 curl timeout을 걸지 않으므로, 가능한 범위에서는 Home Assistant가 반환한 전체 결과를 화면에 출력합니다.
|
||||
|
||||
이 프로젝트는 위치, 주소, 배터리, 활동 기록을 포함하므로 private 저장소와 개인 접근 환경에서만 운영합니다.
|
||||
|
||||
@@ -2188,7 +2188,6 @@ function fetchDeviceData(includeLang = true, range = null) {
|
||||
if (e) params.set('endTime', e);
|
||||
if (hasHistoryRange) {
|
||||
params.set('history', '1');
|
||||
params.set('maxPoints', '800');
|
||||
}
|
||||
|
||||
const url = `https://chaegeon.com/custom/findmydevice/php/api.php?${params.toString()}`;
|
||||
|
||||
+5
-45
@@ -14,6 +14,10 @@ header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Expires: 0');
|
||||
|
||||
if (function_exists('set_time_limit')) {
|
||||
@set_time_limit(0);
|
||||
}
|
||||
|
||||
custom_require_auth();
|
||||
|
||||
$requestData = custom_read_request_data();
|
||||
@@ -77,7 +81,6 @@ if ($startParam && $endParam) {
|
||||
// API URL 생성
|
||||
$historyEndpoint = "/history/period/{$startTime}?filter_entity_id=" . rawurlencode($entities['device']) . "&end_time={$endTime}";
|
||||
$includeHistory = isset($_GET['history']) && $_GET['history'] === '1' && !isset($_GET['hashonly']);
|
||||
$historyMaxPoints = max(20, min(1200, (int)($_GET['maxPoints'] ?? 800)));
|
||||
|
||||
// 공통 요청 함수
|
||||
function getData($entityId) {
|
||||
@@ -202,7 +205,7 @@ $ascendedData = getData($fascendedUrl);
|
||||
$descendedData = getData($fdescendedUrl);
|
||||
$stepsData = getData($stepsUrl);
|
||||
$distanceData = getData($distanceUrl);
|
||||
$historyData = $includeHistory ? (custom_ha_request('seoul', 'GET', $historyEndpoint) ?? []) : [];
|
||||
$historyData = $includeHistory ? (custom_ha_request('seoul', 'GET', $historyEndpoint, null, 0) ?? []) : [];
|
||||
$triggerData = getData($triggerUrl);
|
||||
|
||||
// 경로 기록
|
||||
@@ -218,49 +221,6 @@ if (isset($historyData[0])) {
|
||||
}
|
||||
}
|
||||
|
||||
function path_distance_m(array $a, array $b): float
|
||||
{
|
||||
$earth = 6371000;
|
||||
$lat1 = deg2rad((float)$a['lat']);
|
||||
$lat2 = deg2rad((float)$b['lat']);
|
||||
$dLat = $lat2 - $lat1;
|
||||
$dLng = deg2rad((float)$b['lng'] - (float)$a['lng']);
|
||||
$h = sin($dLat / 2) ** 2 + cos($lat1) * cos($lat2) * sin($dLng / 2) ** 2;
|
||||
return 2 * $earth * asin(min(1, sqrt($h)));
|
||||
}
|
||||
|
||||
function simplify_path(array $path, int $maxPoints): array
|
||||
{
|
||||
$count = count($path);
|
||||
if ($count <= $maxPoints) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$filtered = [];
|
||||
$last = null;
|
||||
foreach ($path as $point) {
|
||||
if ($last === null || path_distance_m($last, $point) >= 5) {
|
||||
$filtered[] = $point;
|
||||
$last = $point;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($filtered) <= $maxPoints) {
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
$sampled = [];
|
||||
$lastIndex = count($filtered) - 1;
|
||||
for ($i = 0; $i < $maxPoints; $i++) {
|
||||
$idx = (int)round($i * $lastIndex / max(1, $maxPoints - 1));
|
||||
$sampled[] = $filtered[$idx];
|
||||
}
|
||||
|
||||
return $sampled;
|
||||
}
|
||||
|
||||
$path = simplify_path($path, $historyMaxPoints);
|
||||
|
||||
$lang = $_GET['lang'] ?? 'en';
|
||||
|
||||
$activityMap = [
|
||||
|
||||
Reference in New Issue
Block a user