-2

I am writing a simple app in Coffeescript to control a Philips Hue light. I have included this module into my project. The below code seems to work fine up until I try to set the color of the lights using setLightState. The compiler says the function isn't a function. I don't quite understand why it doesn't recognize the function.

# Connect with Philips Hue bridge
jsHue = require 'jshue'
hue = jsHue()

# Get the IP address of any bridges on the network
hueBridgeIPAddress = hue.discover().then((bridges) => 
    if bridges.length is 0
        console.log 'No bridges found. :('
    else 
        (b.internalipaddress for b in bridges)
).catch((e) => console.log 'Error finding bridges', e)

if hueBridgeIPAddress.length isnt 0 # if there is at least 1 bridge
    bridge = hue.bridge(hueBridgeIPAddress[0])  #get the first bridge in the list

    # Create a user on that bridge (may need to press the reset button on the bridge before starting the tech buck)
    user = bridge.createUser('myApp#testdevice').then((data) =>
        username = data[0].success.username
        console.log 'New username:', username
        bridge.user(username)
    )

    if user?
        #assuming a user was sucessfully created set the lighting to white
        user.setLightState(1, {on:true, sat:0, bri:100, hue:65280}).then((data) =>
            # process response data, do other things
        )
cHorse
  • 11
  • 1
  • 8

1 Answers1

0

As you can see on the github page of the jshue lib, bridge.createUser does not directly return a user object.

Instead the example code sets the user variable inside the then function of the returned promise:

bridge.createUser('myApp#testdevice').then(data => {
    // extract bridge-generated username from returned data
    var username = data[0].success.username;

    // instantiate user object with username
    var user = bridge.user(username);
    user.setLightState( .... )
});

It can be expected that - using this approach - the user variable will be set correctly and user.setLightState will be defined.

A self-contained example:

Take this Codepen for example:

url = "https://api.ipify.org?format=json"

outside = axios.get(url).then (response) =>
  inside = response.data.ip
  console.log "inside: #{inside}"
  inside

console.log "outside: #{outside}"

The console output is

outside: [object Promise]
inside: 178.19.212.102

You can see that:

  1. the outside log is first and is a Promise object
  2. the inside log comes last and contains the actual object from the Ajax call (in this case your IP)
  3. the then function implicitly returning inside does not change anything
Alexander Presber
  • 6,429
  • 2
  • 37
  • 66
  • The thing is that with Coffeescript the last line of the function `bridge.user(username)` is returned and set to `user` so my code is effectively doing what you are suggesting.... or at least it should be. – cHorse Mar 22 '18 at 16:33
  • @cHorse Not true. `bridge.createUser` returns **immediately** (a `Promise` object). On success of some internal mechanism (probably an Ajax call) the Promise invokes the function passed to it's `then` method **later** with the data from the Ajax call as argument. That the function passed to the Promise's `then` method implicitly returns it's last expression (because of CoffeeScript) doesn't help, the return value of this function is discarded anyway. In fact the whole problem is not related to CoffeeScript at all. – Alexander Presber Mar 22 '18 at 18:01
  • I think I see what you are saying. `createUser` takes some amount of time to come back. While thats going on my code attempts to call `setLightState` on an object that hasn't been initialized yet. Hence the "not a function" error. – cHorse Mar 22 '18 at 23:03
  • Updated to add a stripped-down example. – Alexander Presber Mar 23 '18 at 08:38