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.
1 Answer 1
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. :)
-
\$\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 aboutactions
possible a boolean could be used for true and false and then add theactions
object for switches with multiple states. If possible I'd like to know what you think about updatinglib.json
directly or creating thestate
object. \$\endgroup\$rwxes– rwxes2014年08月11日 22:41:11 +00:00Commented Aug 11, 2014 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– rwxes2014年08月11日 22:41:49 +00:00Commented Aug 11, 2014 at 22:41
-
\$\begingroup\$ In my experience at least
map
is usually a prettier way of writingvar 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– Ben2014年08月11日 22:52:38 +00:00Commented Aug 11, 2014 at 22:52 -
\$\begingroup\$ ahk, thankyou again for your help! much appreciated! \$\endgroup\$rwxes– rwxes2014年08月12日 01:08:19 +00:00Commented Aug 12, 2014 at 1:08
Explore related questions
See similar questions with these tags.
var lib = require('./lib.json');
and it will do the conversion for you. :) \$\endgroup\$lib.json
can change quite often andrequire();
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 userequire();
. Thanks though :) keen to hear your other thoughts \$\endgroup\$