diff --git a/src/api/helpers.ts b/src/api/helpers.ts index f8900da5..f54caa7a 100644 --- a/src/api/helpers.ts +++ b/src/api/helpers.ts @@ -2,8 +2,10 @@ import { ReadData } from './connection'; import { BinarySensorStateResponse, CoverStateResponse, + LegacyCoverState, LightStateResponse, ListEntitiesBinarySensorResponse, + ListEntitiesCoverResponse, ListEntitiesLightResponse, ListEntitiesSensorResponse, ListEntitiesSwitchResponse, @@ -16,7 +18,7 @@ import { ListEntityResponses, StateResponses } from './interfaces'; import { CommandInterface } from '../components'; import { Observable } from 'rxjs'; import { filter } from 'rxjs/operators'; -import { BaseComponent, BinarySensorComponent, LightComponent, SensorComponent, SwitchComponent } from '..'; +import { BaseComponent, BinarySensorComponent, CoverComponent, LightComponent, SensorComponent, SwitchComponent } from '..'; export const stateParser = (data: ReadData): StateResponses | undefined => { switch (data.type) { @@ -98,6 +100,19 @@ export const createComponents = ( component: new SensorComponent(response, state$, emptyCommandInterface), }; } + case MessageTypes.ListEntitiesCoverResponse: { + const response: ListEntitiesCoverResponse = decode(ListEntitiesCoverResponse, data); + const state$ = transformStates(stateEvents$, response); + return knownComponents.has(response.objectId) + ? { + id: response.objectId, + state$, + } + : { + id: response.objectId, + component: new CoverComponent(response, state$, connection), + }; + } } return { id: '' }; }; diff --git a/src/components/cover.ts b/src/components/cover.ts new file mode 100644 index 00000000..e6d649f9 --- /dev/null +++ b/src/components/cover.ts @@ -0,0 +1,68 @@ +import { BaseComponent } from './base'; +import { ComponentType, CoverEntity } from './entities'; +import { MessageTypes } from '../api'; +import { CoverCommandRequest, CoverOperation, LegacyCoverCommand } from '../api/protobuf/api'; +import { CoverStateEvent } from './states'; +import { title } from 'process'; + +export class CoverComponent extends BaseComponent { + public open(): void { + this.queueCommand(MessageTypes.CoverCommandRequest, () => + CoverCommandRequest.encode(this.generateState(LegacyCoverCommand.LEGACY_COVER_COMMAND_OPEN, 1.0)).finish(), + ); + } + + public close(): void { + this.queueCommand(MessageTypes.CoverCommandRequest, () => + CoverCommandRequest.encode(this.generateState(LegacyCoverCommand.LEGACY_COVER_COMMAND_CLOSE, 0.0)).finish(), + ); + } + + public stop(): void { + this.queueCommand(MessageTypes.CoverCommandRequest, () => + CoverCommandRequest.encode(this.generateState(LegacyCoverCommand.LEGACY_COVER_COMMAND_STOP, -1)).finish(), + ); + } + + public setPosition(position: number): void { + if (!this.supportsPosition) { + return; + } + + this.queueCommand(MessageTypes.CoverCommandRequest, () => + CoverCommandRequest.encode({ + ...this.generateState(LegacyCoverCommand.UNRECOGNIZED, position), + }).finish(), + ); + } + + public get assumedState(): boolean { + return this.listEntity.assumedState; + } + + public get supportsPosition(): boolean { + return this.listEntity.supportsPosition; + } + + public get supportsTilt(): boolean { + return this.listEntity.supportsTilt; + } + + public get type(): ComponentType { + return 'cover'; + } + + private generateState(command: LegacyCoverCommand, position: number): CoverCommandRequest { + const state = this.state.getValue(); + return { + key: this.key, + hasLegacyCommand: command ? true : false, + legacyCommand: command, + hasPosition: command != LegacyCoverCommand.LEGACY_COVER_COMMAND_STOP, + position: position, + hasTilt: false, + tilt: 0, + stop: command === LegacyCoverCommand.LEGACY_COVER_COMMAND_STOP, + }; + } +} diff --git a/src/components/entities.ts b/src/components/entities.ts index 4f05c492..cd175cd5 100644 --- a/src/components/entities.ts +++ b/src/components/entities.ts @@ -22,4 +22,10 @@ export interface LightEntity extends ListEntity { supportsRgb: boolean; } -export type ComponentType = 'light' | 'binarySensor' | 'sensor' | 'switch'; +export interface CoverEntity extends ListEntity { + assumedState: boolean; + supportsPosition: boolean; + supportsTilt: boolean; +} + +export type ComponentType = 'light' | 'binarySensor' | 'sensor' | 'switch' | 'cover'; diff --git a/src/components/index.ts b/src/components/index.ts index 5cf41719..69c5b5c2 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -2,6 +2,7 @@ export * from './base'; export * from './binarySensor'; export * from './binarySensorTypes'; export * from './commandInterface'; +export * from './cover'; export * from './entities'; export * from './helpers'; export * from './interfaces'; diff --git a/src/components/states.ts b/src/components/states.ts index 87e13466..2c59a9cf 100644 --- a/src/components/states.ts +++ b/src/components/states.ts @@ -1,3 +1,5 @@ +import { CoverOperation, LegacyCoverState } from "../api/protobuf/api"; + export interface StateEvent { key: number; } @@ -20,3 +22,10 @@ export interface LightStateEvent extends StateEvent { blue?: number; effect?: string; } + +export interface CoverStateEvent extends StateEvent { + state?: LegacyCoverState; + position?: number; + tilt?: number; + operationr?: CoverOperation; +} diff --git a/src/run.ts b/src/run.ts index 90e6d076..d49fee75 100644 --- a/src/run.ts +++ b/src/run.ts @@ -1,6 +1,7 @@ import { filter, take, tap } from 'rxjs/operators'; -import { LightComponent } from './components/light'; -import { EspDevice, isSwitchComponent, isTrue } from './api'; +import { EspDevice, isTrue } from './api'; +import { BaseComponent } from './components/base'; +import { CoverComponent } from './components/cover'; const device = new EspDevice('172.16.0.112'); device.discovery$ @@ -8,13 +9,13 @@ device.discovery$ filter(isTrue), take(1), tap(() => { - const kitchenLights = device.components['kitchen_lights:'] as LightComponent; - const livingRoomDehumidifier = device.components['living_room_dehumidifier']; - console.log(livingRoomDehumidifier.name); - - if (isSwitchComponent(livingRoomDehumidifier)) { - livingRoomDehumidifier.state$.pipe(tap(console.log)).subscribe(); - livingRoomDehumidifier.turnOff(); + for (const [key, value] of Object.entries(device.components)) { + console.log(key, value.type); + if (value instanceof CoverComponent) { + value.open(); + value.close(); + value.stop(); + } } }), )