rthewhite / homebridge-homewizard

23 stars 13 forks source link

Homekit scene bug with HomeWizard "dimmer" lightbulb switches #45

Closed DB-Alex closed 7 years ago

DB-Alex commented 8 years ago

I created a scene in Homekit with several dimmer lightbulbs. When I activate the scene none of the dimmer lightbulbs go to the required brightness.

In a scene you almost set a required brightness for a dimmer every time (why else make a scene ;)). But when I activate a scene and I check the docker terminal I only see things like:

Switched LightbulbDimmer1 to: on
Switched LightbulbDimmer2 to: on
Switched LightbulbDimmer3 to: on

Where I would expect things like:

Switched LightbulbDimmer1 to: on
Set brightness for: LightbulbDimmer1 to: 45
Switched LightbulbDimmer2 to: on
Set brightness for: LightbulbDimmer2 to: 35
Switched LightbulbDimmer3 to: on
Set brightness for: LightbulbDimmer3 to: 25

This also results in another bug, for example, when LightbulbDimmer1 is already on and I activate a scene it sends the on signal again to LightbulbDimmer1 without a brightness state. This results in a fading lightbulb since the KaKu sensor is waiting for a brightness state.

I suspect the following lines of code in src/accessories/switch.js line 36-41:

if (this.hwObject.type === 'dimmer') {
  service
    .getCharacteristic(this.hap.Characteristic.Brightness)
    .on('set', this.setBrightness.bind(this))
    .on('get', this.getBrightness.bind(this));
}

I do believe the hwObject.type is not set properly when a scene is activated. Although I lag the skill for debugging this properly.

It would be great if someone can help me out so we can make this an even better plugin!

PS: Let me know if I can help at some point

DB-Alex commented 8 years ago

@ygageot or @rthewhite Some of you able to solve this issue?

Please let me know if I can help!

rthewhite commented 8 years ago

@alexvandervegt the type is retrieved from the HomeWizard when you start homebridge, you could verify the type being send by the HomeWizard if you open the api call directly in your browser:

http://ipofhomewizard:port/password/swlist

The other lines are the lines that tell Siri which functions there are available for the accessory. In the case of dimmer that it can retrieve and set the brightness using those functions.

If Siri then doesn't call the set brightness function when you start a scene it's gonna be difficult to solve this issue. Especially for me since i don't have a HomeWizard anymore or any Kaku dimmers.

From what i remember the dimmers for me never really worked correctly even with the HomeWizard app itself. Most Kaku dimmers don't have the option to set a specific brightness but you can make them start fading and stop fading using a command most of the time by sending the on command again, the HomeWizard api exposes an call to set an specific brightness which is being used here but i'm not completely sure if it works correctly...

ygageot commented 8 years ago

Hello, At home I have only HUE lights and I don't know exactly your equipment.. Can you execute the request : http://IPADRESS:PORT/PASSWORD/get-sensors with the IPADRESS:PORT and PASSWORD of your HW , locate the section of one of your dimmers and send it to me.

DB-Alex commented 8 years ago

@rthewhite there is a command for setting a specific dim value for a dimmer:

/sw/dim/<dimmer-number>/<value 0 ... 255>

So what we need to acomplish is the following, when a dimmer is called from Homebridge it need to watch for the "dim-value" in Homebridge and then send this command:

/sw/dim/LightbulbDimmer1/65

In the example above 65 is a value for the dimmer retrieved from Homebridge. In this case a dimmer will always be send the correct value and it will never start fading, because its on and it got it's dimmer-number right after it.

At the moment it sends:

/sw/LightbulbDimmer1/on
DB-Alex commented 8 years ago

@ygageot here you go:

{"id":2,"name":"Kroonluchter","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"}
rthewhite commented 8 years ago

That's exactly the command the plugin will send to the HomeWizard, IF Siri calls it. But it looks like Siri doesn't call the command that's why it won't work because the type is correct.

DB-Alex commented 8 years ago

Then we need to force call it. So when a LightBulb on command is send we first need to verify is this a normal LightBulb or a Dimmer. If its a Dimmer, we need to fetch the dimmer-value from Homebridge and only then we send the correct command.

rthewhite commented 8 years ago

