First, one class of solutions for home automation is provided by large for-profit companies. Such solutions, like the
Google Home platform and Alexa, are intuitive to set up and use, but they’re quite rigid in the possibility of
customization — meaning that you’ve only got the integrations that Google or Amazon provide you with, based on the
partnerships they decide to build, you’ve only got to use the user interfaces they provide you with on the devices they
decide to support, you can’t install the platform wherever you like or interact with it in any way outside of what’s
provided by the company, and such decisions also subject to change over time. Additionally, a truly connected house will
generate a lot of data about you (much more than what you generate by browsing the web), and I feel a bit uncomfortable
sharing that data
with [people who don’t seem to bother to share it with anyone else without my consent](https://www.cnbc.com/2019/07/11/google-admits-leaked-private-voice-conversations.html).
Plus, the integrations provided by such platforms often break (see this, this and this, and they’re only a few examples)
. It can be quite annoying if all of a sudden you can no longer control your expensive lights or cameras from your
expensive assistant or smart screen, and the code for controlling them runs on somebody else’s cloud, and that somebody
else just informs you that “they’re working on that”.
Another issue with home automation solutions so far is fragmentation. You’ll easily have to buy 3–4 different bridges,
devices or adapters if you want to control your smart lights, smart buttons, switches or a living room media centre.
Compatibility with existing remotes is also most of the times neglected. Not to mention the number of apps you’ll have
to download — each provided by a different author, each eating up space on your phone, and don’t expect that many
options to make them communicate with each other. Such fragmentation has been indeed one of the core issues I’ve tried
to tackle when building platypush, as I aimed to have only one central entry point, one control panel, one dashboard,
one protocol to control everything, while still providing all the needed flexibility in terms of supported communication
backends and APIs. The need for multiple bridges for home automation also goes away once you provide modules to manage
Bluetooth, Zigbee and Z-Wave, and all you need to interact with your devices is a physical adapter connected to any kind
of computer. The core idea is that, if there is a Python library or API to do what you want to do (or at least
something that can be wrapped in a simple Python logic), then there should also be a plugin to effortlessly integrate
what you want to do into the ecosystem you already have. It’s similar to the solution that Google has later tried to
provide with the [device custom actions](https://developers.google.com/assistant/sdk/guides/library/python/extend/custom-actions), even though the latter is limited to assistant interactions so far, and it’s
currently subject to change because of the [deprecation of the assistant library](https://developers.google.com/assistant/sdk/guides/library/python/).
Another class of solutions for such problems come from open source products like [Home Assistant](https://www.home-assistant.io/).
While Platypush and the Home Assistant share quite a few things — they both started being developed around the same
time, both started out as a bunch of scripts that we developers used to control our own things, and we eventually ended
up gluing together in a larger platform for general use, both are open source and developed in Python, and both aim to
bring the logic for controlling your house inside your house instead of running it on somebody else’s cloud — there are a
couple of reasons why I eventually decided to keep working on my own platform instead of converging my efforts into Home
Assistant.
First, Home Assistant has a strong Raspberry Pi-first approach. The suggested way to get started is to flash the Hass.io
image to an SD card and boot up your RPi. While my solution is heavily tested within the Raspberry Pi ecosystem as well,
it aims to run on any device that comes with a CPU and a Python interpreter. You can easily install it and run it on any
x86/x86_64 architecture too if you want to handle your automation logic on an old laptop, a desktop or any Intel-based
micro-computer. You can easily run it on other single-board computers, such as the Asus Tinkerboard, any BananaPi or
Odroid device. You can even run it on Android if you have an implementation of the Python interpreter installed. You can
even run a stripped-down version on a microcontroller that runs MicroPython. While Home Assistant has tackled its growth
and increasing complexity by narrowing down the devices it supports, and providing pre-compiled OS and Docker images to
reduce the complex process of getting it to run on bare-metal, I've tried to keep Platypush as modular, lightweight and
easy to setup and run as possible. You can run it in a Python virtual environment, in a Docker container, in a virtual
machine or KVM — if you can name it, you can probably do it already. I have even managed to run it on an old Nokia N900,
both on the original Maemo and Arch Linux, and on several Android smartphones and tablets. And, most of all, it has a
very small memory and CPU footprint. Running hotword detection, assistant, web panel, camera, lights, music control and
a few sensors on a small Raspberry Zero is guaranteed to take not more than 5-10% of CPU load and just a few MBs of RAM.
The flexibility of Platypush comes however a slightly steeper learning curve, but it rewards the user with much more
room for customization. You are expected to install it via [pip](https://pypi.org/project/platypush/) or
the [Gitlab](https://git.platypush.tech/platypush/platypush) repo, install the dependencies based on the plugins you
want (although managing per-plugin dependencies is quite easy via `pip`), and manually create or edit a configuration
file. But it provides much, much more flexibility. It can listen for messages on MQTT, HTTP (but you don’t have to run
the webserver if you don’t want to), websocket, TCP socket, Redis, Kafka, Pushbullet — you name it, it has probably got
it already. It allows you to create powerful procedures and event hooks written either in an intuitive YAML-based language
or as drop-in Python scripts. Its original mission is to simplify home automation, but it doesn't stop there: you
can use it to send text messages, read notifications from Android devices, control robots, turn your old box into a fully
capable media center (with support for torrents, YouTube, Kodi, Plex, Chromecast, vlc, subtitles and many other players
and formats)
or a music center (with support for local collections, Spotify, SoundCloud, radios etc.), stream audio from your house,
play raw or sampled sounds from a MIDI interface, monitor access to the file system on a server, run custom actions when
some NFC tag is detected by your reader, read and extract content from RSS feeds and send it to your Kindle, read and
write data to a remote database, send metrics to Grafana, create a custom voice assistant, run and train machine
learning models, and so on — basically, you can do anything that comes
with [one of the hundreds of supported plugin](https://platypush.readthedocs.io/en/latest/).
Another issue I’ve tried to tackle is the developer and power user experience. I wanted to make it easy to use the
automation platform as a library or a general-purpose API, so you can easily invoke a custom logic to turn on the lights
or control the music in any of your custom scripts through something as simple as a get_plugin('light.hue').on() call,
or by sending a simple JSON request over whichever API, queue or socket communication you have set up. I also wanted to
make it easy to create complex custom actions (something like “when I get home, turn on the lights if it’s already dark,
turn on the fan if it’s hot, the thermostat if it’s cold, the dehumidifier if it’s too humid, and play the music you
were listening on your phone”) through native pre-configured action — similar to what is offered by Node-Red but with
more flexibility and ability to access the local context, and less agnostic when it comes to plugins, similar to what is
offered by IFTTT and Microsoft Flow but running in your own network instead of somebody else’s cloud, similar to the
flexibility offered by apps like Tasker and AutoApps, but not limited to your Android device. My goal was also to build
a platform that aims to be completely agnostic about how the messages are exchanged and which specific logic is
contained in the plugins. As long as you’ve got plugins and backends that implement a certain small set of elements,
then you can plug them in.
Another issue I’ve tried to tackle is the developer and power user experience. I wanted to make it easy to use the
automation platform as a library or a general-purpose API, so you can easily invoke a custom logic to turn on the lights
or control the music in any of your custom scripts through something as simple as a `get_plugin('light.hue').on()` call,
or by sending a simple JSON request over whichever API, queue or socket communication you have set up. I also wanted to
make it easy to create complex custom actions (something like _“when I get home, turn on the lights if it’s already dark,
turn on the fan if it’s hot, the thermostat if it’s cold, the dehumidifier if it’s too humid, and play the music I was
listening on my phone”_) through native pre-configured action — similar to what is offered by Node-Red but with
more flexibility and ability to access the local context, and without delegating too much of the integrations logic to
other blocks; similar to what is offered by IFTTT and Microsoft Flow, but running in your own network instead of somebody
else’s cloud; similar to the flexibility offered by apps like Tasker and AutoApps, but not limited to your Android
device.
Finally, extensibility was also a key factor I had in mind. I know how fundamental the contribution of other developers
is if you want your platform to support as many things as possible out there. One of my goals has been to provide
developers with the possibility of building a simple plugin in around 15 lines of Python code, and a UI integration in
around 40 lines of HTML+Javascript code thanks to a consistent API that takes care of all the boilerplate.
Let’s briefly analyze how platypush is designed to better grasp how it can provide more features and flexibility than
most of the platforms I’ve seen so far.
The building blocks
-------------------
There are a couple of connected elements at the foundations of platypush that allow users to build whichever solution
they like:
- **Plugins**: they are arguably the most important component of the platform. A plugin is a Python class that handles a
type of device or service (like lights, music, calendar etc.), and it exposes a set of methods that enable you to
programmatically invoke _actions_ over those devices and services (like turn on, play, get upcoming events etc.).
All plugins implement an abstract `Plugin` class and their configuration is completely transparent to the constructor
arguments of the plugin itself - i.e. you can look at the constructor itself in the source code to understand which
arguments a plugin takes, and you can fill those variables directly in your `config.yaml`. Example:
```yaml
light.hue:
bridge: 192.168.1.100
groups:
- Living Room
- Bathroom
```
- **Backends**: they are threads that run in the background and listen for something to happen (an HTTP request, a
websocket or message queue message, a voice assistant interaction, a new played song or movie…). When it happens, they
will trigger _events_, and other parts of the platform can asynchronously react to those events.
- **Messages**: a message in platypush is just a simple JSON string that comes with a type and a set of arguments. You
have three main types of messages on the platform:
- **Requests**: they are messages used to require a certain plugin action to be executed. The format of the action name
is quite simple (`plugin_name.method_name`), and you can, of course, pass extra arguments to the action. Actions are
mapped one-to-one to methods in the associated plugin class through the `@action` annotation. It means that a request
object is transparent to the organization of the plugin, and such a paradigm enables the user to build flexible
JSON-RPC-like APIs. For example, the `on` action of the `light.hue` plugin accepts lights and groups as optional
parameters. It means that you can easily build a request like this and deliver it to platypush through whichever
backend you prefer (note that `args` are optional in this case):
```json
{
"type":"request",
"action":"light.hue.on",
"args": {
"groups": [
"Living Room",
"Bathroom"
]
}
}
```
If you have the HTTP backend running, for example, you can easily dispatch such a request to it through the available
JSON-RPC execute endpoint (after logging at least once at the control panel at `http://localhost:8008` and creating a