iobroker.nuki-extended
Version:
207 lines (179 loc) • 7.24 kB
JavaScript
const Library = require('./library');
const _LOCK = require('../_LOCK.js');
const _OPENER = require('../_OPENER.js');
/**
*
*/
class NukiTools {
static DEVICES = {};
/**
* @param nukiId
* @see https://developer.nuki.io/t/nuki-opener-different-smartlock-id-in-bridge-api-compared-to-web-api/3195/2?u=zefau
*/
static getNukiHex(nukiId) {
return nukiId.toString(16).substr(-8);
}
/**
* Update states of Nuki Door based on payload.
*
* @param payload
* @param {Library} library
* @param adapter
*/
static updateLock(payload, library, adapter) {
library.set(Library.CONNECTION, true);
// get NukiHexId or NukiId
if (payload.nukiId && !payload.nukiHexId) {
payload.nukiHexId = NukiTools.getNukiHex(payload.nukiId);
} else if (!payload.nukiId && payload.nukiHexId) {
payload.nukiId = parseInt(payload.nukiHexId, 16);
} else {
return false;
}
// index Nuki
let type, path;
if (this.DEVICES[payload.nukiHexId] === undefined || !this.DEVICES[payload.nukiHexId].path) {
let actions = null;
//
if (!payload.name || payload.deviceType === undefined) {
adapter.log.debug(`Error updating device due to missing data (${JSON.stringify(payload)}).`);
return false;
}
// Nuki Smartlock
if (payload.deviceType === 0 || !payload.deviceType) {
library.set(library.getNode('smartlocks'));
type = 'Smartlock';
actions = _LOCK.ACTIONS;
}
// Nuki Box
else if (payload.deviceType === 1) {
library.set(library.getNode('boxes'));
type = 'Box';
}
// Nuki Opener
else if (payload.deviceType === 2) {
library.set(library.getNode('openers'));
type = 'Opener';
actions = _OPENER.ACTIONS;
}
// Nuki Smart Door
if (payload.deviceType === 3) {
library.set(library.getNode('smartlocks'));
type = 'Smart Door';
actions = _LOCK.ACTIONS;
}
// Nuki Smartlock 3.0
if (payload.deviceType === 4) {
library.set(library.getNode('smartlocks'));
type = 'Smartlock';
actions = _LOCK.ACTIONS;
}
// Nuki Smartlock 4.x / Pro (deviceType 5)
if (payload.deviceType === 5) {
library.set(library.getNode('smartlocks'));
type = 'Smartlock';
actions = _LOCK.ACTIONS;
}
// index device
path = `${(type || 'Smartlock').toLowerCase()}s.${library.clean(payload.name, true, '_')}`;
this.DEVICES[payload.nukiHexId] = {
id: payload.nukiId,
hex: payload.nukiHexId,
smartlockId: parseInt(payload.deviceType + payload.nukiHexId, 16),
name: payload.name,
type: type,
path: path,
bridge: null,
};
// add action
if (actions !== null) {
let actionPath = `${path}._ACTION`;
library.set(
{ ...library.getNode('action'), node: actionPath, common: { write: true, states: actions } },
0,
);
adapter.subscribeStates(actionPath); // attach state listener
for (let key in actions) {
if (key > 0) {
let action = actions[key];
library.set(
{
description: `Trigger ${action} action`,
type: 'boolean',
role: 'button',
node: `${actionPath}.${action.replace(/ /g, '_')}`,
common: { write: true },
},
false,
);
adapter.subscribeStates(`${actionPath}.${action.replace(/ /g, '_')}`); // attach state listener
}
}
}
}
// retrieve Nuki name
else {
path = this.DEVICES[payload.nukiHexId].path;
}
// update state
if (payload.deviceType === 2 && payload.state && payload.state.state === 1 && payload.mode === 3) {
// change ONLINE & CONTINOUS to RING_TO_OPEN
payload.state.state = 3;
}
// update bridge
if (payload.bridge !== undefined) {
this.DEVICES[payload.nukiHexId].bridge = payload.bridge;
}
// update instance
if (payload.nuki !== undefined) {
this.DEVICES[payload.nukiHexId].instance = payload.nuki;
}
// update config
if (payload.config !== undefined) {
this.DEVICES[payload.nukiHexId].config = payload.config;
}
// update advancedConfig
if (payload.advancedConfig !== undefined) {
this.DEVICES[payload.nukiHexId].advancedConfig = payload.advancedConfig;
}
// update openerAdvancedConfig
if (payload.openerAdvancedConfig !== undefined) {
this.DEVICES[payload.nukiHexId].openerAdvancedConfig = payload.openerAdvancedConfig;
}
// add additional states
if (this.DEVICES[payload.nukiHexId].type === 'Smartlock' && payload.state && payload.state.doorState) {
payload.state.closed = payload.state.doorState;
}
if (this.DEVICES[payload.nukiHexId].type === 'Smartlock' && payload.state && payload.state.state) {
payload.state.locked = payload.state.state;
}
if (this.DEVICES[payload.nukiHexId].type === 'Smart Door' && payload.state && payload.state.doorState) {
payload.state.closed = payload.state.doorState;
}
if (this.DEVICES[payload.nukiHexId].type === 'Smart Door' && payload.state && payload.state.state) {
payload.state.locked = payload.state.state;
}
if (
payload.state &&
payload.state.state &&
payload.state.state !== library.getDeviceState(`${path}.state.lockState`)
) {
payload.state.lastStateUpdate = Date.now();
}
// remove unnecessary states
if (payload.state && payload.state.stateName) {
delete payload.state.stateName;
}
if (payload.state && payload.state.deviceType) {
delete payload.state.deviceType;
}
if (payload.nuki) {
delete payload.nuki;
}
// create / update device
adapter.log.debug(`Updating device ${path} with payload: ${JSON.stringify(payload)}`);
library.set({ node: path, description: `${this.DEVICES[payload.nukiHexId].name}`, role: 'channel' });
library.readData('', payload, path);
}
}
module.exports = NukiTools;