From 04a60782ac0b017d323fd4ce08ddff2182b0977b Mon Sep 17 00:00:00 2001 From: Joe Lu Date: Sat, 23 Feb 2019 06:42:56 -0800 Subject: [PATCH] Add support for Keen Home smart vent (#276) * - added support for Keen Home smart vent * - added more from-zigbee handler for keen vent - added more model# for keen vent * Update devices.js * - updated reporting interval and only handle attReport and ignore devChange on temperature and pressure * - added cover_position handler * - added cover_position to keen home toZigbee * - added transtime to cover_position.set - changed key to state for cover_position * Update toZigbee.js * Update devices.js * - added cover_state and cover_position fromZigbee handler - made changes to cover_open_close toZigbee handler so it'd work correctly * - added devChange fromZigbee handler for keen home pressure, temperature and battery - updated cover_position and cover_position_report fromZigbee handler to return both position and state (state is determined by position now) - updated cover_open_close to only change currentLevel - adjusted attReport interval for kee home vent * - removed reporting config * - fixed lint errors --- converters/fromZigbee.js | 46 +++++++++++++++++++++++++++++++++++++ converters/toZigbee.js | 49 ++++++++++++++++++++++++++++++++++++++++ devices.js | 36 +++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/converters/fromZigbee.js b/converters/fromZigbee.js index 000e4f63adda49..72b5f19ef7755f 100644 --- a/converters/fromZigbee.js +++ b/converters/fromZigbee.js @@ -823,6 +823,14 @@ const converters = { } }, }, + generic_temperature_change: { + cid: 'msTemperatureMeasurement', + type: 'devChange', + convert: (model, msg, publish, options) => { + const temperature = parseFloat(msg.data.data['measuredValue']) / 100.0; + return {temperature: precisionRoundOptions(temperature, options, 'temperature')}; + }, + }, xiaomi_temperature: { cid: 'msTemperatureMeasurement', type: 'attReport', @@ -4225,6 +4233,44 @@ const converters = { return {action: `${direction}`}; }, }, + cover_position: { + cid: 'genLevelCtrl', + type: 'devChange', + convert: (model, msg, publish, options) => { + const currentLevel = msg.data.data['currentLevel']; + const position = Math.round(Number(currentLevel) / 2.55).toString(); + const state = position > 0 ? 'OPEN' : 'CLOSE'; + return {state: state, position: position}; + }, + }, + cover_position_report: { + cid: 'genLevelCtrl', + type: 'attReport', + convert: (model, msg, publish, options) => { + const currentLevel = msg.data.data['currentLevel']; + const position = Math.round(Number(currentLevel) / 2.55).toString(); + const state = position > 0 ? 'OPEN' : 'CLOSE'; + return {state: state, position: position}; + }, + }, + keen_home_smart_vent_pressure: { + cid: 'msPressureMeasurement', + type: 'devChange', + convert: (model, msg, publish, options) => { + // '{"cid":"msPressureMeasurement","data":{"32":990494}}' + const pressure = parseFloat(msg.data.data['32']) / 1000.0; + return {pressure: precisionRoundOptions(pressure, options, 'pressure')}; + }, + }, + keen_home_smart_vent_pressure_report: { + cid: 'msPressureMeasurement', + type: 'attReport', + convert: (model, msg, publish, options) => { + // '{"cid":"msPressureMeasurement","data":{"32":990494}}' + const pressure = parseFloat(msg.data.data['32']) / 1000.0; + return {pressure: precisionRoundOptions(pressure, options, 'pressure')}; + }, + }, // Ignore converters (these message dont need parsing). ignore_onoff_report: { diff --git a/converters/toZigbee.js b/converters/toZigbee.js index cc8c6be34fe1ac..f99cce87481e7b 100644 --- a/converters/toZigbee.js +++ b/converters/toZigbee.js @@ -2359,6 +2359,55 @@ const converters = { return converters.light_colortemp.convert(key, value, message, type, postfix); }, }, + cover_open_close: { + key: ['state'], + convert: (key, value, message, type, postfix) => { + if (type === 'set') { + if (typeof value !== 'string') { + return; + } + + const positionByState = { + 'open': 100, + 'close': 0, + }; + + value = positionByState[value.toLowerCase()]; + } + + return converters.cover_position.convert(key, value, message, type, postfix); + }, + }, + cover_position: { + key: ['position'], + convert: (key, value, message, type, postfix) => { + const cid = 'genLevelCtrl'; + const attrId = 'currentLevel'; + + if (type === 'set') { + value = Math.round(Number(value) * 2.55).toString(); + return { + cid: cid, + cmd: 'moveToLevelWithOnOff', + cmdType: 'functional', + zclData: { + level: value, + transtime: 0, + }, + cfg: cfg.default, + readAfterWriteTime: 0, + }; + } else if (type === 'get') { + return { + cid: cid, + cmd: 'read', + cmdType: 'foundation', + zclData: [{attrId: zclId.attr(cid, attrId).value}], + cfg: cfg.default, + }; + } + }, + }, // Ignore converters ignore_transition: { diff --git a/devices.js b/devices.js index 0e36f90bba6d63..aa59ac81b3df3e 100755 --- a/devices.js +++ b/devices.js @@ -8155,6 +8155,42 @@ const devices = [ }, }, + // Keen Home + { + zigbeeModel: ['SV01-410-MP-1.0', 'SV01-410-MP-1.4', 'SV01-410-MP-1.5'], + model: 'SV01', + vendor: 'Keen Home', + description: 'Smart vent', + supports: 'open, close, position, temperature, pressure, battery', + fromZigbee: [ + fz.cover_position, + fz.cover_position_report, + fz.generic_temperature, + fz.generic_temperature_change, + fz.generic_battery, + fz.generic_battery_change, + fz.keen_home_smart_vent_pressure, + fz.keen_home_smart_vent_pressure_report, + fz.ignore_onoff_change, + fz.ignore_onoff_report, + ], + toZigbee: [ + tz.cover_open_close, + tz.cover_position, + ], + configure: (ieeeAddr, shepherd, coordinator, callback) => { + const device = shepherd.find(ieeeAddr, 1); + const actions = [ + (cb) => device.bind('genLevelCtrl', coordinator, cb), + (cb) => device.bind('genPowerCfg', coordinator, cb), + (cb) => device.bind('msTemperatureMeasurement', coordinator, cb), + (cb) => device.bind('msPressureMeasurement', coordinator, cb), + ]; + + execute(device, actions, callback); + }, + }, + // ELKO { zigbeeModel: ['ElkoDimmerZHA'],