Skip to content

Commit

Permalink
Fix Lidl 14149505L/14149506L color handling (#5514)
Browse files Browse the repository at this point in the history
* Fix color handling for LIDL light bar (Koenkk/zigbee2mqtt#13421)

* Update lidl.js

---------

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
  • Loading branch information
AndreKR and Koenkk committed Feb 23, 2023
1 parent ac726b5 commit 985fe1e
Showing 1 changed file with 104 additions and 1 deletion.
105 changes: 104 additions & 1 deletion devices/lidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ 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 {ColorMode} = require('../lib/constants');
const libColor = require('../lib/color');

const tuyaLocal = {
dataPoints: {
Expand Down Expand Up @@ -142,6 +145,104 @@ const fzLocal = {
},
};
const tzLocal = {
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 || ColorMode.ColorTemp;

// 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 = ColorMode.ColorTemp;
if ('color' in meta.message) colorMode = ColorMode.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 == ColorMode.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).
const transtime = 'transition' in meta.message ? meta.message.transition * 10 : 1;

if (colorMode == ColorMode.ColorTemp) {
if ('brightness' in meta.message) {
const zclData = {level: Number(meta.message.brightness), 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;
}
} else if (colorMode == ColorMode.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', 'currentLevel', 'tuyaRgbMode', 'colorTemperature']);
},
},
zs_thermostat_child_lock: {
key: ['child_lock'],
convertSet: async (entity, key, value, meta) => {
Expand Down Expand Up @@ -739,7 +840,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.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 985fe1e

Please sign in to comment.