findmydevice 고정밀 상태 토글과 5초 갱신

This commit is contained in:
seo
2026-07-10 20:32:08 +09:00
parent 2e93c4151f
commit eea0846e68
3 changed files with 34 additions and 6 deletions
+1 -1
View File
@@ -50,7 +50,7 @@ PWA standalone으로 진입한 경우에는 설치형 앱 사용성을 우선해
페이지 본문에는 `<div id="findmydevice"></div>`만 두면 됩니다. `main.js`는 이 컨테이너 안에 지도, 헤더, 설정/기록/위치/업데이트/배터리/활동 섹션과 iOS PWA 안내 영역을 항상 자동 생성합니다. 상단 복귀 링크는 `chaegeon.com`이면 채건닷컴, `/blog`이면 블로그처럼 알려진 경로명을 우선 표시하고, 같은 출처의 다른 이전 페이지는 문서 제목을 읽어 표시합니다. 직접 접속처럼 이전 페이지 확인이 어려우면 채건닷컴으로 표시하고 `https://chaegeon.com/`로 이동합니다.
위치 갱신 명령은 `/custom/common/config.php``findmydevice_location_refresh` 설정을 사용합니다. `seoul`, `main` Home Assistant 프로필의 `notify.mobile_app_seocaegeonyi_z_fold7` 서비스로 Companion App notification command를 보냅니다. 자동 업데이트는 서울 집과 목포 집 150m 반경 밖이고 충전 중이거나 `Niro` 블루투스가 연결되어 있을 때만 Android high accuracy mode를 5초 간격으로 설정하고 `force_on`, `request_location_update`, `command_update_sensors`를 호출합니다. 집 안이거나 충전 중도 아니고 `Niro`도 연결되어 있지 않으면 자동 명령은 `force_off`로 고정밀 위치 갱신을 끕니다.
위치 갱신 명령은 `/custom/common/config.php``findmydevice_location_refresh` 설정을 사용합니다. `seoul`, `main` Home Assistant 프로필의 `notify.mobile_app_seocaegeonyi_z_fold7` 서비스로 Companion App notification command를 보냅니다. 자동 업데이트는 서울 집과 목포 집 150m 반경 밖이고 충전 중이거나 `Niro` 블루투스가 연결되어 있을 때만 Android high accuracy mode를 5초 간격으로 설정하고 `force_on`, `request_location_update`, `command_update_sensors`를 호출합니다. 화면이 열려 있으면 5초마다 위치/센서 갱신 명령을 반복하고, HA 자동화도 30초마다 같은 조건을 확인합니다. 집 안이거나 충전 중도 아니고 `Niro`도 연결되어 있지 않으면 자동 명령은 `force_off`로 고정밀 위치 갱신을 끕니다.
집 판정 중심은 `/custom/common/config.php``findmydevice_home` 설정을 사용합니다. 현재 서울 집 좌표는 `37.558924572072, 127.20413804054`, 반경은 `150m`입니다. 목포 집은 Home Assistant `zone.home` 기준인 `34.80634217996409, 126.38442277908327`, 반경 `150m`를 고정밀 위치 갱신 제외 구역으로 사용합니다. API 응답의 `home` 값을 브라우저가 사용하므로 설정 변경 시 집 원, 체류/외출 판정, GPS 튐 흡수 기준이 같은 좌표로 적용됩니다.
+28 -5
View File
@@ -464,6 +464,7 @@ let langCode = localStorage.getItem("currentLang") || deviceLang,
lastLat,
lastLng,
lastUpdateISOTime,
highAccuracyModeActive = false,
map,
marker,
circle,
@@ -980,7 +981,12 @@ document.getElementById('wakeLockSwitch').addEventListener('change', async funct
document.getElementById('autoUpdateSwitch').addEventListener('change', () => {
syncUpdateBtn();
const isChecked = document.getElementById('autoUpdateSwitch')?.checked;
const switchEl = document.getElementById('autoUpdateSwitch');
const isChecked = switchEl?.checked;
if (switchEl?.disabled) {
return;
}
if (isChecked) {
callDeviceWebhook('auto_on');
@@ -995,7 +1001,7 @@ document.getElementById('autoUpdateSwitch').addEventListener('change', () => {
const switchEl = document.getElementById('autoUpdateSwitch');
const isAutoUpdateOn = switchEl?.checked;
if (isAutoUpdateOn) {
if (isAutoUpdateOn && !switchEl?.disabled) {
callDeviceWebhook('auto_off', true);
// 스위치 UI 강제 끔
@@ -1007,10 +1013,10 @@ document.getElementById('autoUpdateSwitch').addEventListener('change', () => {
setInterval(() => {
if (!findmydeviceAuthenticated) return;
if (document.getElementById('autoUpdateSwitch')?.checked) {
if (document.getElementById('autoUpdateSwitch')?.checked || highAccuracyModeActive) {
callDeviceWebhook('auto_tick');
}
}, 10000);
}, 5000);
setInterval(() => {
if (!findmydeviceAuthenticated) return;
@@ -1129,6 +1135,9 @@ function setCookieHours(name, value, hours) {
}
function updateDOM(data) {
highAccuracyModeActive = !!data.highAccuracyMode;
syncUpdateBtn();
const textMap = {
currentPosition: data.address,
lastUpdateTime: data.updated ? getRelativeTime(data.updated) : "-",
@@ -2480,7 +2489,21 @@ function syncLocateBtn() {
}
function syncUpdateBtn() {
const isChecked = document.getElementById('autoUpdateSwitch').checked;
const switchEl = document.getElementById('autoUpdateSwitch');
if (!switchEl) return;
if (highAccuracyModeActive) {
switchEl.dataset.highAccuracyLocked = '1';
switchEl.checked = true;
switchEl.disabled = true;
} else {
switchEl.disabled = false;
if (switchEl.dataset.highAccuracyLocked === '1') {
switchEl.checked = false;
delete switchEl.dataset.highAccuracyLocked;
}
}
const isChecked = switchEl.checked;
const parent = document.getElementById('autoUpdateBtn');
const exist = document.getElementById('updateBtn');
+5
View File
@@ -442,6 +442,7 @@ $fdescendedUrl = $entities['daily_floors'];
$stepsUrl = $entities['daily_steps'];
$distanceUrl = $entities['daily_distance'];
$triggerUrl = $entities['trigger'];
$highAccuracyModeUrl = $entities['high_accuracy_mode'] ?? 'binary_sensor.seocaegeonyi_z_fold7_high_accuracy_mode';
// GET 파라미터 읽기
$startParam = $_GET['startTime'] ?? null;
@@ -587,6 +588,7 @@ $ascendedData = getData($fascendedUrl);
$descendedData = getData($fdescendedUrl);
$stepsData = getData($stepsUrl);
$distanceData = getData($distanceUrl);
$highAccuracyModeData = getData($highAccuracyModeUrl);
$historySets = [];
if ($includeHistory) {
foreach ($findmydeviceHaProfiles as $profile) {
@@ -833,6 +835,7 @@ $activityState = $activityData['state'] ?? null;
$aaccuracyState = $activityData['attributes']['Confidence'] ?? $activityData['attributes']['confidence'] ?? null;
$connectionState = $connectionData['state'] ?? null;
$batteryState = $batteryStateData['state'] ?? null;
$highAccuracyMode = strtolower((string)($highAccuracyModeData['state'] ?? '')) === 'on';
$address = null;
@@ -890,6 +893,7 @@ if (isset($_GET['hashonly']) && $_GET['hashonly'] == '1') {
'activity' => $activityMap[$lang][$activityState] ?? $activityState ?? null,
'aaccuracy' => $aaccuracyMap[$lang][$aaccuracyState] ?? $aaccuracyState ?? null,
'connection' => $connectionMap[$lang][$connectionState] ?? $connectionState ?? null,
'highAccuracyMode' => $highAccuracyMode,
'sensors' => $sensorSections,
'home' => $findmydeviceHome,
]);
@@ -914,6 +918,7 @@ echo json_encode([
'activity' => $activityMap[$lang][$activityState] ?? $activityState ?? null,
'aaccuracy' => $aaccuracyMap[$lang][$aaccuracyState] ?? $aaccuracyState ?? null,
'connection' => $connectionMap[$lang][$connectionState] ?? $connectionState ?? null,
'highAccuracyMode' => $highAccuracyMode,
'sensors' => $sensorSections,
'home' => $findmydeviceHome,
'history' => $includeHistory ? $path : null,