Skip to content

Commit

Permalink
Release 3.1.0 (#439)
Browse files Browse the repository at this point in the history
Release 3.1.0 

* Unify logs (#415)

* Fixes for Local Key Updates by Tuya. (#413)

* Adding back the original set multistate command as the new "setMultiState" function from PR #267 Breaks the Fan Code by splitting the command into two. For devices like the DETA Smart Fan Controller Switch that by default set the speed as 3 the new code in the setMultiState function causes issues. This commit is is adding it back as "setMultiStateLegacy" so as to not revert the issue fixed in PR (#267).

* Remove SimpleBlinds2 from config.schema.json and index.js (#390)
---------

Co-authored-by: 05TEVE <>
Co-authored-by: Valentin Dusollier <valentin.dusollier@icloud.com>
Co-authored-by: Long Zheng <long.zheng@gmail.com>
  • Loading branch information
3 people authored Feb 5, 2024
1 parent f8f3ae6 commit 95789f8
Show file tree
Hide file tree
Showing 17 changed files with 518 additions and 312 deletions.
42 changes: 35 additions & 7 deletions config.schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"pluginAlias": "Tuya",
"pluginAlias": "TuyaLan",
"pluginType": "platform",
"singular": true,
"headerDisplay": "<p align='center'><img height='60px' src='https://user-images.githubusercontent.com/3979615/78354049-dc7ff780-75f6-11ea-8026-2f8bf81d8331.png'></p>\n\nBefore using the Tuya plugin you need to discover your devices by following [these instructions](https://github.com/AMoo-Miki/homebridge-tuya-lan/wiki/Setup-Instructions).\n\n",
Expand All @@ -24,7 +24,7 @@
"null"
]
},
{
{
"title": "Smart Plug / Barely Smart Power Strip",
"enum": [
"Outlet"
Expand Down Expand Up @@ -97,15 +97,21 @@
]
},
{
"title": "Simple Blinds2",
"title": "Smart Plug w/ White and Color Lights",
"enum": [
"Simple Blinds2"
"RGBTWOutlet"
]
},
{
"title": "Smart Plug w/ White and Color Lights",
"title": "Simple Fan",
"enum": [
"RGBTWOutlet"
"Fan"
]
},
{
"title": "Simple Fan Light",
"enum": [
"FanLight"
]
}
]
Expand All @@ -120,7 +126,7 @@
},
"id": {
"type": "string",
"title": "Tuya ID",
"title": "Tuya ID",
"description": "If you don't have the Tuya ID or Key, follow the steps found on the <a href='https://github.com/AMoo-Miki/homebridge-tuya-lan/wiki/Setup-Instructions' target='_blank'>Setup Instructions</a> page.",
"required": true,
"condition": {
Expand All @@ -135,6 +141,14 @@
"functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
}
},
"ip": {
"title": "IP Address",
"type": "string",
"required": false,
"condition": {
"functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
}
},
"manufacturer": {
"type": "string",
"description": "Anything you'd like to use to help identify this device.",
Expand Down Expand Up @@ -366,6 +380,20 @@
"functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
}
},
"maxSpeed": {
"type": "integer",
"placeholder": "3",
"condition": {
"functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
}
},
"fanDefaultSpeed": {
"type": "integer",
"placeholder": "1",
"condition": {
"functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
}
},
"dpChildLock": {
"type": "integer",
"placeholder": "6",
Expand Down
7 changes: 5 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const SwitchAccessory = require('./lib/SwitchAccessory');
const ValveAccessory = require('./lib/ValveAccessory');
const OilDiffuserAccessory = require('./lib/OilDiffuserAccessory');

const PLUGIN_NAME = 'homebridge-tuya-lan';
const PLUGIN_NAME = 'homebridge-tuya';
const PLATFORM_NAME = 'TuyaLan';

const CLASS_DEF = {
Expand Down Expand Up @@ -105,7 +105,7 @@ class TuyaLan {

this.log.info('Starting discovery...');

TuyaDiscovery.start({ids: deviceIds})
TuyaDiscovery.start({ids: deviceIds, log: this.log})
.on('discover', config => {
if (!config || !config.id) return;
if (!devices[config.id]) return this.log.warn('Discovered a device that has not been configured yet (%s@%s).', config.id, config.ip);
Expand All @@ -116,6 +116,7 @@ class TuyaLan {

const device = new TuyaAccessory({
...devices[config.id], ...config,
log: this.log,
UUID: UUID.generate(PLUGIN_NAME + ':' + config.id),
connect: false
});
Expand All @@ -126,6 +127,7 @@ class TuyaLan {
this.log.info('Adding fake device: %s', config.name);
this.addAccessory(new TuyaAccessory({
...config,
log: this.log,
UUID: UUID.generate(PLUGIN_NAME + ':fake:' + config.id),
connect: false
}));
Expand All @@ -141,6 +143,7 @@ class TuyaLan {

const device = new TuyaAccessory({
...devices[deviceId],
log: this.log,
UUID: UUID.generate(PLUGIN_NAME + ':' + deviceId),
connect: false
});
Expand Down
12 changes: 10 additions & 2 deletions lib/BaseAccessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ class BaseAccessory {
this.setMultiState({[dp.toString()]: value}, callback);
}

setMultiStateLegacy(dps, callback) {
//Adding back the original set multistate command as the multistate command from PR #267 Breaks the Fan Code by splitting the command into two.
//For devices like the DETA Smart Fan Controller Switch that by default set the speed as 3 the new code in the setMultiState function causes issues.
if (!this.device.connected) return callback(true);
const ret = this.device.update(dps);
callback && callback(!ret);
}

setMultiState(dps, callback) {
if (!this.device.connected) return callback(true);
for (const dp in dps) {
Expand Down Expand Up @@ -106,11 +114,11 @@ class BaseAccessory {
this.colorFunction = this.device.context.colorFunction && {HSB: 'HSB', HEXHSB: 'HEXHSB'}[this.device.context.colorFunction.toUpperCase()];
if (!this.colorFunction && value) {
this.colorFunction = {12: 'HSB', 14: 'HEXHSB'}[value.length] || 'Unknown';
if (this.colorFunction) console.log(`[Tuya] Color format for ${this.device.context.name} (${this.device.context.version}) identified as ${this.colorFunction} (length: ${value.length}).`);
if (this.colorFunction) this.log.info(`Color format for ${this.device.context.name} (${this.device.context.version}) identified as ${this.colorFunction} (length: ${value.length}).`);
}
if (!this.colorFunction) {
this.colorFunction = 'Unknown';
console.log(`[Tuya] Color format for ${this.device.context.name} (${this.device.context.version}) is undetectable.`);
this.log.info(`Color format for ${this.device.context.name} (${this.device.context.version}) is undetectable.`);
} else if (this.colorFunction === 'HSB') {
// If not overridden by config, use the scale of 1000
if (!this.device.context.scaleBrightness) this.device.context.scaleBrightness = 1000;
Expand Down
16 changes: 3 additions & 13 deletions lib/GarageDoorAccessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,15 @@ class GarageDoorAccessory extends BaseAccessory {

// function to return a ID string for log messages
_logPrefix() {
return '[Tuya] ' +
(this.manufacturer ? this.manufacturer + ' ' : '') + 'GarageDoor';
return (this.manufacturer ? this.manufacturer + ' ' : '') + 'GarageDoor';
}

// function to prefix a string ID and always log to console
_alwaysLog(...args) { console.log(this._logPrefix(), ...args); }
_alwaysLog(...args) { this.log.info(this._logPrefix(), ...args); }

// function to log to console if debug is on
_debugLog(...args) {
if (this.debug) {
this._alwaysLog(...args);
}
this.log.debug(this._logPrefix(), ...args);
}

// function to return true if the garage door manufacturer is Kogan and false
Expand All @@ -82,13 +79,6 @@ class GarageDoorAccessory extends BaseAccessory {
const service = this.accessory.getService(Service.GarageDoorOpener);
this._checkServiceName(service, this.device.context.name);

// set the debug flag
if (this.device.context.debug) {
this.debug = true;
} else {
this.debug = false;
}

// Set the manufacturer string
// If the manufacturer string matches a known manufacturer, set to that string
// Otherwise set the manufacturer to the defined value
Expand Down
2 changes: 1 addition & 1 deletion lib/MultiOutletAccessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class MultiOutletAccessory extends BaseAccessory {
this.accessory.services
.filter(service => service.UUID === Service.Outlet.UUID && !_validServices.includes(service))
.forEach(service => {
console.log('Removing', service.displayName);
this.log.info('Removing', service.displayName);
this.accessory.removeService(service);
});
}
Expand Down
2 changes: 1 addition & 1 deletion lib/RGBTWLightAccessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class RGBTWLightAccessory extends BaseAccessory {
}

setColorTemperature(value, callback) {
console.log(`[Tuya] setColorTemperature: ${value}`);
this.log.debug(`setColorTemperature: ${value}`);
if (value === 0) return callback(null, true);

const newColor = this.convertHomeKitColorTemperatureToHomeKitColor(value);
Expand Down
26 changes: 13 additions & 13 deletions lib/SimpleBlindsAccessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class SimpleBlindsAccessory extends BaseAccessory {
.on('get', this.getPositionState.bind(this));

this.device.on('change', changes => {
console.log("[Tuya] Blinds saw change to " + changes[this.dpAction]);
this.log.info(" Blinds saw change to " + changes[this.dpAction]);
if (changes.hasOwnProperty(this.dpAction)) {
switch (changes[this.dpAction]) {
case this.cmdOpen: // Starting to open
Expand All @@ -126,7 +126,7 @@ class SimpleBlindsAccessory extends BaseAccessory {
const durationToOpen = Math.abs(this.assumedPosition - BLINDS_OPEN) * this.duration * 10;
this.changeTime = Date.now() - durationToOpen;

console.log("[Tuya] Blinds will be marked open in " + durationToOpen + "ms");
this.log.info(" Blinds will be marked open in " + durationToOpen + "ms");

if (this.changeTimeout) clearTimeout(this.changeTimeout);
this.changeTimeout = setTimeout(() => {
Expand All @@ -135,7 +135,7 @@ class SimpleBlindsAccessory extends BaseAccessory {
this.changeTime = false;
this.assumedPosition = BLINDS_OPEN;
this.assumedState = BLINDS_STOPPED;
console.log("[Tuya] Blinds marked open");
this.log.info(" Blinds marked open");
}, durationToOpen);
}
break;
Expand All @@ -151,7 +151,7 @@ class SimpleBlindsAccessory extends BaseAccessory {
const durationToClose = Math.abs(this.assumedPosition - BLINDS_CLOSED) * this.duration * 10;
this.changeTime = Date.now() - durationToClose;

console.log("[Tuya] Blinds will be marked closed in " + durationToClose + "ms");
this.log.info(" Blinds will be marked closed in " + durationToClose + "ms");

if (this.changeTimeout) clearTimeout(this.changeTimeout);
this.changeTimeout = setTimeout(() => {
Expand All @@ -160,15 +160,15 @@ class SimpleBlindsAccessory extends BaseAccessory {
this.changeTime = false;
this.assumedPosition = this.minPosition;
this.assumedState = BLINDS_STOPPED;
console.log("[Tuya] Blinds marked closed");
this.log.info(" Blinds marked closed");
}, durationToClose);
}
break;

case this.cmdStop: // Stopped in middle
if (this.changeTimeout) clearTimeout(this.changeTimeout);

console.log("[Tuya] Blinds last change was " + this.changeTime + "; " + (Date.now() - this.changeTime) + 'ms ago');
this.log.info(" Blinds last change was " + this.changeTime + "; " + (Date.now() - this.changeTime) + 'ms ago');

if (this.changeTime) {
/*
Expand All @@ -188,7 +188,7 @@ class SimpleBlindsAccessory extends BaseAccessory {
characteristicCurrentPosition.updateValue(adjustedPosition);
characteristicTargetPosition.updateValue(adjustedPosition);
characteristicPositionState.updateValue(Characteristic.PositionState.STOPPED);
console.log("[Tuya] Blinds marked stopped at " + adjustedPosition + "; assumed to be at " + this.assumedPosition);
this.log.info(" Blinds marked stopped at " + adjustedPosition + "; assumed to be at " + this.assumedPosition);

this.changeTime = this.targetPosition = false;
this.assumedState = BLINDS_STOPPED;
Expand Down Expand Up @@ -241,20 +241,20 @@ class SimpleBlindsAccessory extends BaseAccessory {
}

setTargetPosition(value, callback) {
console.log('[Tuya] Blinds asked to move from ' + this.assumedPosition + ' to ' + value);
this.log.info('Blinds asked to move from ' + this.assumedPosition + ' to ' + value);

if (this.changeTimeout) clearTimeout(this.changeTimeout);
this.targetPosition = value;

if (this.changeTime !== false) {
console.log("[Tuya] Blinds " + (this.assumedState === BLINDS_CLOSING ? 'closing' : 'opening') + " had started " + this.changeTime + "; " + (Date.now() - this.changeTime) + 'ms ago');
this.log.info(" Blinds " + (this.assumedState === BLINDS_CLOSING ? 'closing' : 'opening') + " had started " + this.changeTime + "; " + (Date.now() - this.changeTime) + 'ms ago');
const disposition = ((Date.now() - this.changeTime) / (10 * this.duration));
if (this.assumedState === BLINDS_CLOSING) {
this.assumedPosition = BLINDS_OPEN - disposition;
} else {
this.assumedPosition = this.minPosition + disposition;
}
console.log("[Tuya] Blinds' adjusted assumedPosition is " + this.assumedPosition);
this.log.info(" Blinds' adjusted assumedPosition is " + this.assumedPosition);
}

const duration = Math.abs(this.assumedPosition - value) * this.duration * 10;
Expand All @@ -272,10 +272,10 @@ class SimpleBlindsAccessory extends BaseAccessory {
}

if (value !== BLINDS_OPEN && value !== BLINDS_CLOSED) {
console.log("[Tuya] Blinds will stop in " + duration + "ms");
console.log("[Tuya] Blinds assumed started " + this.changeTime + "; " + (Date.now() - this.changeTime) + 'ms ago');
this.log.info(" Blinds will stop in " + duration + "ms");
this.log.info(" Blinds assumed started " + this.changeTime + "; " + (Date.now() - this.changeTime) + 'ms ago');
this.changeTimeout = setTimeout(() => {
console.log("[Tuya] Blinds asked to stop");
this.log.info(" Blinds asked to stop");
this.setState(this.dpAction, this.cmdStop);
}, duration);
}
Expand Down
10 changes: 5 additions & 5 deletions lib/SimpleFanAccessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class SimpleFanAccessory extends BaseAccessory {
if (changes.hasOwnProperty(this.dpRotationSpeed) && characteristicRotationSpeed.value !== changes[this.dpRotationSpeed])
characteristicRotationSpeed.updateValue(changes[this.dpRotationSpeed]);

console.log('[Tuya] SimpleFan changed: ' + JSON.stringify(state));
this.log.debug('SimpleFan changed: ' + JSON.stringify(state));
});
}

Expand Down Expand Up @@ -78,10 +78,10 @@ class SimpleFanAccessory extends BaseAccessory {
} else {
if (this.fanCurrentSpeed === 0) {
// The current fanDefaultSpeed Variable is there to have the fan set to a sensible default if turned on.
return this.setMultiState({[this.dpFanOn]: value, [this.dpRotationSpeed]: this.fanDefaultSpeed.toString()}, callback);
return this.setMultiStateLegacy({[this.dpFanOn]: value, [this.dpRotationSpeed]: this.fanDefaultSpeed.toString()}, callback);
} else {
// The current fanCurrentSpeed Variable is there to ensure the fan speed doesn't change if the fan is already on.
return this.setMultiState({[this.dpFanOn]: value, [this.dpRotationSpeed]: this.fanCurrentSpeed.toString()}, callback);
return this.setMultiStateLegacy({[this.dpFanOn]: value, [this.dpRotationSpeed]: this.fanCurrentSpeed.toString()}, callback);
}
}
callback();
Expand All @@ -105,12 +105,12 @@ class SimpleFanAccessory extends BaseAccessory {
const {Characteristic} = this.hap;
if (value === 0) {
// This is to set the fan speed variable to be 1 when the fan is off.
return this.setMultiState({[this.dpFanOn]: false, [this.dpRotationSpeed]: this.fanDefaultSpeed.toString()}, callback);
return this.setMultiStateLegacy({[this.dpFanOn]: false, [this.dpRotationSpeed]: this.fanDefaultSpeed.toString()}, callback);
} else {
// This is to set the fan speed variable to match the current speed.
this.fanCurrentSpeed = value;
// This uses the multistate set command to send the fan on and speed request in one call.
return this.setMultiState({[this.dpFanOn]: true, [this.dpRotationSpeed]: value.toString()}, callback);
return this.setMultiStateLegacy({[this.dpFanOn]: true, [this.dpRotationSpeed]: value.toString()}, callback);
}
callback();
}
Expand Down
Loading

0 comments on commit 95789f8

Please sign in to comment.