Skip to content

Commit

Permalink
Handle bare JavaScript Booleans returned from apply() functions, and …
Browse files Browse the repository at this point in the history
…pass values for Boolean properties to apply functions without prior conversion to string
  • Loading branch information
arachnetech committed Mar 14, 2020
1 parent 9781e42 commit 027dccb
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 23 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
# homebridge-mqttthing
Homebridge plugin supporting various services over MQTT, originally based on homebrige-mqttswitch and homebridge-mqttlightbulb

---

* [Installation](#installation)
* [Configuration](#configuration)
* [Supported Accessories](#supported-accessories)
* [Release notes](#release-notes)

## Compatibility with previous versions

**From version 1.1.x, raw JavaScript values for Boolean properties are passed to MQTT apply functions.** This may change published message formats, e.g. when apply functions are used to build JSON strings.

For full details of changes please see the [Release notes](#release-notes) section.

# Installation
Follow the instructions in [homebridge](https://www.npmjs.com/package/homebridge) for the homebridge server installation.
This plugin is published through [NPM](https://www.npmjs.com/package/homebridge-mqttthing) and should be installed "globally" by typing:
Expand Down Expand Up @@ -1277,6 +1285,11 @@ Window covering position state can be **DECREASING**, **INCREASING** or **STOPPE

# Release notes

Version 1.1.1
+ Changed Boolean value handling to support bare JavaScript Booleans returned from incoming MQTT apply() functions (`"true" != true` but both are now accepted).
+ Boolean property values passed to outgoing MQTT apply() functions are no-longer converted to strings first (for consistency with the change above). This allows easier publishing of JSON containing correctly typed values, but **may change outgoing message format with existing configurations in some situations**.
+ Added option to configure garage door target values independently of current values - thanks, Charles Powell

Version 1.0.50
+ Stateless Programmable Switch: allow multiple buttons under a single switch - thanks, Jacob Nite

Expand Down
86 changes: 65 additions & 21 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,10 @@ function makeThing(log, config) {
};
}

// Convert from boolean true/false to MQTT-published boolean value (as configured) - returns null if no offValue
function onOffValue(value) {
var mqttval;
//! Determine appropriate on/off value for Boolean property (not forced to string) for MQTT publishing.
//! Returns null if no offValue.
function getOnOffPubValue( value ) {
let mqttval;
if( config.onValue ) {
// using onValue/offValue
mqttval = value ? config.onValue : config.offValue;
Expand All @@ -261,18 +262,59 @@ function makeThing(log, config) {
if( mqttval === undefined || mqttval === null ) {
return null;
} else {
return mqttval.toString();
return mqttval;
}
}

function onlineOfflineValue( value ) {
//! Test whether a value represents 'on'
function isRecvValueOn( mqttval ) {
let onval = getOnOffPubValue( true );
return mqttval === onval || mqttval == ( onval + '' );
}

//! Test whether a value represents 'off'
function isRecvValueOff( mqttval ) {
let offval = getOnOffPubValue( false );

if( offval === null ) {
// there is no off value
return false;
}

if( mqttval === offval || mqttval == ( offval + '' ) ) {
// off value match - it's definitely off
return true;
}

if( config.otherValueOff ) {
if( ! isRecvValueOn( mqttval ) ) {
// it's not the on value and we consider any other value to be off
return true;
}
}

// not off
return false;
}

function getOnlineOfflinePubValue( value ) {
var pubVal = ( value ? config.onlineValue : config.offlineValue );
if( pubVal === undefined ) {
pubVal = onOffValue( value );
pubVal = getOnOffPubValue( value );
}
return pubVal;
}

function isRecvValueOnline( mqttval ) {
let onval = getOnlineOfflinePubValue( true );
return mqttval === onval || mqttval == ( onval + '' );
}

function isRecvValueOffline( mqttval ) {
let offval = getOnlineOfflinePubValue( false );
return mqttval === offval || mqttval == ( offval + '' );
}

function mapValueForHomebridge(val, mapValueFunc) {
if (mapValueFunc) {
return mapValueFunc(val);
Expand Down Expand Up @@ -313,7 +355,7 @@ function makeThing(log, config) {
charac.on('set', function (value, callback, context) {
if (context !== c_mySetContext) {
state[property] = value;
publish( onOffValue( value ) );
publish( getOnOffPubValue( value ) );
}
callback();

Expand All @@ -326,7 +368,7 @@ function makeThing(log, config) {
autoOffTimer = null;

state[property] = false;
publish( onOffValue( false ) );
publish( getOnOffPubValue( false ) );
service.getCharacteristic(characteristic).setValue(mapValueForHomebridge(false, mapValueFunc), undefined, c_mySetContext);

}, turnOffAfterms );
Expand All @@ -340,16 +382,15 @@ function makeThing(log, config) {
// subscribe to get topic
if (getTopic) {
mqttSubscribe(getTopic, function (topic, message) {
// determine whether this is an on or off value
let newState = false; // assume off
if( message == onOffValue( true ) ) {
if( isRecvValueOn( message ) ) {
newState = true; // received on value so on
} else {
let offValue = onOffValue( false );
if( offValue !== null && message != offValue && ! config.otherValueOff ) {
// there is a specific off value, but we've received something else - so ignore message
return;
}
} else if ( ! isRecvValueOff( message ) ) {
// received value NOT acceptable as 'off' so ignore message
return;
}
// if it changed, set characteristic
if (state[property] != newState) {
state[property] = newState;
service.getCharacteristic(characteristic).setValue(mapValueForHomebridge(newState, mapValueFunc), undefined, c_mySetContext);
Expand All @@ -369,21 +410,24 @@ function makeThing(log, config) {
}
}

function booleanState( property, getTopic, initialValue, onOffFunc ) {
function booleanState( property, getTopic, initialValue, isOnFunc, isOffFunc ) {
// default state
state[ property ] = ( initialValue ? true : false );

// MQTT subscription
if( getTopic ) {
mqttSubscribe( getTopic, function( topic, message ) {
var newState = ( message == onOffFunc( true ) );
state[ property ] = newState;
if( isOnFunc( message ) ) {
state[ property ] = true;
} else if( isOffFunc( message ) ) {
state[ property ] = false;
}
} );
}
}

function state_Online() {
booleanState( 'online', config.topics.getOnline, true, onlineOfflineValue );
booleanState( 'online', config.topics.getOnline, true, isRecvValueOnline, isRecvValueOffline );
}

function integerCharacteristic(service, property, characteristic, setTopic, getTopic, initialValue) {
Expand Down Expand Up @@ -1966,7 +2010,7 @@ function makeThing(log, config) {
function timerFunc() {
durationTimer = null;
state.active = false;
mqttPublish( config.topics.setActive, onOffValue( false ) );
mqttPublish( config.topics.setActive, getOnOffPubValue( false ) );
characActive.updateValue( Characteristic.Active.INACTIVE );
}

Expand All @@ -1986,7 +2030,7 @@ function makeThing(log, config) {
charac.updateValue( getRemainingDuration() );
});
} else {
// device will handle the timer by itfelf
// device will handle the timer by itself
characActive.on('change', function (obj) {
if ( obj.newValue == Characteristic.Active.ACTIVE ) {
state.durationEndTime = Math.floor(Date.now() / 1000) + state.setDuration;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "homebridge-mqttthing",
"version": "1.0.50",
"version": "1.1.1",
"description": "Homebridge plugin supporting various services over MQTT",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion test/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"setOn": { "topic": "test/rgblight/on/set", "apply": "return JSON.stringify( { state: { power: message }, version: 1 } );" }
},
"logMqtt": true,
"integerValue": true,
"integerValue": false,
"hex": true
},
{
Expand Down

0 comments on commit 027dccb

Please sign in to comment.