From 748a5cae39c2be5a42342f0cdd1a70d0c0f42a64 Mon Sep 17 00:00:00 2001 From: tsightler Date: Thu, 15 Oct 2020 11:05:41 -0400 Subject: [PATCH] Minor enhancements * Properly disconnect from devices on exit * Monitor for Home Assistant status and resend discovery --- devices/rgbtw-light.js | 14 ++++++++++---- devices/simple-dimmer.js | 3 +++ devices/simple-switch.js | 3 +++ devices/tuya-device.js | 1 - tuya-mqtt.js | 42 ++++++++++++++++++++++++++++++++++------ 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/devices/rgbtw-light.js b/devices/rgbtw-light.js index 1d13620..1a66781 100644 --- a/devices/rgbtw-light.js +++ b/devices/rgbtw-light.js @@ -5,12 +5,16 @@ const utils = require('../lib/utils') class RGBTWLight extends TuyaDevice { async init() { - await this.guessLightInfo() + // 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 @@ -25,7 +29,6 @@ class RGBTWLight extends TuyaDevice { 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 @@ -66,7 +69,7 @@ class RGBTWLight extends TuyaDevice { // If device supports Color Temperature add color temp device topic if (this.config.dpsColorTemp) { - // Values used for tranform + // 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 @@ -104,6 +107,9 @@ class RGBTWLight extends TuyaDevice { 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 } diff --git a/devices/simple-dimmer.js b/devices/simple-dimmer.js index 23e2c3e..766117e 100644 --- a/devices/simple-dimmer.js +++ b/devices/simple-dimmer.js @@ -44,6 +44,9 @@ class SimpleDimmer extends TuyaDevice { command_topic: this.baseTopic+'command', brightness_state_topic: this.baseTopic+'brightness_state', brightness_command_topic: this.baseTopic+'brightness_command', + availability_topic: this.baseTopic+'status', + payload_available: 'online', + payload_not_available: 'offline', unique_id: this.config.id, device: this.deviceData } diff --git a/devices/simple-switch.js b/devices/simple-switch.js index e0f57c7..ef8337e 100644 --- a/devices/simple-switch.js +++ b/devices/simple-switch.js @@ -33,6 +33,9 @@ class SimpleSwitch extends TuyaDevice { name: (this.config.name) ? this.config.name : this.config.id, state_topic: this.baseTopic+'state', command_topic: this.baseTopic+'command', + availability_topic: this.baseTopic+'status', + payload_available: 'online', + payload_not_available: 'offline', unique_id: this.config.id, device: this.deviceData } diff --git a/devices/tuya-device.js b/devices/tuya-device.js index e3ef901..ae27a89 100644 --- a/devices/tuya-device.js +++ b/devices/tuya-device.js @@ -1,7 +1,6 @@ const TuyAPI = require('tuyapi') const { evaluate } = require('mathjs') const utils = require('../lib/utils') -const { msSleep } = require('../lib/utils') const debug = require('debug')('tuya-mqtt:tuyapi') const debugState = require('debug')('tuya-mqtt:state') const debugCommand = require('debug')('tuya-mqtt:command') diff --git a/tuya-mqtt.js b/tuya-mqtt.js index ecf30bf..811c5b1 100644 --- a/tuya-mqtt.js +++ b/tuya-mqtt.js @@ -9,10 +9,27 @@ const SimpleSwitch = require('./devices/simple-switch') const SimpleDimmer = require('./devices/simple-dimmer') const RGBTWLight = require('./devices/rgbtw-light') const GenericDevice = require('./devices/generic-device') +const utils = require('./lib/utils') var CONFIG = undefined var tuyaDevices = new Array() +// Setup Exit Handlers +process.on('exit', processExit.bind(0)) +process.on('SIGINT', processExit.bind(0)) +process.on('SIGTERM', processExit.bind(0)) +process.on('uncaughtException', processExit.bind(1)) + +// Set unreachable status on exit +async function processExit(exitCode) { + for (let tuyaDevice of tuyaDevices) { + tuyaDevice.device.disconnect() + } + if (exitCode || exitCode === 0) debug('Exit code: '+exitCode) + await utils.sleep(1) + process.exit() +} + function getDevice(configDevice, mqttClient) { const deviceInfo = { configDevice: configDevice, @@ -40,6 +57,15 @@ function initDevices(configDevices, mqttClient) { } } +async function republishDevices() { + // Republish devices and state after 30 seconds if restart of HA is detected + debug('Resending device config/state in 30 seconds') + await utils.sleep(30) + for (let device of tuyaDevices) { + device.init() + } +} + // Main code function const main = async() => { let configDevices @@ -84,10 +110,9 @@ const main = async() => { mqttClient.on('connect', function (err) { debug('Connection established to MQTT server') let topic = CONFIG.topic + '#' - mqttClient.subscribe(topic, { - retain: CONFIG.retain, - qos: CONFIG.qos - }) + mqttClient.subscribe(topic) + mqttClient.subscribe('homeassistant/status') + mqttClient.subscribe('hass/status') initDevices(configDevices, mqttClient) }) @@ -111,8 +136,13 @@ const main = async() => { const commandTopic = splitTopic[topicLength - 1] const deviceTopicLevel = splitTopic[1] - // If it looks like a valid command topic try to process it - if (commandTopic.includes('command')) { + if (topic === 'homeassistant/status' || topic === 'hass/status' ) { + debug('Home Assistant state topic '+topic+' received message: '+message) + if (message === 'online') { + republishDevices() + } + } else if (commandTopic.includes('command')) { + // If it looks like a valid command topic try to process it debugCommand('Received MQTT message -> ', JSON.stringify({ topic: topic, message: message