Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Philips Hue Adapter #99

Closed
wants to merge 8 commits into from

Conversation

hobinjk
Copy link
Contributor

@hobinjk hobinjk commented Jun 14, 2017

It exposes each light as an onOffSwitch.

There's currently an issue in the first run where the bridge pairs then shows only one device which is missing the id key required for being saved as a thing.

This should be ready once that issue is fixed.

@hobinjk hobinjk force-pushed the philips-hue-adapter branch 2 times, most recently from 7e6a446 to 7ec6560 Compare June 15, 2017 14:37
@hobinjk
Copy link
Contributor Author

hobinjk commented Jun 15, 2017

I figure out the issue! It turns out that discoverLights would keep adding new lights which would in turn cause handleNewThing to occur for the first light to be added.

@dhylands This should be good to go whenever you're available

Copy link
Contributor

@dhylands dhylands left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had an issue when I initially paired the hub. One of 3 lights showed up, but I when I clicked Save, nothing happened. When I cancelled out of adding, and re-entered then my 3 hue bulbs showed up and the save worked as expected.

@@ -0,0 +1,233 @@
/**
*
* PhilipsHueAdapter - an adapter for controlling TP-Link Smart Lights
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo? (reference to TP-Link?)

'use strict';

var PhilipsHueAdapter = require('./philips-hue-adapter');
var rp = require('request-promise-native');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request (a dependency of request-promise-native) appears to be missing from package.json

tip: When adding lots of new stuff, I generally like to clone the repository into another directory and verify that it runs from a fresh clone.

That helps to identify missing dependencies as well as files you may have forgotten to add to the PR (one of my favorite tricks).

Copy link
Contributor Author

@hobinjk hobinjk Jun 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the heads-up! I assumed incorrectly that request-promise-native would have request as a dependency instead of a peer dependency.

this.pairing = true;
var endTime = Date.now() + timeoutSeconds * 1000;

var attemptPairing = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I don't understand why you create a function and then call it rather than just put the contents inline?

return storage.init();
}).then(() => {
return storage.getItem(KNOWN_BRIDGE_USERNAMES);
}).then(knownBridgeUsernames => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't knownBridgeNames have parens around it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally believe the code looks cleaner without them, especially in cases like catch(e => {}). I can add them here, but is there a style guide I should be following?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, I guess it was more a case of not realizing that you could even do it that way.

The only style guide that we really have is the suggestions from the linter, and this passed the linter. @benfrancis may have an opinion, but otherwise I think its fine.

var attemptPairing = () => {
this.pair().then(username => {
this.username = username;
return this.discoverLights();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also isn't clear to me why you're returning anything when the return value isn't used?
I've seen this being used before - and I'm probably just not getting something.

}
knownBridgeUsernames[this.bridge.id] = this.username;
return storage.setItem(KNOWN_BRIDGE_USERNAMES, knownBridgeUsernames);
}).catch(e => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it useful to do console.error(e) this then prints a complete backtrace when e is an error. When you add anything else (like in the line below) then it prints the string representation of e which doesn't include the backtrace.


/**
* Perform a single attempt at pairing
* @return {Promise} Resolved with username if pairing succeeds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this paring the hub? or pairing a light?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pairing a hub then discovering lights, I updated the comment to be a bit more clear

@hobinjk
Copy link
Contributor Author

hobinjk commented Jun 16, 2017

The problem where 1 light shows up and can't be added is related to the way that startPairing works. I'm trying to write a test to demonstrate this, but the behavior I've found is that only one device can be added during an instance of pairing. It gets this one device from models/action.js handling the 'pair'.

AdapterManager.addNewThing().then(function(thing) {
  Things.handleNewThing(thing);
  action.status = 'completed';
})...

Once the Hue hub is paired and can create lights, the mechanism that causes those multiple devices to show up is the NewThingsController.ws or NewThingsController.get handlers. These don't function in the first run because they each only run getNewThings once at the beginning when the hue hub is still unpaired.

I don't really know how to fix this issue, although I could probably fix the issue causing the one device that shows up to be unable to be saved.

@hobinjk
Copy link
Contributor Author

hobinjk commented Jun 16, 2017

There were two issues in play. First, the "Send Thing instead of description" allows the user to save Things that are dynamically added while the Add New Things menu is open.

Second, the Things/Actions models now properly work together to communicate all newly available Things instead of just the first that appears. Actions was using the Promise resolution as its only source of new things, meaning that all of the pairing attempts would "race" to be the first to resolve the Promise. The winning Thing would then be sent via handleNewThing to the Add New Things menu. I replaced this one-shot approach with a listener attached to AdapterManager's thing-added event that calls handleNewThing.

I'm now looking at how to write a test that will demonstrate this behavior.

(there was a bit of delay after I spilled half a cup of tea on my computer causing its display to short out and its keyboard to die, but the passage of time is a perfect panacea)

@hobinjk
Copy link
Contributor Author

hobinjk commented Jun 16, 2017

@benfrancis I think you probably have some opinions on the movement of handleNewThing (at least that's what git blame tells me :P). Is this the proper approach to take? 

@hobinjk
Copy link
Contributor Author

hobinjk commented Jun 16, 2017

Since the changes to AdapterManager, NewThingsController, and the Actions model are pretty far removed from the Philips Hue adapter I've moved them to #103

@benfrancis
Copy link
Member

Only being able to pair one "Thing" at a time was actually an intentional design decision. IIRC this is because the push button commissioning method used by ZigBee and Z-Wave creates a security vulnerability in that the pairing mechanism allows any device to connect to the hub while in pairing mode without any form of authentication. A malicious device could try to pair with the hub while it is in pairing mode and go unnoticed by the user as they add the device they intended to add.

By locking this down to only allow one device to be paired at a time it makes it much more obvious to the user when a device was added unintentionally. However, with the UI we ended up with this does get confusing because you can still have multiple devices displayed in the "add device" dialog and "pairing" and "adding" have become separate user interactions. So maybe its right to re-visit this decision.

I guess this becomes more of an issue when you pair the gateway with another hub which may have multiple devices already connected to it. I personally don't like the idea of a "hub of hubs" and think we should focus on supporting standards like ZigBee, Z-Wave and Bluetooth, but I know Dave feels differently about this. I'm sure there will be demand for a Phillips Hue adapter and the encryption used by the Zigbee Light Link profile makes it tricky to support the bulbs directly. Regardless, our pairing UI is probably going to need some refinement to support the quirks of the various pairing mechanisms used by devices!

See my review in #103 for the specifics around the changes to /new_things

@hobinjk
Copy link
Contributor Author

hobinjk commented Jun 19, 2017

Okay, so if I understand correctly the ZigBee and Z-wave startPairing tell the adapter to permit any device to pair with it.

The interpretation of startPairing that I use with the Philips Hue is that the adapter begins attempting to get an API key from the hub. Notably, this then requires the user to press the physical button on top of the hub to allow the acquiring of the API key. I definitely agree that there's room for a clearer separation of pairing adapters and adding devices, which would also solve the problem of how to prompt a user to press the hub's button if and only if they are attempting to pair a Philips Hue hub.

@dhylands
Copy link
Contributor

ZigBee always allows multiple devices to join for the duration that the controller is pairing. What the adapter does is that it uses the first one to resolve the promise. Remaining devices that get added are just added to the adapter manager and will be visible the next time you enter the Add Thing screen.

I think that having the new devices be posted via a web socket would allow them to appear in real-time.

@dhylands
Copy link
Contributor

I also think that we need to think of a way that the adapter can tell the UI that it needs user input.

For Zigbee, adding a new device doesn't require pressing a button. If the adapter is in pariing mode and you plug in an unparied device, it will automatically get added with no button press required.

For Hue, it would be nice to prompt the user that the hub needs to be paired (perhaps at the very beginning of the add process).

For ZWave, you actually need to press a button on the device, and if the user was used to the ZigBee behaviour of not having to press a button, then they might not realize that they're supposed to press a button.

@benfrancis
Copy link
Member

Yeah it doesn't really make sense as currently implemented. The original intention was that adding and pairing would be the same thing and you could only add/pair one device at a time. The reality turned out to be different as the underlying protocols allow multiple devices to be paired and we just don't show them, which is much worse. "Adding" (to the database) is currently a separate interaction to "pairing" (with the dongle) and we currently have no UI for "unpairing", only "removing".

This can definitely be improved but I'm hesitant to try to make major changes to the way it works a week before release. I'd suggest we fix the bugs we find (like the one James seems to have found, and the fact we don't show all the devices that are paired) and hold off adding new features (including new adapters that require major changes to the core) until the next release.

As an aside, I think it was someone from Develco who suggested only allowing one ZigBee device to pair at a time, as a mitigation for using push button commissioning without requiring the entry of a serial number in the UI as an extra security measure.

@codecov-io
Copy link

codecov-io commented Jun 23, 2017

Codecov Report

Merging #99 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@          Coverage Diff           @@
##           master     #99   +/-   ##
======================================
  Coverage    82.6%   82.6%           
======================================
  Files          30      30           
  Lines         920     920           
======================================
  Hits          760     760           
  Misses        160     160
Impacted Files Coverage Δ
config/test.js 100% <ø> (ø) ⬆️
config/default.js 100% <ø> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 050e2db...dff1ca4. Read the comment docs.

@andrenatal
Copy link
Contributor

@hobinjk what's the current status of this PR? Would we be able to demo this feature too?

@hobinjk
Copy link
Contributor Author

hobinjk commented Sep 22, 2017

@andrenatal I've spun it off into https://github.com/hobinjk/philips-hue-adapter and the current plan is to use the adapter API once it's finished although for now I've been manually adding the adapter to config/default.js

@hobinjk hobinjk closed this Sep 22, 2017
@mrstegeman mrstegeman added this to Done in WebThings Gateway Apr 10, 2019
@mrstegeman mrstegeman removed this from Done in WebThings Gateway Apr 10, 2019
@mrstegeman mrstegeman added this to In progress in WebThings Gateway via automation Apr 10, 2019
@mrstegeman mrstegeman moved this from In progress to Done in WebThings Gateway Apr 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

None yet

5 participants