Don't believe there is a way to retrieve that value from Homebridge, it's just a communication layer for Siri to proxy commands to, there is no state in Homebridge itself and i don't think we can retrieve that information through Homebridge from Siri. If the dimmer value doesn't get supplied by Siri with the on command i don't think there is anyway to solve this properly.

But i could be wrong, it has been a while since i looked into Homebridge and HAP-NodeJS. But i don't have time to look any further into it sadly enough. I think the easiest way would be to make the scene in the HomeWizard app, you can expose scene through the plugin as well and then use that scene with Homekit to create your scene. Maybe that solves your problem.

DB-Alex commented 8 years ago

@ygageot you have time to solve this issue?

ygageot commented 8 years ago

I will only at the end of the afternoon !

Have you the ability to insert traces in the source ?

DB-Alex commented 8 years ago

What do you mean?

ygageot commented 8 years ago

insert the line this.log(``switchType: ${switchType} for: ${this.name}``); before switch (switchType) { in switch.js

and execute

DB-Alex commented 8 years ago

In which file?

DB-Alex commented 8 years ago

I was just looking at src/switch.js again. And I think we need to change:

setPowerState(state, callback) {
    const value = state ? 'on' : 'off';
    const url = `sw/${this.id}/${value}`;

    this.api.request({url}).then(() => {
      this.log(`Switched ${this.name} to: ${value}`);
      callback();
    }).catch(error => {
      this.log(`Failed to switch ${this.name}`);
      this.log(error);
      callback(error);
    });
  }

to:

setPowerState(state, callback) {

if(THIS === DIMMER) {
const value = GET_DIMMER_NUMBER_FROM_HOMEBRIDGE;
    const url = `sw/dim/${this.id}/${value}`;
} else {
    const value = state ? 'on' : 'off';
    const url = `sw/${this.id}/${value}`;
}
    this.api.request({url}).then(() => {
      this.log(`Switched ${this.name} to: ${value}`);
      callback();
    }).catch(error => {
      this.log(`Failed to switch ${this.name}`);
      this.log(error);
      callback(error);
    });
  }
ygageot commented 8 years ago

accessories/switch.js

DB-Alex commented 8 years ago

I can adjust it, but my Synology is running the dist folder. I tried to change a few lines in the dist folder but the log was not comming up in the terminal after restarting docker.

DB-Alex commented 8 years ago

@rthewhite Maybe there is something you know about the code above?

rthewhite commented 8 years ago

I get what you are looking for, but like i said there is no way to retrieve that GET_DIMMER_NUMBER_FROM_HOMEBRIDGE. When that function is called, state is only a boolean either true or false which get's translated to a string on or off for the homewizard. There is no additional information like the brightness and no way to retrieve it from homebridge or siri.

When adding or changing lines off code for testing locally, you will have to change it in the dist folder which is transpiled code from the original source. Which is little more hard to read/edit but do-able.

DB-Alex commented 8 years ago

What about this?

setPowerState(state, callback) {
    if (this.hwObject.type === 'dimmer') {
      const value = this.hap.Characteristic.Brightness;
      const url = `sw/dim/${this.id}/${value}`;
    } else {
      const value = state ? 'on' : 'off';
      const url = `sw/${this.id}/${value}`;
    }

    this.api.request({url}).then(() => {
      if (this.hwObject.type === 'dimmer') {
        this.log(`Set brightness for ${this.name} to: ${value}`);
      } else {
        this.log(`Switched ${this.name} to: ${value}`);  
      }
      callback();
    }).catch(error => {
      this.log(`Failed to switch ${this.name}`);
      this.log(error);
      callback(error);
    });
  }

I see simular code in: https://github.com/nfarina/homebridge/blob/6500912f54a70ff479e63e2b72760ab589fa558a/example-plugins/homebridge-lockitron/index.js

ygageot commented 8 years ago

Can you try the Home app ? Do yo see your lightbulb with the possibility to obtain and change the brightness with the graphic interface ? I want to be sure that the code service.getCharacteristic(this.hap.Characteristic.Brightness) .on('set', this.setBrightness.bind(this)) .on('get', this.getBrightness.bind(this)); is executed in switch.js

DB-Alex commented 8 years ago

Yes I see it, and its working

ygageot commented 8 years ago

Can you ask Siri with

Turn all lights on Set lights to 50% Set lights to 1%

DB-Alex commented 8 years ago

Yes i can

ygageot commented 8 years ago

it works ?

DB-Alex commented 8 years ago

Thats works. But dimmers in a scene do not work

ygageot commented 8 years ago

Can you follow this scenario with Home app (not Siri) and send me the log ?

NB I have not your dimmer but I tried wit Home scene and Hue lights and it works. I suspect that no memorization of the level of brightness is done with your dimmer. If it is the problem I can update switch.js like philips-hue.js to store the level when you turn off to restore it when you turn on. But I want first to be sure of the behavior.

DB-Alex commented 8 years ago

As far as I can see, the home app scene does send a "turn on" signal for a dimmer but it does not send a "turn brightness to 50%" signal.

Or can you see both when you trigger a dimmer in a Home app scene?

ygageot commented 8 years ago

I think I will memorize the brightness of the dimmers in the bridge, to set the previous brightness when you turn it on. But to be sure can you send me the json entries for HTTP request

get-sensors

and

get-status

for one dimmer

rthewhite commented 8 years ago

Storing the previous brightness is not gonna solve this issue. The brightness might be different between scenes. So if you have multiple scenes with the same dimmer in there with different brightness levels storing the previous brightness is not solving the issue.

DB-Alex commented 8 years ago

Its a good backup method though

DB-Alex commented 8 years ago

I just got another issue, when I activate a scene almost every time some lights stay out. We can solve this easy to cache the request from Homebridge in the app. Then we send all requests to Homewizard. Then 10 seconds later we send the same requests. If all lights are already on, no problem we won't see a thing. But if some lights were off they will be turned on by Homewizard.

So I think its perfect to create a nice caching layer and then use this internal layer to send out requests to Homewizard.

DB-Alex commented 8 years ago

@ygageot here you go:

get-sensors

{"status": "ok", "version": "3.372", "request": {"route": "/get-sensors" }, "response": {"preset":0,"time":"2016-09-20 10:43","switches":[{"id":0,"name":"Tuin Spots L","type":"switch","status":"off","favorite":"no"},{"id":1,"name":"Drankkast LED","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":2,"name":"Kroonluchter","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":3,"name":"Eethoek","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":4,"name":"Kristallen bol","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":5,"name":"Spots LED","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":6,"name":"Drankkast Spots","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":7,"name":"Vloer LED","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":8,"name":"Keuken onder","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":9,"name":"Keuken boven","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":10,"name":"Toilet lamp","type":"switch","status":"off","favorite":"no"},{"id":11,"name":"Toilet spots","type":"switch","status":"off","favorite":"no"},{"id":12,"name":"Trap LED","type":"switch","status":"off","favorite":"no"},{"id":13,"name":"Gang lamp","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":14,"name":"Voordeur lamp","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":15,"name":"Gang 1e","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":16,"name":"Washok","type":"switch","status":"off","favorite":"no"},{"id":17,"name":"Riley","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":18,"name":"Slaapkamer","type":"switch","status":"off","favorite":"no"},{"id":19,"name":"Tuin Spots R","type":"switch","status":"off","favorite":"no"},{"id":20,"name":"Gang 2e","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":21,"name":"Jaxon","type":"dimmer","status":"off","dimlevel":0,"favorite":"no"},{"id":22,"name":"LED Spots","type":"switch","status":"off","favorite":"no"},{"id":23,"name":"Dressoir LED","type":"switch","status":"off","favorite":"no"},{"id":24,"name":"Bureaulamp","type":"switch","status":"off","favorite":"no"},{"id":25,"name":"Keuken LED","type":"switch","status":"off","favorite":"no"},{"id":26,"name":"Kledingkamer","type":"switch","status":"off","favorite":"no"}],"uvmeters":[],"windmeters":[],"rainmeters":[],"thermometers":[{"id":0,"name":"Woonkamer","channel":3,"model":0,"te":22.4,"hu":53,"te+":22.7,"te+t":"00:01","te-":22.3,"te-t":"07:08","hu+":54,"hu+t":"08:08","hu-":52,"hu-t":"00:01","outside":"yes","favorite":"no"}],"weatherdisplays":[], "energymeters": [], "energylinks": [], "heatlinks": [], "hues": [], "scenes": [{"id": 0, "name": "BG Normaal", "favorite": "yes"},{"id": 4, "name": "BG Alles", "favorite": "yes"},{"id": 5, "name": "1e Alles", "favorite": "no"},{"id": 6, "name": "2e Alles", "favorite": "no"},{"id": 7, "name": "BG Minimaal", "favorite": "no"},{"id": 12, "name": "Vakantie", "favorite": "no"}], "kakusensors": [{"id":0,"name":"Begane grond","status":null,"type":"smoke","favorite":"no","timestamp":"00:00","cameraid":null},{"id":1,"name":"1e verdieping","status":null,"type":"smoke","favorite":"no","timestamp":"00:00","cameraid":null},{"id":2,"name":"2e verdieping","status":null,"type":"smoke","favorite":"no","timestamp":"00:00","cameraid":null},{"id":3,"name":"3e verdieping","status":null,"type":"smoke","favorite":"no","timestamp":"00:00","cameraid":null},{"id":4,"name":"Trap beneden","status":"yes","type":"motion","favorite":"no","timestamp":"10:42","cameraid":null},{"id":5,"name":"Voordeur","status":"no","type":"contact","favorite":"no","timestamp":"09:54","cameraid":null},{"id":6,"name":"Trap boven","status":"yes","type":"motion","favorite":"no","timestamp":"10:42","cameraid":null},{"id":7,"name":"BG Schemer","status":null,"type":"light","favorite":"no","timestamp":"00:00","cameraid":null}], "cameras": []}}

get-status

{"status": "ok", "version": "3.372", "request": {"route": "/get-status" }, "response": {"preset":0,"time":"2016-09-20 10:44","switches":[{"id":0,"type":"switch","status":"off"},{"id":1,"type":"dimmer","status":"off","dimlevel":0},{"id":2,"type":"dimmer","status":"off","dimlevel":0},{"id":3,"type":"dimmer","status":"off","dimlevel":0},{"id":4,"type":"dimmer","status":"off","dimlevel":0},{"id":5,"type":"dimmer","status":"off","dimlevel":0},{"id":6,"type":"dimmer","status":"off","dimlevel":0},{"id":7,"type":"dimmer","status":"off","dimlevel":0},{"id":8,"type":"dimmer","status":"off","dimlevel":0},{"id":9,"type":"dimmer","status":"off","dimlevel":0},{"id":10,"type":"switch","status":"off"},{"id":11,"type":"switch","status":"off"},{"id":12,"type":"switch","status":"off"},{"id":13,"type":"dimmer","status":"off","dimlevel":0},{"id":14,"type":"dimmer","status":"off","dimlevel":0},{"id":15,"type":"dimmer","status":"off","dimlevel":0},{"id":16,"type":"switch","status":"off"},{"id":17,"type":"dimmer","status":"off","dimlevel":0},{"id":18,"type":"switch","status":"off"},{"id":19,"type":"switch","status":"off"},{"id":20,"type":"dimmer","status":"off","dimlevel":0},{"id":21,"type":"dimmer","status":"off","dimlevel":0},{"id":22,"type":"switch","status":"off"},{"id":23,"type":"switch","status":"off"},{"id":24,"type":"switch","status":"off"},{"id":25,"type":"switch","status":"off"},{"id":26,"type":"switch","status":"off"}],"uvmeters":[],"windmeters":[],"rainmeters":[],"thermometers":[{"id":0,"te":22.4,"hu":53,"favorite":"no"}],"weatherdisplays":[], "energymeters": [], "energylinks": [], "heatlinks": [], "kakusensors": [{"id":0,"status":null,"timestamp":"00:00"},{"id":1,"status":null,"timestamp":"00:00"},{"id":2,"status":null,"timestamp":"00:00"},{"id":3,"status":null,"timestamp":"00:00"},{"id":4,"status":"yes","timestamp":"10:42"},{"id":5,"status":"no","timestamp":"09:54"},{"id":6,"status":"yes","timestamp":"10:42"},{"id":7,"status":null,"timestamp":"00:00"}]}}
ygageot commented 8 years ago

@alexvandervegt In this capture, all the dimmers are off, the dimlevels are always 0.

Can you confirm me that when

I want to be sure of the last point

DB-Alex commented 8 years ago

@ygageot when a dimmer is for example at 25% the status = on and the dimlevel = 35 for example, means its at 35% ofcourse.

When you put it off the status = off and the dimlevel = 0 again.