Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion converters/fromZigbee.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ const converters = {
}

if (msg.data.hasOwnProperty('colorMode')) {
result.color_mode = msg.data['colorMode'];
result.color_mode = constants.colorMode.hasOwnProperty(msg.data['colorMode']) ?
constants.colorMode[msg.data['colorMode']] : msg.data['colorMode'];
}

if (
Expand Down
47 changes: 38 additions & 9 deletions converters/toZigbee.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ const converters = {
await entity.read('genOnOff', ['startUpOnOff']);
},
},
light_color_mode: {
key: ['color_mode'],
convertGet: async (entity, key, meta) => {
await entity.read('lightingColorCtrl', ['colorMode']);
},
},
light_color_options: {
key: ['color_options'],
convertSet: async (entity, key, value, meta) => {
Expand Down Expand Up @@ -514,12 +520,13 @@ const converters = {

await entity.command('lightingColorCtrl', 'moveColorTemp', payload, utils.getOptions(meta.mapped, entity));

// As we cannot determine the new brightness state, we read it from the device
// We cannot determine the color temperaturefrom the current state so we read it, because
// - Color mode could have been swithed (x/y or colortemp)
Comment thread
Koenkk marked this conversation as resolved.
if (value === 'stop' || value === 0) {
const entityToRead = utils.getEntityOrFirstGroupMember(entity);
if (entityToRead) {
await utils.sleep(100);
await entityToRead.read('lightingColorCtrl', ['colorTemperature']);
await entityToRead.read('lightingColorCtrl', ['colorTemperature', 'colorMode']);
}
}
} else {
Expand Down Expand Up @@ -559,7 +566,7 @@ const converters = {
const entityToRead = utils.getEntityOrFirstGroupMember(entity);
if (entityToRead) {
await utils.sleep(100 + (transition * 100));
await entityToRead.read('lightingColorCtrl', [attribute]);
await entityToRead.read('lightingColorCtrl', [attribute, 'colorMode']);
}
},
},
Expand All @@ -585,12 +592,13 @@ const converters = {

await entity.command('lightingColorCtrl', command, payload, utils.getOptions(meta.mapped, entity));

// As we cannot determine the new brightness state, we read it from the device
// We cannot determine the hue/saturation from the current state so we read it, because
// - Color mode could have been swithed (x/y or colortemp)
if (value === 'stop' || value === 0) {
const entityToRead = utils.getEntityOrFirstGroupMember(entity);
if (entityToRead) {
await utils.sleep(100);
await entityToRead.read('lightingColorCtrl', [attribute]);
await entityToRead.read('lightingColorCtrl', [attribute, 'colorMode']);
}
}
},
Expand Down Expand Up @@ -731,7 +739,7 @@ const converters = {

const payload = {colortemp: value, transtime: utils.getTransition(entity, key, meta).time};
await entity.command('lightingColorCtrl', 'moveToColorTemp', payload, utils.getOptions(meta.mapped, entity));
return {state: {color_temp: value}, readAfterWriteTime: payload.transtime * 100};
return {state: {color_temp: value, color_mode: constants.colorMode[2]}, readAfterWriteTime: payload.transtime * 100};
},
convertGet: async (entity, key, meta) => {
await entity.read('lightingColorCtrl', ['colorTemperature']);
Expand Down Expand Up @@ -928,6 +936,7 @@ const converters = {

switch (command) {
case 'enhancedMoveToHueAndSaturationAndBrightness':
newState.color_mode = constants.colorMode[0];
await entity.command(
'genLevelCtrl',
'moveToLevelWithOnOff',
Expand All @@ -940,15 +949,18 @@ const converters = {
command = 'enhancedMoveToHueAndSaturation';
break;
case 'enhancedMoveToHueAndSaturation':
newState.color_mode = constants.colorMode[0];
zclData.enhancehue = value.hue;
zclData.saturation = value.saturation;
zclData.direction = value.direction || 0;
break;
case 'enhancedMoveToHue':
newState.color_mode = constants.colorMode[0];
zclData.enhancehue = value.hue;
zclData.direction = value.direction || 0;
break;
case 'moveToHueAndSaturationAndBrightness':
newState.color_mode = constants.colorMode[0];
await entity.command(
'genLevelCtrl',
'moveToLevelWithOnOff',
Expand All @@ -961,15 +973,18 @@ const converters = {
command = 'moveToHueAndSaturation';
break;
case 'moveToHueAndSaturation':
newState.color_mode = constants.colorMode[0];
zclData.hue = value.hue;
zclData.saturation = value.saturation;
zclData.direction = value.direction || 0;
break;
case 'moveToHue':
newState.color_mode = constants.colorMode[0];
zclData.hue = value.hue;
zclData.direction = value.direction || 0;
break;
case 'moveToSaturation':
newState.color_mode = constants.colorMode[0];
zclData.saturation = value.saturation;
break;

Expand All @@ -986,6 +1001,7 @@ const converters = {
}

newState.color = {x: value.x, y: value.y};
newState.color_mode = constants.colorMode[1];
zclData.colorx = Math.round(value.x * 65535);
zclData.colory = Math.round(value.y * 65535);
}
Expand Down Expand Up @@ -3820,23 +3836,36 @@ const converters = {
const sceneid = value;
await entity.command('genScenes', 'recall', {groupid, sceneid}, utils.getOptions(meta.mapped));

const addColorMode = (newState) => {
Comment thread
Koenkk marked this conversation as resolved.
if (newState.hasOwnProperty('color_temp')) {
newState.color_mode = constants.colorMode[2];
} else if (newState.hasOwnProperty('color')) {
if (newState.color.hasOwnProperty('x')) {
newState.color_mode = constants.colorMode[1];
} else {
newState.color_mode = constants.colorMode[0];
}
}

return newState;
};

const isGroup = entity.constructor.name === 'Group';
const metaKey = `${sceneid}_${groupid}`;
if (isGroup) {
const membersState = {};
for (const member of entity.members) {
if (member.meta.hasOwnProperty('scenes') && member.meta.scenes.hasOwnProperty(metaKey)) {
membersState[member.getDevice().ieeeAddr] = member.meta.scenes[metaKey].state;
membersState[member.getDevice().ieeeAddr] = addColorMode(member.meta.scenes[metaKey].state);
} else {
meta.logger.warn(`Unknown scene was recalled for ${member.getDevice().ieeeAddr}, can't restore state.`);
membersState[member.getDevice().ieeeAddr] = {};
}
}

return {membersState};
} else {
if (entity.meta.scenes.hasOwnProperty(metaKey)) {
return {state: entity.meta.scenes[metaKey].state};
return {state: addColorMode(entity.meta.scenes[metaKey].state)};
} else {
meta.logger.warn(`Unknown scene was recalled for ${entity.deviceIeeeAddress}, can't restore state.`);
return {state: {}};
Expand Down
6 changes: 3 additions & 3 deletions devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const preset = {
const exposes = [e.light_brightness_colortemp(options.colorTempRange), ...(!options.disableEffect ? [e.effect()] : [])];
const toZigbee = [tz.light_onoff_brightness, tz.light_colortemp, tz.ignore_transition, tz.ignore_rate, tz.light_brightness_move,
tz.light_colortemp_move, tz.light_brightness_step, tz.light_colortemp_step, tz.light_colortemp_startup, tz.level_config,
tz.power_on_behavior, tz.light_color_options, ...(!options.disableEffect ? [tz.effect] : [])];
tz.power_on_behavior, tz.light_color_options, tz.light_color_mode, ...(!options.disableEffect ? [tz.effect] : [])];
const fromZigbee = [fz.color_colortemp, fz.on_off, fz.brightness, fz.level_config, fz.power_on_behavior, fz.ignore_basic_report];

if (options.disableColorTempStartup) {
Expand All @@ -94,7 +94,7 @@ const preset = {
const fromZigbee = [fz.color_colortemp, fz.on_off, fz.brightness, fz.level_config, fz.power_on_behavior, fz.ignore_basic_report];
const toZigbee = [tz.light_onoff_brightness, tz.light_color, tz.ignore_transition, tz.ignore_rate, tz.light_brightness_move,
tz.light_brightness_step, tz.level_config, tz.power_on_behavior, tz.light_hue_saturation_move,
tz.light_hue_saturation_step, tz.light_color_options, ...(!options.disableEffect ? [tz.effect] : [])];
tz.light_hue_saturation_step, tz.light_color_options, tz.light_color_mode, ...(!options.disableEffect ? [tz.effect] : [])];

return {
exposes, fromZigbee, toZigbee, meta: {configureKey: 2},
Expand All @@ -116,7 +116,7 @@ const preset = {
tz.light_onoff_brightness, tz.light_color_colortemp, tz.ignore_transition, tz.ignore_rate, tz.light_brightness_move,
tz.light_colortemp_move, tz.light_brightness_step, tz.light_colortemp_step, tz.light_hue_saturation_move,
tz.light_hue_saturation_step, tz.light_colortemp_startup, tz.level_config, tz.power_on_behavior, tz.light_color_options,
...(!options.disableEffect ? [tz.effect] : [])];
tz.light_color_mode, ...(!options.disableEffect ? [tz.effect] : [])];

if (options.disableColorTempStartup) {
exposes[0].removeFeature('color_temp_startup');
Expand Down
9 changes: 9 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ const armMode = {
10: 'arming_away',
};

// ID's from ZCL mapped to ha names where appropriate
// https://github.com/home-assistant/core/pull/47720
const colorMode = {
0: 'hs',
1: 'xy',
2: 'color_temp',
};

module.exports = {
OneJanuary2000,
repInterval,
Expand All @@ -126,4 +134,5 @@ module.exports = {
keypadLockoutMode,
lockSourceName,
armMode,
colorMode,
};