webdeck / homebridge-indigo

Homebridge Plugin for Indigo
Apache License 2.0
13 stars 6 forks source link

iOS 10 Home App - dimmers sending multiple brightness+on commands #9

Closed dgburtonbv closed 7 years ago

dgburtonbv commented 7 years ago

Hi,

The new iOS 10 Home App seems to be sending large numbers of "set brightness" and "on" commands as the user drags the brightness slider up and down.

This causes the requests to either get queued or Indigo to get swamped; the result is for a 2-second drag on the slider tens of brightness commands are enqueued and the dimmer flickers between different brightness settings for the next 20 secs or so (I'm testing this with a Fibaro Z-Wave dimmer device so I assume Indigo isn't able to dispatch the Z-Wave commands quick enough to keep up with the rate at which homebridge-indigo is enqueuing them).

Is it possible to implement a lag timer for brightness commands in homebridge-indigo so it waits 500ms before passing the command on to Indigo?

Also - the iOS 10 Home app seems to send both a "set brightness" and "on" command. Indigo only requires the "set brightness" command (as setting to brightness > 0 implies "on") - this results in double the number of commands being sent to Indigo than is needed.

Thanks so much for your work on this!

dgburtonbv commented 7 years ago

@webdeck please don't judge the code, but this is the kind of thing I was hoping for. I'm sure you'll have a more elegant solution!

var indigoRequestDictionary = {};

function updateStatusTimeout(that, qs, callback, key) {

    that.log("updateStatusTimeout of %s: %s", that.name, JSON.stringify(qs));

    that.platform.indigoRequest(that.deviceURL, "PUT", qs,
        function(error, response, body) {
            if (error) {
                //callback(error);
            } else {
                //callback();
            }
        }
    );
}

// Invokes callback(error), error is undefined if no error occurred
IndigoAccessory.prototype.updateStatus = function(qs, callback) {

    this.log("updateStatus of %s: %s", this.name, JSON.stringify(qs));

    // dimmable devices implement a 1 second lag timer to avoid sending "on" and "brighten" requests at the same time
    if (this.typeSupportsDim) {

        var enqueue = true;

        var key = this.deviceURL;
        if (indigoRequestDictionary.hasOwnProperty(key)) {
            var data = indigoRequestDictionary[key];

            if (data.qs.brightness != undefined) {
                if (qs.isOn != undefined) {
                    if (qs.isOn == 1) {
                        this.log("** queued brightness command exists, and we've got an isOn=1, disregard this one");
                        enqueue = false;
                    }

                }
            }

            try {
                //indigoRequestDictionary[key].callback();
            } catch(err) {}
            if (enqueue) {
                clearTimeout(data.timeoutState);
            }
        }

        if (enqueue) {
            myVar = setTimeout(updateStatusTimeout,350, this, qs, callback, key);

            var data = {
                deviceURL: this.deviceURL,
                qs: qs,
                callback: callback,
                timeoutState: myVar,
                this: this
            }

            indigoRequestDictionary[key] = data;
        }
        callback();

    } else {

        this.platform.indigoRequest(this.deviceURL, "PUT", qs,
            function(error, response, body) {
                if (error) {
                    callback(error);
                } else {
                    callback();
                }
            }.bind(this)
        );

    }

};
webdeck commented 7 years ago

Thanks for the code - I will take a look at it. It's a shame having to do something like this that slows down responsiveness only because Apple's Home app does something silly. I see all of homebridge is having this issue with Apple's app, based on the issues in the main homebridge repository.

Does this happen if you use Siri to adjust brightness?

dgburtonbv commented 7 years ago

Yep - agreed. Seems to be the behaviour Apple have settled on though unfortunately.

When you adjust the brightness via Siri it issues just 1 command, so that's just fine. It's the behaviour when you drag the slider where the problem is.

sommerlund commented 7 years ago

I have the following problem. Seems to be related...? For context:

  1. I was using Siri
  2. I have two lights in the master bedroom.
  3. I asked Siri to set the lights in the master bedroom to 50%

Here is what happened:

  WebServer                       request to turn on device "Master Can Lights" from 127.0.0.1
  Sent INSTEON                    "Master Can Lights" on to 100
  WebServer                       request to set device "Master Ceiling Fan Lights" brightness from 127.0.0.1
  Sent INSTEON                    "Master Ceiling Fan Lights" on to 50
  WebServer                       request to set device "Master Can Lights" brightness from 127.0.0.1
  Sent INSTEON                    "Master Can Lights" on to 50
  WebServer                       request to turn on device "Master Ceiling Fan Lights" from 127.0.0.1
  Sent INSTEON                    "Master Ceiling Fan Lights" on to 100
[10/16/2016, 4:43:15 PM] [My Indigo Server] Indigo request: http://127.0.0.1:8176/devices/Master%20Can%20Lights.json
[10/16/2016, 4:43:15 PM] [My Indigo Server] Indigo request: http://127.0.0.1:8176/devices/Master%20Ceiling%20Fan%20Lights.json
[10/16/2016, 4:43:16 PM] [My Indigo Server] Indigo request: http://127.0.0.1:8176/devices/Master%20Can%20Lights.json
[10/16/2016, 4:43:17 PM] [My Indigo Server] Indigo request: http://127.0.0.1:8176/devices/Master%20Ceiling%20Fan%20Lights.json

Thoughts?

webdeck commented 7 years ago

When I look at what the Home app is doing - it is assuming that when you turn a light on, it is independent of the brightness level of the light. However, Indigo interprets an on as setting the device to its default on level.

So, in addition to the above problems, it causes other issues. For example, if I dim a light to 50% with the Home app, then turn it off, and then turn it on, the Home app thinks it is still at 50%, but Indigo now has it as 100%.

One option, instead of deferring the on command, which would cause delays every time you turn a light on, I could change it to issue a set brightness call to whatever the previous brightness level was. It would have no effect if you're adjusting the brightness level, and it would mimic the behavior that the Home app is expecting if you turn a light off and on - it returns to the same brightness level it was at before you turned it off.

The only case where this wouldn't work is for lights that are off when homekit first starts up, as it wouldn't know what brightness level to set them to. In that case, I can just send an on command as normal, but then the issue self-corrects after that.

Thoughts?

sommerlund commented 7 years ago

For example, if I dim a light to 50% with the Home app, then turn it off, and then turn it on, the Home app thinks it is still at 50%, but Indigo now has it as 100%. Confirmed.

One option, instead of deferring the on command, which would cause delays every time you turn a light on, I could change it to issue a set brightness call to whatever the previous brightness level was. It would have no effect if you're adjusting the brightness level, and it would mimic the behavior that the Home app is expecting if you turn a light off and on - it returns to the same brightness level it was at before you turned it off. Good idea.

Another thought. When adding a brightness command to the queue it could replace any existing brightness commands to the same light with a new one, removing the redundant commands. One might get multiple, but it shouldn't be as many as dgburton said.

The only case where this wouldn't work is for lights that are off when homekit first starts up, as it wouldn't know what brightness level to set them to. In that case, I can just send an on command as normal, but then the issue self-corrects after that. Acceptable.