symlink | misc | home IoT

This is a "show and tell" post.

As a person deeply into Computers and Computer Networks, I strongly dislike the idea of actually having a 'smart' home where lights turn on autonomously. Yet at the same time I do like hardware which can be controlled via TCP/IP somehow, such as ordinary Wi-Fi lightbulbs or power outlets, and I have a few of those.

The current choice is TP-Link 'Tapo' series products, because they are cheap and have a local API easily available – that is, they rely only minimally on a cloud service, and can be controlled offline after initial provisioning. (As of firmware 1.4, one needs to enable "Third-Party Interoperability" in the Tapo app's global settings for this to work.)

Their 'Tapo' local API is implemented by python-kasa, but as with Python in general, it takes quite a while to "boot up" so I've instead written my own Perl implementation.

Usecase 1: Remote power-cycle and power metering of Dunelab devices. The perl-tapo repository contains a plug.pl which is a CGI script that displays current status of the specified outlet (both connected to local Dunelab Wi-Fi).

Usecase 2: I have a basic L510 light bulb on my room. Instead of a smart switch, however, I am using my Wi-Fi router's "WPS" button, which is prominent at the top of the router and scriptable within the constraints of RouterOS – meaning, it can perform an HTTP query into a Linux host.

/system/script/add name=button \
 source={/tool/fetch url=http://myth.sym/cgi-bin/bulbctl.pl output=none}

/system/routerboard/wps-button/set enabled=yes on-event=button

The bulbctl.pl CGI script runs on my home server (though it could potentially run within a container on the router itself), using perl-tapo to control the lightbulb and keeping a little bit of state to implement off-low-med-high cycling. Even with the added latency of multiple HTTP requests and one /bin/perl spawn, the response latency is sufficiently low – approximately same as the official Tapo app, but without having to wait half a minute for the app to actually load.

my $clnt = Tapo::Client->new($host, $user, $pass);
$clnt->call(set_device_info => {device_on => \1, brightness => $level});

RouterOS also turns out to support MQTT in the iot package, so I've rewritten the Perl CGI script to run as a stand-alone daemon, and instead of HTTP one can use:

/system/script/add name=button \
  source={/iot/mqtt/publish broker=myth topic=bulb message=toggle}

which results in even lower latency.