iobroker.lovelace
Version:
With this adapter you can build visualization for ioBroker with Home Assistant Lovelace UI
154 lines (140 loc) • 6.14 kB
JavaScript
const utils = require('./utils');
const adapterData = require('./../dataSingleton');
/**
* Create manual alarm_control_panel entity.
* @param id - id of "main" object, i.e. state.
* @param obj - iobroker object of id param
* @param entity - already created entity
* @param objects - id object cache
* @param custom - custom part of object.
* @returns {Promise<[entity]>}
*/
exports.processManualEntity = async function(id, obj, entity, objects, custom) {
const states = custom.states || {
state: id
};
objects[id] = obj; //keep hack for 'our' alarm object.
return fillEntityFromStates.call(this, states, objects, entity);
};
function fillEntityFromStates(states, objects, entity) {
// - alarm_control_panel =>
// STATE disarmed/armed/armed_home/armed_away/armed_night/armed_custom_bypass/pending/arming/disarming/triggered
// attributes: [code_format]
// commands: alarm_arm_away, alarm_arm_home, alarm_arm_night, alarm_arm_custom_bypass, alarm_disarm (code will be sent)
// we support only armed/disarmed
// the code must be in the object in native as alarm_code
entity.attributes.code_format = 'number';
if (states.state) {
const obj = objects[states.state];
if (obj && obj.common) {
if (obj.common.custom && obj.common.custom[adapterData.adapter.namespace]) {
entity.attributes.code_format = obj.common.custom[adapterData.adapter.namespace].code_format || 'number';
}
//boolean -> just true/false. Otherwise enter string.
entity.context.STATE.isBoolean = obj.common.type === 'boolean';
entity.context.STATE.map = obj.common.states;
}
entity.context.STATE.setId = states.state;
entity.context.STATE.getId = states.state;
utils.addID2entity(states.state, entity);
}
const getParser = (entity, attr, state) => {
if (!state) {
entity.state = 'unknown';
return;
}
if (state.val === true) {
entity.state = 'armed';
} else if (state.val === false) {
entity.state = 'disarmed';
} else {
if (attr.map && attr.map[state.val]) {
entity.state = attr.map[state.val]; //translate state using states map.
} else {
entity.state = state.val;
}
}
};
if (states.arm_state) {
const id = states.arm_state;
const obj = objects[id];
entity.context.ATTRIBUTES = [{
attribute: 'arm_state',
getId: id,
setId: id,
getParser,
map: obj ? obj.common ? obj.common.states : undefined : undefined
}];
utils.addID2entity(id, entity);
}
entity.context.STATE.getParser = getParser;
const processCommand = async (entity, command, data, user) => {
const targetState = data.service.replace('alarm_', '').replace('arm', 'armed');
// alarm_arm_away, alarm_arm_home, alarm_arm_night, alarm_arm_custom_bypass, alarm_disarm (code will be sent)
const id = entity.context.STATE.setId;
adapterData.log.debug(data.service + ': ' + id + ' = ' + data.service_data.code ? 'XXX' : 'none');
//require code to disarm.
if (!adapterData.adapter.config.alarmCheckCodeOnDisarmOnly || targetState.includes('disarm')) {
if ((data.service_data == null || data.service_data.code == null)) {
throw new Error('code is empty');
}
const obj = await adapterData.adapter.getForeignObjectAsync(id);
if (!obj.native.alarm_code) {
adapterData.log.warn(`No code is defined! To provide the code add to object ${id} native.alarm_code with desired code`);
throw new Error('iobroker misconfigured.');
} else if (obj.native.alarm_code.toString() !== data.service_data.code.toString()) {
throw new Error('invalid code');
}
}
//ok, now set some objects:
if (entity.context.STATE.isBoolean) {
await adapterData.adapter.setForeignStateAsync(entity.context.STATE.setId, !targetState.includes('disarm'), false, {user});
} else {
let valToSet = targetState;
if (entity.context.STATE.map) {
valToSet = Object.keys(entity.context.STATE.map).find(key => entity.context.STATE.map[key] === targetState);
if (!valToSet) {
valToSet = targetState;
}
}
await adapterData.adapter.setForeignStateAsync(entity.context.STATE.setId, valToSet, false, {user});
}
if (entity.context.ATTRIBUTES) {
const attr = entity.context.ATTRIBUTES.find(a => a.attribute === 'arm_state');
if (attr) {
let valToSet = targetState;
if (attr.map) {
valToSet = Object.keys(attr.map).find(key => attr.map[key] === targetState);
if (!valToSet) {
valToSet = targetState;
}
}
await adapterData.adapter.setForeignStateAsync(attr.setId, valToSet, false, {user});
}
}
};
if (!entity.context.COMMANDS) {
entity.context.COMMANDS = [];
}
entity.context.COMMANDS.push({
service: 'alarm_arm_away',
parseCommand: processCommand
});
entity.context.COMMANDS.push({
service: 'alarm_arm_home',
parseCommand: processCommand
});
entity.context.COMMANDS.push({
service: 'alarm_arm_night',
parseCommand: processCommand
});
entity.context.COMMANDS.push({
service: 'alarm_arm_custom_bypass',
parseCommand: processCommand
});
entity.context.COMMANDS.push({
service: 'alarm_disarm',
parseCommand: processCommand
});
return [entity];
}