@di-zed/yandex-smart-home
Version:
The Yandex Smart Home skills for the different device types.
197 lines (196 loc) • 9.44 kB
JavaScript
;
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();