Skip to main content

Error Handling & Connection Status

Building reliable Home Assistant interfaces requires proper error handling and connection management. hass-react provides comprehensive tools for managing errors and monitoring connection status.

Error Types and Handling

hass-react provides specific error types to help you handle different scenarios appropriately. All custom errors extend HomeAssistantError and include:

  • message: Technical error message for logging/debugging
  • userMessage: User-friendly message safe to display in UI
  • recoverable: Whether the error can be retried (used by automatic retry logic)
  • retryAction: Suggested action to take ('retry', 'check_entity', 'check_network', 'check_config', 'contact_admin', or 'none')
  • code: Unique error code for programmatic handling
  • context: Additional error context data

Displaying User-Friendly Error Messages

import { getUserFriendlyErrorMessage } from 'hass-react';

function LightControl() {
const light = useLight('light.living_room');
const [error, setError] = useState(null);

const handleToggle = async () => {
try {
await light.toggle();
setError(null);
} catch (err) {
// Display user-friendly message in UI
setError(getUserFriendlyErrorMessage(err));
// Log technical details for debugging
console.error('Toggle failed:', err.message, err.context);
}
};

return (
<div>
<button onClick={handleToggle}>Toggle Light</button>
{error && <div className="error">{error}</div>}
</div>
);
}

Automatic Retry for Recoverable Errors

Service calls automatically retry recoverable errors with exponential backoff. You can configure retry behavior in HAProvider:

<HAProvider
url="http://homeassistant.local:8123"
options={{
serviceRetry: {
maxAttempts: 3, // Maximum retry attempts (default: 3)
baseDelay: 1000, // Initial delay in ms (default: 1000)
exponentialBackoff: true, // Use exponential backoff (default: true)
maxDelay: 10000 // Maximum delay in ms (default: 10000)
}
}}
>
<App />
</HAProvider>

The retry logic automatically handles:

  • Network timeouts
  • Temporary service unavailability (503, 502 errors)
  • Connection errors
  • Any error where error.recoverable === true

Non-retryable errors (like feature not supported, invalid parameters) fail immediately.

Connection Errors

import { ConnectionError } from 'hass-react';

function LightControl() {
const light = useLight('light.living_room');
const [error, setError] = useState(null);

const handleToggle = async () => {
try {
await light.toggle();
setError(null);
} catch (err) {
if (err instanceof ConnectionError) {
setError('Not connected to Home Assistant. Please check your connection.');
} else {
setError(`Failed to toggle light: ${err.message}`);
}
}
};

return (
<div>
<button onClick={handleToggle}>Toggle Light</button>
{error && <div className="error">{error}</div>}
</div>
);
}

Entity Availability Errors

function RobustSensorDisplay() {
const sensor = useSensor('sensor.temperature');
const { connected } = useHAConnection();

// Check for entity-level errors
if (sensor.error) {
return (
<div className="warning">
<h3>Sensor Unavailable</h3>
<p>{sensor.error.message}</p>
{connected && (
<p>The sensor may not exist or be temporarily offline.</p>
)}
</div>
);
}

// Check for connection issues
if (!connected) {
return (
<div className="info">
<p>Waiting for Home Assistant connection...</p>
</div>
);
}

return (
<div>
<h3>Temperature</h3>
<p>{sensor.value}° {sensor.unitOfMeasurement}</p>
</div>
);
}

Feature Support Errors

function SmartLightControl() {
const light = useLight('light.smart_bulb');
const [error, setError] = useState(null);

const handleColorChange = async (color) => {
if (!light.supportsRgb) {
setError('This light does not support color changes');
return;
}

try {
await light.setRgbColor(color);
setError(null);
} catch (err) {
setError(`Failed to change color: ${err.message}`);
}
};

return (
<div>
<h3>Smart Light</h3>
<button onClick={() => light.toggle()}>
{light.isOn ? 'Turn Off' : 'Turn On'}
</button>

{light.supportsRgb && (
<button onClick={() => handleColorChange([255, 0, 0])}>
Set Red
</button>
)}

{error && <div className="error">{error}</div>}
</div>
);
}

Monitoring Connection Status

Many errors are related to connection state. The useHAConnection hook provides complete access to your Home Assistant connection state:

import { useHAConnection } from 'hass-react';

