UNPKG

@constructorfleet/ultimate-govee

Version:

Library for interacting with Govee devices written in Typescript.

190 lines 7.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DeviceOpState = exports.DeviceState = exports.filterCommands = void 0; const rxjs_1 = require("rxjs"); const _ultimate_govee_common_1 = require("../../../common"); const common_1 = require("@nestjs/common"); const uuid_1 = require("uuid"); const equal_lib_1 = require("@santi100/equal-lib"); const states_types_1 = require("./states.types"); const StatusCommand = 'status'; const filterCommands = (commands, type, identifier) => commands .filter((command) => { if (type === undefined) { return true; } const identifiers = identifier === undefined ? undefined : typeof identifier === 'number' ? [identifier] : identifier; const [cmdType, ...cmdIdentifiers] = command.slice(0, 1 + (identifiers?.length ?? 0)); if (cmdType !== type) { return false; } if (identifiers === undefined) { return false; } return cmdIdentifiers.every((i, index) => identifiers[index] < 0 || i === identifiers[index]); }) .map((command) => { if (type === undefined && identifier === undefined) { return command; } if (identifier === undefined) { return command.slice(1); } return command.slice(1 + (typeof identifier === 'number' ? 1 : identifier.length)); }); exports.filterCommands = filterCommands; class DeviceState { get isCommandable() { return this.stateToCommand !== undefined; } subscribe(observerOrNext) { const sub = this.stateValue .pipe((0, rxjs_1.distinctUntilChanged)((previous, current) => (0, equal_lib_1.deepEquality)(previous, current))) .subscribe(observerOrNext); this.subscriptions.push(sub); return sub; } get value() { return this.stateValue.getValue(); } constructor(device, name, initialValue, parseOption = states_types_1.ParseOption.state) { this.device = device; this.name = name; this.logger = new common_1.Logger(this.constructor.name); this.pendingCommands = new Map(); this.commandBus = new rxjs_1.Subject(); this.clearCommand$ = new rxjs_1.Subject(); this.clearCommand = (0, rxjs_1.connectable)(this.clearCommand$); this.history = new _ultimate_govee_common_1.FixedLengthStack(5); this.subscriptions = []; this.parseOption = parseOption; this.history.enstack(initialValue); this.stateValue = new _ultimate_govee_common_1.ForwardBehaviorSubject(initialValue); this.subscriptions.push(this.subscribe((state) => this.history.enstack(state))); this.subscriptions.push(this.device.status?.subscribe((status) => this.parse(status)), this.clearCommand.subscribe(({ commandId }) => this.pendingCommands.delete(commandId))); } previousState(last = 1) { let state = undefined; while (last > 0) { state = this.history.destack(); last--; } if (state === undefined) { return []; } return this.setState(state); } // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars parseState(data) { // no-op } parse(data) { if (data.cmd && data.cmd !== StatusCommand) { return; } const commandId = Array.from(this.pendingCommands.entries()) .filter(([_, statuses]) => statuses.some((s) => (0, _ultimate_govee_common_1.deepPartialCompare)(s.state, data.state))) .map(([commandId, _]) => commandId) .at(0); this.parseState(data); if (commandId !== undefined) { this.clearCommand$.next({ commandId, state: this.name, value: this.value, }); } } setState(nextState) { const commandAndStatus = this.stateToCommand === undefined ? undefined : this.stateToCommand(nextState); if (commandAndStatus === undefined) { return []; } const { command, status } = commandAndStatus; const commandId = (0, uuid_1.v4)(); const commands = (Array.isArray(command) ? command : [command]).map((cmd) => ({ commandId, ...cmd, })); this.pendingCommands.set(commandId, Array.isArray(status) ? status : [status]); return commands.map((cmd) => { this.commandBus.next(cmd); return cmd.commandId; }); } onModuleDestroy() { this.subscriptions .filter((sub) => sub !== undefined) .forEach((sub) => sub.unsubscribe()); } } exports.DeviceState = DeviceState; class DeviceOpState extends DeviceState { constructor({ opType, identifier }, device, name, initialValue, parseOption = states_types_1.ParseOption.opCode) { super(device, name, initialValue, parseOption); this.opType = opType; this.identifier = identifier; } // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars, no-unused-vars parseOpCommand(opCommand) { } // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars, no-unused-vars parseMultiOpCommand(opCommands) { } parse(data) { if (this.parseOption.hasFlag(states_types_1.ParseOption.none)) { return; } const commands = data.op?.command ?? []; const foundCommands = this.filterOpCommands(commands); if (commands.length > 0) { if (this.parseOption.hasFlag(states_types_1.ParseOption.opCode)) { foundCommands.forEach((command) => { const commandId = Array.from(this.pendingCommands.entries()).find(([_, statuses]) => statuses.some((s) => s.op?.command ?.at(0) ?.every((c, i) => c === undefined || command[i] === c)))?.[0]; this.parseOpCommand(command); if (commandId !== undefined) { this.clearCommand$.next({ commandId, state: this.name, value: this.value, }); } }); } else if (this.parseOption.hasFlag(states_types_1.ParseOption.multiOp)) { const commandIds = Array.from(this.pendingCommands.entries()) .filter(([_, statuses]) => foundCommands.filter((command) => statuses.some((s) => s.op?.command ?.at(0) ?.every((c, i) => c === undefined || command[i] === c)))) ?.map((entry) => entry[0]); this.parseMultiOpCommand(foundCommands); commandIds.forEach((commandId) => { if (commandId !== undefined) { this.clearCommand$.next({ commandId, state: this.name, value: this.value, }); } }); } } if (this.parseOption.hasFlag(states_types_1.ParseOption.state)) { this.parseState(data); } } filterOpCommands(opCommands) { if (this.opType === null) { return opCommands; } return (0, exports.filterCommands)(opCommands, this.opType, this.identifier ?? undefined); } } exports.DeviceOpState = DeviceOpState; //# sourceMappingURL=device.state.js.map