From cf71d1fa6af252c1cff156de68b13b5d7ce21137 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 12 Jan 2021 17:22:14 +0100 Subject: [PATCH] fix: set retain to false for stateless valueIds (#215) * fix: set retain to false for stateless valueIds * fix: reset stateless values * fix: set lower timeout --- lib/Gateway.js | 2 +- lib/MqttClient.js | 5 ++++- lib/ZwaveClient.js | 38 +++++++++++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/Gateway.js b/lib/Gateway.js index 7092ef5042..f8a962c5aa 100755 --- a/lib/Gateway.js +++ b/lib/Gateway.js @@ -324,7 +324,7 @@ function onValueChanged (valueId, node, changed) { this.topicValues[topic] = valueId } - this.mqtt.publish(topic, data) + this.mqtt.publish(topic, data, valueId.stateless ? { retain: false } : null) } function onNotification (node, notificationLabel, parameters) { diff --git a/lib/MqttClient.js b/lib/MqttClient.js index 303b78327c..b1b168c962 100644 --- a/lib/MqttClient.js +++ b/lib/MqttClient.js @@ -343,11 +343,14 @@ MqttClient.prototype.subscribe = function (topic) { */ MqttClient.prototype.publish = function (topic, data, options, prefix) { if (this.client) { - options = options || { + const settingOptions = { qos: this.config.qos, retain: this.config.retain } + // by default use settingsOptions + options = Object.assign(settingOptions, options) + topic = (prefix || this.config.prefix) + '/' + topic logger.log( diff --git a/lib/ZwaveClient.js b/lib/ZwaveClient.js index fc4cd4eb18..ef691f4cc0 100644 --- a/lib/ZwaveClient.js +++ b/lib/ZwaveClient.js @@ -49,6 +49,8 @@ function ZwaveClient (config, socket) { this.cfg = config this.socket = socket + this.statelessTimeouts = {} + this.closed = false this.driverReady = false this.scenes = jsonStore.get(store.scenes) @@ -469,11 +471,11 @@ function onNodeValueAdded (zwaveNode, args) { * @param {import('zwave-js/build/lib/node/Types').ZWaveNodeValueNotificationArgs} args */ function onNodeValueNotification (zwaveNode, args) { - logger.debug( - 'In onNodeValueNotification: Overwriting args.newValue with args.value' - ) + // notification hasn't `newValue` args.newValue = args.value - onNodeValueUpdated.call(this, zwaveNode, args, true) + // specify that this is stateless + args.stateless = true + onNodeValueUpdated.call(this, zwaveNode, args) } /** @@ -483,11 +485,11 @@ function onNodeValueNotification (zwaveNode, args) { * @param {import('zwave-js').ZWaveNodeValueUpdatedArgs} args * @param {boolean} isNotification */ -function onNodeValueUpdated (zwaveNode, args, isNotification) { +function onNodeValueUpdated (zwaveNode, args) { updateValue.call(this, zwaveNode, args) logger.info( `Node ${zwaveNode.id}: value ${ - isNotification ? 'notification' : 'updated' + args.stateless ? 'notification' : 'updated' }: ${getValueID(args)} ${args.prevValue} => ${args.newValue}` ) @@ -794,7 +796,8 @@ function updateValueMetadata (zwaveNode, zwaveValue, zwaveValueMeta) { writeable: zwaveValueMeta.writeable, description: zwaveValueMeta.description, label: zwaveValueMeta.label || zwaveValue.propertyName + ' (property)', // when label is missing, re use propertyName. Usefull for webinterface - default: zwaveValueMeta.default + default: zwaveValueMeta.default, + stateless: false // used for notifications to specify that this should not be persisted (retained) } if (zwaveValueMeta.ccSpecific) { @@ -906,8 +909,22 @@ function updateValue (zwaveNode, args) { if (valueId) { valueId.value = args.newValue + valueId.stateless = !!args.stateless this.emit('valueChanged', valueId, node, args.prevValue !== args.newValue) + + const self = this + + if (valueId.stateless) { + if (this.statelessTimeouts[valueId.id]) { + clearTimeout(this.statelessTimeouts[valueId.id]) + } + + this.statelessTimeouts[valueId.id] = setTimeout(() => { + valueId.value = undefined + self.emit('valueChanged', valueId, node, false) + }, 1000) + } } node.lastActive = Date.now() } @@ -1220,6 +1237,13 @@ ZwaveClient.prototype.close = async function () { this.healTimeout = null } + if (this.statelessTimeouts) { + for (const k in this.statelessTimeouts) { + clearTimeout(this.statelessTimeouts[k]) + delete this.statelessTimeouts[k] + } + } + if (this.driver) { this.driverReady = false this.removeAllListeners()