homebridge
Version:
HomeKit support for the impatient
107 lines • 4.55 kB
JavaScript
/**
* ServiceArea Cluster Behavior
*
* Handles service area selection for robotic vacuum cleaners
*/
import { ServiceAreaServer } from '@matter/main/behaviors/service-area';
import { Status, StatusResponseError } from '@matter/main/types';
import { MatterStatus } from '../errors.js';
import { getRegistryManager } from './EndpointContext.js';
/**
* Custom ServiceArea Server that calls plugin handlers
*/
export class HomebridgeServiceAreaServer extends ServiceAreaServer {
/**
* Get the registry for this behavior's endpoint
*/
getRegistry() {
return getRegistryManager(this.endpoint).getRegistry(this.endpoint.id);
}
/**
* Sync current service area state to cache for UI updates
* Helper method to avoid code duplication
*
* @param includeProgress - Whether to include progress information in the sync
*/
syncServiceAreaStateToCache(includeProgress = false) {
const endpointId = this.endpoint.id;
const registry = this.getRegistry();
const currentState = this.state;
const stateUpdate = {};
if (currentState.selectedAreas !== undefined) {
stateUpdate.selectedAreas = currentState.selectedAreas;
}
if (currentState.currentArea !== undefined) {
stateUpdate.currentArea = currentState.currentArea;
}
if (includeProgress && currentState.progress !== undefined) {
stateUpdate.progress = currentState.progress;
}
if (Object.keys(stateUpdate).length > 0) {
registry.syncStateToCache(endpointId, 'serviceArea', stateUpdate);
}
}
/**
* Handle select areas command
* Allows user to select which areas the vacuum should clean
*
* @param request - Area selection request with area IDs to clean
* @returns Response indicating success or failure
*/
async selectAreas(request) {
const endpointId = this.endpoint.id;
const registry = this.getRegistry();
try {
// Execute user handler
await registry.executeHandler(endpointId, 'serviceArea', 'selectAreas', request);
// Only reached if handler succeeded - call base implementation
const result = await super.selectAreas(request);
// Sync state to cache
this.syncServiceAreaStateToCache();
return result;
}
catch (error) {
// If user handler already threw a StatusResponseError, propagate it as-is
// This sends a proper Matter protocol error response to the controller
if (MatterStatus.isMatterProtocolError(error)) {
throw error;
}
// For other errors, wrap in appropriate StatusResponseError
// This prevents the endpoint from crashing and keeps the device online
const message = error instanceof Error ? error.message : String(error);
throw new StatusResponseError(`Failed to select areas: ${message}`, Status.Failure);
}
}
/**
* Handle skip area command
* Allows user to skip cleaning a specific area
*
* @param request - Skip area request with area ID to skip
* @returns Response indicating success or failure
*/
async skipArea(request) {
const endpointId = this.endpoint.id;
const registry = this.getRegistry();
try {
// Execute user handler
await registry.executeHandler(endpointId, 'serviceArea', 'skipArea', request);
// Only reached if handler succeeded - call base implementation
const result = await super.skipArea(request);
// Sync state to cache (include progress for skip operations)
this.syncServiceAreaStateToCache(true);
return result;
}
catch (error) {
// If user handler already threw a StatusResponseError, propagate it as-is
// This sends a proper Matter protocol error response to the controller
if (MatterStatus.isMatterProtocolError(error)) {
throw error;
}
// For other errors, wrap in appropriate StatusResponseError
// This prevents the endpoint from crashing and keeps the device online
const message = error instanceof Error ? error.message : String(error);
throw new StatusResponseError(`Failed to skip area: ${message}`, Status.Failure);
}
}
}
//# sourceMappingURL=ServiceAreaBehavior.js.map