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.