TP-Link Home Control With NodeJS

So, if you can’t tell from my recent posts, I am currently obsessed with remote control. Powering things on and off. I work on my laptop a lot, and typing is a lot quicker for me than moving the mouse around, so I spend a lot of time with terminal open just for the sake of it, even when it’s not in use.

Anyway, I have a Google Home Mini device in my bedroom, along with a tp-link LB130 smart bulb, which Google can turn on and off at my vocal command. It’s pretty nice, but I wanted to be able to type it instead. Enter nodejs.

Why node? Well, the first library I saw when I googled tp-link smart bulb api was a nodejs library. I’m familiar with node, I have it installed and it’s ready to go. So I installed the tplink-smarthome-api from npmjs. That said, there is also a python library available, but I saw it after the fact.

npm install -g tplink-smarthome-api installs the library globally, you can opt to install it locally instead if you prefer.

Then I set up a very crude nodeJS script to test the api. I needed the IP address of my light bulb, first, though. So I logged in to my router settings, looked at the wifi devices and looked for the appropriate one. While I was there I set up some DHCP address reservation, so my light bulb will always have the same local IP address.

let { Client } = require('tplink-smarthome-api'); let client = new Client(); let plug = client.getDevice({host: 'ip.goes.in.here'}).then((device)=>{ device.getSysInfo().then(console.log); device.setPowerState(true);

This code snippet, with the right IP address, simply sets the light to be on. You can change the boolean on line 5 device.setPowerState(false); to false in order to turn off the light, to test. Line 4 prints a bunch of device info, I commented this line out in the next iteration but left it in the script in case I ever wanted to refer to it again.

Now that I could see that the tplink api library works as expected, I wanted to add this node script to my global /scripts/ path, so I can run it from any location on my laptop, within terminal. I also wanted to be able to pass a parameter to determine whether to turn the light on or off. So let’s break that down into two tasks, I’ll start with the command line arguments to set the state of the bulb.

let { Client } = require('tplink-smarthome-api'); if(process.argv.length == 3) { if(process.argv[2].toLowerCase() == 'on' || process.argv[2].toLowerCase() == 'off') { let state = (process.argv[2].toLowerCase() == 'on') ? true : false; let client = new Client(); let plug = client.getDevice({host: 'ip.goes.in.here'}).then((device)=>{ //device.getSysInfo().then(console.log); device.setPowerState(state); }); } else { console.log("on or off, nothing else"); } } else { console.log("arg length mismatch"); }

process.argv[] is an array that contains a list of command line arguments. As with most indexed arrays, it starts at 0 for the first element. The first two arguments are always the node executable path and the script path, so there will always be two arguments even if we don’t provide any ourselves. With that in mind, we get the length of process.argv and compare it to a hard-coded number, 3. The two guaranteed arguments and our own, three.

if(process.argv.length == 3) – if this is true, we’re going to evaluate the third command line argument, the one we provided. We are expecting ‘on’ or ‘off’, and if we have either of these arguments, we’ll set a state variable based on the value, run our code to manipulate the light and pass our state variable to the setPowerState() function.

For convenience and to save writing another if-else block, I used the ternary operator for that on-the-fly conditional assignment.

let state = (process.argv[2].toLowerCase() == ‘on’) ? true : false;

If the argument value is ‘on’ then we set the state to true, otherwise we set it to false; since we already know its value will be ‘on’ or ‘off’ due to the previous if condition. Then we use the code provided in the example from the library documentation to toggle our light. Let’s take a quick look at that code for a second.

let client = new Client(); – we’re creating a new Client() object and assigning it to a constant variable, `client`.

let plug = client.getDevice({host: ‘ip.goes.in.here’}) – this constant is never used, but we use the client object we created above in order to get our device with the `getDevice()` function. We then chain .then() to this so we can run some code once we have got a handle to our device. Also known as a Promise. Within this in-line function, we take our handle to the device and then set its state with the variable we previously created from our command-line argument: device.setPowerState(state);.

So that’s the code. The summary:

  • Check command-line argument count
  • If it equals 3, check that the 3rd argument is equal to either ‘on’ or ‘off’
  • Create a true or false boolean variable based on whether we pass ‘on’ or ‘off’
  • Instantiate a Client() object and get a handle to our device
  • Set the power state of the device

For running this from terminal, anywhere, as with my other scripts, it lives in a /scripts/ directory which is added to the PATH env var. I had to give the script the permission to execute; on mac I type chmod +x light.js. I then remove the extension because I don’t want to type that every time, too. So the js file is now just called light. Make sure you don’t name your files in a way that might clash with other programs either now or in the future.

Finally, I had to add a shebang (#!) to the first line of the file, to tell the system to use nodeJS as the interpreter. This looks like: #! /usr/local/bin/node.

And so, with all of that done, I can open terminal and run light on or light off and it will do exactly as expected, turn that light on or off!

Bookmark the permalink.

Comments are closed.