Merge findmydevice data from both HA profiles
This commit is contained in:
+110
-16
@@ -26,7 +26,7 @@ function findmydevice_mobile_command(string $message, array $data = []): bool
|
||||
{
|
||||
$config = custom_config();
|
||||
$refresh = $config['findmydevice_location_refresh'] ?? [];
|
||||
$profile = (string)($refresh['profile'] ?? 'seoul');
|
||||
$profiles = (array)($refresh['profiles'] ?? [$refresh['profile'] ?? 'seoul']);
|
||||
$service = (string)($refresh['notify_service'] ?? '');
|
||||
|
||||
if ($service === '') {
|
||||
@@ -38,7 +38,12 @@ function findmydevice_mobile_command(string $message, array $data = []): bool
|
||||
$payload['data'] = $data;
|
||||
}
|
||||
|
||||
return custom_ha_service($profile, 'notify', $service, $payload, 5);
|
||||
$ok = false;
|
||||
foreach (array_values(array_unique(array_filter(array_map('strval', $profiles)))) as $profile) {
|
||||
$ok = custom_ha_service($profile, 'notify', $service, $payload, 5) || $ok;
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
function findmydevice_location_refresh(string $name): array
|
||||
@@ -100,14 +105,81 @@ if (isset($_GET['action']) && $_GET['action'] === 'webhook') {
|
||||
|
||||
$config = custom_config();
|
||||
$entities = $config['entities'];
|
||||
$allStates = custom_ha_request('seoul', 'GET', '/states') ?? [];
|
||||
$stateMap = [];
|
||||
foreach ($allStates as $stateRow) {
|
||||
if (isset($stateRow['entity_id'])) {
|
||||
$stateMap[$stateRow['entity_id']] = $stateRow;
|
||||
}
|
||||
$findmydeviceHaProfiles = ['seoul', 'main'];
|
||||
|
||||
function isMeaningfulHaValue($state): bool
|
||||
{
|
||||
return !($state === null || $state === '' || $state === 'unknown' || $state === 'unavailable' || $state === '<not connected>' || $state === '<not available>' || $state === 'none');
|
||||
}
|
||||
|
||||
function haRowTimestamp(array $row): int
|
||||
{
|
||||
$time = $row['last_updated'] ?? $row['last_changed'] ?? null;
|
||||
return $time ? (strtotime((string)$time) ?: 0) : 0;
|
||||
}
|
||||
|
||||
function mergeHaAttributes(array $primary, array $fallback): array
|
||||
{
|
||||
$attrs = is_array($primary['attributes'] ?? null) ? $primary['attributes'] : [];
|
||||
$fallbackAttrs = is_array($fallback['attributes'] ?? null) ? $fallback['attributes'] : [];
|
||||
|
||||
foreach ($fallbackAttrs as $key => $value) {
|
||||
if (!array_key_exists($key, $attrs) || !isMeaningfulHaValue($attrs[$key])) {
|
||||
$attrs[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $attrs;
|
||||
}
|
||||
|
||||
function mergeHaStateRow(?array $current, array $candidate): array
|
||||
{
|
||||
if ($current === null) {
|
||||
return $candidate;
|
||||
}
|
||||
|
||||
$currentMeaningful = isMeaningfulHaValue($current['state'] ?? null);
|
||||
$candidateMeaningful = isMeaningfulHaValue($candidate['state'] ?? null);
|
||||
|
||||
if ($candidateMeaningful && !$currentMeaningful) {
|
||||
$candidate['attributes'] = mergeHaAttributes($candidate, $current);
|
||||
return $candidate;
|
||||
}
|
||||
|
||||
if (!$candidateMeaningful && $currentMeaningful) {
|
||||
$current['attributes'] = mergeHaAttributes($current, $candidate);
|
||||
return $current;
|
||||
}
|
||||
|
||||
if (haRowTimestamp($candidate) > haRowTimestamp($current)) {
|
||||
$candidate['attributes'] = mergeHaAttributes($candidate, $current);
|
||||
return $candidate;
|
||||
}
|
||||
|
||||
$current['attributes'] = mergeHaAttributes($current, $candidate);
|
||||
return $current;
|
||||
}
|
||||
|
||||
function loadMergedStateMap(array $profiles): array
|
||||
{
|
||||
$stateMap = [];
|
||||
foreach ($profiles as $profile) {
|
||||
$allStates = custom_ha_request((string)$profile, 'GET', '/states') ?? [];
|
||||
foreach ($allStates as $stateRow) {
|
||||
if (!isset($stateRow['entity_id']) || !is_array($stateRow)) {
|
||||
continue;
|
||||
}
|
||||
$entityId = (string)$stateRow['entity_id'];
|
||||
$stateRow['_source_profile'] = (string)$profile;
|
||||
$stateMap[$entityId] = mergeHaStateRow($stateMap[$entityId] ?? null, $stateRow);
|
||||
}
|
||||
}
|
||||
|
||||
return $stateMap;
|
||||
}
|
||||
|
||||
$stateMap = loadMergedStateMap($findmydeviceHaProfiles);
|
||||
|
||||
// 엔드포인트 URL
|
||||
$deviceUrl = $entities['device'];
|
||||
$geoUrl = $entities['geo'];
|
||||
@@ -265,20 +337,41 @@ $ascendedData = getData($fascendedUrl);
|
||||
$descendedData = getData($fdescendedUrl);
|
||||
$stepsData = getData($stepsUrl);
|
||||
$distanceData = getData($distanceUrl);
|
||||
$historyData = $includeHistory ? (custom_ha_request('seoul', 'GET', $historyEndpoint, null, 0) ?? []) : [];
|
||||
$historySets = [];
|
||||
if ($includeHistory) {
|
||||
foreach ($findmydeviceHaProfiles as $profile) {
|
||||
$historySets[(string)$profile] = custom_ha_request((string)$profile, 'GET', $historyEndpoint, null, 0) ?? [];
|
||||
}
|
||||
}
|
||||
$triggerData = getData($triggerUrl);
|
||||
|
||||
// 경로 기록
|
||||
$path = [];
|
||||
if (isset($historyData[0])) {
|
||||
foreach ($historyData[0] as $item) {
|
||||
$lat = $item['attributes']['latitude'] ?? null;
|
||||
$lng = $item['attributes']['longitude'] ?? null;
|
||||
$time = $item['last_changed'] ?? null;
|
||||
if ($lat && $lng) {
|
||||
$path[] = ['lat' => $lat, 'lng' => $lng, 'time' => $time];
|
||||
$historySourceCounts = [];
|
||||
if ($historySets) {
|
||||
$pathByKey = [];
|
||||
foreach ($historySets as $profile => $historyData) {
|
||||
$historySourceCounts[$profile] = isset($historyData[0]) && is_array($historyData[0]) ? count($historyData[0]) : 0;
|
||||
if (!isset($historyData[0]) || !is_array($historyData[0])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($historyData[0] as $item) {
|
||||
$lat = $item['attributes']['latitude'] ?? null;
|
||||
$lng = $item['attributes']['longitude'] ?? null;
|
||||
$time = $item['last_changed'] ?? null;
|
||||
if ($lat && $lng && $time) {
|
||||
$timeKey = (string)(strtotime((string)$time) ?: $time);
|
||||
$key = $timeKey . ':' . round((float)$lat, 5) . ':' . round((float)$lng, 5);
|
||||
if (!isset($pathByKey[$key])) {
|
||||
$pathByKey[$key] = ['lat' => $lat, 'lng' => $lng, 'time' => $time, 'source' => $profile];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$path = array_values($pathByKey);
|
||||
usort($path, static function (array $a, array $b): int {
|
||||
return (strtotime((string)$a['time']) ?: 0) <=> (strtotime((string)$b['time']) ?: 0);
|
||||
});
|
||||
}
|
||||
|
||||
function pathDistanceM(array $a, array $b): float
|
||||
@@ -695,5 +788,6 @@ echo json_encode([
|
||||
'history' => $includeHistory ? $path : null,
|
||||
'historyRawCount' => $includeHistory ? $historyRawCount : null,
|
||||
'historyRenderCount' => $includeHistory ? count($path) : null,
|
||||
'historySourceCounts' => $includeHistory ? $historySourceCounts : null,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user