UNPKG

@constructorfleet/ultimate-govee

Version:

Library for interacting with Govee devices written in Typescript.

225 lines 8.66 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Device = exports.DefaultFactory = void 0; const rxjs_1 = require("rxjs"); const common_1 = require("@nestjs/common"); const _ultimate_govee_common_1 = require("../../common"); const equal_lib_1 = require("@santi100/equal-lib"); const _ultimate_govee_persist_1 = require("../../persist"); const device_state_1 = require("./states/device.state"); const mode_state_1 = require("./states/mode.state"); const device_refresh_event_1 = require("./cqrs/events/device-refresh.event"); const device_state_command_event_1 = require("./cqrs/events/device-state-command.event"); const device_state_changed_event_1 = require("./cqrs/events/device-state-changed.event"); const json_stringify_safe_1 = __importDefault(require("json-stringify-safe")); exports.DefaultFactory = 'default'; const buildStates = (stateFactories, device) => stateFactories .map((factory) => typeof factory === 'object' ? factory[device.model] ?? factory[exports.DefaultFactory] : factory) .filter((factory) => factory !== undefined) .map((factory) => Array.isArray(factory) ? factory.map((f) => f(device)) : factory(device)) .flat(); class Device extends rxjs_1.BehaviorSubject { get deviceType() { return Device.deviceType; } addState(state) { if (state instanceof device_state_1.DeviceOpState && state.identifier !== undefined && state.identifier !== null) { this.opIdentifiers.add(state.identifier); } this.subscriptions.push(this.device.status.subscribe((status) => state.parse(status))); this.deviceStates.set(state.name, state); this.subscriptions.push(state.subscribe(() => { this.next(this); })); this.subscriptions.push(state.clearCommand.subscribe((command) => { this.eventBus.publish(new device_state_changed_event_1.DeviceStateChangedEvent(this, command.state, command.value, command.commandId, this.isDebug)); })); this.subscriptions.push(state.commandBus.subscribe((cmd) => { if (this.isDebug) { this.logger.debug('Publishing state command'); } this.eventBus.publish(new device_state_command_event_1.DeviceStateCommandEvent(this.id, state.name, { deviceId: this.id, commandId: cmd.commandId, command: cmd.command, cmdVersion: cmd.cmdVersion ?? 0, type: cmd.type ?? 1, data: { ...cmd.data, ...(cmd.data.command !== undefined ? { command: cmd.data.command.map((x) => (0, _ultimate_govee_common_1.hexToBase64)(x)) } : {}), }, }, { iotTopic: this.iotTopic, bleAddress: this.bleAddress, }, this.isDebug)); setTimeout(() => this.refresh(), 2000); })); return state; } get id() { return this.device.id; } get model() { return this.device.model; } get name() { return this.device.name; } get goodsType() { return this.device.goodsType; } get pactCode() { return this.device.pactCode; } get images() { const resources = this.device.images; if (resources === undefined) { return {}; } return { sku: resources.imageUrl, on: resources.onImageUrl, off: resources.offImageUrl, }; } get pactType() { return this.device.pactType; } get iotTopic() { return this.device.iotTopic; } get bleAddress() { return this.device.bleAddress; } get version() { return this.device.version; } get states() { return Object.fromEntries(Array.from(this.deviceStates.entries())); } currentStates() { const result = Object.fromEntries(Object.entries(this.states ?? {}).map(([k, v]) => [ k, k === mode_state_1.ModeStateName ? v?.activeMode?.name : v?.value, ])); return result; } previousStates() { return Object.fromEntries(Object.entries(this.states ?? {}).map(([k, v]) => [ k, k === mode_state_1.ModeStateName ? v?.activeMode?.history.peekAll() : v?.history.peekAll(), ])); } state(stateName) { return this.deviceStates.get(stateName); } deviceStatus(status) { if (status.cmd !== 'status') { this.refresh$.next(); } else { this.device.status.next(status); } } refresh() { if (this.isDebug) { this.logger.debug(`Refreshing state ${this.iotTopic} ${this.bleAddress}`); } this.eventBus.publish(new device_refresh_event_1.DeviceRefeshEvent(this.id, this.model, this.goodsType, { iotTopic: this.iotTopic, bleAddress: this.bleAddress, }, Array.from(this.opIdentifiers), this.isDebug)); } setState(stateName, nextState) { return this.state(stateName)?.setState(nextState); } debug(isDebug) { this.isDebug = isDebug; return this; } constructor(device, eventBus, commandBus, stateFactories) { super(undefined); this.device = device; this.eventBus = eventBus; this.commandBus = commandBus; this.deviceStates = new _ultimate_govee_common_1.DeltaMap({ isModified: (current, previous) => !(0, equal_lib_1.deepEquality)(current.value, previous.value), }); this.opIdentifiers = new Set(); this.refresh$ = new rxjs_1.Subject(); this.subscriptions = []; this.isDebug = false; this.next(this); this.subscriptions.push(this.refresh$.pipe((0, rxjs_1.sampleTime)(2000)).subscribe(() => this.refresh())); this.logger = new common_1.Logger(`${this.constructor.name}-${device.name}`); buildStates(stateFactories, device).forEach((state) => { this.addState(state); state.parse({ cmd: 'status', ...device.status.value, }); }); this.subscriptions.push((0, rxjs_1.interval)(10000).subscribe(() => this.refresh())); this.subscriptions.push(this.deviceStates.delta$.subscribe(() => { this.next(this); })); this.subscribe(() => { this.logState(); }); } loggableState(deviceId) { const state = { deviceId, name: this.name, model: this.model, type: this.constructor.name, iotTopic: this.iotTopic, bleAddress: this.bleAddress, states: JSON.parse((0, json_stringify_safe_1.default)(this.currentStates() ?? {})), history: JSON.parse((0, json_stringify_safe_1.default)(this.previousStates() ?? {})), }; return state; } logState() { if (this.isDebug) { this.loggableState(this.id); } } closeSubscriptions() { this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } onModuleDestroy() { this.closeSubscriptions(); } } exports.Device = Device; Device.deviceType = 'unknown'; __decorate([ (0, _ultimate_govee_persist_1.PersistResult)({ filename: 'govee.{0}.state.json', }), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", void 0) ], Device.prototype, "loggableState", null); //# sourceMappingURL=device.js.map