const TuyaDevice = require('./tuya-device') const debug = require('debug')('tuya-mqtt:device-detect') const debugDiscovery = require('debug')('tuya-mqtt:discovery') const utils = require('../lib/utils') class RGBTWLight extends TuyaDevice { async init() { await this.guessLightInfo() // Set device specific variables this.config.dpsPower = this.config.dpsPower ? this.config.dpsPower : this.guess.dpsPower this.config.dpsMode = this.config.dpsMode ? this.config.dpsMode : this.guess.dpsMode this.config.dpsWhiteValue = this.config.dpsWhiteValue ? this.config.dpsWhiteValue : this.guess.dpsWhiteValue this.config.whiteValueScale = this.config.whiteValueScale ? this.config.whiteValueScale : this.guess.whiteValueScale this.config.dpsColorTemp = this.config.dpsColorTemp ? this.config.dpsColorTemp : this.guess.dpsColorTemp this.config.minColorTemp = this.config.minColorTemp ? this.config.minColorTemp : 165 this.config.maxColorTemp = this.config.maxColorTemp ? this.config.maxColorTemp : 375 this.config.colorTempScale = this.config.colorTempScale ? this.config.colorTempScale : this.guess.colorTempScale this.config.dpsColor = this.config.dpsColor ? this.config.dpsColor : this.guess.dpsColor this.config.colorType = this.config.colorType ? this.config.colorType : this.guess.colorType this.deviceData.mdl = 'RGBTW Light' this.isRgbtwLight = true // Map generic DPS topics to device specific topic names this.deviceTopics = { state: { key: this.config.dpsPower, type: 'bool' }, white_value_state: { key: this.config.dpsWhiteValue, type: 'int', min: 1, max: 100, scale: this.config.whiteValueScale, stateMath: '/('+this.config.whiteValueScale+'/100)', commandMath: '*('+this.config.whiteValueScale+'/100)' }, hs_state: { key: this.config.dpsColor, type: this.config.colorType, components: 'h,s' }, brightness_state: { key: this.config.dpsColor, type: this.config.colorType, components: 'b' }, hsb_state: { key: this.config.dpsColor, type: this.config.colorType, components: 'h,s,b' }, mode_state: { key: this.config.dpsMode, type: 'str' } } // If device supports Color Temperature add color temp device topic if (this.config.dpsColorTemp) { // Values used for tranform const rangeFactor = (this.config.maxColorTemp-this.config.minColorTemp)/100 const scaleFactor = this.config.colorTempScale/100 const tuyaMaxColorTemp = this.config.maxColorTemp/rangeFactor*scaleFactor this.deviceTopics.color_temp_state = { key: this.config.dpsColorTemp, type: 'int', min: this.config.minColorTemp, max: this.config.maxColorTemp, stateMath: '/'+scaleFactor+'*-'+rangeFactor+'+'+this.config.maxColorTemp, commandMath: '/'+rangeFactor+'*-'+scaleFactor+'+'+tuyaMaxColorTemp } } // Send home assistant discovery data and give it a second before sending state updates this.initDiscovery() await utils.sleep(1) // Get initial states and start publishing topics this.getStates() } initDiscovery() { const configTopic = 'homeassistant/light/'+this.config.id+'/config' const discoveryData = { name: (this.config.name) ? this.config.name : this.config.id, state_topic: this.baseTopic+'state', command_topic: this.baseTopic+'command', brightness_state_topic: this.baseTopic+'brightness_state', brightness_command_topic: this.baseTopic+'brightness_command', brightness_scale: 100, hs_state_topic: this.baseTopic+'hs_state', hs_command_topic: this.baseTopic+'hs_command', white_value_state_topic: this.baseTopic+'white_value_state', white_value_command_topic: this.baseTopic+'white_value_command', white_value_scale: 100, unique_id: this.config.id, device: this.deviceData } if (this.config.dpsColorTemp) { discoveryData.color_temp_state_topic = this.baseTopic+'color_temp_state' discoveryData.color_temp_command_topic = this.baseTopic+'color_temp_command' discoveryData.min_mireds = this.config.minColorTemp discoveryData.max_mireds = this.config.maxColorTemp } debugDiscovery('Home Assistant config topic: '+configTopic) debugDiscovery(discoveryData) this.publishMqtt(configTopic, JSON.stringify(discoveryData)) } async guessLightInfo() { this.guess = new Object() debug('Attempting to detect light capabilites and DPS values...') debug('Querying DPS 2 for white/color mode setting...') let mode = await this.device.get({"dps": 2}) if (mode && (mode === 'white' || mode === 'colour' || mode.toString().includes('scene'))) { debug('Detected probably Tuya color bulb at DPS 1-5, checking more details...') this.guess = {'dpsPower': 1, 'dpsMode': 2, 'dpsWhiteValue': 3, 'whiteValueScale': 255, 'dpsColorTemp': 4, 'colorTempScale': 255, 'dpsColor': 5} } else { debug('Detected likely Tuya color bulb at DPS 20-24, checking more details...') this.guess = {'dpsPower': 20, 'dpsMode': 21, 'dpsWhiteValue': 22, 'whiteValueScale': 1000, 'dpsColorTemp': 23, 'colorTempScale': 1000, 'dpsColor': 24} } if (this.guess.dpsPower) { debug('Attempting to detect if bulb supports color temperature...') const colorTemp = await this.device.get({"dps": this.guess.dpsColorTemp}) if (colorTemp !== '' && colorTemp >= 0 && colorTemp <= this.guess.colorTempScale) { debug('Detected likely color temerature support') } else { debug('No color temperature support detected') this.guess.dpsColorTemp = 0 } debug('Attempting to detect Tuya color format used by device...') const color = await this.device.get({"dps": this.guess.dpsColor}) this.guess.colorType = (color && color.length === 12) ? 'hsb' : 'hsbhex' debug ('Detected Tuya color format '+this.guess.colorType.toUpperCase()) } else { debug('No Tuya color bulb detected, if this device is definitely a Tuya bulb please manually specify settings.') } } } module.exports = RGBTWLight