diff --git a/server/src/services/neatoService/index.js b/server/src/services/neatoService/index.js index 2b2e5560..2d0a8cb1 100644 --- a/server/src/services/neatoService/index.js +++ b/server/src/services/neatoService/index.js @@ -78,9 +78,36 @@ function hasEntity(entityIdValue) { return Boolean(readRaw(entityIdValue)); } +function isEntityAvailable(entityIdValue) { + const raw = readRaw(entityIdValue); + if (!raw) return false; + const state = String(raw.state ?? '').trim().toLowerCase(); + if (!state) return false; + return state !== 'unavailable'; +} + +function requiredEntityIds() { + return [ + ENTITY_IDS.buttons.start, + ENTITY_IDS.buttons.sendHome, + ENTITY_IDS.buttons.locate, + ENTITY_IDS.buttons.clearErrors, + ENTITY_IDS.sensors.batteryPercent, + ENTITY_IDS.sensors.batteryVoltage, + ENTITY_IDS.binarySensors.chargingActive, + ENTITY_IDS.binarySensors.extPowerPresent, + ENTITY_IDS.textSensors.uiState, + ENTITY_IDS.textSensors.robotError, + ENTITY_IDS.textSensors.robotAlert, + ].filter(Boolean); +} + function buildState() { const configured = Boolean(device); - const connected = isHomeAssistantConnected(); + const haConnected = isHomeAssistantConnected(); + const requiredIds = requiredEntityIds(); + const entitiesAvailable = requiredIds.length > 0 && requiredIds.every((id) => isEntityAvailable(id)); + const connected = Boolean(haConnected && entitiesAvailable); const enabled = Boolean(homeAssistantEnabled && configured); const controls = { diff --git a/webui/src/components/vip/VipNeatoCard.jsx b/webui/src/components/vip/VipNeatoCard.jsx index 5ceaac3b..ba92348f 100644 --- a/webui/src/components/vip/VipNeatoCard.jsx +++ b/webui/src/components/vip/VipNeatoCard.jsx @@ -1,7 +1,7 @@ // Vip Neato Card // Purpose: Defines the Vip Neato Card module and the local helpers/components used in this file. // Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit. -import { useMemo, useState } from 'react'; +import { useState } from 'react'; function normalizeState(value) { return String(value || '').trim(); @@ -56,7 +56,6 @@ export default function VipNeatoCard({ const charging = Boolean(neato?.telemetry?.chargingActive); const uiStateLabel = humanizeUiState(neato?.telemetry?.uiState); - const uiStateRaw = normalizeState(neato?.telemetry?.uiState).toUpperCase(); const battery = neato?.telemetry?.batteryPercent; const batteryLabel = Number.isFinite(battery) ? `${battery}%` : '--'; const voltage = neato?.telemetry?.batteryVoltage; @@ -73,29 +72,8 @@ export default function VipNeatoCard({ const canLocate = Boolean(controls?.locate?.available); const canClearErrors = Boolean(controls?.clearErrors?.available); - const primaryAction = useMemo(() => { - const looksDockedByState = uiStateRaw.includes('STATE_IDLE') || uiStateRaw.includes('STATE_STANDBY'); - if (docked || looksDockedByState) { - return { - key: 'start', - label: 'Start cleaning', - pending: 'Starting...', - toneClass: 'bg-emerald-600 hover:bg-emerald-500 text-white', - canRun: canStart, - fn: onStart, - }; - } - return { - key: 'home', - label: 'Send to dock', - pending: 'Sending...', - toneClass: 'bg-sky-600 hover:bg-sky-500 text-white', - canRun: canSendHome, - fn: onSendHome, - }; - }, [docked, uiStateRaw, canStart, onStart, canSendHome, onSendHome]); - - const canRunPrimary = configured && connected && primaryAction.canRun; + const canRunStart = configured && connected && canStart; + const canRunSendHome = configured && connected && canSendHome; const canRunLocate = configured && connected && canLocate; const canRunClearErrors = configured && connected && canClearErrors; @@ -125,7 +103,7 @@ export default function VipNeatoCard({

Neato Controls

-

Control the autonomous Neato robovac

+

Control the autonomous Neato robovac. Be nice to him.

-
-
-
-
State
-
{primaryState}
-
- +
+
+
State
+
{primaryState}
+
+
+ +
+
+ +
+
@@ -175,7 +165,12 @@ export default function VipNeatoCard({ - + - {!configured || !connected || !primaryAction.canRun || !canLocate || !canClearErrors ? ( + {!configured || !connected || !canStart || !canSendHome || !canLocate || !canClearErrors ? (

{!configured ? 'Set homeAssistant.neato.device in server config to enable Neato controls.'