UNPKG

iobroker.lovelace

Version:

With this adapter you can build visualization for ioBroker with Home Assistant Lovelace UI

312 lines (298 loc) 10.9 kB
const utils = require('./../entities/utils'); const adapterData = require('./../dataSingleton'); /** * Create manual alarm_control_panel entity. * * @param id {string} - id of "main" object, i.e. state. * @param obj {ioBroker.Object} - iobroker object of id param * @param entity {object} - already created entity * @param objects {Record<string, ioBroker.Object>} - id object cache * @param custom {object} - custom part of object. * @returns {Promise<[entity]>} - created entity in array. */ 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); }; /** * Augment the entity from the functions found / defined. * * @param states {Record<string, string>} - translation from function to ioBroker.Object ids. * @param objects {Record<string, ioBroker.Object>} - id object cache. * @param entity {object} - already created entity. * @returns {*[]} - created entity in array. */ 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 if (entity.context.STATE.map && entity.context.STATE.map[state.val]) { entity.state = entity.context.STATE.map[state.val]; } 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_arm_vacation, 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 = Number( Object.keys(entity.context.STATE.map).find(key => entity.context.STATE.map[key] === targetState), ); if (isNaN(valToSet) || valToSet === null || valToSet === undefined) { 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 = Number(Object.keys(attr.map).find(key => attr.map[key] === targetState)); if (isNaN(valToSet) || valToSet === null || valToSet === undefined) { 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_vacation', parseCommand: processCommand, }); entity.context.COMMANDS.push({ service: 'alarm_arm_custom_bypass', parseCommand: processCommand, }); entity.context.COMMANDS.push({ service: 'alarm_disarm', parseCommand: processCommand, }); return [entity]; } /** * Augment services with alarm_control_panel. * * @param services {Record<string, any>} - services to augment. */ function augmentServices(services) { services.alarm_control_panel = { alarm_arm_away: { name: 'Arm away', description: 'Arms the alarm in away mode.', fields: { code: { selector: { number: null, }, name: 'Code', description: 'The code to arm the alarm.', }, }, target: { entity: [ { domain: ['alarm_control_panel'], }, ], }, }, alarm_arm_home: { name: 'Arm home', description: 'Arms the alarm in home mode.', fields: { code: { selector: { number: null, }, name: 'Code', description: 'The code to arm the alarm.', }, }, target: { entity: [ { domain: ['alarm_control_panel'], }, ], }, }, alarm_arm_night: { name: 'Arm night', description: 'Arms the alarm in night mode.', fields: { code: { selector: { number: null, }, name: 'Code', description: 'The code to arm the alarm.', }, }, target: { entity: [ { domain: ['alarm_control_panel'], }, ], }, }, alarm_arm_vacation: { name: 'Arm vacation', description: 'Arms the alarm in vacation mode.', fields: { code: { selector: { number: null, }, name: 'Code', description: 'The code to arm the alarm.', }, }, target: { entity: [ { domain: ['alarm_control_panel'], }, ], }, }, alarm_arm_custom_bypass: { name: 'Arm custom', description: 'Arms the alarm in custom mode.', fields: { code: { selector: { number: null, }, name: 'Code', description: 'The code to arm the alarm.', }, }, target: { entity: [ { domain: ['alarm_control_panel'], }, ], }, }, alarm_disarm: { name: 'Disarm', description: 'Disarms the alarm.', fields: { code: { required: true, selector: { number: null, }, name: 'Code', description: 'The code to disarm the alarm.', }, }, target: { entity: [ { domain: ['alarm_control_panel'], }, ], }, }, }; } augmentServices(adapterData.services);