Initial commit: Electron + React touchscreen kiosk dashboard for Home Assistant
This commit is contained in:
139
src/hooks/useEntity.ts
Normal file
139
src/hooks/useEntity.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useEntity as useEntityFromStore, useEntityState, useEntityAttribute } from '@/stores/haStore';
|
||||
import { HassEntity } from 'home-assistant-js-websocket';
|
||||
|
||||
/**
|
||||
* Hook for accessing a single Home Assistant entity
|
||||
*/
|
||||
export function useEntity(entityId: string): HassEntity | undefined {
|
||||
return useEntityFromStore(entityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for accessing entity state value
|
||||
*/
|
||||
export function useEntityStateValue(entityId: string): string | undefined {
|
||||
return useEntityState(entityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for accessing a specific entity attribute
|
||||
*/
|
||||
export function useEntityAttributeValue<T>(entityId: string, attribute: string): T | undefined {
|
||||
return useEntityAttribute<T>(entityId, attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for climate/thermostat entities
|
||||
*/
|
||||
export function useClimate(entityId: string) {
|
||||
const entity = useEntity(entityId);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!entity) return null;
|
||||
|
||||
return {
|
||||
state: entity.state,
|
||||
currentTemperature: entity.attributes.current_temperature as number | undefined,
|
||||
targetTemperature: entity.attributes.temperature as number | undefined,
|
||||
targetTempHigh: entity.attributes.target_temp_high as number | undefined,
|
||||
targetTempLow: entity.attributes.target_temp_low as number | undefined,
|
||||
hvacMode: entity.state as string,
|
||||
hvacModes: entity.attributes.hvac_modes as string[] | undefined,
|
||||
hvacAction: entity.attributes.hvac_action as string | undefined,
|
||||
minTemp: entity.attributes.min_temp as number | undefined,
|
||||
maxTemp: entity.attributes.max_temp as number | undefined,
|
||||
targetTempStep: entity.attributes.target_temp_step as number | undefined,
|
||||
friendlyName: entity.attributes.friendly_name as string | undefined,
|
||||
};
|
||||
}, [entity]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for light entities
|
||||
*/
|
||||
export function useLight(entityId: string) {
|
||||
const entity = useEntity(entityId);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!entity) return null;
|
||||
|
||||
return {
|
||||
state: entity.state,
|
||||
isOn: entity.state === 'on',
|
||||
brightness: entity.attributes.brightness as number | undefined,
|
||||
brightnessPct: entity.attributes.brightness
|
||||
? Math.round((entity.attributes.brightness as number) / 255 * 100)
|
||||
: undefined,
|
||||
colorMode: entity.attributes.color_mode as string | undefined,
|
||||
rgbColor: entity.attributes.rgb_color as [number, number, number] | undefined,
|
||||
friendlyName: entity.attributes.friendly_name as string | undefined,
|
||||
};
|
||||
}, [entity]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for lock entities
|
||||
*/
|
||||
export function useLock(entityId: string) {
|
||||
const entity = useEntity(entityId);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!entity) return null;
|
||||
|
||||
return {
|
||||
state: entity.state,
|
||||
isLocked: entity.state === 'locked',
|
||||
isUnlocked: entity.state === 'unlocked',
|
||||
isJammed: entity.state === 'jammed',
|
||||
isLocking: entity.state === 'locking',
|
||||
isUnlocking: entity.state === 'unlocking',
|
||||
friendlyName: entity.attributes.friendly_name as string | undefined,
|
||||
};
|
||||
}, [entity]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for alarm control panel entities (Alarmo)
|
||||
*/
|
||||
export function useAlarm(entityId: string) {
|
||||
const entity = useEntity(entityId);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!entity) return null;
|
||||
|
||||
return {
|
||||
state: entity.state,
|
||||
isDisarmed: entity.state === 'disarmed',
|
||||
isArmedHome: entity.state === 'armed_home',
|
||||
isArmedAway: entity.state === 'armed_away',
|
||||
isArmedNight: entity.state === 'armed_night',
|
||||
isPending: entity.state === 'pending' || entity.state === 'arming',
|
||||
isTriggered: entity.state === 'triggered',
|
||||
codeRequired: entity.attributes.code_arm_required as boolean | undefined,
|
||||
codeFormat: entity.attributes.code_format as string | undefined,
|
||||
changedBy: entity.attributes.changed_by as string | undefined,
|
||||
openSensors: entity.attributes.open_sensors as Record<string, string> | undefined,
|
||||
friendlyName: entity.attributes.friendly_name as string | undefined,
|
||||
};
|
||||
}, [entity]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for binary sensor entities
|
||||
*/
|
||||
export function useBinarySensor(entityId: string) {
|
||||
const entity = useEntity(entityId);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!entity) return null;
|
||||
|
||||
return {
|
||||
state: entity.state,
|
||||
isOn: entity.state === 'on',
|
||||
isOff: entity.state === 'off',
|
||||
deviceClass: entity.attributes.device_class as string | undefined,
|
||||
friendlyName: entity.attributes.friendly_name as string | undefined,
|
||||
};
|
||||
}, [entity]);
|
||||
}
|
||||
Reference in New Issue
Block a user