I finally found a solution, i am not sure if it is efficient, but it works, 
i used async.waterfall, thanks Floby for your help !

// initialise previousState
var previousState = "Original";

io.sockets.on('connection', function (socket) {
    setInterval(function(){
            async.waterfall([
                function getLightsId(callback) {
                    args = {
                        path: {
                            "username": "webjeremie"
                        }
                    };

                    client.registerMethod("getLightState", 
"http://hue.jeremieledieu.fr/api/${username}/lights/";, "GET");

                    client.methods.getLightState(args, function (data, 
response) {
                        var ids = [];
                        for (key in data) {
                            ids.push(key);
                        }
                        callback(null, ids);
                    });
                },
                function getLightsState(ids, callback) {
                    var lightsState = new Object();
                    async.reduce(ids, {}, function(lightsState, id, 
rcallback) {
                      getLightState(id, function(state) {
                        lightsState[id] = state;
                        rcallback(null, lightsState);
                        });
                    }, callback);
                },
        ], 
        function (err, currentState) {
            if(JSON.stringify(currentState) !== 
JSON.stringify(previousState)){
                io.sockets.emit('updateLightsState', currentState);
                previousState = currentState;
                console.log("state changed");
            }            
        });
    },1000);
 });


Le vendredi 4 avril 2014 15:11:55 UTC+2, Floby a écrit :
>
> Haha, no problem. Maybe I gave you the hard version a little bit too soon.
>
>    1. I don't have a full understanding of how your application works as 
>    a whole, but as I understood you can in fact call getLightsIds and upon 
>    getting the result, calling initLightState with that result.
>    2. Yes, reduce is pretty much a forEach in this case. You can refactor 
>    this part to something you like more very safely.
>    3. tasks is an object assigning an asynchronous task to each id. so 
>    it's in fact something like {'my-first-lamp': function (callback) {...}} 
>    and so on. It is an object for which every field is a function describing 
>    how to get a result for that particuliar field. This is probably unclear, 
>    which leads me to the next point
>    4. async.parallel does exactly what is said here (
>    https://github.com/caolan/async#parallel). It takes several 
>    asynchronous tasks, executes them all in parallel and calls its own 
>    callback with an aggregation of the results of all the tasks
>    5. lastKnownStates in my code is empty, and it's a mistake! sorry. 
>    lastKnownState is meant to be the last states of your lamps that you 
>    notified your client with. So you should probably update it when you 
> notify 
>    your clients =)
>
> Hope this helps.
>
> On Friday, 4 April 2014 14:35:38 UTC+2, JL wrote:
>>
>> Hello, 
>>
>> First, thanks A LOT for taking the time to help me.. i appreciate it !
>>
>> I really tried your way, but my head hurts :p
>>
>> Could you please comment more the example you provided ?
>>
>> Here's what i don't understand :
>>
>>
>>    1. First, your initLightState should be in my getLightsId function so 
>>       i can pass my array of Ids in it ?
>>       2. the ids.reduce is like ids.forEach() ?
>>       3. if i understand the tasks[id] = getLightState.bind(id); is 
>>       making an array (tasks) that contains my lights state ?
>>       4. I dont get what async.parallel does
>>       5.  lastKnownStates in your code is empty, when should i fill it ?
>>    
>> I am sorry for all my question, i really have trouble understanding how 
>> it works..
>>
>> Thank you for your time.
>>
>>
>> Le vendredi 4 avril 2014 11:06:06 UTC+2, Floby a écrit :
>>>
>>> Hello, this seems like a fairly well addressed use case. You're not so 
>>> far !
>>>
>>> First of all, I strongly suggest you stick to the convention of error 
>>> first callbacks. Believe me it will help you use other tools and 
>>> interoperate them with your code.
>>> The principle is simple : whenever a method/function is asynchronous
>>>
>>>    - it takes a callback as last argument
>>>    - when an error occurs during that operation, it calls the callback 
>>>    with an error as first argument
>>>    - when successful, it calls the callback with null as first argument 
>>>    and the result as second argument
>>>
>>> If you can change your methods to follow this pattern, then you'll be 
>>> able to use the async [1] module directly to handle your aggregation of 
>>> several asynchronous results.
>>> If you want to trigger events only if the state of the lamps have 
>>> changed, you could use something like deep-equal [2] to compare results 
>>> over time.
>>>
>>> In the end, you should be able to write something like this
>>>
>>> var deepEqual = require('deep-equal');var async = require('async');
>>> function initLightState (ids, callback) {
>>>   var lastKnownStates = {}; // initialise to empty array
>>>   var tasks = ids.reduce(function (tasks, id) {
>>>     tasks[id] = getLightState.bind(id);
>>>     // If you want to use less magic
>>>     // the following is strictly equivalent
>>>     tasks[id] = function (callback) {
>>>       getLightState(id, callback);
>>>     }
>>>     return tasks;
>>>   } {});
>>>
>>>   // checking states every 500 ms
>>>   return setInterval(checkState, 500);
>>>
>>>   function checkState () {
>>>     async.parallel(tasks, function (err, states) {
>>>       if(!deepEqual(states, lastKnownStates)) {
>>>         notifyClient(states);
>>>       }
>>>     });
>>>   };}
>>>
>>>
>>> [1] https://www.npmjs.org/package/async
>>> [2] https://www.npmjs.org/package/deep-equal
>>>
>>> On Thursday, 3 April 2014 20:13:38 UTC+2, JL wrote:
>>>>
>>>> Hello everyone,
>>>>
>>>> I am learning javascript and nodejs, im currently making an nodejs app 
>>>> to manage my philips hue lamps.
>>>>
>>>> And i am struggling with the asynchronous and callbacks.
>>>>
>>>> First let me explain what i want to achieve.
>>>>
>>>> I have a function that get the id of all my lights, named getLightsId :
>>>>
>>>> function getLightsId(callback){
>>>>     args ={
>>>>         path:{"username":"username"}
>>>>     };
>>>>
>>>>     client.registerMethod("getLightState", 
>>>> "bridge_adress/api/${username}/lights/", "GET");
>>>>
>>>>     client.methods.getLightState(args, function(data,response){
>>>>         var id = [];
>>>>         for(key in data){
>>>>             id.push(key);
>>>>         }
>>>>         callback(id);
>>>>     });}
>>>>
>>>> Then i have a function getLightState that get the state of a specific 
>>>> lamp determined by its id
>>>>
>>>> function getLightState(id, callback){
>>>>
>>>>     args ={
>>>>         path:{"username":"username", "id":id}
>>>>     };
>>>>
>>>>     client.registerMethod("getLightState", 
>>>> "http://bridge_address/api/${username}/lights/${id}";, "GET");
>>>>
>>>>     client.methods.getLightState(args, function(data,response){
>>>>         callback(data);
>>>>     });}
>>>>
>>>> And finally i have a function initLightsState that send the state of 
>>>> all the lights in an object to my client. be prepared to see ugly shit :p, 
>>>> its pretty dirty, but hey, it works (kinda).
>>>>
>>>> function initLightsState(callback){
>>>>
>>>>     getLightsId(function(idArray) {
>>>>
>>>>         var lightsState = new Object();
>>>>
>>>>         idArray.forEach(function(id) {
>>>>
>>>>             setInterval(function(){getLightState(id, function(state) {
>>>>
>>>>                 lightsState[id] = state;
>>>>             });},500);
>>>>         });
>>>>
>>>>         callback(lightsState);
>>>>         io.sockets.on('connection', function (socket) {
>>>>             setInterval(function(){
>>>>                 socket.emit('updateLightsState', lightsState);
>>>>             },500);
>>>>         });
>>>>     });}
>>>>
>>>> I had to put a setInterval() to my getLightState function because 
>>>> otherwise it was always sending me the same object with the same data, i 
>>>> know its dirty but i couldnt find another way.
>>>>
>>>> then i emit also with a setInterval() my object to my client.
>>>>
>>>> The problem is that its obviously spamming my client with the state of 
>>>> my lights.. it works, but its very far from being the cleanest way to do 
>>>> this.
>>>>
>>>> What i want to do, is to compare server-side the previous state of my 
>>>> light with the current one, and only if its different send it to the 
>>>> client.
>>>>
>>>> But im stuck with the callback and everything and cant get it work.
>>>>
>>>> Could someone please show me the simplest way to do this ?
>>>>
>>>> Thanks a lot.
>>>>
>>>

-- 
-- 
Job Board: http://jobs.nodejs.org/
Posting guidelines: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

--- 
You received this message because you are subscribed to the Google Groups 
"nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to