feat(smarthome): add smart home features and Home Assistant integration (WebSocket protocol, discovery, factories, interfaces)
This commit is contained in:
421
ts/interfaces/smarthome.interfaces.ts
Normal file
421
ts/interfaces/smarthome.interfaces.ts
Normal file
@@ -0,0 +1,421 @@
|
||||
/**
|
||||
* Smart Home Device Interfaces
|
||||
* Generic types for smart home features (lights, climate, sensors, etc.)
|
||||
* Protocol-agnostic - can be implemented by Home Assistant, Hue, MQTT, etc.
|
||||
*/
|
||||
|
||||
import type { TFeatureState, IFeatureInfo } from './feature.interfaces.js';
|
||||
|
||||
// ============================================================================
|
||||
// Light Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TLightProtocol = 'home-assistant' | 'hue' | 'mqtt' | 'zigbee';
|
||||
|
||||
export interface ILightCapabilities {
|
||||
supportsBrightness: boolean;
|
||||
supportsColorTemp: boolean;
|
||||
supportsRgb: boolean;
|
||||
supportsHs: boolean; // Hue/Saturation
|
||||
supportsXy: boolean; // CIE xy color
|
||||
supportsEffects: boolean;
|
||||
supportsTransition: boolean;
|
||||
effects?: string[];
|
||||
minMireds?: number;
|
||||
maxMireds?: number;
|
||||
minColorTempKelvin?: number;
|
||||
maxColorTempKelvin?: number;
|
||||
}
|
||||
|
||||
export interface ILightState {
|
||||
isOn: boolean;
|
||||
brightness?: number; // 0-255
|
||||
colorTemp?: number; // Kelvin
|
||||
colorTempMireds?: number; // Mireds (1000000/Kelvin)
|
||||
rgbColor?: [number, number, number];
|
||||
hsColor?: [number, number]; // [hue 0-360, saturation 0-100]
|
||||
xyColor?: [number, number]; // CIE xy
|
||||
effect?: string;
|
||||
}
|
||||
|
||||
export interface ILightFeatureInfo extends IFeatureInfo {
|
||||
type: 'light';
|
||||
protocol: TLightProtocol;
|
||||
capabilities: ILightCapabilities;
|
||||
currentState: ILightState;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Climate/Thermostat Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TClimateProtocol = 'home-assistant' | 'nest' | 'ecobee' | 'mqtt';
|
||||
|
||||
export type THvacMode =
|
||||
| 'off'
|
||||
| 'heat'
|
||||
| 'cool'
|
||||
| 'heat_cool' // Auto dual setpoint
|
||||
| 'auto'
|
||||
| 'dry'
|
||||
| 'fan_only';
|
||||
|
||||
export type THvacAction =
|
||||
| 'off'
|
||||
| 'heating'
|
||||
| 'cooling'
|
||||
| 'drying'
|
||||
| 'idle'
|
||||
| 'fan';
|
||||
|
||||
export interface IClimateCapabilities {
|
||||
hvacModes: THvacMode[];
|
||||
presetModes?: string[]; // 'away', 'eco', 'boost', 'sleep'
|
||||
fanModes?: string[]; // 'auto', 'low', 'medium', 'high'
|
||||
swingModes?: string[]; // 'off', 'vertical', 'horizontal', 'both'
|
||||
supportsTargetTemp: boolean;
|
||||
supportsTargetTempRange: boolean; // For heat_cool mode
|
||||
supportsHumidity: boolean;
|
||||
supportsAuxHeat: boolean;
|
||||
minTemp: number;
|
||||
maxTemp: number;
|
||||
tempStep: number; // Temperature increment (e.g., 0.5, 1)
|
||||
minHumidity?: number;
|
||||
maxHumidity?: number;
|
||||
}
|
||||
|
||||
export interface IClimateState {
|
||||
currentTemp?: number;
|
||||
targetTemp?: number;
|
||||
targetTempHigh?: number; // For heat_cool mode
|
||||
targetTempLow?: number; // For heat_cool mode
|
||||
hvacMode: THvacMode;
|
||||
hvacAction?: THvacAction;
|
||||
presetMode?: string;
|
||||
fanMode?: string;
|
||||
swingMode?: string;
|
||||
humidity?: number;
|
||||
targetHumidity?: number;
|
||||
auxHeat?: boolean;
|
||||
}
|
||||
|
||||
export interface IClimateFeatureInfo extends IFeatureInfo {
|
||||
type: 'climate';
|
||||
protocol: TClimateProtocol;
|
||||
capabilities: IClimateCapabilities;
|
||||
currentState: IClimateState;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Sensor Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TSensorProtocol = 'home-assistant' | 'mqtt' | 'snmp';
|
||||
|
||||
export type TSensorDeviceClass =
|
||||
| 'temperature'
|
||||
| 'humidity'
|
||||
| 'pressure'
|
||||
| 'illuminance'
|
||||
| 'battery'
|
||||
| 'power'
|
||||
| 'energy'
|
||||
| 'voltage'
|
||||
| 'current'
|
||||
| 'frequency'
|
||||
| 'gas'
|
||||
| 'co2'
|
||||
| 'pm25'
|
||||
| 'pm10'
|
||||
| 'signal_strength'
|
||||
| 'timestamp'
|
||||
| 'duration'
|
||||
| 'distance'
|
||||
| 'speed'
|
||||
| 'weight'
|
||||
| 'monetary'
|
||||
| 'data_size'
|
||||
| 'data_rate'
|
||||
| 'water'
|
||||
| 'irradiance'
|
||||
| 'precipitation'
|
||||
| 'precipitation_intensity'
|
||||
| 'wind_speed';
|
||||
|
||||
export type TSensorStateClass =
|
||||
| 'measurement' // Instantaneous reading
|
||||
| 'total' // Cumulative total
|
||||
| 'total_increasing'; // Monotonically increasing total
|
||||
|
||||
export interface ISensorCapabilities {
|
||||
deviceClass?: TSensorDeviceClass;
|
||||
stateClass?: TSensorStateClass;
|
||||
unit?: string;
|
||||
nativeUnit?: string;
|
||||
precision?: number; // Decimal places
|
||||
}
|
||||
|
||||
export interface ISensorState {
|
||||
value: string | number | boolean;
|
||||
numericValue?: number;
|
||||
unit?: string;
|
||||
lastUpdated: Date;
|
||||
}
|
||||
|
||||
export interface ISensorFeatureInfo extends IFeatureInfo {
|
||||
type: 'sensor';
|
||||
protocol: TSensorProtocol;
|
||||
capabilities: ISensorCapabilities;
|
||||
currentState: ISensorState;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Camera Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TCameraProtocol = 'home-assistant' | 'onvif' | 'rtsp';
|
||||
|
||||
export interface ICameraCapabilities {
|
||||
supportsStream: boolean;
|
||||
supportsPtz: boolean; // Pan-tilt-zoom
|
||||
supportsSnapshot: boolean;
|
||||
supportsMotionDetection: boolean;
|
||||
frontendStreamType?: 'hls' | 'web_rtc';
|
||||
streamUrl?: string;
|
||||
}
|
||||
|
||||
export interface ICameraState {
|
||||
isRecording: boolean;
|
||||
isStreaming: boolean;
|
||||
motionDetected: boolean;
|
||||
}
|
||||
|
||||
export interface ICameraFeatureInfo extends IFeatureInfo {
|
||||
type: 'camera';
|
||||
protocol: TCameraProtocol;
|
||||
capabilities: ICameraCapabilities;
|
||||
currentState: ICameraState;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Cover/Blind Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TCoverProtocol = 'home-assistant' | 'mqtt' | 'somfy';
|
||||
|
||||
export type TCoverDeviceClass =
|
||||
| 'awning'
|
||||
| 'blind'
|
||||
| 'curtain'
|
||||
| 'damper'
|
||||
| 'door'
|
||||
| 'garage'
|
||||
| 'gate'
|
||||
| 'shade'
|
||||
| 'shutter'
|
||||
| 'window';
|
||||
|
||||
export type TCoverState = 'open' | 'opening' | 'closed' | 'closing' | 'stopped' | 'unknown';
|
||||
|
||||
export interface ICoverCapabilities {
|
||||
deviceClass?: TCoverDeviceClass;
|
||||
supportsOpen: boolean;
|
||||
supportsClose: boolean;
|
||||
supportsStop: boolean;
|
||||
supportsPosition: boolean; // set_cover_position
|
||||
supportsTilt: boolean; // set_cover_tilt_position
|
||||
}
|
||||
|
||||
export interface ICoverStateInfo {
|
||||
state: TCoverState;
|
||||
position?: number; // 0-100, 0 = closed, 100 = fully open
|
||||
tiltPosition?: number; // 0-100
|
||||
}
|
||||
|
||||
export interface ICoverFeatureInfo extends IFeatureInfo {
|
||||
type: 'cover';
|
||||
protocol: TCoverProtocol;
|
||||
capabilities: ICoverCapabilities;
|
||||
currentState: ICoverStateInfo;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Switch Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TSwitchProtocol = 'home-assistant' | 'mqtt' | 'tasmota' | 'tuya';
|
||||
|
||||
export type TSwitchDeviceClass = 'outlet' | 'switch';
|
||||
|
||||
export interface ISwitchCapabilities {
|
||||
deviceClass?: TSwitchDeviceClass;
|
||||
}
|
||||
|
||||
export interface ISwitchState {
|
||||
isOn: boolean;
|
||||
}
|
||||
|
||||
export interface ISwitchFeatureInfo extends IFeatureInfo {
|
||||
type: 'switch';
|
||||
protocol: TSwitchProtocol;
|
||||
capabilities: ISwitchCapabilities;
|
||||
currentState: ISwitchState;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Lock Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TLockProtocol = 'home-assistant' | 'mqtt' | 'august' | 'yale';
|
||||
|
||||
export type TLockState =
|
||||
| 'locked'
|
||||
| 'unlocked'
|
||||
| 'locking'
|
||||
| 'unlocking'
|
||||
| 'jammed'
|
||||
| 'unknown';
|
||||
|
||||
export interface ILockCapabilities {
|
||||
supportsOpen: boolean; // Physical open (some locks can open the door)
|
||||
}
|
||||
|
||||
export interface ILockStateInfo {
|
||||
state: TLockState;
|
||||
isLocked: boolean;
|
||||
}
|
||||
|
||||
export interface ILockFeatureInfo extends IFeatureInfo {
|
||||
type: 'lock';
|
||||
protocol: TLockProtocol;
|
||||
capabilities: ILockCapabilities;
|
||||
currentState: ILockStateInfo;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Fan Feature Types
|
||||
// ============================================================================
|
||||
|
||||
export type TFanProtocol = 'home-assistant' | 'mqtt' | 'bond';
|
||||
|
||||
export type TFanDirection = 'forward' | 'reverse';
|
||||
|
||||
export interface IFanCapabilities {
|
||||
supportsSpeed: boolean;
|
||||
supportsOscillate: boolean;
|
||||
supportsDirection: boolean;
|
||||
supportsPresetModes: boolean;
|
||||
presetModes?: string[];
|
||||
speedCount?: number; // Number of discrete speed levels
|
||||
}
|
||||
|
||||
export interface IFanState {
|
||||
isOn: boolean;
|
||||
percentage?: number; // 0-100 speed
|
||||
presetMode?: string;
|
||||
oscillating?: boolean;
|
||||
direction?: TFanDirection;
|
||||
}
|
||||
|
||||
export interface IFanFeatureInfo extends IFeatureInfo {
|
||||
type: 'fan';
|
||||
protocol: TFanProtocol;
|
||||
capabilities: IFanCapabilities;
|
||||
currentState: IFanState;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Protocol Client Interfaces (for dependency injection)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Light protocol client interface
|
||||
* Implemented by HomeAssistantProtocol, HueProtocol, etc.
|
||||
*/
|
||||
export interface ILightProtocolClient {
|
||||
turnOn(entityId: string, options?: { brightness?: number; colorTemp?: number; rgb?: [number, number, number]; transition?: number }): Promise<void>;
|
||||
turnOff(entityId: string, options?: { transition?: number }): Promise<void>;
|
||||
toggle(entityId: string): Promise<void>;
|
||||
setBrightness(entityId: string, brightness: number, transition?: number): Promise<void>;
|
||||
setColorTemp(entityId: string, kelvin: number, transition?: number): Promise<void>;
|
||||
setRgbColor(entityId: string, r: number, g: number, b: number, transition?: number): Promise<void>;
|
||||
setEffect(entityId: string, effect: string): Promise<void>;
|
||||
getState(entityId: string): Promise<ILightState>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Climate protocol client interface
|
||||
*/
|
||||
export interface IClimateProtocolClient {
|
||||
setHvacMode(entityId: string, mode: THvacMode): Promise<void>;
|
||||
setTargetTemp(entityId: string, temp: number): Promise<void>;
|
||||
setTargetTempRange(entityId: string, low: number, high: number): Promise<void>;
|
||||
setPresetMode(entityId: string, preset: string): Promise<void>;
|
||||
setFanMode(entityId: string, mode: string): Promise<void>;
|
||||
setSwingMode(entityId: string, mode: string): Promise<void>;
|
||||
setAuxHeat(entityId: string, enabled: boolean): Promise<void>;
|
||||
getState(entityId: string): Promise<IClimateState>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensor protocol client interface (read-only)
|
||||
*/
|
||||
export interface ISensorProtocolClient {
|
||||
getState(entityId: string): Promise<ISensorState>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Camera protocol client interface
|
||||
*/
|
||||
export interface ICameraProtocolClient {
|
||||
getSnapshot(entityId: string): Promise<Buffer>;
|
||||
getSnapshotUrl(entityId: string): Promise<string>;
|
||||
getStreamUrl(entityId: string): Promise<string>;
|
||||
getState(entityId: string): Promise<ICameraState>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cover protocol client interface
|
||||
*/
|
||||
export interface ICoverProtocolClient {
|
||||
open(entityId: string): Promise<void>;
|
||||
close(entityId: string): Promise<void>;
|
||||
stop(entityId: string): Promise<void>;
|
||||
setPosition(entityId: string, position: number): Promise<void>;
|
||||
setTiltPosition(entityId: string, position: number): Promise<void>;
|
||||
getState(entityId: string): Promise<ICoverStateInfo>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch protocol client interface
|
||||
*/
|
||||
export interface ISwitchProtocolClient {
|
||||
turnOn(entityId: string): Promise<void>;
|
||||
turnOff(entityId: string): Promise<void>;
|
||||
toggle(entityId: string): Promise<void>;
|
||||
getState(entityId: string): Promise<ISwitchState>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock protocol client interface
|
||||
*/
|
||||
export interface ILockProtocolClient {
|
||||
lock(entityId: string): Promise<void>;
|
||||
unlock(entityId: string): Promise<void>;
|
||||
open(entityId: string): Promise<void>; // Physical open if supported
|
||||
getState(entityId: string): Promise<ILockStateInfo>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fan protocol client interface
|
||||
*/
|
||||
export interface IFanProtocolClient {
|
||||
turnOn(entityId: string, percentage?: number): Promise<void>;
|
||||
turnOff(entityId: string): Promise<void>;
|
||||
toggle(entityId: string): Promise<void>;
|
||||
setPercentage(entityId: string, percentage: number): Promise<void>;
|
||||
setPresetMode(entityId: string, mode: string): Promise<void>;
|
||||
setOscillating(entityId: string, oscillating: boolean): Promise<void>;
|
||||
setDirection(entityId: string, direction: TFanDirection): Promise<void>;
|
||||
getState(entityId: string): Promise<IFanState>;
|
||||
}
|
||||
Reference in New Issue
Block a user