3
\$\begingroup\$

I'm working on a web-based on/off controller for multiple switches. I'm looking for a good way to manage the current state of a switch and updating the current state on change.

So far I've got a lib.json file which looks like this:

{   
    "Lights":[{
        "name": "light-one",
        "pin":"3",
        "command":"gpioDo",
        "actions": {
            "on":"1",
            "off":"0"
        }
    },{
        "name": "light-two",
        "pin":"5",
        "command":"gpioDo",
        "actions": {
            "on":"1",
            "off":"0"
        }
    },{
        "name": "light-three",
        "pin":"7",
        "command":"gpioDo",
        "actions": {
            "on":"1",
            "off":"0"
        }
    }],
    "Locks":[{
        "name": "lock-one",
        "pin":"8",
        "command":"gpioDo",
        "actions": {
            "on":"1",
            "off":"0"
        }
    },{
        "name": "lock-two",
        "pin":"12",
        "command":"gpioDo",
        "actions": {
            "on":"1",
            "off":"0"
        }
    }]
}

A web-page is dynamically created using some jQuery and appropriate groups of buttons are created according to the lib.json.

On the server I take that lib.json file and create a state object via this little snippet (note that on initial run all states must be off):

var state = [];
var lib = JSON.parse(fs.readFileSync('lib.json', 'utf8'));
...
for (i in lib) {
  for (x in lib[i]){
    state.push({pin:lib[i][x].pin, val:0});
  }
}

which produces:

[ { pin: '5', val: 0 },
  { pin: '7', val: 0 },
  { pin: '8', val: 0 },
  { pin: '12', val: 0 } ]

When a web-page button is pushed, the server receives a string containing misc elements of the lib.json referencing a command with parameters to perform.

It also updates the state object to represent the change with an updateVal() command.

function updateVal(pinId, valId){
  var i;
  for (i = 0; i < state.length; ++i) {
    if (state[i].pin == pinId) {
      state[i].val = valId;
    }
  }
}

I also have a controller designer which allows you to create groups of buttons which in turn modifies the lib.json. It's basically a hacked up JSON tree editor.

How efficient is this code? Could I be doing something better, and if so, what? I can imagine that creating and updating a state key and value in lib.json could be more effective and reliable.

\$\endgroup\$
  • \$\begingroup\$ Haven't got time just now to write up a full answer, but in node you can just do var lib = require('./lib.json'); and it will do the conversion for you. :) \$\endgroup\$ – Ben Aug 11 '14 at 7:57
  • \$\begingroup\$ I do (generally)! but the lib.json can change quite often and require(); holds a cached version. I'd get into time-stamped versioning stuff but it's a bit excessive with no real value apart from being able to use require();. Thanks though :) keen to hear your other thoughts \$\endgroup\$ – rwxes Aug 11 '14 at 9:13
3
\$\begingroup\$

A few things to consider;

Is it worth abstracting the collection into the lights and locks arrays? The data format is effectively identical, and I think separating them makes the collection as a whole harder to iterate over.

To follow up from the first point, I try to avoid for loops in JavaScript because there's so many efficient and readable alternatives for working with arrays. If we were to rewrite your data structure to be the following:

{
    "switches": [{
        "name": "light-one",
        "pin": 3, // definitely store integers as ints and not wrapped in quotes!
        "command":"gpioDo",
        "actions": {
            "on": 1,
            "off": 0
        }
    }, {
        // ...
    }]
}

We can then rewrite your first example to be the following:

var state = lib.map(function(switch) {
    return {
        pin: switch.pin,
        val: 0
    };
});

This removes the index variables completely, and in my opinion makes the code more readable. In the case of not rewriting the data structure you could just iterate over the lights and locks arrays with a map function, then concat them together.

In the same way we can iterate over this when you want to set the values.

var updateVal = function(pinID, valID) {
    state.forEach(function(s) {
        s.pin === pinID && (s.val = valID);
    });
};

The function expression is just a personal preference, but I like it as it forces you to declare a function before using it.

I'm also not sure if the actions key needs to be like it is; perhaps you need it for other entities that have other actions, but I would probably replace it with a boolean active (to represent on and off), for simplicity.

Hope this helps. :)

\$\endgroup\$
  • \$\begingroup\$ Exactly what I wanted to see! The use of Lights & Locks was just for simpler grouping but adding a group key would remove the need for it. I've always been a little nervous using .map due to lack of experience but I'll be sure to learn more about it, clearly it's a much prettier and effective method. I'm still unsure about actions possible a boolean could be used for true and false and then add the actions object for switches with multiple states. If possible I'd like to know what you think about updating lib.json directly or creating the state object. \$\endgroup\$ – rwxes Aug 11 '14 at 22:41
  • \$\begingroup\$ Really appreciate the time you've spent, thanks again - rwxes! (I'll be sure to upvote when I hit 15r) \$\endgroup\$ – rwxes Aug 11 '14 at 22:41
  • \$\begingroup\$ In my experience at least map is usually a prettier way of writing var a=[];[{d:1},{d:2}].forEach(function(c){a.push(c.d)}); but it's often better than that :) I think you can update the JSON file directly, but of course it depends on your use case; single user would be fine but add more and you'll probably want to start looking into databases. Glad I could help. :) \$\endgroup\$ – Ben Aug 11 '14 at 22:52
  • \$\begingroup\$ ahk, thankyou again for your help! much appreciated! \$\endgroup\$ – rwxes Aug 12 '14 at 1:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.