fetched version from zigbee2mqtt-pullrequest

This commit is contained in:
formtapez
2019-09-02 21:18:36 +02:00
parent d0f9c3b111
commit c14e12ebba
3 changed files with 1443 additions and 127 deletions

View File

@@ -2,7 +2,7 @@
const utils = require('./utils');
const common = require('./common');
const zclId = require('zigbee-herdsman/dist/zcl-id');
const Zcl = require('zigbee-herdsman/dist/zcl');
const cfg = {
default: {
@@ -31,8 +31,22 @@ const cfg = {
manufSpec: 1,
manufCode: 0x110c,
},
sinope: {
manufSpec: 1,
manufCode: 0x119C,
},
};
function getTransition(message, options) {
if (message.hasOwnProperty('transition')) {
return message.transition;
} else if (options.hasOwnProperty('transition')) {
return options.transition;
} else {
return 0;
}
}
const converters = {
/**
* Generic
@@ -75,7 +89,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -124,7 +138,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -170,12 +184,64 @@ const converters = {
}
},
},
cover_control: {
key: ['state'],
convert: (key, value, message, type, postfix, options) => {
const zclCmdLookup = {
'open': 'upOpen',
'close': 'downClose',
'stop': 'stop',
'on': 'upOpen',
'off': 'downClose',
};
const zclCmd = zclCmdLookup[value.toLowerCase()];
if (zclCmd) {
return [{
cid: 'closuresWindowCovering',
cmdType: 'functional',
cmd: zclCmd,
zclData: {},
cfg: cfg.default,
}];
}
},
},
cover_gotopercentage: {
key: ['position', 'tilt'],
convert: (key, value, message, type, postfix, options) => {
const isPosition = (key === 'position');
const cid = 'closuresWindowCovering';
const attrId = isPosition ? 'currentPositionLiftPercentage' : 'currentPositionTiltPercentage';
// ZigBee officially expects "open" to be 0 and "closed" to be 100 whereas
// HomeAssistant etc. work the other way round.
value = 100 - value;
if (type === 'set') {
return [{
cid: cid,
cmdType: 'functional',
cmd: isPosition ? 'goToLiftPercentage' : 'goToTiltPercentage',
zclData: isPosition ? {percentageliftvalue: value} : {percentagetiltvalue: value},
cfg: cfg.default,
}];
} else if (type === 'get') {
return [{
cid: cid,
cmdType: 'foundation',
cmd: 'read',
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
},
},
occupancy_timeout: {
// set delay after motion detector changes from occupied to unoccupied
key: ['occupancy_timeout'],
convert: (key, value, message, type, postfix, options) => {
const cid = 'msOccupancySensing'; // 1030
const attrId = zclId.attr(cid, 'pirOToUDelay').value; // = 16
const attrId = Zcl.getAttributeLegacy(cid, 'pirOToUDelay').value; // = 16
if (type === 'set') {
return [{
@@ -228,7 +294,7 @@ const converters = {
cmdType: 'functional',
zclData: {
level: Number(value),
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
transtime: getTransition(message, options) * 10,
},
cfg: cfg.default,
newState: {brightness: Number(value)},
@@ -240,7 +306,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -255,7 +321,7 @@ const converters = {
const brightnessValue = message.hasOwnProperty('brightness') ?
message.brightness : message.brightness_percent;
const hasState = message.hasOwnProperty('state');
const hasTrasition = message.hasOwnProperty('transition');
const hasTrasition = message.hasOwnProperty('transition') || options.hasOwnProperty('transition');
const state = hasState ? message.state.toLowerCase() : null;
if (hasState && (state === 'off' || !hasBrightness) && !hasTrasition) {
@@ -279,17 +345,19 @@ const converters = {
brightness = Math.round(Number(message.brightness_percent) * 2.55).toString();
}
const transition = getTransition(message, options);
return [{
cid: 'genLevelCtrl',
cmd: 'moveToLevelWithOnOff',
cmdType: 'functional',
zclData: {
level: Number(brightness),
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
transtime: transition * 10,
},
cfg: options.disFeedbackRsp ? cfg.defaultdisFeedbackRsp : cfg.default,
newState: {state: brightness === 0 ? 'OFF' : 'ON', brightness: Number(brightness)},
readAfterWriteTime: message.hasOwnProperty('transition') ? message.transition * 1000 : 0,
readAfterWriteTime: transition * 1000,
}];
}
} else if (type === 'get') {
@@ -298,14 +366,14 @@ const converters = {
cid: 'genOnOff',
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr('genOnOff', 'onOff').value}],
zclData: [{attrId: Zcl.getAttributeLegacy('genOnOff', 'onOff').value}],
cfg: cfg.default,
},
{
cid: 'genLevelCtrl',
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr('genLevelCtrl', 'currentLevel').value}],
zclData: [{attrId: Zcl.getAttributeLegacy('genLevelCtrl', 'currentLevel').value}],
cfg: cfg.default,
},
];
@@ -332,7 +400,7 @@ const converters = {
cmdType: 'functional',
zclData: {
colortemp: value,
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
transtime: getTransition(message, options) * 10,
},
cfg: cfg.default,
newState: {color_temp: value},
@@ -343,7 +411,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -383,7 +451,7 @@ const converters = {
}
const zclData = {
transtime: message.hasOwnProperty('transition') ? message.transition * 10 : 0,
transtime: getTransition(message, options) * 10,
};
let newState = null;
@@ -424,8 +492,8 @@ const converters = {
cmd: 'read',
cmdType: 'foundation',
zclData: [
{attrId: zclId.attr(cid, 'currentX').value},
{attrId: zclId.attr(cid, 'currentY').value},
{attrId: Zcl.getAttributeLegacy(cid, 'currentX').value},
{attrId: Zcl.getAttributeLegacy(cid, 'currentY').value},
],
cfg: cfg.default,
}];
@@ -460,9 +528,9 @@ const converters = {
cmd: 'read',
cmdType: 'foundation',
zclData: [
{attrId: zclId.attr(cid, 'currentX').value},
{attrId: zclId.attr(cid, 'currentY').value},
{attrId: zclId.attr(cid, 'colorTemperature').value},
{attrId: Zcl.getAttributeLegacy(cid, 'currentX').value},
{attrId: Zcl.getAttributeLegacy(cid, 'currentY').value},
{attrId: Zcl.getAttributeLegacy(cid, 'colorTemperature').value},
],
cfg: cfg.default,
}];
@@ -509,7 +577,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -526,8 +594,8 @@ const converters = {
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: zclId.attr(cid, attrId).value,
dataType: zclId.attrType(cid, attrId).value,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: Math.round(value * 10),
}],
cfg: cfg.default,
@@ -537,7 +605,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -553,7 +621,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -570,8 +638,8 @@ const converters = {
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: zclId.attr(cid, attrId).value,
dataType: zclId.attrType(cid, attrId).value,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100,
}],
cfg: cfg.default,
@@ -581,7 +649,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -598,8 +666,8 @@ const converters = {
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: zclId.attr(cid, attrId).value,
dataType: zclId.attrType(cid, attrId).value,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100,
}],
cfg: cfg.default,
@@ -609,7 +677,35 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
},
},
thermostat_occupied_cooling_setpoint: {
key: 'occupied_cooling_setpoint',
convert: (key, value, message, type, postfix, options) => {
const cid = 'hvacThermostat';
const attrId = 'occupiedCoolingSetpoint';
if (type === 'set') {
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: (Math.round((value * 2).toFixed(1))/2).toFixed(1) * 100,
}],
cfg: cfg.default,
}];
} else if (type === 'get') {
return [{
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -632,8 +728,8 @@ const converters = {
// Bit 1 = 1 outdoor temperature sensed remotely
// Bit 2 = 0 occupancy sensed internally
// Bit 2 = 1 occupancy sensed remotely
attrId: zclId.attr(cid, attrId).value,
dataType: zclId.attrType(cid, attrId).value,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: value, // TODO: Lookup in Zigbee documentation
}],
cfg: cfg.default,
@@ -643,7 +739,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -660,8 +756,8 @@ const converters = {
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: zclId.attr(cid, attrId).value,
dataType: zclId.attrType(cid, attrId).value,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: utils.getKeyByValue(common.thermostatControlSequenceOfOperations, value, value),
}],
cfg: cfg.default,
@@ -671,7 +767,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -688,8 +784,8 @@ const converters = {
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: zclId.attr(cid, attrId).value,
dataType: zclId.attrType(cid, attrId).value,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: utils.getKeyByValue(common.thermostatSystemModes, value, value),
}],
cfg: cfg.default,
@@ -700,7 +796,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -735,7 +831,7 @@ const converters = {
cmd: 'setWeeklySchedule',
cmdType: 'functional',
zclData: {
dataType: zclId.attrType(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: value, // TODO: Combine attributes in attrData?
temperature_setpoint_hold: value.temperature_setpoint_hold,
temperature_setpoint_hold_duration: value.temperature_setpoint_hold_duration,
@@ -825,7 +921,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -841,7 +937,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -858,9 +954,29 @@ const converters = {
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: zclId.attr(cid, attrId).value,
dataType: zclId.attrType(cid, attrId).value,
attrData: value,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: utils.getKeyByValue(common.temperatureDisplayMode, value, value),
}],
cfg: cfg.default,
}];
}
},
},
thermostat_keypad_lockout: {
key: 'keypad_lockout',
convert: (key, value, message, type, postfix, options) => {
const cid = 'hvacUserInterfaceCfg';
const attrId = 'keypadLockout';
if (type === 'set') {
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: utils.getKeyByValue(common.keypadLockoutMode, value, value),
}],
cfg: cfg.default,
}];
@@ -881,7 +997,7 @@ const converters = {
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value, attrData: attrData, dataType: 48}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value, attrData: attrData, dataType: 48}],
cfg: cfg.default,
newState: {fan_mode: value, fan_state: value === 'off' ? 'OFF' : 'ON'},
}];
@@ -890,7 +1006,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -1062,7 +1178,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -1329,7 +1445,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -1361,7 +1477,7 @@ const converters = {
cid: cid,
cmd: 'read',
cmdType: 'foundation',
zclData: [{attrId: zclId.attr(cid, attrId).value}],
zclData: [{attrId: Zcl.getAttributeLegacy(cid, attrId).value}],
cfg: cfg.default,
}];
}
@@ -1380,7 +1496,7 @@ const converters = {
gledopto_light_color_colortemp: {
key: ['color', 'color_temp', 'color_temp_percent'],
convert: (key, value, message, type, postfix, options) => {
if (message.hasOwnProperty('transition')) {
if (message && message.hasOwnProperty('transition')) {
message.transition = message.transition * 3.3;
}
@@ -1390,7 +1506,7 @@ const converters = {
gledopto_light_colortemp: {
key: ['color_temp', 'color_temp_percent'],
convert: (key, value, message, type, postfix, options) => {
if (message.hasOwnProperty('transition')) {
if (message && message.hasOwnProperty('transition')) {
message.transition = message.transition * 3.3;
}
@@ -1532,6 +1648,195 @@ const converters = {
},
},
// Sinope
sinope_thermostat_backlight_autodim_param: {
key: 'backlight_auto_dim',
convert: (key, value, message, type, postfix, options) => {
const cid = 'hvacThermostat';
const attrId = 0x0402;
if (type === 'set') {
const sinopeBacklightAutoDimParam = {
0: 'on demand',
1: 'sensing',
};
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: attrId,
dataType: 0x30,
attrData: utils.getKeyByValue(sinopeBacklightAutoDimParam, value, value),
}],
cfg: cfg.default,
}];
}
},
},
sinope_thermostat_enable_outdoor_temperature: {
key: 'enable_outdoor_temperature',
convert: (key, value, message, type, postfix, options) => {
const cid = 0xFF01;
const attrId = 0x0011;
if (type === 'set' && value.toLowerCase()=='on') {
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: attrId,
dataType: 0x21,
// set outdoor temperature timer to 3 hours
attrData: 10800,
}],
cfg: cfg.sinope,
}];
} else if (type === 'set' && value.toLowerCase()=='off') {
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: attrId,
dataType: 0x21,
// set timer to 30sec in order to disable outdoor temperature
attrData: 30,
}],
cfg: cfg.sinope,
}];
}
},
},
sinope_thermostat_outdoor_temperature: {
key: 'thermostat_outdoor_temperature',
convert: (key, value, message, type, postfix, options) => {
const cid = 0xFF01;
const attrId = 0x0010;
if (type === 'set' && value > -100 && value < 100) {
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: attrId,
dataType: 0x29,
attrData: value * 100,
}],
cfg: cfg.sinope,
}];
}
},
},
sinope_thermostat_time: {
key: 'thermostat_time',
convert: (key, value, message, type, postfix, options) => {
const cid = 0xFF01;
const attrId = 0x0020;
if (type === 'set' && value === '' ) {
const thermostatDate = new Date();
const thermostatTimeSec = thermostatDate.getTime() / 1000;
const thermostatTimezoneOffsetSec = thermostatDate.getTimezoneOffset() * 60;
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: attrId,
dataType: 0x23,
// Current time in second since 2000-01-01T00:00 in the current time zone
attrData: Math.round(thermostatTimeSec - thermostatTimezoneOffsetSec - 946684800),
}],
cfg: cfg.sinope,
}];
} else if (type === 'set' && value !== '' ) {
return [{
cid: cid,
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: attrId,
dataType: 0x23,
attrData: value,
}],
cfg: cfg.sinope,
}];
}
},
},
DTB190502A1_LED: {
key: ['LED'],
convert: (key, value, message, type, postfix, options) => {
if (type === 'set') {
if (value === 'default') {
value = 1;
}
const lookup = {
'OFF': '0',
'ON': '1',
};
value = lookup[value];
// Check for valid data
if ( ((value >= 0) && value < 2) == false ) value = 0;
return [{
cid: 'genBasic',
cmd: 'write',
cmdType: 'foundation',
zclData: [{
attrId: 0x4010,
dataType: 0x21,
attrData: value,
}],
cfg: cfg.default,
}];
}
},
},
ptvo_switch_trigger: {
key: ['trigger', 'interval'],
convert: (key, value, message, type, postfix, options) => {
console.log('ptvo_switch_trigger:', key, value, message, type, postfix);
if (type === 'set') {
value = parseInt(value);
if (!value) {
return;
}
const cid = 'genOnOff';
if (key === 'trigger') {
return [{
cid: cid,
cmd: 'onWithTimedOff',
cmdType: 'functional',
zclData: {
ctrlbits: 0,
ontime: value,
offwaittime: 0,
},
cfg: cfg.default,
}];
} else if (key === 'interval') {
const attrId = 'onOff';
return [{
cid: cid,
cmd: 'configReport',
cmdType: 'foundation',
zclData: [{
direction: 0,
attrId: Zcl.getAttributeLegacy(cid, attrId).value,
dataType: Zcl.getAttributeTypeLegacy(cid, attrId).value,
attrData: value,
minRepIntval: value,
maxRepIntval: value,
}],
cfg: cfg.default,
}];
}
}
return;
},
},
/**
* Ignore converters
*/