Files
yandex2mqtt/device.js
Eugene Abramov 93c9d11b79 Add to initState
2022-06-05 23:17:31 +03:00

228 lines
7.4 KiB
JavaScript

const {logger} = global;
/* function for convert system values to Yandex (depends of capability or property type) */
function convertToYandexValue(val, actType) {
switch(actType) {
case 'range':
case 'float': {
if (val == undefined) return 0.0;
try {
const value = parseFloat(val);
return isNaN(value) ? 0.0 : value;
} catch(e) {
logger.log('error', {message: `Can't parse to float: ${val}`});
return 0.0;
}
}
case 'toggle':
case 'on_off': {
if (val == undefined) return false;
if (['true', 'on', '1'].indexOf(String(val).toLowerCase()) != -1) return true;
else return false;
}
default:
return val;
}
}
/* Device class defenition */
class Device {
constructor(options) {
const id = global.devices.length;
this.data = {
id: options.id || String(id),
name: options.name || 'Без названия',
description: options.description || '',
room: options.room || '',
type: options.type || 'devices.types.light',
custom_data: {
mqtt: options.mqtt || [],
valueMapping: options.valueMapping || [],
},
capabilities: (options.capabilities || []).map(c => Object.assign({}, c, {state: (c.state == undefined) ? this.initState(c) : c.state})),
properties: (options.properties || []).map(p => Object.assign({}, p, {state: (p.state == undefined) ? this.initState(p) : p.state})),
};
this.meta = {
allowedUsers: options.allowedUsers || ['1'],
};
}
/* Create init state (for capabilities and properties) on device object create */
initState(cp) {
const {type, parameters} = cp;
const actType = String(type).split('.')[2];
switch(actType) {
case 'float': {
return {
instance: parameters.instance,
value: 0
}
}
case 'on_off': {
return {
instance: 'on',
value: false
}
}
case 'mode': {
return {
instance: parameters.instance,
value: parameters.modes[0].value
}
}
case 'range': {
return {
instance: parameters.instance,
value: parameters.range.min
}
}
case 'toggle': {
return {
instance: parameters.instance,
value: false
}
}
case 'event': {
return {
instance: parameters.instance,
value: undefined
}
}
default: {
logger.log('error', {message: `Unsupported capability type: ${type}`});
return undefined;
}
}
}
/* Find capability by type (and instance) */
findCapability(type, instance) {
const {capabilities} = this.data;
if (instance != undefined) {
return capabilities.find(c => c.type === type && c.state.instance === instance);
} else {
return capabilities.find(c => c.type === type);
}
}
/* Find property by type (and instance) */
findProperty(type, instance) {
const {properties} = this.data;
if (instance != undefined) {
return properties.find(p => p.type === type && p.state.instance === instance);
} else {
return properties.find(p => p.type === type);
}
}
/* Find 'set' topic by instance*/
findTopicByInstance(instance) {
return this.data.custom_data.mqtt.find(i => i.instance === instance).set;
}
/* Get mapped value (if exist) for capability type */
/**
*
* @param {*} val value
* @param {*} actType capability type
* @param {*} y2m mapping direction (yandex to mqtt, mqtt to yandex)
*/
getMappedValue(val, actType, y2m) {
const map = this.data.custom_data.valueMapping.find(m => m.type == actType);
if (map == undefined) return val;
var from, to;
if (y2m == true) [from, to] = map.mapping;
else [to, from] = map.mapping;
const mappedValue = to[from.indexOf(val)];
return (mappedValue != undefined) ? mappedValue : val;
}
getInfo() {
const {id, name, description, room, type, capabilities, properties} = this.data;
return {id, name, description, room, type, capabilities, properties};
}
/* Get only needed for response device info (bun not full device defenition) */
getState () {
const {id, capabilities, properties} = this.data;
const device = {
id,
capabilities: (() => {
return capabilities.filter(c => c.retrievable === true).map(c => {
return {
type: c.type,
state: c.state
}
})
})() || [],
properties: (() => {
return properties.filter(p => p.retrievable === true).map(p => {
return {
type: p.type,
state: p.state
}
})
})() || [],
}
return device;
}
/* Change device capability state and publish value to MQTT topic */
setCapabilityState(val, type, instance) {
const {id} = this.data;
const actType = String(type).split('.')[2];
const value = this.getMappedValue(val, actType, true);
let message;
let topic;
try {
const capability = this.findCapability(type, instance);
if (capability == undefined) throw new Error(`Can't find capability '${type}' in device '${id}'`);
capability.state.value = value;
topic = this.findTopicByInstance(instance);
if (topic == undefined) throw new Error(`Can't find set topic for '${type}' in device '${id}'`);
message = `${value}`;
} catch(e) {
topic = false;
logger.log('error', {message: `${e}`});
}
if (topic) {
global.mqttClient.publish(topic, message);
}
return {
type,
'state': {
instance,
'action_result': {
'status': 'DONE'
}
}
}
}
/* Update device capability or property state */
updateState(val, instance) {
const {id, capabilities, properties} = this.data;
try {
const cp = [].concat(capabilities, properties).find(cp => (cp.state.instance === instance));
if (cp == undefined) throw new Error(`Can't instance '${instance}' in device '${id}'`);
const actType = String(cp.type).split('.')[2];
const value = this.getMappedValue(val, actType, false);
cp.state = {instance, value: convertToYandexValue(value, actType)};
} catch(e) {
logger.log('error', {message: `${e}`});
}
}
}
module.exports = Device;