Skip to content

Commit

Permalink
Fix color handling for LIDL light bar (Koenkk/zigbee2mqtt#13421)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreKR committed Feb 23, 2023
1 parent 1691f8e commit 8c47764
Showing 1 changed file with 121 additions and 1 deletion.
122 changes: 121 additions & 1 deletion devices/lidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ const ea = exposes.access;
const tuya = require('../lib/tuya');
const globalStore = require('../lib/store');
const ota = require('../lib/ota');
const utils = require('../lib/utils');
const constants = require('../lib/constants');
const libColor = require('../lib/color');

const COLOR_MODE_COLOR_TEMP = constants.colorMode[2];
const COLOR_MODE_HS = constants.colorMode[0];

const tuyaLocal = {
dataPoints: {
Expand Down Expand Up @@ -356,6 +362,118 @@ const tzLocal = {
await tuya.sendDataPointRaw(entity, (109+day-1), results);
},
},
tuya_led_control: {
key: ['brightness', 'color', 'color_temp', 'transition'],
options: [exposes.options.color_sync()],
convertSet: async (entity, _key, _value, meta) => {
const newState = {};


// The color mode encodes whether the light is using its white LEDs or its color LEDs
let colorMode = meta.state.color_mode || COLOR_MODE_COLOR_TEMP;

// Color mode switching is done by setting color temperature (switch to white LEDs) or setting color (switch
// to color LEDs)
if ('color_temp' in meta.message) {
colorMode = COLOR_MODE_COLOR_TEMP;
}
if ('color' in meta.message) {
colorMode = COLOR_MODE_HS;
}

if (colorMode != meta.state.color_mode) {
newState.color_mode = colorMode;

// We need to send a command to switch from white LEDs to color LEDs. We don't need to send one to
// switch back because the color LEDs are automatically turned off by the moveToColorTemp and
// moveToLevel commands.
if (colorMode == COLOR_MODE_HS) {
await entity.command('lightingColorCtrl', 'tuyaRgbMode', {enable: 1}, {}, {disableDefaultResponse: true});
}
}


// A transition time of 0 would be treated as about 1 second, probably some kind of fallback/default
// transition time, so for "no transition" we use 1 (tenth of a second).
let transtime = 1;
if ('transition' in meta.message) {
transtime = meta.message.transition * 10;
}


if (colorMode == COLOR_MODE_COLOR_TEMP) {
if ('brightness' in meta.message) {
const zclData = {level: Number(meta.message.brightness), transtime: transtime};
await entity.command('genLevelCtrl', 'moveToLevel', zclData, utils.getOptions(meta.mapped, entity));
newState.brightness = meta.message.brightness;
}

if ('color_temp' in meta.message) {
const zclData = {colortemp: meta.message.color_temp, transtime: transtime};
await entity.command('lightingColorCtrl', 'moveToColorTemp', zclData, utils.getOptions(meta.mapped, entity));
newState.color_temp = meta.message.color_temp;
}
}

if (colorMode == COLOR_MODE_HS) {
if ('brightness' in meta.message || 'color' in meta.message) {
// We ignore the brightness of the color and instead use the overall brightness setting of the lamp
// for the brightness because I think that's the expected behavior and also because the color
// conversion below always returns 100 as brightness ("value") even for very dark colors, except
// when the color is completely black/zero.

// Load current state or defaults
const newSettings = {
brightness: meta.state.brightness || 254, // full brightness
hue: (meta.state.color || {}).h || 0, // red
saturation: (meta.state.color || {}).s || 100, // full saturation
};

// Apply changes
if ('brightness' in meta.message) {
newSettings.brightness = meta.message.brightness;
newState.brightness = meta.message.brightness;
}
if ('color' in meta.message) {
// The Z2M UI sends `{ hex:'#xxxxxx' }`.
// Home Assistant sends `{ h: xxx, s: xxx }`.
// We convert the former into the latter.
const c = libColor.Color.fromConverterArg(meta.message.color);
if (c.isRGB()) {
// https://github.com/Koenkk/zigbee2mqtt/issues/13421#issuecomment-1426044963
c.hsv = c.rgb.gammaCorrected().toXY().toHSV();
}
const color = c.hsv;

newSettings.hue = color.hue;
newSettings.saturation = color.saturation;

newState.color = {
h: color.hue,
s: color.saturation,
};
}

// Convert to device specific format and send
const zclData = {
brightness: utils.mapNumberRange(newSettings.brightness, 0, 254, 0, 1000),
hue: newSettings.hue,
saturation: utils.mapNumberRange(newSettings.saturation, 0, 100, 0, 1000),
};
// This command doesn't support a transition time
await entity.command('lightingColorCtrl', 'tuyaMoveToHueAndSaturationBrightness2', zclData,
utils.getOptions(meta.mapped, entity));
}
}

return {state: newState};
},
convertGet: async (entity, key, meta) => {
await entity.read('lightingColorCtrl', [
'currentHue', 'currentSaturation', 'tuyaBrightness', 'tuyaRgbMode', 'colorTemperature',
]);
},
},
};

module.exports = [
Expand Down Expand Up @@ -739,7 +857,9 @@ module.exports = [
model: '14149505L/14149506L',
vendor: 'Lidl',
description: 'Livarno Lux light bar RGB+CCT (black/white)',
extend: tuya.extend.light_onoff_brightness_colortemp_color({noConfigure: true}),
toZigbee: [tz.on_off, tzLocal.tuya_led_control],
fromZigbee: [fz.on_off, fz.tuya_led_controller, fz.brightness, fz.ignore_basic_report],
exposes: [e.light_brightness_colortemp_colorhs([153, 500]).removeFeature('color_temp_startup')],
configure: async (device, coordinatorEndpoint, logger) => {
device.getEndpoint(1).saveClusterAttributeKeyValue('lightingColorCtrl', {colorCapabilities: 29});
},
Expand Down

0 comments on commit 8c47764

Please sign in to comment.