Vacation Plan Manager is a platform that manages a vacation lighting plan for one or more SmartThings locations tied to a single SmartThings user.
The platform is written in Python 3. It has two components: a daemon process running as a systemd user service, and a command line tool. The command line tool communicates with the daemon via a RESTful API using a private UNIX socket. You use the command line tool to configure your vacation plans, to enable or disable vacation plans, and to test your devices.
The platform is lightweight and will work on most Linux systems that have internet access and are configured to run continuously, including low-cost hardware such as the Raspberry Pi.
A vacation lighting plan describes how to turn on and off various lighting
devices in a specific pattern when you are away from home. The plan can be
varied by day of week (weekday, weekend, or particular day) and it also allows
for random variation in the timing, so your lights do not turn on or off at
exactly the same time every day. It works for any device with the switch
capability.
Underneath, the vacation lighting plan is implemented in your SmartThings account as a set of rules. To operate within the SmartThings platform restrictions, rules tied to your SmartThings account are updated on a daily basis, to reflect the randomized plan for that day.
This is a developer-focused tool.
My goal was to write something I could use myself on my own hardware. The code is well tested and functions properly, but I haven't spent a lot of effort on making the installation process simple or the error handling pretty. If you're not already comfortable with the UNIX command line, you may have a hard time getting this to work.
This is not a general purpose, multi-user solution.
This platform is intended for local use by a single Linux user. Security is based on simple UNIX filesystem permissions, which ensure that only the owner can read the underlying sqlite database and make API calls via the private UNIX socket. If you run the API in some other way — especially if you run it on some local port like :8080 instead of using the private UNIX socket — you risk exposing secrets such as your SmartThings PAT token.
Developer documentation is found in DEVELOPER.md. See that file for notes about how the code is structured, how to set up a development environment, etc.
The platform is distributed at GitHub. To install the software, download the .whl
file for the latest release,
and install it using pipx, like:
$ pipx install --force --include-deps ./vplan-0.7.1-py3-none-any.whl
On Debian, I install pipx using:
apt-get install pipx --no-install-suggests --no-install-recommends
Next, configure the platform. Download the configuration bundle for the latest release. Extract the tar file to your user configuration directory:
$ mkdir -p ~/.config
$ tar zxvf vplan-config-0.6.0.tar.gz -C ~/.config
This creates two directories within ~/.config
: vplan
and systemd
. The
systemd
directory contains configuration for the systemd user service that
you will create shortly:
systemd/user/vplan.service
systemd/user/vplan.socket
The vplan
directory contains configuration for the vplan daemon process and
the command line client. There are also two runtime directories, to contain
the UNIX socket and the small database that is used to maintain state.
vplan/client/application.yaml
vplan/server/application.yaml
vplan/server/logging.yaml
vplan/server/db
vplan/server/run
The default configuration should work for most people, so there is probably no need to modify any of these files.
Next, configure systemd:
$ sudo loginctl enable-linger <your-user> # restart user services at reboot
$ systemctl --user enable vplan # enable the vplan service
$ systemctl --user start vplan # start the vplan service
$ systemctl --user status vplan # show status for the vplan service
At this point, the systemd service should be running, and the command line client should be operable. Check connectivity. If you get any errors, check that you installed the software as described above.
$ vplan check
API is healthy, versions: package='0.6.0' api='2.0.0'
If necessary, you can check the logs from the service:
$ journalctl --pager-end --user-unit vplan
If you do need to change any of the systemd config files (unlikely), make sure to reload them afterwards, before trying to do any further testing:
$ systemctl --user daemon-reload
Finally, reboot and confirm that the service starts automatically. After
reboot, use the same vplan check
command shown above to confirm things are
working.
The process is similar to installing. Download the .whl
file for
the latest release, and install it
using pipx, like:
$ pipx install --force --include-deps ./vplan-0.7.1-py3-none-any.whl
On Debian, I install pipx using:
apt-get install pipx --no-install-suggests --no-install-recommends
Reload configuration and restart the systemd service::
$ systemctl --user daemon-reload
$ systemctl --user restart vplan
Finally, run the check and confirm what version you are running on:
$ vplan check
API is healthy, versions: package='0.6.0' api='2.0.0'
The vacation plan manager needs a SmartThings PAT token. The PAT token is used to interact with the SmartThings API.
Retrieve a token from: https://account.smartthings.com/tokens
Your PAT token requires the following scopes:
Devices:
List all devices (l:devices)
See all devices (r:devices:*)
Control all devices (x:devices:*)
Locations
See all locations (r:locations:*)
Rules
See all rules (r:rules:*)
Manage all rules (w:rules:*)
Control this rule (x:rules:*)
Once you have retrieved your PAT token, set up your account:
$ vplan account set
Enter PAT token: <your token>
Account created
You can spot-check that it was set properly using the show
command:
$ vplan account show
PAT token: 0d14****************************3251
In the future, you can change your PAT token using the same set
command shown
above. See other account commands using vplan account --help
.
A vacation plan is defined in a YAML file. Here is a very simple example:
version: 1.1.0
plan:
name: my-house
location: My House
refresh_time: "00:30"
refresh_zone: "America/Chicago" # if you don't specify a zone, it runs in UTC
groups:
- name: first-floor-lights
devices:
- room: Living Room
device: Sofa Table Lamp
- room: Dining Room
device: China Cabinet
component: leftOutlet
triggers:
- days: [ weekdays ]
on_time: "19:30"
off_time: "22:45"
variation: "+/- 30 minutes"
- days: [ tue, thu, sat ]
on_time: sunset
off_time: sunrise
variation: none
All plans require:
- a name - an identifier matching the regex
[a-z0-9-]+
, unique among all of your plans - a location - whatever it's called in your SmartThings infrastructure
- a refresh time - the HH24:MM time of day when rules will be refreshed at SmartThings
- one or more device groups
For the refresh time, pick a time of day when none of your groups will be changing state from on to off or off to on — probably the middle of the night or the middle of the day.
A device group consists of:
- a name - an identifier matching the regex
[a-z0-9-]+
, unique within this plan - one or more devices - all devices in a device group will turn on and off together, like a scene
- one or more triggers - a trigger is in scope on certain days and describes the times when a device group will turn on and off
Each device consists of:
- a room - the human-readable name of the room where the device lives in your SmartThings infrastructure
- a device - the human-readable name of the device in SmartThings, which must support the
switch
capability - a optional component - used for multi-component devices (see Multi-Component Devices, below)
Each trigger consists of:
- a list of days - days of week like
sun
,tue
, orthursday
or the special daysall
,weekends
orweekdays
- an on time - either a time in HH24:MM format or special times
sunrise
,sunset
,midnight
, ornoon
- an off time - either a time in HH24:MM format or special times
sunrise
,sunset
,midnight
, ornoon
- a variation - either
none
or a specifier like described below
The on time and off time are in the timezone of your location, as
defined in SmartThings. In the YAML, you should always quote times, like
"18:30"
.
The variation controls how much random variation will be placed into the on
and off times. If a variation is configured, each day will be slightly
different. A specifier like - 15 minutes
means that the device group will
turn on or off up to 15 minutes earlier than the given time. Similarly, + 15 minutes
means 15 minutes later, and +/- 15 minutes
means 15 minutes earlier
or later. You can create specifiers using minutes
or hours
.
In the YAML, you should always quote these specifiers with double quotes, like
"+/- 15 minutes"
.
Historically, in the old DTH driver environment, devices that had multiple components (i.e. smart outlets with two receptacles) would result in multiple SmartThings devices that could be named and addressed independently. With the move toward Edge drivers, that is no longer the case.
For instance, the custom DTH for the Zooz ZEN25 outlet used to generate one
device for each receptacle, plus one for the main power control, plus another
one for the USB port. We could name each device individually and address those
devices in the vacation plan simply as Living Room/Lamp Under Window
.
With the new Edge driver, we now get a single device for the ZEN25, but that
device has multiple components (main
, leftOutlet
, rightOutlet
, usb
)
that can be controlled indivdually. Since there is only one device, the
vacation plan needs to address devices like Living Room/Tree Outlet/leftOutlet
.
The best way to figure out what components you have available is by using the SmartThings CLI in conjunction with jq.
In this example, I have a device called Tree Outlet, a ZEN25 that is behind a fake tree in the living room. Assuming the name of the device is unique in your location, you can just do this:
$ smartthings devices --json | jq -r '.[] | select(.label=="Tree Outlet") | .components[].id'
leftOutlet
rightOutlet
usb
main
If the name of the device isn't unique, run smartthings devices
to get a list
of your devices and pick the right one:
$ smartthings devices
┌────┬────────────────────────┬───────────────────────────┬────────┬──────────────────────────────────────┐
│ # │ Label │ Name │ Type │ Device Id │
├────┼────────────────────────┼───────────────────────────┼────────┼──────────────────────────────────────┤
│ 1 │ Tree Outlet │ zooz-zen25-double-plug │ ZWAVE │ c98330b5-xxxx-xxxx-xxxx-972b4372fcde │
└────┴────────────────────────┴───────────────────────────┴────────┴──────────────────────────────────────┘
Grab the device id out of the Device Id column and run a command like this to pull out the components:
$ smartthings devices c98330b5-xxxx-xxxx-xxxx-972b4372fcde --json | jq -r '.components[].id'
leftOutlet
rightOutlet
usb
main
If you don't have jq
installed, you can just save off the JSON and look
through it by hand. Each device has a list of components
, and you are
looking for the id
of the component.
Once you have created your YAML file, you will use it to create a plan in the vacation plan manager.
$ vplan plan create file.yaml
Created plan: my-house
If there are any errors in your YAML file, you will get feedback at this point,
and you can correct your file. If the create operation fails at the server,
you can look in the daemon log (journalctl --user-unit vplan
) to get more
information. The same is true for any other operation you might run via the
command line interface.
Any newly-created plan will be disabled by default. You can enable a plan like this:
$ vplan plan enable my-house
Plan my-house is enabled
Once a plan is enabled, rules will be written immediately into the SmartThings infrastructure, and your plan will be operational.
The plan is implemented underneath by SmartThings rules, and is not dependent on the vplan daemon. So, even if you stop the daemon or shut down your Linux system, the plan will continue to execute. However, there won't be any daily variations in the trigger times, because the daemon is not around to make those changes.
See other plan commands using vplan plan --help
. In particular, you may want
to use the test
command to confirm that your various device groups are
working like you intend, before you enable the plan.