function ConnectionStatus() {
const {
connected,
connecting,
error,
connectionState,
retryCount,
nextRetryIn,
isAutoRetrying,
reconnect,
config
} = useHAConnection();

if (connecting) {
return <div>Connecting to Home Assistant...</div>;
}

if (error) {
return (
<div className="error">
<p>Connection Error: {error.message}</p>
<button onClick={reconnect}>Retry Connection</button>
</div>
);
}

if (!connected) {
return <div>Disconnected from Home Assistant</div>;
}

return (
<div className="status">
<p>Connected to {config.url}</p>
<p>Retry count: {retryCount}</p>
{isAutoRetrying && nextRetryIn && (
<p>Auto-retry in {Math.ceil(nextRetryIn / 1000)} seconds</p>
)}
</div>
);
}

Connection States

The connectionState property provides detailed status information:

function DetailedConnectionStatus() {
const { connectionState, connected, connecting, error } = useHAConnection();

const getStatusMessage = () => {
switch (connectionState) {
case 'idle':
return 'Ready to connect';
case 'connecting':
return 'Establishing connection...';
case 'connected':
return 'Successfully connected';
case 'disconnected':
return 'Connection lost';
case 'error':
return `Connection failed: ${error?.message}`;
default:
return 'Unknown status';
}
};

const getStatusColor = () => {
switch (connectionState) {
case 'connected':
return 'green';
case 'connecting':
return 'orange';
case 'error':
return 'red';
default:
return 'gray';
}
};

return (
<div style={{ color: getStatusColor() }}>
<strong>{getStatusMessage()}</strong>
</div>
);
}

Connection Recovery UI

function App() {
const { connected, connecting, error, reconnect, isAutoRetrying, nextRetryIn } = useHAConnection();

if (!connected && !connecting) {
return (
<div className="connection-lost">
<h2>Connection Lost</h2>
<p>Unable to connect to Home Assistant</p>

{error && (
<div className="error-details">
<p>Error: {error.message}</p>
</div>
)}

{isAutoRetrying ? (
<div className="auto-retry">
<p>Auto-retrying in {Math.ceil((nextRetryIn || 0) / 1000)} seconds...</p>
<button onClick={reconnect}>Retry Now</button>
</div>
) : (
<button onClick={reconnect}>Reconnect</button>
)}
</div>
);
}

return <YourMainApp />;
}

Global Error Boundary

For handling unexpected errors throughout your app:

import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error, resetErrorBoundary }) {
const { connected, reconnect } = useHAConnection();

return (
<div className="error-boundary">
<h2>Something went wrong</h2>
<details>
<summary>Error details</summary>
<pre>{error.message}</pre>
</details>

{!connected ? (
<div>
<p>You appear to be disconnected from Home Assistant.</p>
<button onClick={reconnect}>Reconnect</button>
</div>
) : (
<button onClick={resetErrorBoundary}>Try Again</button>
)}
</div>
);
}

function App() {
return (
<HAProvider url="http://homeassistant.local:8123">
<ErrorBoundary FallbackComponent={ErrorFallback}>
<YourApp />
</ErrorBoundary>
</HAProvider>
);
}

Best Practices

1. Always Check Connection Status

function MyComponent() {
const { connected } = useHAConnection();
const light = useLight('light.living_room');

// Don't render controls when disconnected
if (!connected) {
return <div>Connecting to Home Assistant...</div>;
}

return <LightControls light={light} />;
}

2. Handle Entity Errors Gracefully

function EntityDisplay({ entityId }) {
const entity = useEntity(entityId);

if (entity.error) {
return (
<div className="entity-error">
<p>Warning: {entity.attributes.friendly_name || entityId}</p>
<small>{entity.error.message}</small>
</div>
);
}

return (
<div className="entity-display">
<p>{entity.attributes.friendly_name || entityId}</p>
<p>State: {entity.state}</p>
</div>
);
}

3. Provide User Feedback for Actions

function LightControl() {
const light = useLight('light.living_room');
const [error, setError] = useState(null);

const handleToggle = async () => {
try {
await light.toggle();
setError(null); // Clear any previous errors
} catch (err) {
setError(err.message);
}
};

return (
<div>
<button onClick={handleToggle}>
{light.isOn ? 'Turn Off' : 'Turn On'}
</button>
{error && (
<div className="error-message">
Failed to toggle light: {error}
</div>
)}
</div>
);
}

With proper error handling and connection management, your Home Assistant interface will be robust and provide a great user experience even when network issues occur.