mirror of
https://github.com/lehanspb/tuya-mqtt.git
synced 2025-12-18 16:17:30 +00:00
RGBTW light fixes
This commit is contained in:
@@ -11,7 +11,6 @@ class GenericDevice extends TuyaDevice {
|
|||||||
// Map generic DPS topics to device specific topic names
|
// Map generic DPS topics to device specific topic names
|
||||||
this.deviceTopics = this.config.template
|
this.deviceTopics = this.config.template
|
||||||
} else {
|
} else {
|
||||||
this.deviceTopics = {}
|
|
||||||
// Try to get schema to at least know what DPS keys to get initial update
|
// Try to get schema to at least know what DPS keys to get initial update
|
||||||
const result = await this.device.get({"schema": true})
|
const result = await this.device.get({"schema": true})
|
||||||
if (!utils.isJsonString(result)) {
|
if (!utils.isJsonString(result)) {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ class RGBTWLight extends TuyaDevice {
|
|||||||
|
|
||||||
this.deviceData.mdl = 'RGBTW Light'
|
this.deviceData.mdl = 'RGBTW Light'
|
||||||
|
|
||||||
|
this.isRgbtwLight = true
|
||||||
|
|
||||||
// Map generic DPS topics to device specific topic names
|
// Map generic DPS topics to device specific topic names
|
||||||
this.deviceTopics = {
|
this.deviceTopics = {
|
||||||
state: {
|
state: {
|
||||||
|
|||||||
@@ -33,10 +33,13 @@ class TuyaDevice {
|
|||||||
mf: 'Tuya'
|
mf: 'Tuya'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variables to hold device state data
|
// Property to hold device state data
|
||||||
this.dps = {} // Current dps state data for device
|
this.dps = {} // Current dps state data for device
|
||||||
this.dpsPub = {} // Published dps state data for device
|
this.dpsPub = {} // Published dps state data for device
|
||||||
this.color = {'h': 0, 's': 0, 'b': 0, 't': 0, 'w': 0} // Current color values (Hue, Saturation, Brightness, White Temp, White Level)
|
this.color = {'h': 0, 's': 0, 'b': 0} // HSB color value cache
|
||||||
|
|
||||||
|
// Property to hold friendly topics template
|
||||||
|
this.deviceTopics = {}
|
||||||
|
|
||||||
// Build the MQTT topic for this device (friendly name or device id)
|
// Build the MQTT topic for this device (friendly name or device id)
|
||||||
if (this.options.name) {
|
if (this.options.name) {
|
||||||
@@ -158,7 +161,7 @@ class TuyaDevice {
|
|||||||
break;
|
break;
|
||||||
case 'hsb':
|
case 'hsb':
|
||||||
if (this.dps[key]) {
|
if (this.dps[key]) {
|
||||||
state = this.getColorState(this.dps[key], topic)
|
state = this.convertFromTuyaHsbColor(this.dps[key], topic)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'str':
|
case 'str':
|
||||||
@@ -305,80 +308,87 @@ class TuyaDevice {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'hsb':
|
case 'hsb':
|
||||||
tuyaCommand.set = this.getColorCommand(command, deviceTopic)
|
tuyaCommand.set = this.convertToTuyaHsbColor(command, deviceTopic)
|
||||||
this.setLightMode(deviceTopic)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tuyaCommand.set === '!!!INVALID!!!') {
|
if (tuyaCommand.set === '!!!INVALID!!!') {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
if (this.config.dpsWhiteValue === deviceTopic.key) {
|
if (this.isRgbtwLight) {
|
||||||
this.setLightMode(deviceTopic)
|
this.setLight(deviceTopic, tuyaCommand)
|
||||||
}
|
} else {
|
||||||
this.set(tuyaCommand)
|
this.set(tuyaCommand)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes the current Tuya color and splits it into component parts
|
// Takes the current Tuya color and splits it into HSB component parts
|
||||||
// Updates cached color state for device and returns decimal format
|
// Updates cached color state for device and returns decimal format
|
||||||
// comma delimeted string of components for selected topic
|
// comma delimeted string of components for selected friendly topic
|
||||||
getColorState(value, topic) {
|
convertFromTuyaHsbColor(value, topic) {
|
||||||
|
// Split Tuya HSB value into component parts
|
||||||
const [, h, s, b] = (value || '000003e803e8').match(/^([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})$/i) || [0, '0', '3e8', '3e8'];
|
const [, h, s, b] = (value || '000003e803e8').match(/^([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})$/i) || [0, '0', '3e8', '3e8'];
|
||||||
|
|
||||||
|
// Convert from Hex to Decimal and cache values
|
||||||
this.color.h = parseInt(h, 16)
|
this.color.h = parseInt(h, 16)
|
||||||
this.color.s = Math.round(parseInt(s, 16) / 10)
|
this.color.s = Math.round(parseInt(s, 16) / 10)
|
||||||
this.color.b = parseInt(b, 16)
|
this.color.b = parseInt(b, 16)
|
||||||
|
|
||||||
|
// Return comma separate array of component values for specific topic
|
||||||
const color = new Array()
|
const color = new Array()
|
||||||
const components = this.deviceTopics[topic].components.split(',')
|
const components = this.deviceTopics[topic].components.split(',')
|
||||||
|
|
||||||
for (let i in components) {
|
for (let i in components) {
|
||||||
if (components.hasOwnProperty([components[i]])) {
|
color.push(this.color[components[i]])
|
||||||
color.push(decimalColor[components[i]])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (color.join(','))
|
return (color.join(','))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes provided decimal HSB components from MQTT topic, combine with existing
|
// Takes provided decimal HSB components from MQTT topic, combines with cached
|
||||||
// settings for unchanged values since brightness is sometimes sent separately
|
// unchanged values since, for example, brightness is sometimes sent separately
|
||||||
// Convert to Tuya hex format and return value
|
// then convers to Tuya hex format and returns value
|
||||||
getColorCommand(value, topic) {
|
convertToTuyaHsbColor(value, topic) {
|
||||||
const [, h, s, b] = (this.dps[topic.key] || '000003e803e8').match(/^([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})$/i) || [0, '0', '3e8', '3e8'];
|
// Start with cached color values
|
||||||
const decimalColor = {
|
const newColor = this.color
|
||||||
h: parseInt(h, 16),
|
|
||||||
s: Math.round(parseInt(s, 16) / 10),
|
// Update any HSB component with a changed value
|
||||||
b: parseInt(b, 16)
|
|
||||||
}
|
|
||||||
const components = topic.components.split(',')
|
const components = topic.components.split(',')
|
||||||
const values = value.split(',')
|
const values = value.split(',')
|
||||||
for (let i in components) {
|
for (let i in components) {
|
||||||
decimalColor[components[i]] = Math.round(values[i])
|
newColor[components[i]] = Math.round(values[i])
|
||||||
}
|
}
|
||||||
const hexColor = decimalColor.h.toString(16).padStart(4, '0') + (10 * decimalColor.s).toString(16).padStart(4, '0') + (decimalColor.b).toString(16).padStart(4, '0')
|
|
||||||
|
// Convert new HSB color to Tuya style HSB format
|
||||||
|
const hexColor = newColor.h.toString(16).padStart(4, '0') + (10 * newColor.s).toString(16).padStart(4, '0') + (newColor.b).toString(16).padStart(4, '0')
|
||||||
return hexColor
|
return hexColor
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set light mode based on received command
|
// Set light based on received command
|
||||||
async setLightMode(topic) {
|
async setLight(topic, command) {
|
||||||
const currentMode = this.dps[this.config.dpsMode]
|
let targetMode = undefined
|
||||||
let targetMode
|
|
||||||
|
|
||||||
if (this.config.dpsWhiteValue === topic.key) {
|
if (this.config.dpsWhiteValue === topic.key) {
|
||||||
// If setting white level, switch to white mode
|
// If setting white level, or saturation = 0, target is white mode
|
||||||
targetMode = 'white'
|
targetMode = 'white'
|
||||||
} else if (this.config.dpsColor === topic.key) {
|
} else if (this.config.dpsColor === topic.key) {
|
||||||
|
// Split Tuya HSB value into component parts
|
||||||
|
const [, h, s, b] = (command.set || '000003e803e8').match(/^([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})$/i) || [0, '0', '3e8', '3e8'];
|
||||||
|
if (s > 0) {
|
||||||
// If setting an HSB value, switch to colour mode
|
// If setting an HSB value, switch to colour mode
|
||||||
targetMode = 'colour'
|
targetMode = 'colour'
|
||||||
|
} else {
|
||||||
|
targetMode = 'white'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the correct light mode
|
// Set the correct light mode
|
||||||
if (targetMode && targetMode !== currentMode) {
|
if (targetMode) {
|
||||||
const tuyaCommand = {
|
const tuyaCommand = {
|
||||||
dps: this.config.dpsMode,
|
dps: this.config.dpsMode,
|
||||||
set: targetMode
|
set: targetMode
|
||||||
}
|
}
|
||||||
await this.set(tuyaCommand)
|
await this.set(tuyaCommand)
|
||||||
}
|
}
|
||||||
|
this.set(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple function to help debug output
|
// Simple function to help debug output
|
||||||
@@ -387,10 +397,9 @@ class TuyaDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set(command) {
|
set(command) {
|
||||||
debug('Set device '+this.options.id+' -> '+command)
|
debug('Set device '+this.options.id+' -> '+JSON.stringify(command))
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.device.set(command).then((result) => {
|
this.device.set(command).then((result) => {
|
||||||
debug(result)
|
|
||||||
resolve(result)
|
resolve(result)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user