mirror of
https://github.com/lehanspb/tuya-mqtt.git
synced 2025-12-16 17:54:36 +00:00
162 lines
7.5 KiB
JavaScript
162 lines
7.5 KiB
JavaScript
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() {
|
|
// If no manual config try to detect device settings
|
|
if (!this.config.dpsPower) {
|
|
await this.guessLightInfo()
|
|
}
|
|
|
|
// If detection failed and no manual config return without initializing
|
|
if (!this.guess.dpsPower && !this.config.dpsPower) {
|
|
debug('Automatic discovery of Tuya bulb settings failed and no manual configuration')
|
|
return
|
|
}
|
|
|
|
// 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 : 154 // ~6500K
|
|
this.config.maxColorTemp = this.config.maxColorTemp ? this.config.maxColorTemp : 400 // ~2500K
|
|
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_brightness_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'
|
|
},
|
|
color_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 tranforming from 1-255 scale to mireds range
|
|
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+'color_brightness_state',
|
|
brightness_command_topic: this.baseTopic+'color_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_brightness_state',
|
|
white_value_command_topic: this.baseTopic+'white_brightness_command',
|
|
white_value_scale: 100,
|
|
availability_topic: this.baseTopic+'status',
|
|
payload_available: 'online',
|
|
payload_not_available: 'offline',
|
|
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...')
|
|
|
|
// Check if DPS 2 contains typical values for RGBTW light
|
|
const mode2 = await this.device.get({"dps": 2})
|
|
const mode21 = await this.device.get({"dps": 21})
|
|
if (mode2 && (mode2 === 'white' || mode2 === 'colour' || mode2.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 if (mode21 && (mode21 === 'white' || mode21 === 'colour' || mode21.toString().includes('scene'))) {
|
|
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())
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = RGBTWLight |