UNPKG

node-red-contrib-smartnora

Version:

Google Smart Home integration via Smart Nora https://smart-nora.eu/

176 lines (175 loc) 8.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const nora_firebase_common_1 = require("@andrei-tatar/nora-firebase-common"); const rxjs_1 = require("rxjs"); const util_1 = require("./util"); module.exports = function (RED) { RED.nodes.registerType('noraf-openclose', function (config) { var _a, _b, _c, _d; RED.nodes.createNode(this, config); const noraConfig = RED.nodes.getNode(config.nora); if (!(noraConfig === null || noraConfig === void 0 ? void 0 : noraConfig.valid)) { return; } const deviceType = `action.devices.types.${config.openclosetype}`; if (!(0, nora_firebase_common_1.isDeviceType)(deviceType)) { this.warn(`Device type not supported: ${deviceType}`); return; } const directions = config.directions; let openCloseDirections = (_a = directions === null || directions === void 0 ? void 0 : directions.split(',')) === null || _a === void 0 ? void 0 : _a.filter(f => !!f); if (!(openCloseDirections === null || openCloseDirections === void 0 ? void 0 : openCloseDirections.length)) { openCloseDirections = undefined; } if (openCloseDirections === null || openCloseDirections === void 0 ? void 0 : openCloseDirections.some(d => !(0, nora_firebase_common_1.isOpenCloseDirection)(d))) { this.warn(`Open/Close direction not supported: ${directions}`); return; } const useDiscreteValues = (_b = config.discrete) !== null && _b !== void 0 ? _b : true; const useOpenCloseDefinedValues = useDiscreteValues && !openCloseDirections && !config.lockunlock; const { value: openValue, type: openType, } = (0, util_1.convertValueType)(RED, config.openvalue, config.openvalueType, { defaultValue: true }); const { value: closeValue, type: closeType, } = (0, util_1.convertValueType)(RED, config.closevalue, config.closevalueType, { defaultValue: false }); const deviceConfig = { type: deviceType, traits: ['action.devices.traits.OpenClose'], name: { name: config.devicename, }, roomHint: config.roomhint, willReportState: true, state: Object.assign({ online: true }, ((openCloseDirections === null || openCloseDirections === void 0 ? void 0 : openCloseDirections.length) ? { openState: openCloseDirections.map(direction => ({ openDirection: direction, openPercent: 0, })) } : { openPercent: 0, })), noraSpecific: { returnOpenCloseErrorCodeIfStateAlreadySet: !!config.errorifstateunchaged, }, attributes: { discreteOnlyOpenClose: useDiscreteValues, openDirection: openCloseDirections, commandOnlyOpenClose: (_c = config.commandonly) !== null && _c !== void 0 ? _c : false, queryOnlyOpenClose: (_d = config.queryonly) !== null && _d !== void 0 ? _d : false, }, }; if (config.lockunlock) { deviceConfig.traits.push('action.devices.traits.LockUnlock'); if ((0, nora_firebase_common_1.isLockUnlock)(deviceConfig)) { deviceConfig.state.isLocked = false; deviceConfig.state.isJammed = false; } } (0, util_1.registerNoraDevice)(this, RED, config, { deviceConfig, updateStatus: ({ state, update }) => { let stateString = 'openPercent' in state ? openPercent(state.openPercent) : state.openState.map(s => `${s.openDirection}:${openPercent(s.openPercent)}`).join(', '); if (isLockUnlockState(deviceConfig, state)) { if (state.isJammed) { stateString += ' jammed'; } else { stateString += ` ${state.isLocked ? 'locked' : 'unlocked'}`; } } update(stateString); }, mapStateToOutput: state => { if (useOpenCloseDefinedValues && 'openPercent' in state) { if (state.openPercent === 0) { return { payload: (0, util_1.getValue)(RED, this, closeValue, closeType), }; } else { return { payload: (0, util_1.getValue)(RED, this, openValue, openType), }; } } else { const payload = { online: state.online }; if (isLockUnlockState(deviceConfig, state)) { payload.locked = state.isLocked; payload.jammed = state.isJammed; } if ('openPercent' in state) { payload.open = state.openPercent; return { payload, }; } else { for (const directionState of state.openState) { return { payload: Object.assign(Object.assign({}, payload), { open: directionState.openPercent, direction: directionState.openDirection }), }; } } } }, handleNodeInput: async ({ msg, updateState, state$ }) => { var _a; if (!useOpenCloseDefinedValues) { const state = await (0, rxjs_1.firstValueFrom)(state$); const payload = Object.assign({}, msg.payload); if ((openCloseDirections === null || openCloseDirections === void 0 ? void 0 : openCloseDirections.length) && 'openState' in state) { if (typeof payload === 'object' && 'open' in payload) { const payloadDirection = (_a = msg === null || msg === void 0 ? void 0 : msg.payload) === null || _a === void 0 ? void 0 : _a.direction; const direction = typeof payloadDirection === 'string' ? payloadDirection.trim().toUpperCase() : null; payload.openState = state.openState.map(st => ({ openDirection: st.openDirection, openPercent: st.openDirection === direction || direction == null ? msg.payload.open : st.openPercent, })); delete payload.open; delete payload.direction; } } await updateState(payload, [{ from: 'open', to: 'openPercent', }, { from: 'locked', to: 'isLocked', }, { from: 'jammed', to: 'isJammed', }]); } else { const myOpenValue = (0, util_1.getValue)(RED, this, openValue, openType); const myCloseValue = (0, util_1.getValue)(RED, this, closeValue, closeType); if (RED.util.compareObjects(myOpenValue, msg.payload)) { await updateState({ openPercent: 100 }); } else if (RED.util.compareObjects(myCloseValue, msg.payload)) { await updateState({ openPercent: 0 }); } else { await updateState(msg.payload); } } }, }); function openPercent(percent) { switch (percent) { case 0: return 'closed'; case 100: return 'open'; default: return `${percent}%`; } } function isLockUnlockState(device, _state) { return (0, nora_firebase_common_1.isLockUnlock)(device); } }); };