cflurin / homebridge-websocket

Homebridge Plugin
Apache License 2.0
40 stars 7 forks source link

Scenes only set last characteristics value #2

Closed zieherf closed 8 years ago

zieherf commented 8 years ago

When using the websocket plugin in scenes only the last characteristics value is set. homebridge seems to process the scene correctly - I've added an example with 3 characteristics.

Debug output from homebridge

  EventedHTTPServer [::ffff:192.168.178.21] HTTP request: /characteristics +5m
  HAPServer [CC:22:3D:E3:CE:30] HAP Request: PUT /characteristics +0ms
  Accessory [Homebridge] Processing characteristic set: [{"aid":10,"iid":10,"value":0},{"aid":2,"iid":9,"value":1},{"aid":3,"iid":9,"value":0}] +1ms
  Accessory [Homebridge] Setting Characteristic "Target Door State" to value 0 +1ms
  Accessory [Homebridge] Setting Characteristic "On" to value 1 +1ms
  Accessory [Homebridge] Setting Characteristic "On" to value 0 +0ms
  EventedHTTPServer [::ffff:192.168.178.21] HTTP Response is finished +2ms
[2016-08-12 11:23:35] [websocket] set Einfahrtstor On false
[2016-08-12 11:23:35] [websocket] sendData {"topic":"set","payload":{"name":"Einfahrtstor","characteristic":"On","value":false}}
cflurin commented 8 years ago

Hi, Could you please post the accessory infos. The message you get with:

{topic: "get", payload: {"name": "Einfahrtstor"}}

homebridge-mqtt is an alternative plugin with similar features using the MQTT-API.

zieherf commented 8 years ago

The accessory info (debug output from node-red) reads:

{ "Tischlampe": { "service": "Switch", "characteristics": { "On": false } }, "Einfahrtstor": { "service": "Switch", "characteristics": { "On": false } }, "Garagentor": { "service": "GarageDoorOpener", "characteristics": { "CurrentDoorState": 0, "TargetDoorState": 0, "ObstructionDetected": false }}}

When I edit the scene, it is always the last entry in the "Processing characteristic set: [...]" that is received on the websocket. I didn't do any further debugging but the standard output from running homebridge in debug mode. Obviously, I didn't receive any more messages in node-red on the websocket.

I just saw homebridge-mqtt, which I would even prefer over using websocket. Would it be possible to add username and password to the mqtt platform configuration?

Thanks for looking into it. Franz

cflurin commented 8 years ago

I've to investigate, I'll come back soon.

Regarding mqtt authentication it's on the todo list.

cflurin commented 8 years ago

@zieherf: The GarageDoorOpener has 3 default (required) characteristics:

/**
 * Service "Garage Door Opener"
 */

