UNPKG

@di-zed/yandex-smart-home

Version:

The Yandex Smart Home skills for the different device types.

197 lines (196 loc) 9.44 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * @author DiZed Team * @copyright Copyright (c) DiZed Team (https://github.com/di-zed/) */ const i18n_1 = __importDefault(require("i18n")); const configProvider_1 = __importDefault(require("../providers/configProvider")); const deviceRepository_1 = __importDefault(require("../repositories/deviceRepository")); const userRepository_1 = __importDefault(require("../repositories/userRepository")); const mqttService_1 = __importDefault(require("./mqttService")); const topicService_1 = __importDefault(require("./topicService")); /** * Device Service. */ class DeviceService { /** * Get Devices by User ID. * * @param userId * @returns Promise<Device[]> */ getUserDevices(userId) { return __awaiter(this, void 0, void 0, function* () { const user = yield userRepository_1.default.getUserById(userId); const devices = yield deviceRepository_1.default.getConfigDevices(); const functionGetUserDevices = configProvider_1.default.getConfigOption('functionGetUserDevices'); if (typeof functionGetUserDevices === 'function') { return (yield functionGetUserDevices(user, devices)); } const result = []; user.deviceIds.forEach((deviceId) => { const device = devices.find((element) => element.id === deviceId); if (device) { result.push(device); } }); return result; }); } /** * Get User Device by ID. * * @param userId * @param deviceId * @returns Promise<Device | undefined> */ getUserDeviceById(userId, deviceId) { return __awaiter(this, void 0, void 0, function* () { let result = undefined; const userDevices = yield this.getUserDevices(userId); userDevices.forEach((userDevice) => { if (userDevice.id === deviceId) { result = userDevice; } }); return result; }); } /** * Update User Device. * * @param user * @param device * @param deleteWrongProperties * @returns Device */ updateUserDevice(user_1, device_1) { return __awaiter(this, arguments, void 0, function* (user, device, deleteWrongProperties = true) { var _a, _b, _c, _d, _e; if (!(yield this.isDeviceAvailable(user, device))) { return { id: device.id, error_code: 'DEVICE_UNREACHABLE', error_message: i18n_1.default.__('The device "%s" is disconnected from power or the Internet.', device.id), }; } const deviceClone = JSON.parse(JSON.stringify(device)); const isStateTopicChecked = process.env.TOPIC_STATE_CHECK_IF_COMMAND_IS_UNDEFINED.trim() === '1'; /** * Update Capabilities. */ for (const capability of deviceClone.capabilities || []) { const capabilityTopicNames = yield mqttService_1.default.getTopicNames({ user: user, deviceId: device.id, capabilityType: capability.type, capabilityStateInstance: (_a = capability.state) === null || _a === void 0 ? void 0 : _a.instance, }); let capabilityTopicData = undefined; if (deviceClone.type) { capabilityTopicData = yield mqttService_1.default.getCommandTopicData(capabilityTopicNames.commandTopic, deviceClone.type, { capabilityType: capability.type, capabilityStateInstance: (_b = capability.state) === null || _b === void 0 ? void 0 : _b.instance, }); } let capabilityMessage = yield topicService_1.default.getTopicMessage(capabilityTopicNames.commandTopic); if (capabilityMessage === undefined && capabilityTopicData !== undefined && isStateTopicChecked) { capabilityMessage = yield topicService_1.default.getStateTopicValueByKey(capabilityTopicNames.stateTopic, capabilityTopicData.topicStateKeys); } if (capabilityMessage !== undefined) { capability.state.value = yield topicService_1.default.convertMqttMessageToAliceValue(capabilityMessage, capabilityTopicData); } } /** * Update Properties. */ const handledProperties = []; for (const property of deviceClone.properties || []) { const propertyTopicNames = yield mqttService_1.default.getTopicNames({ user: user, deviceId: device.id, propertyType: property.type, propertyStateInstance: (_c = property.state) === null || _c === void 0 ? void 0 : _c.instance, }); let propertyTopicData = undefined; if (deviceClone.type) { propertyTopicData = yield mqttService_1.default.getCommandTopicData(propertyTopicNames.commandTopic, deviceClone.type, { propertyType: property.type, propertyStateInstance: (_d = property.state) === null || _d === void 0 ? void 0 : _d.instance, }); } let propertyMessage = yield topicService_1.default.getTopicMessage(propertyTopicNames.commandTopic); if (propertyMessage === undefined && propertyTopicData !== undefined && isStateTopicChecked) { propertyMessage = yield topicService_1.default.getStateTopicValueByKey(propertyTopicNames.stateTopic, propertyTopicData.topicStateKeys); } if (propertyMessage !== undefined) { property.state.value = yield topicService_1.default.convertMqttMessageToAliceValue(propertyMessage, propertyTopicData); } /** * Skip the wrong property if needed. */ if (deleteWrongProperties) { if (property.type === 'devices.properties.event') { let isValidEventValue = false; for (const event of ((_e = property.parameters) === null || _e === void 0 ? void 0 : _e.events) || []) { if (event.value === property.state.value) { isValidEventValue = true; } } if (!isValidEventValue) { continue; } } } handledProperties.push(property); } deviceClone.properties = handledProperties; return deviceClone; }); } /** * Is Device Available? * * @param user * @param device * @returns Promise<boolean> */ isDeviceAvailable(user, device) { return __awaiter(this, void 0, void 0, function* () { let result = true; const topicNames = yield mqttService_1.default.getTopicNames({ user: user, deviceId: device.id, }); // For now, it has been decided to abandon using availableTopic to check availability, // since it can be updated differently on each device and be unpredictable. // Instead, we can look at stateTopic. It is NOT a retained topic. Therefore, we can check if this topic exists, // then this means that the device is online, if not, then it is not online. // if (topicNames.availableTopic) { // result = (await topicService.getTopicMessage(topicNames.availableTopic)) === 'online'; // } if (!topicNames.stateTopic || !(yield topicService_1.default.getTopicMessage(topicNames.stateTopic))) { result = false; } const callbackIsDeviceAvailable = configProvider_1.default.getConfigOption('callbackIsDeviceAvailable'); if (typeof callbackIsDeviceAvailable === 'function') { result = yield callbackIsDeviceAvailable(user, device, topicNames, result); } return result; }); } } exports.default = new DeviceService();