diff --git a/assets/app.css b/assets/app.css index 0e06f43..98866f8 100755 --- a/assets/app.css +++ b/assets/app.css @@ -1493,7 +1493,7 @@ body.is-mobile-ui #camera-modal { position: absolute; left: 0; right: 0; - top: 0; + bottom: 0; border-radius: inherit; background: linear-gradient(180deg, rgba(103, 214, 255, 0.96) 0%, rgba(126, 236, 220, 0.94) 58%, rgba(188, 255, 242, 0.96) 100%); @@ -1507,7 +1507,7 @@ body.is-mobile-ui #camera-modal { .entity-modal__cover-handle { position: absolute; left: 50%; - top: -10px; + bottom: -10px; width: 36px; height: 20px; border-radius: 999px; diff --git a/assets/app.js b/assets/app.js index e6d3570..0f4ab16 100755 --- a/assets/app.js +++ b/assets/app.js @@ -2355,10 +2355,7 @@ const rail = document.createElement('div'); rail.className = 'entity-modal__rail entity-modal__rail--cover'; - const currentPosition = Number(entity.attributes?.current_position); - const initialValue = Number.isFinite(currentPosition) - ? Math.max(0, Math.min(100, currentPosition)) - : (String(entity.state || '').toLowerCase() === 'open' ? 100 : 0); + const initialValue = coverPositionValue(entity); const valueRow = document.createElement('div'); valueRow.className = 'entity-modal__cover-meta'; @@ -2372,13 +2369,32 @@ value.textContent = `${initialValue}%`; valueRow.append(label, value); + const actions = document.createElement('div'); + actions.className = 'entity-modal__actions entity-modal__actions--vertical'; + + const openBtn = createButton('Открыть', null, 'mdi:arrow-up', 'mushroom-button mushroom-button--small mushroom-button--square'); + openBtn.addEventListener('click', () => handleEntityAction(entity, 'open')); + + const stopBtn = createButton('Стоп', null, 'mdi:stop', 'mushroom-button mushroom-button--small mushroom-button--square'); + stopBtn.addEventListener('click', () => handleEntityAction(entity, 'stop')); + + const closeBtn = createButton('Закрыть', null, 'mdi:arrow-down', 'mushroom-button mushroom-button--small mushroom-button--square'); + closeBtn.addEventListener('click', () => handleEntityAction(entity, 'close')); + + actions.append(openBtn, stopBtn, closeBtn); + const progress = document.createElement('div'); progress.className = 'entity-modal__cover-track'; + progress.tabIndex = 0; + progress.setAttribute('role', 'slider'); + progress.setAttribute('aria-label', 'Позиция жалюзи'); + progress.setAttribute('aria-valuemin', '0'); + progress.setAttribute('aria-valuemax', '100'); const fill = document.createElement('div'); fill.className = 'entity-modal__cover-fill'; fill.style.height = `${initialValue}%`; - fill.style.top = '0'; + fill.style.bottom = '0'; fill.style.width = '100%'; progress.appendChild(fill); @@ -2386,10 +2402,14 @@ handle.className = 'entity-modal__cover-handle'; progress.appendChild(handle); + let currentValue = initialValue; const syncValue = (nextValue) => { - fill.style.height = `${nextValue}%`; - handle.style.top = nextValue <= 0 ? 'calc(100% - 10px)' : `calc(${nextValue}% - 10px)`; - value.textContent = `${nextValue}%`; + currentValue = Math.max(0, Math.min(100, Math.round(nextValue))); + fill.style.height = `${currentValue}%`; + handle.style.bottom = `calc(${currentValue}% - 10px)`; + value.textContent = `${currentValue}%`; + progress.setAttribute('aria-valuenow', String(currentValue)); + progress.setAttribute('aria-valuetext', `${currentValue}%`); }; syncValue(initialValue); @@ -2398,7 +2418,6 @@ const ratio = 1 - ((clientY - rect.top) / rect.height); const nextValue = Math.max(0, Math.min(100, Math.round(ratio * 100))); syncValue(nextValue); - handleCoverPosition(entity, nextValue); }; let dragPointerId = null; @@ -2415,6 +2434,7 @@ window.removeEventListener('pointermove', onPointerMove); window.removeEventListener('pointerup', onPointerUp); window.removeEventListener('pointercancel', onPointerUp); + handleCoverPosition(entity, currentValue); }; progress.addEventListener('pointerdown', (event) => { @@ -2427,22 +2447,29 @@ window.addEventListener('pointercancel', onPointerUp, { passive: false }); }); + progress.addEventListener('keydown', (event) => { + const step = event.shiftKey ? 10 : 5; + if (event.key === 'ArrowUp' || event.key === 'ArrowRight') { + event.preventDefault(); + syncValue(currentValue + step); + handleCoverPosition(entity, currentValue); + } else if (event.key === 'ArrowDown' || event.key === 'ArrowLeft') { + event.preventDefault(); + syncValue(currentValue - step); + handleCoverPosition(entity, currentValue); + } else if (event.key === 'Home') { + event.preventDefault(); + syncValue(0); + handleCoverPosition(entity, 0); + } else if (event.key === 'End') { + event.preventDefault(); + syncValue(100); + handleCoverPosition(entity, 100); + } + }); + rail.append(valueRow, progress); - - const buttons = document.createElement('div'); - buttons.className = 'entity-modal__actions entity-modal__actions--vertical'; - - const openBtn = createButton('Открыть', null, 'mdi:arrow-up', 'mushroom-button mushroom-button--small mushroom-button--square'); - openBtn.addEventListener('click', () => handleEntityService(entity, 'open')); - - const stopBtn = createButton('Стоп', null, 'mdi:stop', 'mushroom-button mushroom-button--small mushroom-button--square'); - stopBtn.addEventListener('click', () => handleEntityService(entity, 'stop')); - - const closeBtn = createButton('Закрыть', null, 'mdi:arrow-down', 'mushroom-button mushroom-button--small mushroom-button--square'); - closeBtn.addEventListener('click', () => handleEntityService(entity, 'close')); - - buttons.append(openBtn, stopBtn, closeBtn); - wrap.append(rail, buttons); + wrap.append(rail, actions); return wrap; } @@ -2590,6 +2617,16 @@ return labels[key] || String(value ?? '—').replace(/_/g, ' '); } + function coverPositionValue(entity) { + const currentPosition = Number(entity?.attributes?.current_position); + if (Number.isFinite(currentPosition)) { + return Math.max(0, Math.min(100, Math.round(currentPosition))); + } + + const state = String(entity?.state || '').toLowerCase(); + return state === 'open' || state === 'opening' ? 100 : 0; + } + async function handleEntityService(entity, command, value = null, patch = null) { try { if (patch) { @@ -2762,11 +2799,10 @@ function renderCoverCard(entity, options = {}) { const card = document.createElement('article'); - const isOpen = ['open', 'opening'].includes(String(entity.state).toLowerCase()); - const currentPosition = Number(entity.attributes?.current_position); - const hasVisiblePosition = Number.isFinite(currentPosition) - ? currentPosition > 0 - : isOpen; + const currentPosition = coverPositionValue(entity); + const coverState = String(entity.state).toLowerCase(); + const isOpen = ['open', 'opening'].includes(coverState); + const hasVisiblePosition = currentPosition > 0 || isOpen; card.className = `grid-card grid-card--cover ${!options.isMain && isOpen ? 'is-active' : ''}`; card.dataset.entityId = entity.entity_id; card.tabIndex = 0; @@ -2796,7 +2832,7 @@ progress.className = 'cover-progress'; const bar = document.createElement('div'); bar.className = 'cover-progress__value'; - const pos = Number.isFinite(currentPosition) ? currentPosition : 100; + const pos = currentPosition > 0 ? currentPosition : 100; bar.style.width = `${Math.max(0, Math.min(100, pos))}%`; progress.appendChild(bar); diff --git a/index.php b/index.php index d44f22b..4480468 100755 --- a/index.php +++ b/index.php @@ -23,8 +23,8 @@ $appTitle = htmlspecialchars((string)($config['app']['title'] ?? 'Wall Panel'), - - + +
diff --git a/lib/config.php b/lib/config.php index 722cda3..27af67f 100755 --- a/lib/config.php +++ b/lib/config.php @@ -10,6 +10,7 @@ function app_default_config(): array 'main_room_name' => 'Главная', 'main_room_icon' => 'mdi:home', 'edit_mode' => false, + 'battery_history_hours' => 4320, ], 'home_assistant' => [ 'base_url' => '', @@ -114,4 +115,3 @@ function app_save_json_file(string $path, array $data): void file_put_contents($path, $json . PHP_EOL, LOCK_EX); } - diff --git a/lib/dashboard.php b/lib/dashboard.php index 984f50b..49a81f5 100755 --- a/lib/dashboard.php +++ b/lib/dashboard.php @@ -906,6 +906,11 @@ function app_battery_summary_text(array $counts, int $total): string : 'Нет батареек'; } +function app_battery_history_hours(array $config): int +{ + return max(24, (int)($config['app']['battery_history_hours'] ?? 4320)); +} + function app_battery_room(array $config, array $haData, array $rooms, HomeAssistantClient $client, bool $refreshForecast = false): array { $entityIndex = app_entity_index($config, $haData); @@ -927,6 +932,7 @@ function app_battery_room(array $config, array $haData, array $rooms, HomeAssist $cacheItems = is_array($cache['items'] ?? null) ? $cache['items'] : []; $cacheChanged = false; $now = time(); + $historyHours = app_battery_history_hours($config); $batteryEntities = []; $deviceGroups = []; @@ -1013,20 +1019,21 @@ function app_battery_room(array $config, array $haData, array $rooms, HomeAssist 'forecast_reason' => null, ]; - $shouldRefresh = $refreshForecast + $cachedAt = (int)($cacheEntry['loaded_at'] ?? 0); + $cacheMatchesWindow = (int)($cacheEntry['history_hours'] ?? 0) === $historyHours; + $freshEnough = $cachedAt > 0 && ($now - $cachedAt) < 6 * 3600 && $cacheMatchesWindow; + $shouldRefresh = ($refreshForecast || !$cacheMatchesWindow) && $percent !== null && !in_array($status, ['unavailable', 'unknown'], true); - $cachedAt = (int)($cacheEntry['loaded_at'] ?? 0); - $freshEnough = $cachedAt > 0 && ($now - $cachedAt) < 6 * 3600; - if ($shouldRefresh && (!$freshEnough || !isset($cacheEntry['forecast_minutes_left']))) { try { - $history = $client->fetchEntityHistory($entityId, 168); + $history = $client->fetchEntityHistory($entityId, $historyHours); $points = app_battery_history_points($history); $forecast = app_battery_forecast_from_points($points, $percent); $cacheItems[$entityId] = [ 'loaded_at' => $now, + 'history_hours' => $historyHours, 'points' => $points, 'forecast_minutes_left' => $forecast['forecast_minutes_left'], 'forecast_text' => $forecast['forecast_text'], @@ -1045,7 +1052,7 @@ function app_battery_room(array $config, array $haData, array $rooms, HomeAssist ]; } } - } elseif (is_array($cacheEntry) && isset($cacheEntry['forecast_minutes_left'])) { + } elseif ($cacheMatchesWindow && is_array($cacheEntry) && isset($cacheEntry['forecast_minutes_left'])) { $forecast = [ 'forecast_minutes_left' => isset($cacheEntry['forecast_minutes_left']) ? (int)$cacheEntry['forecast_minutes_left'] : null, 'forecast_text' => isset($cacheEntry['forecast_text']) ? (string)$cacheEntry['forecast_text'] : null, diff --git a/storage/battery_cache.json b/storage/battery_cache.json index 4d4aded..8fe16a8 100755 --- a/storage/battery_cache.json +++ b/storage/battery_cache.json @@ -1,10 +1,11 @@ { "items": { "sensor.garage_motion_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -22,15 +23,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.garage_light_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -48,15 +50,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.garage_door_motion_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -74,15 +77,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.stair_up_motion_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -100,15 +104,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.stair_down_motion_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -126,15 +131,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.stair_light_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -152,15 +158,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.door_sensor_2_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 90 }, { @@ -178,15 +185,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 90 }, "sensor.wleak_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -204,15 +212,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.0xa4c138433d675809_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 1 }, { @@ -235,10 +244,11 @@ "percent": 1 }, "sensor.0xa4c138997cb4fdd1_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -256,15 +266,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.printer_knopka_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 74 }, { @@ -282,41 +293,43 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": -0, - "forecast_reason": "Нет заметного разряда", - "percent": 74 - }, - "sensor.lestnitsa_dvizhenie_2_etazh_battery": { - "loaded_at": 1773993995, - "points": [ - { - "timestamp": 1773389195, - "value": 100 - }, - { - "timestamp": 1773411344, - "value": 100 - }, - { - "timestamp": 1773414678, - "value": 100 - }, - { - "timestamp": 1773417954, - "value": 100 - } - ], - "forecast_minutes_left": null, - "forecast_text": null, "forecast_slope_per_hour": 0, "forecast_reason": "Нет заметного разряда", + "percent": 74 + }, + "sensor.lestnitsa_dvizhenie_2_etazh_battery": { + "loaded_at": 1774008710, + "history_hours": 4320, + "points": [ + { + "timestamp": 1773403910, + "value": 100 + }, + { + "timestamp": 1773411344, + "value": 100 + }, + { + "timestamp": 1773414678, + "value": 100 + }, + { + "timestamp": 1773417954, + "value": 100 + } + ], + "forecast_minutes_left": null, + "forecast_text": null, + "forecast_slope_per_hour": -0, + "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.spalnia_knopka_girliand_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 29 }, { @@ -334,15 +347,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": -0, + "forecast_slope_per_hour": 0, "forecast_reason": "Нет заметного разряда", "percent": 29 }, "sensor.ulitsa_temperatura_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 63 }, { @@ -365,10 +379,11 @@ "percent": 63 }, "sensor.0x44e2f8fffeb65d8e_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008698, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403899, "value": 70 }, { @@ -394,35 +409,28 @@ { "timestamp": 1773466259, "value": 60 + }, + { + "timestamp": 1773488508, + "value": 65 + }, + { + "timestamp": 1773488530, + "value": 50 } ], - "forecast_minutes_left": 10497, - "forecast_text": "≈ 7д 6ч до разряда", - "forecast_slope_per_hour": -0.2572, + "forecast_minutes_left": 5642, + "forecast_text": "≈ 3д 22ч до разряда", + "forecast_slope_per_hour": -0.4786, "forecast_reason": null, "percent": 45 }, "sensor.0x54ef4410009a6a11_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008698, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, - "value": 95 - }, - { - "timestamp": 1773391484, - "value": 94 - }, - { - "timestamp": 1773394714, - "value": 95 - }, - { - "timestamp": 1773398043, - "value": 92 - }, - { - "timestamp": 1773401498, + "timestamp": 1773403899, "value": 95 }, { @@ -508,19 +516,36 @@ { "timestamp": 1773475444, "value": 93 + }, + { + "timestamp": 1773478854, + "value": 95 + }, + { + "timestamp": 1773481995, + "value": 90 + }, + { + "timestamp": 1773485044, + "value": 92 + }, + { + "timestamp": 1773488293, + "value": 70 } ], - "forecast_minutes_left": 121234, - "forecast_text": "≈ 84д 4ч до разряда", - "forecast_slope_per_hour": -0.046, + "forecast_minutes_left": 13952, + "forecast_text": "≈ 9д 16ч до разряда", + "forecast_slope_per_hour": -0.4043, "forecast_reason": null, - "percent": 93 + "percent": 94 }, "sensor.0x00124b0035558456_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 82 }, { @@ -538,15 +563,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 82 }, "sensor.0xa4c13874f5fdfd2a_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 92.5 }, { @@ -569,10 +595,11 @@ "percent": 92 }, "sensor.0x54ef44100119db20_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 100 }, { @@ -590,12 +617,13 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", "percent": 100 }, "sensor.door_sensor_spalnya_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [], "forecast_minutes_left": null, "forecast_text": null, @@ -604,10 +632,11 @@ "percent": 100 }, "sensor.0x0ceff6fffe6cffc4_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 45 }, { @@ -645,19 +674,28 @@ { "timestamp": 1773466260, "value": 45 + }, + { + "timestamp": 1773488510, + "value": 50 + }, + { + "timestamp": 1773488531, + "value": 45 } ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0.0849, + "forecast_slope_per_hour": 0.066, "forecast_reason": "Заряд не падает", - "percent": 50 + "percent": 55 }, "sensor.0x0ceff6fffe6cdee0_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 0 }, { @@ -677,21 +715,14 @@ "forecast_text": null, "forecast_slope_per_hour": 0, "forecast_reason": "Нет заметного разряда", - "percent": 55 + "percent": 60 }, "sensor.0x705464fffe43dee0_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008698, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, - "value": 50 - }, - { - "timestamp": 1773402386, - "value": 55 - }, - { - "timestamp": 1773402406, + "timestamp": 1773403899, "value": 50 }, { @@ -713,19 +744,28 @@ { "timestamp": 1773466239, "value": 50 + }, + { + "timestamp": 1773479774, + "value": 45 + }, + { + "timestamp": 1773488510, + "value": 50 } ], - "forecast_minutes_left": 44180, - "forecast_text": "≈ 30д 16ч до разряда", - "forecast_slope_per_hour": -0.0475, + "forecast_minutes_left": 15830, + "forecast_text": "≈ 10д 23ч до разряда", + "forecast_slope_per_hour": -0.1327, "forecast_reason": null, "percent": 35 }, "sensor.0xa4c138259d164c22_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 88.5 }, { @@ -743,41 +783,43 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, - "forecast_reason": "Нет заметного разряда", - "percent": 88.5 - }, - "sensor.0xa4c138fe1cdd2a21_battery": { - "loaded_at": 1773993995, - "points": [ - { - "timestamp": 1773389195, - "value": 87.5 - }, - { - "timestamp": 1773411344, - "value": 87.5 - }, - { - "timestamp": 1773414678, - "value": 87.5 - }, - { - "timestamp": 1773417954, - "value": 87.5 - } - ], - "forecast_minutes_left": null, - "forecast_text": null, "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", + "percent": 88.5 + }, + "sensor.0xa4c138fe1cdd2a21_battery": { + "loaded_at": 1774008710, + "history_hours": 4320, + "points": [ + { + "timestamp": 1773403910, + "value": 87.5 + }, + { + "timestamp": 1773411344, + "value": 87.5 + }, + { + "timestamp": 1773414678, + "value": 87.5 + }, + { + "timestamp": 1773417954, + "value": 87.5 + } + ], + "forecast_minutes_left": null, + "forecast_text": null, + "forecast_slope_per_hour": 0, + "forecast_reason": "Нет заметного разряда", "percent": 85.5 }, "sensor.spalnya_temp_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 3 }, { @@ -803,15 +845,16 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": null, - "forecast_reason": "Батарея уже разряжена", - "percent": 0 + "forecast_slope_per_hour": 0.348, + "forecast_reason": "Заряд не падает", + "percent": 3 }, "sensor.kukhnia_temperatura_battery": { - "loaded_at": 1773993995, + "loaded_at": 1774008710, + "history_hours": 4320, "points": [ { - "timestamp": 1773389195, + "timestamp": 1773403910, "value": 90 }, { @@ -829,9 +872,9 @@ ], "forecast_minutes_left": null, "forecast_text": null, - "forecast_slope_per_hour": 0, + "forecast_slope_per_hour": -0, "forecast_reason": "Нет заметного разряда", - "percent": 90 + "percent": 83 } } } diff --git a/storage/popup_state.json b/storage/popup_state.json index 8b4269f..6e3da04 100755 --- a/storage/popup_state.json +++ b/storage/popup_state.json @@ -1,6 +1,6 @@ { "active": false, - "sensor_entity_id": "binary_sensor.barn_all_occupancy", - "opened_at": 1774006226, + "sensor_entity_id": "binary_sensor.doorbell_all_occupancy", + "opened_at": 1774098512, "expires_at": null } diff --git a/wallpanell.code-workspace b/wallpanell.code-workspace new file mode 100755 index 0000000..876a149 --- /dev/null +++ b/wallpanell.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file