Service.GarageDoorOpener = function(displayName, subtype) {
  Service.call(this, displayName, '00000041-0000-1000-8000-0026BB765291', subtype);

  // Required Characteristics
  this.addCharacteristic(Characteristic.CurrentDoorState);
  this.addCharacteristic(Characteristic.TargetDoorState);
  this.addCharacteristic(Characteristic.ObstructionDetected);

Only TargetDoorState is writeable. You can also set OPEN or CLOSED. Homebridge-websocket (HomebKit) will also only send this characteristic.

zieherf commented 8 years ago

The output from get accessory info returns exactly the required properties for the GarageDoorOpener - it works fine when used as single accessory. I simplified the scene setting with only two Accessories of service type Switch. Exactly the same happens. When used as single accessory, the. All the messages are received. When used in the defined scene, only the last accessory/characteristic is receiving a websocket message.

Two accessories of service type Switch with 'On' characteristics. Scene is defined to switch both on: [{"aid":2,"iid":9,"value":1},{"aid":11,"iid":9,"value":1}] Websocket only receives message for Stehlampe ({"aid":11,"iid":9,"value":1}).

Debug output from running DEBUG=* homebridge -D

  EventedHTTPServer [::ffff:192.168.178.20] HTTP request: /characteristics +20s
  HAPServer [CC:22:3D:E3:CE:30] HAP Request: PUT /characteristics +0ms
  Accessory [Homebridge] Processing characteristic set: [{"aid":2,"iid":9,"value":1},{"aid":11,"iid":9,"value":1}] +1ms
  Accessory [Homebridge] Setting Characteristic "On" to value 1 +1ms
  EventedHTTPServer [::ffff:192.168.178.37] Sending HTTP event '2.9' with data: {"characteristics":[{"aid":2,"iid":9,"value":1}]} +1ms
  EventedHTTPServer [::ffff:192.168.178.20] Muting event '2.9' notification for this connection since it originated here. +2ms
  Accessory [Homebridge] Setting Characteristic "On" to value 1 +1ms
  EventedHTTPServer [::ffff:192.168.178.20] Muting event '11.9' notification for this connection since it originated here. +1ms
  EventedHTTPServer [::ffff:192.168.178.20] HTTP Response is finished +1ms
[2016-08-15 15:29:01] [websocket] set Stehlampe On true
[2016-08-15 15:29:01] [websocket] sendData {"topic":"set","payload":{"name":"Stehlampe","characteristic":"On","value":true}}

Looking into websocket.js:Websocket.prototype.set, could it be that async function called in setTimeout is never called because of the clearTimeout at the beginning of the set function.

210 Websocket.prototype.set = function(name, c, value, callback) {
211 
212   if (typeof(this.ws) !== "undefined" && this.ws.OPEN) {
213     if (set_timeout) {
214       clearTimeout(set_timeout);
215     }
216 
217     var delay;
218 
219     switch (c) {
220       case "On":
221         value = (value == 0 || value == false) ? false : true;
222         delay = 0;
223         break;
224 
225       case "Brightness":
226       case "TargetPosition":
227       case "TargetHorizontalTiltAngle":
228         delay = 300;
229         break;
230 
231       default:
232         delay = 0;
233     }
234 
235     var data = {"topic": "set", "payload": {"name": name, "characteristic": c, "value": value}};
236 
237     set_timeout = setTimeout(function() {
238       this.log.debug("set %s %s %s", name, c, value);
239       this.sendData(data);
240     }.bind(this), delay);
241 
242     callback(); // todo error handling
243   } else {
244     this.log.debug("get client disconnected.");
245     callback("disconnected");
246   }
247 }
cflurin commented 8 years ago

Are you using EVE? Please, post the scene you defined.

cflurin commented 8 years ago

... Ok, I see, I've defined 2 actions in a scene and actually only the last action is sent.

zieherf commented 8 years ago

The issue lies in the clearTimeout on line 214. When commenting this line all the actions on the scene get sent. Do you think clearTimeout is necessary?

cflurin commented 8 years ago

I've commented line 214 and actually it works this way. The timeout is used for Brightness etc. in order to reduce the sent data. I've to do more debugging and look for another solution.

zieherf commented 8 years ago

Ok, I see now why you have used the timeout approach, though you didn't call clearTimeout in case of the homebridge-mqtt plugin :-) I don't use any accessories at the moment with continuous values for the characteristic, but I would expect the HomeKit app to handle (limit) the number of set events when selecting from a range. BTW I like the generalization of your homebridge plugin.

cflurin commented 8 years ago

I've uploaded a new version. It isn't on npm yet. Please install from GitHub:

sudo npm install -g https://github.com/cflurin/homebridge-websocket

That's right! homebridge-mqtt doesn't use clearTimeout(set_timeout); I don't remember the reason. Anyway I'll change mqtt.js too.

zieherf commented 8 years ago

Thanks for for fixing it. Are you planning to increase the version number or will that include more changes?

cflurin commented 8 years ago

There are more scene cases to implement and test. I'll publish v0.1.9 on npm soon.

cflurin commented 8 years ago

v0.1.9 is available on npm.