Skip to content

Commit 33101b1

Browse files
fix: Paul Neuhaus lights: fix color and temperature control (#12668)
1 parent 22a3b87 commit 33101b1

4 files changed

Lines changed: 57 additions & 65 deletions

File tree

src/converters/toZigbee.ts

Lines changed: 46 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export const light_color: Tz.Converter = {
5656
const transtime = utils.getTransition(entity, key, meta).time;
5757
const supportsHueAndSaturation = utils.getMetaValue(entity, meta.mapped, "supportsHueAndSaturation", "allEqual", false);
5858
const supportsEnhancedHue = utils.getMetaValue(entity, meta.mapped, "supportsEnhancedHue", "allEqual", false);
59+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
60+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
5961

6062
if (newColor.isHSV() && supportsHueAndSaturation) {
6163
const hsv = newColor.hsv;
@@ -67,7 +69,7 @@ export const light_color: Tz.Converter = {
6769
await entity.command(
6870
"genLevelCtrl",
6971
"moveToLevelWithOnOff",
70-
{level: utils.mapNumberRange(hsvCorrected.value, 0, 100, 0, 254), transtime, optionsMask: 0, optionsOverride: 0},
72+
{level: utils.mapNumberRange(hsvCorrected.value, 0, 100, 0, 254), transtime, ...optionalParams},
7173
utils.getOptions(meta.mapped, entity),
7274
);
7375
}
@@ -80,15 +82,15 @@ export const light_color: Tz.Converter = {
8082
await entity.command(
8183
"lightingColorCtrl",
8284
"enhancedMoveToHueAndSaturation",
83-
{transtime, enhancehue, saturation, optionsMask: 0, optionsOverride: 0},
85+
{transtime, enhancehue, saturation, ...optionalParams},
8486
utils.getOptions(meta.mapped, entity),
8587
);
8688
} else {
8789
const hue = utils.mapNumberRange(hsvCorrected.hue, 0, 360, 0, 254);
8890
await entity.command(
8991
"lightingColorCtrl",
9092
"moveToHueAndSaturation",
91-
{transtime, hue, saturation, optionsMask: 0, optionsOverride: 0},
93+
{transtime, hue, saturation, ...optionalParams},
9294
utils.getOptions(meta.mapped, entity),
9395
);
9496
}
@@ -100,15 +102,15 @@ export const light_color: Tz.Converter = {
100102
await entity.command(
101103
"lightingColorCtrl",
102104
"enhancedMoveToHue",
103-
{transtime, enhancehue, direction, optionsMask: 0, optionsOverride: 0},
105+
{transtime, enhancehue, direction, ...optionalParams},
104106
utils.getOptions(meta.mapped, entity),
105107
);
106108
} else {
107109
const hue = utils.mapNumberRange(hsvCorrected.hue, 0, 360, 0, 254);
108110
await entity.command(
109111
"lightingColorCtrl",
110112
"moveToHue",
111-
{transtime, hue, direction, optionsMask: 0, optionsOverride: 0},
113+
{transtime, hue, direction, ...optionalParams},
112114
utils.getOptions(meta.mapped, entity),
113115
);
114116
}
@@ -118,7 +120,7 @@ export const light_color: Tz.Converter = {
118120
await entity.command(
119121
"lightingColorCtrl",
120122
"moveToSaturation",
121-
{transtime, saturation, optionsMask: 0, optionsOverride: 0},
123+
{transtime, saturation, ...optionalParams},
122124
utils.getOptions(meta.mapped, entity),
123125
);
124126
}
@@ -148,7 +150,7 @@ export const light_color: Tz.Converter = {
148150
await entity.command(
149151
"lightingColorCtrl",
150152
"moveToColor",
151-
{transtime, colorx, colory, optionsMask: 0, optionsOverride: 0},
153+
{transtime, colorx, colory, ...optionalParams},
152154
utils.getOptions(meta.mapped, entity),
153155
);
154156
} else {
@@ -167,6 +169,8 @@ export const light_colortemp: Tz.Converter = {
167169
convertSet: async (entity, key, value, meta) => {
168170
const [colorTempMin, colorTempMax] = light.findColorTempRange(entity);
169171
const preset = {warmest: colorTempMax, warm: 454, neutral: 370, cool: 250, coolest: colorTempMin};
172+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
173+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
170174

171175
if (key === "color_temp_percent") {
172176
utils.assertNumber(value);
@@ -188,7 +192,7 @@ export const light_colortemp: Tz.Converter = {
188192
await entity.command(
189193
"lightingColorCtrl",
190194
"moveToColorTemp",
191-
{colortemp: value as number, transtime: utils.getTransition(entity, key, meta).time, optionsMask: 0, optionsOverride: 0},
195+
{colortemp: value as number, transtime: utils.getTransition(entity, key, meta).time, ...optionalParams},
192196
utils.getOptions(meta.mapped, entity),
193197
);
194198
return {
@@ -936,6 +940,9 @@ export const light_brightness_step: Tz.Converter = {
936940
key: ["brightness_step", "brightness_step_onoff"],
937941
options: [exposes.options.transition()],
938942
convertSet: async (entity, key, value, meta) => {
943+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
944+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
945+
939946
const onOff = key.endsWith("_onoff");
940947
const command = onOff ? "stepWithOnOff" : "step";
941948
value = Number(value);
@@ -946,7 +953,7 @@ export const light_brightness_step: Tz.Converter = {
946953
await entity.command(
947954
"genLevelCtrl",
948955
command,
949-
{stepmode: mode, stepsize: Math.abs(value), transtime: transition, optionsMask: 0, optionsOverride: 0},
956+
{stepmode: mode, stepsize: Math.abs(value), transtime: transition, ...optionalParams},
950957
utils.getOptions(meta.mapped, entity),
951958
);
952959

@@ -978,8 +985,11 @@ export const light_brightness_step: Tz.Converter = {
978985
export const light_brightness_move: Tz.Converter = {
979986
key: ["brightness_move", "brightness_move_onoff"],
980987
convertSet: async (entity, key, value, meta) => {
988+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
989+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
990+
981991
if (value === "stop" || value === 0) {
982-
await entity.command("genLevelCtrl", "stop", {optionsMask: 0, optionsOverride: 0}, utils.getOptions(meta.mapped, entity));
992+
await entity.command("genLevelCtrl", "stop", {...optionalParams}, utils.getOptions(meta.mapped, entity));
983993

984994
// As we cannot determine the new brightness state, we read it from the device
985995
await utils.sleep(500);
@@ -994,7 +1004,7 @@ export const light_brightness_move: Tz.Converter = {
9941004
await entity.command(
9951005
"genLevelCtrl",
9961006
command,
997-
{movemode: value > 0 ? 0 : 1, rate: Math.abs(value), optionsMask: 0, optionsOverride: 0},
1007+
{movemode: value > 0 ? 0 : 1, rate: Math.abs(value), ...optionalParams},
9981008
utils.getOptions(meta.mapped, entity),
9991009
);
10001010
},
@@ -1003,6 +1013,9 @@ export const light_colortemp_step: Tz.Converter = {
10031013
key: ["color_temp_step"],
10041014
options: [exposes.options.transition()],
10051015
convertSet: async (entity, key, value, meta) => {
1016+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
1017+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
1018+
10061019
value = Number(value);
10071020
utils.assertNumber(value, key);
10081021

@@ -1017,8 +1030,7 @@ export const light_colortemp_step: Tz.Converter = {
10171030
transtime: transition,
10181031
minimum: 0,
10191032
maximum: 600,
1020-
optionsMask: 0,
1021-
optionsOverride: 0,
1033+
...optionalParams,
10221034
},
10231035
utils.getOptions(meta.mapped, entity),
10241036
);
@@ -1036,6 +1048,9 @@ export const light_colortemp_step: Tz.Converter = {
10361048
export const light_colortemp_move: Tz.Converter = {
10371049
key: ["colortemp_move", "color_temp_move"],
10381050
convertSet: async (entity, key, value, meta) => {
1051+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
1052+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
1053+
10391054
// Initialize payload with default constraints
10401055
let minimum = 0;
10411056
let maximum = 600;
@@ -1121,7 +1136,7 @@ export const light_colortemp_move: Tz.Converter = {
11211136
await entity.command(
11221137
"lightingColorCtrl",
11231138
"moveColorTemp",
1124-
{minimum, maximum, rate, movemode, optionsMask: 0, optionsOverride: 0},
1139+
{minimum, maximum, rate, movemode, ...optionalParams},
11251140
utils.getOptions(meta.mapped, entity),
11261141
);
11271142

@@ -1139,6 +1154,9 @@ export const light_color_and_colortemp_via_color: Tz.Converter = {
11391154
key: ["color", "color_temp", "color_temp_percent"],
11401155
options: [exposes.options.color_sync(), exposes.options.transition()],
11411156
convertSet: async (entity, key, value, meta) => {
1157+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
1158+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
1159+
11421160
if (key === "color") {
11431161
return await light_color.convertSet(entity, key, value, meta);
11441162
}
@@ -1152,8 +1170,7 @@ export const light_color_and_colortemp_via_color: Tz.Converter = {
11521170
transtime: utils.getTransition(entity, key, meta).time,
11531171
colorx: utils.mapNumberRange(xy.x, 0, 1, 0, 65535),
11541172
colory: utils.mapNumberRange(xy.y, 0, 1, 0, 65535),
1155-
optionsMask: 0,
1156-
optionsOverride: 0,
1173+
...optionalParams,
11571174
},
11581175
utils.getOptions(meta.mapped, entity),
11591176
);
@@ -1170,6 +1187,9 @@ export const light_hue_saturation_step: Tz.Converter = {
11701187
key: ["hue_step", "saturation_step"],
11711188
options: [exposes.options.transition()],
11721189
convertSet: async (entity, key, value, meta) => {
1190+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
1191+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
1192+
11731193
value = Number(value);
11741194
utils.assertNumber(value, key);
11751195

@@ -1180,7 +1200,7 @@ export const light_hue_saturation_step: Tz.Converter = {
11801200
await entity.command(
11811201
"lightingColorCtrl",
11821202
command,
1183-
{stepmode: mode, stepsize: Math.abs(value), transtime: transition, optionsMask: 0, optionsOverride: 0},
1203+
{stepmode: mode, stepsize: Math.abs(value), transtime: transition, ...optionalParams},
11841204
utils.getOptions(meta.mapped, entity),
11851205
);
11861206

@@ -1196,6 +1216,9 @@ export const light_hue_saturation_step: Tz.Converter = {
11961216
export const light_hue_saturation_move: Tz.Converter = {
11971217
key: ["hue_move", "saturation_move"],
11981218
convertSet: async (entity, key, value, meta) => {
1219+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
1220+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
1221+
11991222
value = value === "stop" ? value : Number(value);
12001223
const command = key === "hue_move" ? "moveHue" : "moveSaturation";
12011224
const attribute = key === "hue_move" ? "currentHue" : "currentSaturation";
@@ -1211,12 +1234,7 @@ export const light_hue_saturation_move: Tz.Converter = {
12111234
movemode = value > 0 ? 1 : 3;
12121235
}
12131236

1214-
await entity.command(
1215-
"lightingColorCtrl",
1216-
command,
1217-
{rate, movemode, optionsMask: 0, optionsOverride: 0},
1218-
utils.getOptions(meta.mapped, entity),
1219-
);
1237+
await entity.command("lightingColorCtrl", command, {rate, movemode, ...optionalParams}, utils.getOptions(meta.mapped, entity));
12201238

12211239
// We cannot determine the hue/saturation from the current state so we read it, because
12221240
// - Color mode could have been switched (x/y or colortemp)
@@ -1238,7 +1256,8 @@ export const light_onoff_brightness: Tz.Converter = {
12381256
const transition = utils.getTransition(entity, "brightness", meta);
12391257
const turnsOffAtBrightness1 = utils.getMetaValue(entity, meta.mapped, "turnsOffAtBrightness1", "allEqual", false);
12401258
const moveToLevelWithOnOffDisable = utils.getMetaValue(entity, meta.mapped, "moveToLevelWithOnOffDisable", "allEqual", false);
1241-
const omitOptionalLevelParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelParams", "allEqual", false);
1259+
const omitOptionalLevelAndColorParams = utils.getMetaValue(entity, meta.mapped, "omitOptionalLevelAndColorParams", "allEqual", false);
1260+
const optionalParams = omitOptionalLevelAndColorParams ? null : {optionsMask: 0, optionsOverride: 0};
12421261
let state = message.state !== undefined ? (typeof message.state === "string" ? message.state.toLowerCase() : null) : undefined;
12431262
let brightness: number;
12441263

@@ -1371,43 +1390,16 @@ export const light_onoff_brightness: Tz.Converter = {
13711390

13721391
if (typeof meta.state.state === "string" && meta.state.state.toLowerCase() !== targetState) {
13731392
if (targetState === "on") {
1374-
const payload = {level: Number(brightness), transtime: transition.time} as {
1375-
level: number;
1376-
transtime: number;
1377-
optionsMask?: number;
1378-
optionsOverride?: number;
1379-
};
1380-
if (!omitOptionalLevelParams) {
1381-
payload.optionsMask = 0;
1382-
payload.optionsOverride = 0;
1383-
}
1393+
const payload = {level: Number(brightness), transtime: transition.time, ...optionalParams};
13841394
await entity.command("genLevelCtrl", "moveToLevel", payload, utils.getOptions(meta.mapped, entity));
13851395
}
13861396
await on_off.convertSet(entity, "state", state, meta);
13871397
} else {
1388-
const payload = {level: Number(brightness), transtime: transition.time} as {
1389-
level: number;
1390-
transtime: number;
1391-
optionsMask?: number;
1392-
optionsOverride?: number;
1393-
};
1394-
if (!omitOptionalLevelParams) {
1395-
payload.optionsMask = 0;
1396-
payload.optionsOverride = 0;
1397-
}
1398+
const payload = {level: Number(brightness), transtime: transition.time, ...optionalParams};
13981399
await entity.command("genLevelCtrl", "moveToLevel", payload, utils.getOptions(meta.mapped, entity));
13991400
}
14001401
} else {
1401-
const payload = {level: Number(brightness), transtime: transition.time} as {
1402-
level: number;
1403-
transtime: number;
1404-
optionsMask?: number;
1405-
optionsOverride?: number;
1406-
};
1407-
if (!omitOptionalLevelParams) {
1408-
payload.optionsMask = 0;
1409-
payload.optionsOverride = 0;
1410-
}
1402+
const payload = {level: Number(brightness), transtime: transition.time, ...optionalParams};
14111403
await entity.command(
14121404
"genLevelCtrl",
14131405
state === null ? "moveToLevel" : "moveToLevelWithOnOff",

src/devices/paul_neuhaus.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,23 @@ export const definitions: DefinitionWithExtend[] = [
5353
vendor: "Paul Neuhaus",
5454
description: "Various color temperature lights (e.g. 100.424.11)",
5555
extend: [m.light({colorTemp: {range: undefined}})],
56-
meta: {omitOptionalLevelParams: true},
56+
meta: {omitOptionalLevelAndColorParams: true},
5757
},
5858
{
5959
zigbeeModel: ["Neuhaus NLG-TW light", "NLG-TW light"],
6060
model: "NLG-TW light",
6161
vendor: "Paul Neuhaus",
6262
description: "Various tunable white lights (e.g. 8195-55)",
6363
extend: [m.light({colorTemp: {range: [153, 370]}})],
64-
meta: {omitOptionalLevelParams: true},
64+
meta: {omitOptionalLevelAndColorParams: true},
6565
},
6666
{
6767
zigbeeModel: ["NLG-RGBW light "], // the space as the end is intentional, as this is what the device sends
6868
model: "NLG-RGBW_light",
6969
vendor: "Paul Neuhaus",
7070
description: "Various RGBW lights (e.g. 100.110.39)",
7171
extend: [m.light({colorTemp: {range: undefined}, color: true})],
72-
meta: {omitOptionalLevelParams: true},
72+
meta: {omitOptionalLevelAndColorParams: true},
7373
endpoint: (device) => {
7474
return {default: 2};
7575
},
@@ -80,15 +80,15 @@ export const definitions: DefinitionWithExtend[] = [
8080
vendor: "Paul Neuhaus",
8181
description: "Various RGBW lights (e.g. 100.111.57)",
8282
extend: [m.light({colorTemp: {range: undefined}, color: true})],
83-
meta: {omitOptionalLevelParams: true},
83+
meta: {omitOptionalLevelAndColorParams: true},
8484
},
8585
{
8686
zigbeeModel: ["NLG-RGB-TW light"],
8787
model: "NLG-RGB-TW light",
8888
vendor: "Paul Neuhaus",
8989
description: "Various RGB + tunable white lights (e.g. 100.470.92)",
9090
extend: [m.light({colorTemp: {range: undefined}, color: true})],
91-
meta: {omitOptionalLevelParams: true},
91+
meta: {omitOptionalLevelAndColorParams: true},
9292
},
9393
{
9494
zigbeeModel: ["NLG-plug"],
@@ -103,7 +103,7 @@ export const definitions: DefinitionWithExtend[] = [
103103
vendor: "Paul Neuhaus",
104104
description: "Q-FLAG LED panel, Smart-Home CCT",
105105
extend: [m.light({colorTemp: {range: undefined}})],
106-
meta: {omitOptionalLevelParams: true},
106+
meta: {omitOptionalLevelAndColorParams: true},
107107
},
108108
{
109109
zigbeeModel: ["JZ-RC-J4R"],
@@ -145,22 +145,22 @@ export const definitions: DefinitionWithExtend[] = [
145145
return {default: 2};
146146
},
147147
extend: [m.light({colorTemp: {range: undefined}, color: true})],
148-
meta: {omitOptionalLevelParams: true},
148+
meta: {omitOptionalLevelAndColorParams: true},
149149
},
150150
{
151151
zigbeeModel: ["JZD60-J4R150"],
152152
model: "100.001.96",
153153
vendor: "Paul Neuhaus",
154154
description: "Q-LED Lamp RGBW E27 socket",
155155
extend: [m.light({colorTemp: {range: undefined}, color: true})],
156-
meta: {omitOptionalLevelParams: true},
156+
meta: {omitOptionalLevelAndColorParams: true},
157157
},
158158
{
159159
zigbeeModel: ["Neuhaus RGB+CCT light"],
160160
model: "100.491.61",
161161
vendor: "Paul Neuhaus",
162162
description: "Q-MIA LED RGBW wall lamp, 9185-13",
163163
extend: [m.light({colorTemp: {range: undefined}, color: true})],
164-
meta: {omitOptionalLevelParams: true},
164+
meta: {omitOptionalLevelAndColorParams: true},
165165
},
166166
];

src/devices/schneider_electric.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2003,7 +2003,7 @@ export const definitions: DefinitionWithExtend[] = [
20032003
schneiderElectricExtend.dimmingMode(),
20042004
indicatorMode(),
20052005
],
2006-
meta: {omitOptionalLevelParams: true},
2006+
meta: {omitOptionalLevelAndColorParams: true},
20072007
configure: async (device, coordinatorEndpoint) => {
20082008
const endpoint = device.getEndpoint(3);
20092009
await reporting.bind(endpoint, coordinatorEndpoint, ["genOnOff", "genLevelCtrl", "lightingBallastCfg"]);

0 commit comments

Comments
 (0)