Skip to content

Commit

Permalink
Edge driver for TPLink smartplugs (#354)
Browse files Browse the repository at this point in the history
Create a driver for the TPLink smartplugs we use internally for power
monitoring.
  • Loading branch information
amrc-benmorrow authored Oct 9, 2024
2 parents c74efce + 5636f1f commit 04edeeb
Show file tree
Hide file tree
Showing 8 changed files with 1,205 additions and 0 deletions.
2 changes: 2 additions & 0 deletions edge-tplink-smartplug/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
tmp
33 changes: 33 additions & 0 deletions edge-tplink-smartplug/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# syntax=docker/dockerfile:1

FROM node:22-alpine AS build
ARG acs_npm=NO
ARG revision=unknown

USER root
RUN <<'SHELL'
install -d -o node -g node /home/node/app
SHELL
WORKDIR /home/node/app
USER node
COPY package*.json ./
RUN <<'SHELL'
touch /home/node/.npmrc
if [ "${acs_npm}" != NO ]
then
npm config set @amrc-factoryplus:registry "${acs_npm}"
fi

npm install --save=false
SHELL
COPY --chown=node . .
RUN <<'SHELL'
echo "export const GIT_VERSION=\"$revision\";" > ./lib/git-version.js
SHELL

FROM node:22-alpine AS run
# Copy across from the build container.
WORKDIR /home/node/app
COPY --from=build --chown=root:root /home/node/app ./
USER node
CMD node bin/driver.js
6 changes: 6 additions & 0 deletions edge-tplink-smartplug/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
top=..
include ${top}/mk/acs.init.mk

repo?=edge-tplink-smartplug

include ${mk}/acs.js.mk
52 changes: 52 additions & 0 deletions edge-tplink-smartplug/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# TP-Link driver

This is a driver for TP link smartplugs using the tplink-smarthome-api package.

## Configuration

The configuration has two components.

Property | Meaning
---|---
`host` | The device to connect to
`timeout` | Timeout in milliseconds (ms) for communication with the plug

## Addresses

All addresses return JSON.

### `SysInfo`

This returns general information about the plug, including:

Name | Type | Description
---|---|---
`mac` | string | The MAC address of the plug
`model` | string | The model number of the plug
`relay_state` | 0/1 | State of the remote control relay

There is additional information included which is not documented here.

### `PowerState`

This returns a Boolean representing whether the Plug relay is on (`true`) or off (`false`).

### `InUse`

This returns a Boolean representing whether the device is in use or not.

### `Meter`

This returns current energy information about the plug, including its current, power and voltage.

Name | Type| Description
---|---|---
`current` | Float | The current through the plug in Amperes (A)
`current_ma` | Integer | The current through the plug in Milliamperes (mA)
`power` | Float | The current power usage of the plug in Watts (W)
`power_mw` | Integer | The current power usage of the plug in Milliwatts (mW)
`voltage` | Float | The voltage across the plug in Volts (V)
`voltage` | Integer | The voltage across the plug in Millivolts (mV)
`total_wh` | Integer | The total energy supplied to the plug in watt-hours (wh)


14 changes: 14 additions & 0 deletions edge-tplink-smartplug/bin/driver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* AMRC Connectivity Stack
* TP Link Smartplug driver
* Copyright 2024 AMRC
*/

import { PolledDriver } from "@amrc-factoryplus/edge-driver";
import { TplinkHandler } from "../lib/tplink.js";

const drv = new PolledDriver({
env: process.env,
handler: TplinkHandler,
serial: true,
});
drv.run();
82 changes: 82 additions & 0 deletions edge-tplink-smartplug/lib/tplink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* AMRC Connectivity Stack
* TP Link Smartplug driver
* Copyright 2024 AMRC
*/

import { BufferX } from "@amrc-factoryplus/edge-driver";
import tplink from 'tplink-smarthome-api';

export class TplinkHandler {
constructor (driver, conf) {
this.driver = driver;
this.conf = conf;

this.log = driver.debug.bound("tcplink");

this.client = new tplink.Client();
}

static create (driver, conf) {
console.log("Handler called: conf %o", conf)
if (conf.host == null)
return;
const h = new TplinkHandler(driver, conf);
console.log("h is ", h)
h.connect();
return h;
}

async connect () {
console.log("connect")
const { driver, client } = this;
const { host, timeout } = this.conf;

const device = await client.getDevice(
{ host },
{ timeout }
)
.catch(() => null);

console.log(`PLUG: Device ${host} connected`);

if (device)
driver.connUp();
else
driver.connFailed();

this.device = device;
}

parseAddr (spec) {
switch (spec) {
case 'SysInfo':
case 'PowerState':
case 'InUse':
case 'Meter':
return spec
default:
return;
}
}

async poll (addr) {
const { device } = this;
if (!device) return;

switch (addr) {
case 'SysInfo':
const value = await device.getSysInfo();
console.log("SysInfo read %o", value);
return BufferX.fromJSON(value);
case 'PowerState':
return BufferX.fromJSON(await device.getPowerState());
case 'InUse':
return BufferX.fromJSON(await device.getInUse());
case 'Meter': {
const value = await device.emeter.getRealtime();
console.log("Meter read %o", value);
return BufferX.fromJSON(value);
}
}
}
}
Loading

0 comments on commit 04edeeb

Please sign in to comment.