New wiki
parent
9383bb5623
commit
0637685825
18 changed files with 2013 additions and 3312 deletions
883
A-full-configuration-example.md
Normal file
883
A-full-configuration-example.md
Normal file
|
@ -0,0 +1,883 @@
|
|||
# A full configuration example
|
||||
|
||||
* [Identifying the required integrations](#identifying-the-required-integrations)
|
||||
* [Preparing the configuration](#preparing-the-configuration)
|
||||
* [File locations](#file-locations)
|
||||
* [Configuration file](#configuration-file)
|
||||
* [Working directory](#working-directory)
|
||||
* [`backend.http`](#backend.http)
|
||||
* [`db`](#db)
|
||||
* [`mqtt`](#mqtt)
|
||||
* [`assistant.google`](#assistant.google)
|
||||
* [`light.hue`](#light.hue)
|
||||
* [`music.mpd`](#music.mpd)
|
||||
* [`media.jellyfin`](#media.jellyfin)
|
||||
* [`media.vlc`](#media.vlc)
|
||||
* [`serial`](#serial)
|
||||
* [`zigbee.mqtt`](#zigbee.mqtt)
|
||||
* [`camera.ffmpeg`](#tts)
|
||||
* [`tts`](#tts)
|
||||
* [Installing the configured service](#installing-the-configured-service)
|
||||
* [UI installation](#ui-installation)
|
||||
* [API installation](#api-installation)
|
||||
* [platydock](#platydock)
|
||||
* [platyvenv](#platyvenv)
|
||||
* [Manual installation](#manual-installation)
|
||||
|
||||
Now that we have familiarized a bit with the building blocks of the platform,
|
||||
let's get the hands dirty with a real-world configuration to showcase how
|
||||
everything plays together.
|
||||
|
||||
We'll build a configuration that includes the following features:
|
||||
|
||||
- It exposes the Web server to control devices and services via UI or API.
|
||||
|
||||
- It includes a voice assistant - we'll use the `assistant.google` extension in
|
||||
this example because it's probably the quickest to get started, but Platypush
|
||||
provides other voice assistant integrations too if you want alternatives.
|
||||
Note: the `assistant.google` integration won't integrate with another Google
|
||||
Assistant device, but it'll run the assistant _on your own_ device, provided
|
||||
that you have a microphone and a speaker.
|
||||
|
||||
- It integrates with a Philips Hue bridge through the `light.hue` extension -
|
||||
but you can pick any other smart device integration of your liking, e.g.
|
||||
Zigbee, Z-Wave, Bluetooth, SmartThings etc.
|
||||
|
||||
- It integrates with a music server like
|
||||
[mpd](https://mpd.readthedocs.io/en/latest/user.html) or
|
||||
[Mopidy](https://mopidy.com), a media service like
|
||||
[Jellyfin](https://jellyfin.org) and a local media player like
|
||||
[vlc](https://www.videolan.org/vlc), but you can pick any other media
|
||||
integrations you like
|
||||
([Plex](https://docs.platypush.tech/platypush/plugins/media.plex.html),
|
||||
[Kodi](https://docs.platypush.tech/platypush/plugins/media.kodi.html),
|
||||
[Chromecast](https://docs.platypush.tech/platypush/plugins/media.chromecast.html)...).
|
||||
|
||||
- It integrates with an Arduino-compatible device over USB and reads some
|
||||
measurements from a temperature and a humidity sensor connected to it.
|
||||
The Arduino will also have an IR receiver in this example, so you can use
|
||||
a traditional infrared remote to control Platypush (for example, play/pause
|
||||
the music, mute the voice assistant, turn off/on the lights etc.).
|
||||
|
||||
- It integrates with an MQTT broker, it subscribes to a topic where other
|
||||
devices may send their sensor measurements, and stores them to a database.
|
||||
|
||||
- It listens to a custom MQTT topic where another device (for example your
|
||||
phone, through Tasker or through a Platypush service running on Android)
|
||||
sends updates when you enter/exit your home. When a message is received, it
|
||||
will perform a custom routine - for example, turn on the lights, say a welcome
|
||||
message and play the music when you arrive home, and turn off the lights and
|
||||
stop the music when you leave home.
|
||||
|
||||
- It integrates with [zigbee2mqtt](https://www.zigbee2mqtt.io/) to control the
|
||||
Zigbee devices connected to a bridge - usually in the form of a Zigbee USB
|
||||
adapter.
|
||||
|
||||
- It integrates with a connected camera (like a USB camera, or a PiCamera if
|
||||
you're using a RaspberryPi-like device) and provides a way to access the
|
||||
stream over HTTP and programmatically control the capture process.
|
||||
|
||||
- It implements simple voice commands to control the lights and the music
|
||||
playback.
|
||||
|
||||
- It performs a periodic backup of the application's configuration and working
|
||||
directories, and uploads them to a remote server via scp.
|
||||
|
||||
## Identifying the required integrations
|
||||
|
||||
The first step is to identify the required integrations from [the documentation
|
||||
page](https://docs.platypush.tech/). In the example above, we'll need:
|
||||
|
||||
- [`backend.http`](https://docs.platypush.tech/platypush/backend/http.html): the
|
||||
default Web server, which exposes the RPC API, the UI, several Websocket
|
||||
routes, media and camera services, and more.
|
||||
|
||||
- [`db`](https://docs.platypush.tech/platypush/plugins/db.html): used to perform
|
||||
custom operations with databases (enabled by default).
|
||||
|
||||
- [`mqtt`](https://docs.platypush.tech/platypush/plugins/mqtt.html): used to
|
||||
publish and subscribe to topics on an MQTT broker.
|
||||
|
||||
- [`assistant.google`](https://docs.platypush.tech/platypush/plugins/assistant.google.html):
|
||||
the Google Assistant integration.
|
||||
|
||||
- [`light.hue`](https://docs.platypush.tech/platypush/plugins/light.hue.html):
|
||||
to integrate with a Philips Hue bridge.
|
||||
|
||||
- [`music.mpd`](https://docs.platypush.tech/platypush/plugins/music.mpd.html):
|
||||
the integration with MPD/Mopidy.
|
||||
|
||||
- [`media.jellyfin`](https://docs.platypush.tech/platypush/plugins/media.jellyfin.html):
|
||||
the integration with Jellyfin.
|
||||
|
||||
- [`media.vlc`](https://docs.platypush.tech/platypush/plugins/media.vlc.html):
|
||||
the integration with VLC.
|
||||
|
||||
- [`serial`](https://docs.platypush.tech/platypush/plugins/serial.html): a
|
||||
plugin that allows you to easily interact with Arduino-compatible devices
|
||||
connected to a USB/serial interface. You can also choose the
|
||||
[`arduino`](https://docs.platypush.tech/platypush/plugins/arduino.html) plugin
|
||||
if you don't want to write the code for the microprocessor yourself - the
|
||||
Arduino integration works with micro-controllers flashed with the
|
||||
[Firmata](https://www.arduino.cc/reference/en/libraries/firmata/) firmware, or
|
||||
with a compatible firmware, but it offers slightly less flexibility than a
|
||||
firmware customized for your specific hardware.
|
||||
|
||||
- [`zigbee.mqtt`](https://docs.platypush.tech/platypush/plugins/zigbee.mqtt.html):
|
||||
used to interact with Zigbee devices through a zigbee2mqtt bridge, which
|
||||
bridges raw Zigbee events to an MQTT broker.
|
||||
|
||||
- [`camera.ffmpeg`](https://docs.platypush.tech/platypush/plugins/camera.ffmpeg.html):
|
||||
used to interact with a generic camera using directly
|
||||
[`ffmpeg`](https://github.com/FFmpeg/FFmpeg). Note that
|
||||
[`camera.gstreamer`](https://docs.platypush.tech/platypush/plugins/camera.ffmpeg.html)
|
||||
is also available if you want a GStreamer interface instead.
|
||||
|
||||
- [`tts`](https://docs.platypush.tech/platypush/plugins/tts.html), or a
|
||||
compatible text-to-speech plugin (other available options:
|
||||
[`tts.google`](https://docs.platypush.tech/platypush/plugins/tts.google.html)
|
||||
and
|
||||
[`tts.mimic3`](https://docs.platypush.tech/platypush/plugins/tts.mimic3.html)):
|
||||
to deliver our custom "welcome home" message through the speakers.
|
||||
|
||||
- [`ssh`](https://docs.platypush.tech/platypush/plugins/ssh.html): used to
|
||||
expose SSH functionalities - including remote command execution and file copy.
|
||||
|
||||
Note: this is only a demo of what it is possible to do through this application,
|
||||
not an exhaustive list of features, nor a mandatory configuration - feel free to
|
||||
skip the sections that don't apply to your use-case.
|
||||
|
||||
## Preparing the configuration
|
||||
|
||||
### File locations
|
||||
|
||||
#### Configuration file
|
||||
|
||||
The configuration file will be in one the following locations:
|
||||
|
||||
1. `$XDG_CONFIG_HOME/platypush/config.yaml` if `XDG_CONFIG_HOME` is set.
|
||||
2. `~/.config/platypush/config.yaml` otherwise, if you're running the
|
||||
application as a non-privileged user.
|
||||
3. `/etc/platypush/config.yaml` if you're running the application as a
|
||||
privileged user, or you installed it through the system package manager, or
|
||||
through a Docker image generated via `platydock`.
|
||||
4. A path specified through the `-c/--config` startup option.
|
||||
|
||||
Your configuration file can also include fragments from other configuration
|
||||
files through the `include` directive, which is useful if you have particularly
|
||||
large configuration files that you want to split onto multiple files, or
|
||||
configuration folders shared among several installations of the service (like in
|
||||
a shared dotfiles repo):
|
||||
|
||||
```yaml
|
||||
include:
|
||||
# Relative paths are relative to the `config.yaml` location, or relative to
|
||||
# the current configuration file if the `include` directive is used in a child
|
||||
# file
|
||||
- assistant.yaml
|
||||
- audio.yaml
|
||||
- db.yaml
|
||||
- lights.yaml
|
||||
- sensors.yaml
|
||||
- zigbee.yaml
|
||||
# ...
|
||||
```
|
||||
|
||||
Note that, after the application is first started, a new `scripts` directory
|
||||
will also be created under the configuration file's folder. This directory can
|
||||
be used to store custom hooks and procedures in the form of small Python
|
||||
snippets - we'll see them later.
|
||||
|
||||
#### Working directory
|
||||
|
||||
The working directory of the service will be one of the following:
|
||||
|
||||
1. `$XDG_DATA_HOME/platypush`, if `XDG_DATA_HOME` is set.
|
||||
2. `~/.local/share/platypush` otherwise, if you're running the application as a
|
||||
non-privileged user.
|
||||
3. `/var/lib/platypush`, if you're running the application as a privileged user
|
||||
or within a Docker container generated via `platydock`.
|
||||
|
||||
This is where the main database file will be stored, and where the integrations
|
||||
will store their files.
|
||||
|
||||
### `backend.http`
|
||||
|
||||
This is usually straightforward for basic use-cases:
|
||||
|
||||
```yaml
|
||||
backend.http:
|
||||
# port: 8008
|
||||
```
|
||||
|
||||
Note that the HTTP backend is enabled by default if no configuration file is
|
||||
specified.
|
||||
|
||||
### `db`
|
||||
|
||||
The `db` plugin is enabled by default, and it's used for general purpose
|
||||
interactions with databases supported by SQLAlchemy.
|
||||
|
||||
If no database is specified in the API calls, nor is specified in the
|
||||
configuration, then the default application SQLite database will be used -
|
||||
stored under `<WORKDIR>/main.db`. In this example, we want to use Platypush as a
|
||||
central node to store on an external database data points published over an MQTT
|
||||
topic from other devices, so we may want to configure the `db` integration to
|
||||
use a different default database for external database calls:
|
||||
|
||||
```yaml
|
||||
db:
|
||||
# SQLAlchemy connection string. In this case, we connect to a Postgres
|
||||
# database through the pg8000 driver
|
||||
engine: postgresql+pg8000://user:pass@host/dbname
|
||||
```
|
||||
|
||||
Note that SQLite comes with built-in support in SQLAlchemy, but other databases
|
||||
need external drivers. If, like in the case above, you opt to interact with a
|
||||
Postgres database through the `pg8000` driver, then you'll have to install the
|
||||
driver on your host machine / virtual environment / Docker image as well - for
|
||||
example, through `pip install pg8000`.
|
||||
|
||||
### `mqtt`
|
||||
|
||||
The configuration of the MQTT plugin will look something like this:
|
||||
|
||||
```yaml
|
||||
mqtt:
|
||||
host: mqtt-host
|
||||
port: 1883
|
||||
username: user
|
||||
password: pass
|
||||
# Topics that the plugin should subscribe to when started
|
||||
topics:
|
||||
- sensors
|
||||
```
|
||||
|
||||
### `assistant.google`
|
||||
|
||||
A note before starting: the `assistant.google` integration is based on the
|
||||
[`google-assistant-library`](https://pypi.org/project/google-assistant-library/),
|
||||
which has been officially **deprecated** by Google.
|
||||
|
||||
Unfortunately, Google hasn't provided any alternatives to run their assistant on
|
||||
other devices, and even their assistant actions SDK has gradually lost features.
|
||||
However, the current version of the library still works fine on x86_64, armv7l
|
||||
and aarch64 architectures, but it requires a bit of tweaking of the dependencies
|
||||
on recent versions of Python, as it depends on some libraries that are by now
|
||||
deprecated. And it's not assured that it'll keep working forever either - Google
|
||||
may just introduced a breaking change on the API layer, and if a new
|
||||
architecture comes out the library most likely won't be built for it. However,
|
||||
given how many Assistant-compatible devices are out there (some of them even
|
||||
several years old), I feel that it's unlikely that Google will introduce
|
||||
breaking changes any time soon - the library has already been deprecated for
|
||||
several years, but it still works fine on all of my devices.
|
||||
|
||||
The first step is to create a new Google development project and follow [these
|
||||
instructions](https://developers.google.com/assistant/sdk/guides/library/python/embed/install-sample#generate_credentials)
|
||||
on how to generate a credentials file.
|
||||
|
||||
Then download the credentials file - if the location isn't specified in the
|
||||
configuration, the plugin will look for it either under
|
||||
`~/.config/google-oauthlib-tool/credentials.json` or
|
||||
`<WORKDIR>/credentials/google/assistant.json`.
|
||||
|
||||
Finally, add the configuration to Platypush:
|
||||
|
||||
```yaml
|
||||
assistant.google:
|
||||
# The device model ID. In theory it should be registered through the
|
||||
# developers console, but `Platypush` (default value) should work just fine.
|
||||
device_model_id: Platypush
|
||||
# The sound to play when a conversation starts.
|
||||
conversation_start_sound: /path/to/sound.mp3
|
||||
# Override the default credentials file locations
|
||||
credentials_file: /path/to/credentials.json
|
||||
```
|
||||
|
||||
### `light.hue`
|
||||
|
||||
The `light.hue` configuration would like this:
|
||||
|
||||
```yaml
|
||||
light.hue:
|
||||
bridge: bridge-ip-or-hostname
|
||||
```
|
||||
|
||||
Note that, when the application is first started after enabling the `light.hue`
|
||||
plugin, a pairing process with the bridge is required. This is usually done by
|
||||
pressing the _Pair_ button on the Hue bridge within 30-60 seconds after starting
|
||||
the client. After pairing the first time, no further manual pairing should be
|
||||
required.
|
||||
|
||||
### `music.mpd`
|
||||
|
||||
[Mopidy](https://mopidy.com) is the best supported music player for Platypush,
|
||||
but the `music.mpd` integration should work also with a vanilla MPD
|
||||
installation.
|
||||
|
||||
We love Mopidy because it comes with dozens of integrations (local files,
|
||||
Spotify, Tidal, SoundCloud, TuneIn, Bandcamp, YouTube...) and it supports dozens
|
||||
of clients as well - from command-line MPD clients like
|
||||
[`mpc`](https://github.com/MusicPlayerDaemon/mpc), to ncurses clients like
|
||||
[`ncmpcpp`](https://github.com/ncmpcpp/ncmpcpp), to full-featured Web interfaces
|
||||
like [Iris](https://mopidy.com/ext/iris/), to mobile apps like
|
||||
[M.A.L.P.](https://www.appbrain.com/app/m-a-l-p-mpd-client/org.gateshipone.malp),
|
||||
and thanks to Platypush you can also build automation routines around your music
|
||||
experience.
|
||||
|
||||
The main difference between MPD and Mopidy is that MPD is a music server thought
|
||||
to mainly expose local audio files, while Mopidy adds a whole system of
|
||||
extensions to that paradigm.
|
||||
|
||||
Note that, as of Mopidy 3.0, the MPD extensions has been decoupled from the core
|
||||
installation, and you'll have to install the
|
||||
[`mopidy-mpd`](https://mopidy.com/ext/mpd/) package separately.
|
||||
|
||||
Once you have a running MPD/Mopidy installation, you can easily configure the
|
||||
Platypush plugin:
|
||||
|
||||
```yaml
|
||||
music.mpd:
|
||||
host: localhost # MPD/Mopidy server
|
||||
port: 6600 # Listen port (default: 6600)
|
||||
```
|
||||
|
||||
### `media.jellyfin`
|
||||
|
||||
Jellyfin is a general-purpose media server that you can use to host your music,
|
||||
movies, videos etc., and consume/stream them on any client.
|
||||
|
||||
If you have a Jellyfin server to serve your media, then you can the Platypush
|
||||
integration to build automation routines around it, or programmatically play
|
||||
content on other device, or control playback:
|
||||
|
||||
```yaml
|
||||
media.jellyfin:
|
||||
# Jellyfin instance base URL
|
||||
server: https://media.example.com
|
||||
# You can get an API key from
|
||||
# https://media.example.com/web/index.html#!/apikeys.html
|
||||
api_key: secret
|
||||
```
|
||||
|
||||
Note that integrations with
|
||||
[Kodi](https://docs.platypush.tech/platypush/plugins/media.kodi.html) and
|
||||
[Plex](https://docs.platypush.tech/platypush/plugins/media.plex.html) are also
|
||||
available. However, since none of the Platypush developers currently uses Plex,
|
||||
the Plex integration hasn't been tested in a while.
|
||||
|
||||
There is also a
|
||||
[Chromecast](https://docs.platypush.tech/platypush/plugins/media.chromecast.html),
|
||||
integration that allows you to programmatically (or via UI) cast any content to
|
||||
a Chromecast-compatible device, but we won't cover it in this example (it should
|
||||
be quite straightforward to configure and enable though).
|
||||
|
||||
### `media.vlc`
|
||||
|
||||
If you have VLC installed on your system, then you can enable the Platypush
|
||||
integration as well. The VLC integration (but the same interface is also exposed
|
||||
through MPlayer, MPV, omxplayer, barebone gstreamer etc.) allows you to turn
|
||||
your device into a general-purpose media player that can be controlled remotely.
|
||||
|
||||
Here's an example configuration of the `media.vlc` integration, but the same
|
||||
interface also applies all the other provided media integrations (just replace
|
||||
e.g. `media.vlc` with `media.mpv`, for example):
|
||||
|
||||
```yaml
|
||||
media.vlc:
|
||||
# Volume level, between 0 and 100
|
||||
volume: 50
|
||||
# Where to store downloaded files
|
||||
download_dir: ~/Downloads
|
||||
# Play videos in fullscreen by default
|
||||
fullscreen: True
|
||||
# If youtube-dl or any compatible application is installed, play requested
|
||||
# videos in this format by default. Default: `best`.
|
||||
# youtube_format: 'mp4[height<=?480]'
|
||||
# Extra arguments to pass to the executable. --play-and-exit may be a good
|
||||
# idea with VLC, so the player terminates upon stop instead of lingering in
|
||||
# the background.
|
||||
args:
|
||||
- --play-and-exit
|
||||
# List of directories to search for media files. The media files in these
|
||||
# folders can be searched through the `media.<player>.search` command, or
|
||||
# through the Web interface.
|
||||
media_dirs:
|
||||
- /mnt/hd/media/movies
|
||||
- /mnt/hd/media/series
|
||||
- /mnt/hd/media/videos
|
||||
- ~/Downloads
|
||||
```
|
||||
|
||||
If you specify a list of `media_dirs`, then those directories will be scanned
|
||||
for media files and stored in Platypush' database. That allows you to use
|
||||
Platypush as its own media server with a built-in client - you can basically use
|
||||
the Web interface to search your local collection, or results from
|
||||
Jellyfin/Plex/YouTube/Kodi, and play it on your Platypush device or on any other
|
||||
compatible player.
|
||||
|
||||
### `serial`
|
||||
|
||||
This is where we can start to get our hands a bit dirty with some code.
|
||||
|
||||
The most versatile way that Platypush provides to interact with external
|
||||
microcontrollers or programmable peripherals is through the
|
||||
[`serial`](https://docs.platypush.tech/platypush/plugins/serial.html)
|
||||
integration.
|
||||
|
||||
`serial` reads data on the wire from a configured device and it expects to
|
||||
receive data in JSON format like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"temperature": 25.0,
|
||||
"humidity": 15.0,
|
||||
"ir": "0xffff"
|
||||
}
|
||||
```
|
||||
|
||||
In the example above, we may have an Arduino-compatible or ESP-compatible device
|
||||
connected over USB, with a temperature/humidity sensor (like one from the
|
||||
[DHT11/DHT22](https://learn.adafruit.com/dht/overview) line) and any infrared
|
||||
receiver connected to it.
|
||||
|
||||
Let's say that you have an Arduino with a DHT temperature+humidity sensor
|
||||
connected to the Arduino on the PIN number 2:
|
||||
|
||||

|
||||
|
||||
And you have a generic infrared receiver connected to the PIN number 7:
|
||||
|
||||

|
||||
|
||||
You can then write some microcontroller code like this to periodically check the
|
||||
sensor for new values and send them down the wire in JSON format:
|
||||
|
||||
```arduino
|
||||
#include <Arduino.h>
|
||||
// Requires the ArduinoJson library: https://arduinojson.org/
|
||||
#include <ArduinoJson.h>
|
||||
// Requires the IRremote library for infrared decoding: https://www.arduino.cc/reference/en/libraries/irremote/
|
||||
#include <IRremote.h>
|
||||
#include <Time.h>
|
||||
#include <Wire.h>
|
||||
// Requires the dht-sensor-library: https://www.arduino.cc/reference/en/libraries/dht-sensor-library/
|
||||
#include <dht.h>
|
||||
|
||||
// Custom values to tell when we haven't got any value
|
||||
#define NO_IR_VALUE 0
|
||||
#define NO_SENSOR_VALUE DHTLIB_INVALID_VALUE
|
||||
// The PIN where the DHT sensor is connected
|
||||
#define DHT11_PIN (2)
|
||||
// The PIN where the IR sensor is connected
|
||||
#define IR_PIN (7)
|
||||
|
||||
dht DHT;
|
||||
IRrecv irRecv(IR_PIN);
|
||||
decode_results ir_results;
|
||||
|
||||
float last_temp_value = NO_IR_VALUE;
|
||||
float last_humidity_value = NO_SENSOR_VALUE;
|
||||
unsigned long last_ir_value = NO_SENSOR_VALUE;
|
||||
|
||||
void setup() {
|
||||
// Change this line if you specified a different baud rate when flashing
|
||||
// your firmware
|
||||
Serial.begin(9600);
|
||||
// Wait for the Serial interface to be available
|
||||
while (!Serial) delay(10);
|
||||
// Prepares to receive data from the infrared receiver
|
||||
irRecv.enableIRIn();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
StaticJsonDocument<500> output;
|
||||
bool has_changes = false;
|
||||
|
||||
// Read temperature/humidity data
|
||||
DHT.read11(DHT11_PIN);
|
||||
float temp = DHT.temperature;
|
||||
float humidity = DHT.humidity;
|
||||
|
||||
if (temp != DHTLIB_INVALID_VALUE && temp != last_temp_value) {
|
||||
doc["temperature"] = temp;
|
||||
has_changes = true;
|
||||
}
|
||||
|
||||
if (humidity != DHTLIB_INVALID_VALUE && humidity != last_humidity_value) {
|
||||
doc["humidity"] = temp;
|
||||
has_changes = true;
|
||||
}
|
||||
|
||||
// Read IR data
|
||||
if (irRecv.decode(&ir_results)) {
|
||||
unsigned long value = ir_results.value;
|
||||
if (value != NO_IR_VALUE && value != last_ir_value) {
|
||||
doc["ir"] = String(value, HEX);
|
||||
has_changes = true;
|
||||
}
|
||||
|
||||
last_ir_value = value;
|
||||
irRecv.resume();
|
||||
} else {
|
||||
if (last_ir_value != NO_IR_VALUE) {
|
||||
doc["ir"] = String(NO_IR_VALUE, HEX);
|
||||
has_changes = true;
|
||||
}
|
||||
|
||||
last_ir_value = NO_IR_VALUE;
|
||||
}
|
||||
|
||||
if (has_changes) {
|
||||
// If we have some new data, then push it down the wire
|
||||
serializeJson(doc, Serial);
|
||||
|
||||
// If we have received an infrared event, then wait half a second before
|
||||
// resuming - that's because the infrared signal may be sent multiple times,
|
||||
// or spurious signals may be received in the transition between the remote
|
||||
// key up and key down
|
||||
if (last_ir_value != NO_IR_VALUE) {
|
||||
delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
```
|
||||
|
||||
Compile the project, flash it to your device from the Arduino IDE or
|
||||
command-line, connect it to your machine, and run a serial monitor to check that
|
||||
it works. For example:
|
||||
|
||||
```bash
|
||||
picocom /dev/ttyUSB0 -b9600
|
||||
```
|
||||
|
||||
Point a remote at it for example and press a button. You should receive a JSON
|
||||
message on the serial interface that the Platypush service can listen to, and
|
||||
where you can hook your custom logic.
|
||||
|
||||
Note that in this example we've taken into consideration a traditional Arduino
|
||||
device with a custom firmware written in C. This isn't the only available option
|
||||
that Platypush provides to interact with microcontrollers. You also have:
|
||||
|
||||
- The
|
||||
[`arduino`](https://docs.platypush.tech/platypush/plugins/arduino.html)
|
||||
specific integration, which interacts with devices flashed with the Firmata
|
||||
firmware or compatible with its protocol. While it takes away most of the
|
||||
hassle of having to write custom code for your microcontroller, it provides a
|
||||
bit less flexibility - for example, it's hard to get it to run out of the box
|
||||
with devices that require specific libraries to work (like `IRremote` in our
|
||||
case).
|
||||
|
||||
- The
|
||||
[`esp`](https://docs.platypush.tech/platypush/plugins/esp.html) plugin, which
|
||||
specifically interacts with ESP-compatible devices over Wi-Fi.
|
||||
|
||||
- The
|
||||
[`sensor.mcp3008`](https://docs.platypush.tech/platypush/plugins/sensor.mcp3008.html),
|
||||
if you want to go more minimal and you only need an analog->digital converter
|
||||
for your sensors connected to e.g. your RaspberryPi.
|
||||
|
||||
Also, note that, while the `serial` plugin requires you to write your own code
|
||||
for the microcontroller, it's also basically language-agnostic and
|
||||
device-agnostic when it comes to the microcontroller on the other side. It can
|
||||
be an Arduino with code written in C, an ESP microcontroller with a Node.js
|
||||
interface, or a RaspberryPi Pico with MicroPython code. It doesn't really
|
||||
matter: as long as it pushes JSON key-value dictionaries down the wire,
|
||||
Platypush should be able to parse all of its messages and generate the
|
||||
appropriate events that you can subscribe to.
|
||||
|
||||
Once your device is ready to produce JSON messages on the wire, you can
|
||||
configure the Platypush integration:
|
||||
|
||||
```yaml
|
||||
serial:
|
||||
# The path to the USB interface with e.g. an Arduino or ESP microcontroller
|
||||
# connected.
|
||||
# A way to get a deterministic path name on Linux, instead of
|
||||
# `/dev/ttyUSB<n>`, can be the following:
|
||||
#
|
||||
# - Get the vendor and product ID of your device via e.g. `lsusb`. For
|
||||
# example, for an Arduino-compatible microcontroller:
|
||||
#
|
||||
# Bus 001 Device 008: ID 1a86:7523 QinHeng Electronics CH340 serial converter
|
||||
#
|
||||
# - In the case above, `1a86` is the vendor ID and `7523` is the product
|
||||
# ID. Create a new udev rule for it, so every time the device is
|
||||
# connected it will also be symlinked to e.g. `/dev/arduino`:
|
||||
#
|
||||
# echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="arduino"' | \
|
||||
# sudo tee /etc/udev/rules.d/98-usb-serial.rules
|
||||
device: /dev/ttyUSB0
|
||||
# How often the interface should be polled for updates, in seconds
|
||||
poll_interval: 1
|
||||
# The tolerance argument can be used to tune when you want to be notified
|
||||
# of data changes through `SensorDataChangeEvent` events. In the case
|
||||
# below, if the microcontroller sends two consecutive temperature reads,
|
||||
# one for 22.0 and one for 22.2, then only one `SensorDataChangeEvent` will
|
||||
# be triggered (for the first read), since the absolute value of the
|
||||
# difference between the two events is less than the configured tolerance.
|
||||
# However, if the device sends two temperature reads, one for 22.0 and one
|
||||
# for 22.7, then two `SensorDataChangeEvent` events will be triggered.
|
||||
# The tolerance for all the metrics is set to a value close to zero by
|
||||
# default - i.e. any read, unless it's exactly the same as the previous
|
||||
# one, will trigger a new event.
|
||||
tolerance:
|
||||
temperature: 0.5
|
||||
humidity: 0.75
|
||||
luminosity: 5
|
||||
|
||||
# If a threshold is defined for a sensor, and the value of that sensor goes
|
||||
# below/above that temperature between two reads, then a
|
||||
# `SensorDataBelowThresholdEvent` or a `SensorDataAboveThresholdEvent` will
|
||||
# be triggered respectively.
|
||||
thresholds:
|
||||
temperature: 25.0
|
||||
```
|
||||
|
||||
Note that the same interface/configuration of the `serial` plugin applies to all
|
||||
plugins that implement support for sensors.
|
||||
|
||||
### `zigbee.mqtt`
|
||||
|
||||
[`zigbee2mqtt`](https://www.zigbee2mqtt.io/) is a popular DIY framework for
|
||||
running your own Zigbee bridge. You can connect any Hue-compatible light or
|
||||
sensor to it, as well as most of the e.g. modern Ikea bulbs and any electronic
|
||||
appliance that communicates over Zigbee.
|
||||
|
||||
You can flash a zigbee2mqtt-compatible firmware on a variety of USB dongles
|
||||
following the instructions on the project's website or on the [plugin
|
||||
documentation
|
||||
page](https://docs.platypush.tech/platypush/plugins/zigbee.mqtt.html). Then you
|
||||
can pull a zigbee2mqtt image and configure it to connect to an MQTT broker.
|
||||
|
||||
The next step is to enable the `zigbee.mqtt` integration in your configuration:
|
||||
|
||||
```yaml
|
||||
zigbee.mqtt:
|
||||
# Host of the MQTT broker
|
||||
host: my-mqtt-broker
|
||||
# Listen port of the MQTT broker
|
||||
port: 1883
|
||||
# Base topic, as specified in `<zigbee2mqtt_dir>/data/configuration.yaml`
|
||||
topic_prefix: zigbee2mqtt
|
||||
```
|
||||
|
||||
You should now be ready to pair and control Zigbee devices on your bridge
|
||||
through Platypush.
|
||||
|
||||
### `camera.ffmpeg`
|
||||
|
||||
[`camera.ffmpeg`](https://docs.platypush.tech/platypush/plugins/camera.ffmpeg.html)
|
||||
is the most extensively tested way of integrating with hardware cameras. It
|
||||
supports basically any camera that speaks the v4l2 protocol and a variety of
|
||||
other ffmpeg-supported protocols.
|
||||
|
||||
[`camera.gstreamer`](https://docs.platypush.tech/platypush/plugins/camera.gstreamer.html)
|
||||
is also available if you want to use a
|
||||
[GStreamer](https://gstreamer.freedesktop.org/) backend,
|
||||
[`camera.cv`](https://docs.platypush.tech/platypush/plugins/camera.cv.html) if
|
||||
you want to leverage the [OpenCV](https://opencv.org/) framework (usually
|
||||
because you want to run some computer vision transformation on your images or
|
||||
feed), and a deprecated
|
||||
[`camera.pi`](https://docs.platypush.tech/platypush/plugins/camera.pi.html)
|
||||
integration for the (now deprecated) PiCamera backend (note that PiCameras
|
||||
are now v4l2-compatible, so they should work fine also using the FFmpeg or
|
||||
GStreamer integrations).
|
||||
|
||||
Regardless of which integration you pick, all camera plugins share the same
|
||||
configuration options/interface:
|
||||
|
||||
```yaml
|
||||
camera.ffmpeg:
|
||||
# Default video device to use
|
||||
device: /dev/video0
|
||||
# Default resolution
|
||||
resolution:
|
||||
- 640
|
||||
- 480
|
||||
# The directory that will be used to store captured frames/images
|
||||
frames_dir: ~/Camera/Photos
|
||||
# Default image scaling factors (default: 1, no scaling)
|
||||
scale_x: 1.5
|
||||
scale_y: 1.5
|
||||
# Default rotation of the image, in degrees (default: 0, no rotation)
|
||||
rotate: 90
|
||||
# Grayscale mode (default: False):
|
||||
grayscale: false
|
||||
# Default frames per second (default: 16)
|
||||
fps: 16
|
||||
# Whether to flip the image along the horizontal axis (default: False)
|
||||
horizontal_flip: false
|
||||
# Whether to flip the image along the horizontal axis (default: False)
|
||||
vertical_flip: false
|
||||
```
|
||||
|
||||
### `tts`
|
||||
|
||||
Platypush currently supports three text-to-speech integrations:
|
||||
|
||||
- [tts](https://docs.platypush.tech/platypush/plugins/tts.html): it's the
|
||||
default TTS plugin. It leverages Google Translate's unofficial frontend API to
|
||||
render text to speech. This means that it requires no authentication nor extra
|
||||
configuration, but the quality of the rendered speech and the flexibility of
|
||||
the API may be a bit inferior to that that you would get through the
|
||||
[tts.google](https://docs.platypush.tech/platypush/plugins/tts.google.html),
|
||||
which leverages Google's official text-to-speech API (the `tts` plugin should
|
||||
work just fine for simple interactions though). A full open-source alternative
|
||||
is
|
||||
[tts.mimic3](https://docs.platypush.tech/platypush/plugins/tts.mimic3.html),
|
||||
which leverages the open-source [Mimic 3 TTS
|
||||
engine](https://mycroft.ai/mimic-3/), part of the (now defunct) Mycroft open
|
||||
voice suite.
|
||||
|
||||
All these plugins share the same base configuration, and some may have
|
||||
integration-specific extra options (like voice or gender):
|
||||
|
||||
```yaml
|
||||
tts:
|
||||
language: en-US
|
||||
volume: 100
|
||||
```
|
||||
|
||||
## Installing the configured service
|
||||
|
||||
Once we're happy with our configuration, we can proceed with installing the
|
||||
service with all of the extra dependencies required by the configured
|
||||
extensions.
|
||||
|
||||
You can consult the [Installation](Installation) and [Installing
|
||||
extensions](#Installing-extensions) wiki pages for more details about the
|
||||
supported installation methods. This section assumes that you have already
|
||||
installed the core service with its base dependencies.
|
||||
|
||||
Let's recap some of the supported ways, now that we have a full configuration.
|
||||
|
||||
### UI installation
|
||||
|
||||
This is a viable, user-friendly route if you have installed the base service
|
||||
(via `pip`, package manager or vanilla Docker image) and you want to install
|
||||
your dependencies in the same environment through the Web interface. Note that
|
||||
this method requires the `backend.http` integration to be enabled (and by
|
||||
default it is).
|
||||
|
||||
1. Start Platypush via `platypush [--start-redis] [...]`. NOTE: do not start
|
||||
Platypush from your new configuration file yet. If some of the configured
|
||||
extensions have missing dependencies, the service may fail to start too.
|
||||
|
||||
2. Head to the Web panel, by default at `http://ip:8008/`, and register/login.
|
||||
|
||||
3. Click on _Extensions_ at the bottom of the main menu. The page may take a
|
||||
while to load the first time or after an update, as it has to scan the source
|
||||
code for extensions metadata, but it's much faster once the extensions have
|
||||
been cached.
|
||||
|
||||
4. Select the extensions that you want to install, and install their
|
||||
dependencies through the _Install_ tab.
|
||||
|
||||

|
||||
|
||||
When you are done installing all the extensions, you can proceed with restarting
|
||||
the application.
|
||||
|
||||
### API installation
|
||||
|
||||
Alternatively, you can install the extra dependencies in your environment
|
||||
through the Web API.
|
||||
|
||||
Get an authentication token (from the UI, _Settings_ ➡️ _Tokens_) and then use
|
||||
the
|
||||
[`application.install`](https://docs.platypush.tech/platypush/plugins/application.html#platypush.plugins.application.ApplicationPlugin.install)
|
||||
API to install the extra dependencies:
|
||||
|
||||
```bash
|
||||
# Repeat for all the desired integrations
|
||||
curl -XPOST -H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer <TOKEN>" \
|
||||
-d '
|
||||
{
|
||||
"type": "request",
|
||||
"action": "application.install",
|
||||
"args": {
|
||||
"extension": "mqtt"
|
||||
}
|
||||
}' \
|
||||
'http://my-host:8008/execute'
|
||||
```
|
||||
|
||||
You can also use the API through the Python REPL itself:
|
||||
|
||||
```python
|
||||
>>> from platypush import run
|
||||
>>> run('application.install', 'mqtt')
|
||||
```
|
||||
|
||||
### platydock
|
||||
|
||||
It's quite easy to build a Platypush Docker image given a configuration file
|
||||
through the `platydock` command:
|
||||
|
||||
```bash
|
||||
# Available base images: -i {alpine,debian,fedora,ubuntu}
|
||||
platydock -c /path/to/config.yaml -d device-name -t platypush
|
||||
```
|
||||
|
||||
This command will build a Platypush base image, infer the extra dependencies
|
||||
from the extensions that you specified in your configuration file, and install
|
||||
everything that is required to start your service.
|
||||
|
||||
If instead of building the container you want to just generate a `Dockerfile`
|
||||
for your installation, which you can customize to your liking, you can use the
|
||||
`--print` option of `platydock`.
|
||||
|
||||
You can then start a container via:
|
||||
|
||||
```bash
|
||||
docker run -it --rm
|
||||
--name platypush \
|
||||
-v /path/to/your/confdir:/etc/platypush \
|
||||
-v /path/to/your/workdir:/var/lib/platypush \
|
||||
-p 8008:8008 \
|
||||
platypush
|
||||
```
|
||||
|
||||
Note that you may need to expose extra devices to the container via `--device`
|
||||
option if you configured extensions that require that access. For instance, if
|
||||
you enabled a camera plugin your container may need to be started with `--device
|
||||
/dev/video0`, or if you enabled a voice assistant, text-to-speech or
|
||||
sound-dependent plugin then you may have to expose the sound devices to the
|
||||
container via `--device /dev/snd`.
|
||||
|
||||
### platyvenv
|
||||
|
||||
Another option is to create a virtual environment for Platypush, with all the
|
||||
required dependencies automatically installed.
|
||||
|
||||
If you already installed the base service, then you can leverage the `platyvenv`
|
||||
utility for it, which supports the same base options as `platydock`:
|
||||
|
||||
```bash
|
||||
platyvenv -c /path/to/config.yaml -d device-name -o venv-output-dir
|
||||
```
|
||||
|
||||
This command will install a virtual environment under `venv-output-dir` with all
|
||||
the dependencies required by your configured extensions.
|
||||
|
||||
You can then start it with:
|
||||
|
||||
```bash
|
||||
source VENV_PATH/bin/activate
|
||||
platypush -c /path/to/config.yaml [--start-redis] [...opts]
|
||||
```
|
||||
|
||||
### Manual installation
|
||||
|
||||
Finally, you have the manual way.
|
||||
|
||||
Check out the documentation page of each of your extensions on [the main
|
||||
documentation](https://docs.platypush.tech), scroll to the dependencies section,
|
||||
and run the commands one by one.
|
214
APIs.md
Normal file
214
APIs.md
Normal file
|
@ -0,0 +1,214 @@
|
|||
# APIs
|
||||
|
||||
## HTTP API
|
||||
|
||||
Actions and procedures can also be called using the JSON-RPC API exposed by
|
||||
Platypush.
|
||||
|
||||
Your configuration requires the [`backend.http`
|
||||
section](https://docs.platypush.tech/platypush/backend/http.html) enabled if
|
||||
you want to use the HTTP API - default listen port: `8008`.
|
||||
|
||||
After ensuring that the HTTP backend is enabled, head to
|
||||
`http://localhost:8008` and register a new user.
|
||||
|
||||

|
||||
|
||||
From the Web UI, head to _Settings_ → _Tokens_, insert your password again and
|
||||
click _Generate JWT token_.
|
||||
|
||||

|
||||
|
||||
Alternatively, you can retrieve a token via HTTP request:
|
||||
|
||||
```shell
|
||||
❯ curl -XPOST -H 'Content-Type: application/json' -d '
|
||||
{
|
||||
"username": "$YOUR_USER",
|
||||
"password": "$YOUR_PASSWORD"
|
||||
}' http://localhost:8008/auth
|
||||
```
|
||||
|
||||
You can then send requests to Platypush using a simple RPC API:
|
||||
|
||||
```bash
|
||||
❯ curl -XPOST \
|
||||
-d '{"type":"request", "action":"procedure.at_home"}' \
|
||||
-H "Authorization: Bearer $YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8008/execute
|
||||
❮
|
||||
{
|
||||
"id": "724754df98968247a284557ce32f74bb",
|
||||
"type": "response",
|
||||
"target": "http",
|
||||
"origin": "myhost",
|
||||
"_timestamp": 1716575901.046127,
|
||||
"response": {
|
||||
"output": {
|
||||
"success": true
|
||||
},
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If your procedure returned something, then that will be returned on the API
|
||||
response too, so downstream consumers can use it.
|
||||
|
||||
The `POST /execute` endpoint accepts a payload in the format:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"type": "request", // Constant
|
||||
"action": "<plugin-name>.<action-name>", // Or procedure.<name>
|
||||
"args": {
|
||||
"arg1": "arg2",
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In our `procedure.at_home` example, you can for instance create an automation
|
||||
snippet paired with your phone that runs the routine whenever you arrive home
|
||||
(or your phone does):
|
||||
|
||||
1. Install an app like [Tasker](https://tasker.joaoapps.com/) to create
|
||||
automation tasks on your Android device.
|
||||
|
||||
2. Install a plugin like [AutoLocation](https://joaoapps.com/autolocation/) to
|
||||
create automation tasks based on your phone's location.
|
||||
|
||||
3. Create a profile that triggers whenever you enter your home location (and/or
|
||||
exit it).
|
||||
|
||||

|
||||
|
||||
4. Leverage the [HTTP
|
||||
Request](https://tasker.joaoapps.com/userguide/en/help/ah_http_request.html)
|
||||
Tasker action to send a request to your Platypush API to trigger the routine.
|
||||
|
||||
### The _Execute_ tab
|
||||
|
||||
The Web interface also provides an _Execute_ tab under the menu sidebar. You
|
||||
can use this tab to dynamically discover the actions exposed by various plugins
|
||||
(and also your own procedures):
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Websocket API
|
||||
|
||||
### Events
|
||||
|
||||
You can subscribe to events generated by the application over the `/ws/events`
|
||||
Websocket endpoint, and send events to this endpoint too.
|
||||
|
||||
This is useful if you want to synchronize Platypush events with another client,
|
||||
or send custom events outside of those native to the application and build
|
||||
custom automation hooks on them.
|
||||
|
||||
Sending events:
|
||||
|
||||
```bash
|
||||
❯ wscat -H "Authorization: Bearer $YOUR_TOKEN" \
|
||||
-c "ws://localhost:8008/ws/events" \
|
||||
-w 1 \
|
||||
-x '
|
||||
{
|
||||
"type": "event",
|
||||
"args": {
|
||||
"type": "platypush.message.event.custom.CustomEvent",
|
||||
"subtype": "foo",
|
||||
"args": {
|
||||
"bar": "baz"
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
Receiving events:
|
||||
|
||||
```bash
|
||||
❯ wscat -H "Authorization: Bearer $YOUR_TOKEN" -c "ws://localhost:8008/ws/events"
|
||||
```
|
||||
|
||||
### Actions
|
||||
|
||||
You can also send requests to the `/ws/requests` Websocket endpoint, and get
|
||||
responses asynchronously on the same channel:
|
||||
|
||||
```bash
|
||||
❯ wscat -H "Authorization: Bearer $YOUR_TOKEN" \
|
||||
-c "ws://localhost:8008/ws/requests" \
|
||||
-w 1 \
|
||||
-x '{"type": "requests", "action": "procedure.foo.bar"}'
|
||||
```
|
||||
|
||||
## Web hooks
|
||||
|
||||
You can use Platypush to expose your custom routines as dynamic Web hooks that
|
||||
can be called by any client.
|
||||
|
||||
All you need is to register a listener for a
|
||||
[`WebhookEvent`](https://docs.platypush.tech/platypush/events/http.hook.html#platypush.message.event.http.hook.WebhookEvent)
|
||||
|
||||
```python
|
||||
from platypush import run, when
|
||||
from platypush.events.http.hook import WebhookEvent
|
||||
|
||||
hook_token = "abcdefabcdef"
|
||||
|
||||
# Expose the hook under the /hook/at_home endpoint
|
||||
@when(WebhookEvent, hook="at_home")
|
||||
def at_home_webhook(event: WebhookEvent):
|
||||
# Unlike the calls to /execute, custom web hooks are unauthenticated.
|
||||
# If you want authentication, you'll need to implement your custom logic by
|
||||
# parsing the event headers
|
||||
if event.headers.get("X-Token") != hook_token:
|
||||
# Tuple with <response, http-code, [response-headers]>
|
||||
event.send_response(("Unauthorized", 401))
|
||||
return
|
||||
|
||||
run('procedure.at_home')
|
||||
|
||||
# Return anything back to the client
|
||||
return {'status': 'ok'}
|
||||
```
|
||||
|
||||
Then you can invoke your custom logic over HTTP:
|
||||
|
||||
```bash
|
||||
❯ curl -H 'X-Token: abcdefabcdef' 'http://localhost:8008/hook/at_home'
|
||||
```
|
||||
|
||||
## Platypush as a library
|
||||
|
||||
You can also use Platypush as a library in your own scripts.
|
||||
|
||||
For example, you may want to run a bunch of scripts that control your lights
|
||||
outside of Platypush, but use a Platypush configuration file as your script
|
||||
configuration, and use a plugin as the API for your controller:
|
||||
|
||||
```python
|
||||
from platypush import run
|
||||
from platypush.config import Config
|
||||
|
||||
# Optional. Defaults to the default config.yaml if missing
|
||||
Config.init('/path/to/my/config.yaml')
|
||||
|
||||
# ...
|
||||
|
||||
run('light.hue.toggle', groups=['Living Room', 'Hall'])
|
||||
|
||||
# ...
|
||||
```
|
1409
Backends.md
1409
Backends.md
File diff suppressed because it is too large
Load diff
190
Configuration.md
Normal file
190
Configuration.md
Normal file
|
@ -0,0 +1,190 @@
|
|||
# Configuration
|
||||
|
||||
## Configuration file
|
||||
|
||||
You can use the [default
|
||||
`config.yaml`](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/config/config.yaml)
|
||||
as a template/reference.
|
||||
|
||||
The location of the `config.yaml` to be used by the application is determined
|
||||
in the following way:
|
||||
|
||||
1. It can be passed through the command-line `-c`/`--config` argument.
|
||||
2. If not specified via `-c`, it will be read from the `PLATYPUSH_CONFIG`
|
||||
environment variable.
|
||||
3. If not specified, use `./config.yaml` if available.
|
||||
4. If not available, and you are running Platypush within a Docker container,
|
||||
or as a privileged user (and usually you shouldn't), or as a systemd service
|
||||
created by a supported package manager, then `/etc/platypush/config.yaml`
|
||||
will be used if available.
|
||||
5. Otherwise, if you are running Platypush as a non-privileged user or in a
|
||||
virtual environment, `$XDG_CONFIG_HOME/platypush/config.yaml` will be used
|
||||
(defaults to `~/.config/platypush/config.yaml`).
|
||||
|
||||
### Scripts directory
|
||||
|
||||
By default, any custom Python scripts will be searched under
|
||||
`<CONFDIR>/scripts`, where `<CONFDIR>` is the path to your `config.yaml`.
|
||||
|
||||
You can override it in your `config.yaml`:
|
||||
|
||||
```yaml
|
||||
scripts_dir: /path/to/custom/scripts
|
||||
```
|
||||
|
||||
Since everything under the scripts directory will be imported as a submodule,
|
||||
you can create your own libraries of scripts that can import other scripts:
|
||||
|
||||
```python
|
||||
# Content of scripts/music.py
|
||||
|
||||
from platypush import run
|
||||
|
||||
def music_play(plugin='music.mopidy', resource=None):
|
||||
run(f'{plugin}.play', resource)
|
||||
|
||||
# Content of scripts/lights.py
|
||||
|
||||
from platypush import run
|
||||
|
||||
def lights_toggle(plugin='light.hue', groups=('Living Room',)):
|
||||
run(f'{plugin}.toggle', groups=groups)
|
||||
|
||||
# Content of scripts/home.py
|
||||
|
||||
from platypush import procedure
|
||||
|
||||
from scripts.music import music_play
|
||||
from scripts.lights import lights_toggle
|
||||
|
||||
@procedure
|
||||
def at_home():
|
||||
music_play()
|
||||
lights_toggle()
|
||||
```
|
||||
|
||||
### Splitting configuration on multiple files
|
||||
|
||||
The `config.yaml` file can become very complex, especially if you embed many
|
||||
hooks and procedures in it in YAML format.
|
||||
|
||||
To make the configuration more maintainable, and also to isolate modules that
|
||||
you can reuse across multiple instances, you can leverage the `include`
|
||||
directive:
|
||||
|
||||
```yaml
|
||||
# All paths are relative to config.yaml, or to the location of the current file
|
||||
include:
|
||||
- assistant.yaml
|
||||
- db.yaml
|
||||
- media.yaml
|
||||
- mqtt.yaml
|
||||
- sensors.yaml
|
||||
# ...
|
||||
```
|
||||
|
||||
## Working directory
|
||||
|
||||
This is where the application will store its data and integration plugins will
|
||||
store their data. The order of precedence is:
|
||||
|
||||
* `-w`/`--workdir` command line argument.
|
||||
* The `PLATYPUSH_WORKDIR` environment variable.
|
||||
* The `workdir` field in the configuration file.
|
||||
* `$XDG_DATA_HOME/platypush` (default: `~/.local/share/platypush`) if launched
|
||||
with a non-privileged user, `/var/lib/platypush` if launched as root or with
|
||||
a system user.
|
||||
|
||||
## Database
|
||||
|
||||
The application stores entities, variables, users, integrations state and more
|
||||
on a database. The engine configuration supports the [SQLAlchemy engine
|
||||
syntax](https://docs.sqlalchemy.org/en/20/core/engines.html).
|
||||
|
||||
**Note**: The application uses a local SQLite database by default, which is
|
||||
natively supported by SQLAlchemy. The application has also been tested against
|
||||
MySQL/MariaDB and Postgres, and should work fine with any modern relational
|
||||
database supported by SQLAlchemy. However, any backend other than SQLite may
|
||||
require an additional Python dependency for the SQLAlchemy driver (for example
|
||||
[`pg8000`](https://pypi.org/project/pg8000/) for PostgreSQL).
|
||||
|
||||
Order of precedence for the engine:
|
||||
|
||||
* `--main-db`/`--db` command line argument.
|
||||
* The `PLATYPUSH_DB` environment variable.
|
||||
* The `main.db` field in the configuration file.
|
||||
* `sqlite:///<WORKDIR>/main.db`
|
||||
|
||||
## Device ID
|
||||
|
||||
The device ID is a unique identifier for a Platypush instance on a network and
|
||||
is used to reliably dispatch messages when multiple instances use a shared
|
||||
backend.
|
||||
|
||||
The order of precedence is:
|
||||
|
||||
* `--device-id` command line argument.
|
||||
* The `PLATYPUSH_DEVICE_ID` environment variable.
|
||||
* The `device_id` field in the configuration file.
|
||||
* The hostname of the machine.
|
||||
|
||||
## systemd service
|
||||
|
||||
If you installed Platypush from a system package manager then you'll also have
|
||||
a `systemd` service installed for it.
|
||||
|
||||
You can start/enable Platypush like any other `systemd` service:
|
||||
|
||||
```
|
||||
# systemctl start platypush
|
||||
# systemctl enable platypush
|
||||
```
|
||||
|
||||
Or, if you want to run the Platypush service as a generic user:
|
||||
|
||||
```bash
|
||||
❯ systemctl --user start platypush
|
||||
❯ systemctl --user enable platypush
|
||||
```
|
||||
|
||||
Otherwise, you can create your own `systemd` service copying the [provided
|
||||
`.service`
|
||||
file](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/systemd/platypush.service)
|
||||
to e.g. `~/.config/systemd/user` or `/etc/systemd/system`.
|
||||
|
||||
## Redis
|
||||
|
||||
Platypush uses Redis as a in-memory queue to deliver messages and as a pub/sub
|
||||
bus for inter-process communication.
|
||||
|
||||
If you installed Platypush through a package manager, then the Redis service
|
||||
will automatically be installed and started if you launch the Platypush service
|
||||
as a privileged user.
|
||||
|
||||
If you run Platypush in a container then by default it'll start its own Redis
|
||||
instance through the `--start-redis` command-line option.
|
||||
|
||||
You can customize the Redis configuration through the:
|
||||
|
||||
1. `--redis-host`, `--redis-port` and `--redis-queue` command-line options.
|
||||
2. `PLATYPUSH_REDIS_HOST`, `PLATYPUSH_REDIS_PORT` and `PLATYPUSH_REDIS_QUEUE`
|
||||
environment variables.
|
||||
3. Through your `config.yaml`:
|
||||
|
||||
```yaml
|
||||
# See https://redis-py.readthedocs.io/en/latest/connections.html#redis.Redis
|
||||
# for the full list of supported parameters
|
||||
redis:
|
||||
host: redis-host
|
||||
port: 6379
|
||||
username: redis-user
|
||||
password: redis-pass
|
||||
```
|
||||
|
||||
## nginx
|
||||
|
||||
If you want to access your Platypush web panel outside your home network, it may
|
||||
be a good idea to use an nginx/Apache reverse proxy with a valid SSL certificate
|
||||
(e.g. managed by certbot). A [sample an nginx
|
||||
configuration](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/nginx/nginx.sample.conf)
|
||||
is provided in the repository.
|
40
Entities.md
Normal file
40
Entities.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Entities
|
||||
|
||||
Entities are another building block of Platypush. Many integrations will store
|
||||
their state or connected devices in the form of entities - e.g. the sensors
|
||||
detected by the Z-Wave/Zigbee/Bluetooth integration, or the lights connected to
|
||||
a Hue bridge, or your cloud nodes, or your custom Arduino/ESP machinery, and so
|
||||
on.
|
||||
|
||||
Entities provide a consistent interface to interact with your integrations
|
||||
regardless of their type and the plugin that handles them. For instance, all
|
||||
temperature sensors will expose the same interface, regardless if they are
|
||||
Bluetooth or Zigbee sensors, and all the media plugins will expose the same
|
||||
interface, regardless if they manage Chromecasts, Kodi, Plex, Jellyfin or a
|
||||
local VLC player.
|
||||
|
||||
Once you enable the HTTP backend and a few integrations that export entities
|
||||
and register a user, you can query the detected entities via:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $YOUR_TOKEN" \
|
||||
-d '{"type":"request", "action":"entities.get"}' \
|
||||
http://localhost:8008/execute
|
||||
```
|
||||
|
||||
All the entities expose the same interface and can be manipulated through the
|
||||
same API. Also, when an entity is updated it always emits an
|
||||
[`EntityUpdateEvent`](https://docs.platypush.tech/platypush/events/entities.html#platypush.message.event.entities.EntityUpdateEvent),
|
||||
so you can easily create hooks that react to these events and act on multiple
|
||||
types of entities.
|
||||
|
||||
If you enabled the HTTP backend, then you can also access all the entities from
|
||||
the home panel of the Web UI.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
207
Home.md
207
Home.md
|
@ -1,137 +1,100 @@
|
|||
Platypush
|
||||
=========
|
||||
# Home
|
||||
|
||||
* [Architecture](#architecture)
|
||||
* [Installation](#installation)
|
||||
* [Quickstart](quickstart)
|
||||
* [Plugins](plugins)
|
||||
* [Backends](backends)
|
||||
* [Run Platypush in a virtual environment](run-platypush-in-a-virtual-environment)
|
||||
* [Run Platypush in a container](run-platypush-in-a-container)
|
||||
* [Writing your plugins](writing-your-own-plugins)
|
||||
* [Writing your backends](writing-your-own-backends)
|
||||
- [Quickstart](Quickstart)
|
||||
- [Installation](Installation)
|
||||
- [Plugins installation](Plugins-installation)
|
||||
- [APIs](APIs)
|
||||
- [Variables](Variables)
|
||||
- [Entities](Entities)
|
||||
- [Configuration](Configuration)
|
||||
- [A full configuration example](A-full-configuration-example)
|
||||
- [The Web interface](The-Web-interface)
|
||||
|
||||
# Architecture
|
||||
Platypush is a general-purpose and extensible platform for automation across
|
||||
multiple services and devices with [hundreds of supported
|
||||
integrations](https://docs.platypush.tech/plugins.html).
|
||||
|
||||
The base components are:
|
||||
It enables users to create their own self-hosted pieces of automation based on
|
||||
events (*if this happens then do that*)
|
||||
and it provides a comprehensive and customizable user interface that collects
|
||||
everything you need to visualize and control under one roof.
|
||||
|
||||
* __Messages__: _requests_, _responses_ or _events_. The main difference between a request and an event is that the former specifies an explicit action to be executed through a _plugin_ (and the sender will usually wait for a _response_), while an event only notifies that something happened on a connected data source and can either be ignored or trigger some custom actions specified in the configuration.
|
||||
It borrows concepts from [IFTTT](https://ifttt.com),
|
||||
[Tasker](https://tasker.joaoapps.com/) and [Home
|
||||
Assistant](https://www.home-assistant.io/) to provide an environment where the
|
||||
user can easily connect things together. It focuses on an automation-as-code
|
||||
and API-first approach, offering power users great flexibility in customizing
|
||||
their routines.
|
||||
|
||||
* The __Bus__: An internal queue where all the other components exchange messages.
|
||||
It's built with compatibility and flexibility in mind, and it can easily run on
|
||||
any device that can run a Python interpreter - from a Raspberry Pi, to an old
|
||||
smartphone, to a beefy server.
|
||||
|
||||
* __Backends__: Components that poll other data sources (a local queue, a remote websocket, a Kafka instance, or even a vocal assistant, a programmable button or a sensor) and post either requests or events on the bus when something happens on the data source. Some of them can have a full-duplex integration with the bus, i.e. post requests and events on the bus as they come and deliver responses from the bus back to the sender (examples: PushBullet, Apache Kafka, HTTP services, sockets), while some are pure data sources that will only post events on the bus (examples: sensors, buttons, vocal assistants). Check [our documentation](https://docs.platypush.tech/en/latest/backends.html) for a complete reference of the available backends.
|
||||
## Core concepts
|
||||
|
||||
* __Plugins__: Configurable components which expose _actions_ that can be triggered by requests or events. Examples: smart lights, music controls, YouTube or torrentcast features, text-to-speech, generic shell commands, etc.). They would usually deliver output and errors as responses on the bus. Check [our documentation](https://docs.platypush.tech/en/latest/plugins.html) for a complete reference of the available plugins.
|
||||
The foundations of Platypush rest on a few simple building blocks that offer
|
||||
great versatility to build arbitrarily complex automation routines:
|
||||
|
||||
* __Procedures__: Pre-configured lists of actions that can be triggered by requests or events.
|
||||
- 🧩 **Plugins**. Plugins are the bread-and-butter of the platform. Each plugin
|
||||
exposes an API to interact with an integration - there are plugins for media
|
||||
players and devices, calendars, sensors, voice assistants, smart devices,
|
||||
cloud services, and so on.
|
||||
|
||||
* Event __Hooks__: Pre-configured actions that will be executed when certain events are processed. They include:
|
||||
* A _condition_, which can be fuzzly compared against an event. The matching logic will also return a _match score_ if the condition is met. The score is a function of the number of atomic matches (string tokens, scalars, key-values etc.) in the condition that are satisfied by a certain event. If multiple hooks are satisfied by a certain event, the algorithm will only run the ones with the highest score.
|
||||
* One or more _actions_ to be executed in case of event match (e.g. "turn on the lights", "send a Messenger message to my s.o.", "turn on the heating", "play the radio" etc.)
|
||||
- ⏻ **Actions**. These are the methods of a plugin transparently exposed to the
|
||||
user over a simple JSON RPC API, and they are always expressed in the
|
||||
format `<plugin_name>.<action_name>`. For instance,
|
||||
[`light.hue.on`](https://docs.platypush.tech/platypush/plugins/light.hue.html#platypush.plugins.light.hue.LightHuePlugin.on)
|
||||
can be used to turn on Philips Hue-compatible lights,
|
||||
[`media.vlc.play`](https://docs.platypush.tech/platypush/plugins/media.vlc.html#platypush.plugins.media.vlc.MediaVlcPlugin.play)
|
||||
to play some media on a VLC player, etc.
|
||||
|
||||
Check [our documentation](https://docs.platypush.tech/en/latest/events.html) for a complete reference of the available events.
|
||||
- ⚙️ **Backends**. These are special integrations whose main purpose is to
|
||||
deliver messages to the main application. The principal one is the
|
||||
[`http` backend](https://docs.platypush.tech/platypush/backend/http.html),
|
||||
which exposes the HTTP and WebSocket APIs, serves the main UI and is used
|
||||
by several integrations to provide additional services. A [`nodered`
|
||||
backend](https://docs.platypush.tech/platypush/backend/nodered.html) is
|
||||
also available to expose a Platypush action component to a Node-RED
|
||||
instance, as well as an internal [`redis`
|
||||
backend](https://docs.platypush.tech/platypush/backend/redis.html) and an
|
||||
(insecure) [`tcp`
|
||||
backend](https://docs.platypush.tech/platypush/backend/tcp.html) to receive
|
||||
raw messages.
|
||||
|
||||
# Installation
|
||||
- 📧 **Events**. Plugins emit _events_ whenever some particular conditions happen
|
||||
for example, a [new media track is
|
||||
played](https://docs.platypush.tech/platypush/events/media.html#platypush.message.event.media.MediaPlayEvent),
|
||||
a [voice assistant conversation has
|
||||
started](https://docs.platypush.tech/platypush/events/assistant.html#platypush.message.event.assistant.ConversationStartEvent),
|
||||
and so on.
|
||||
|
||||
First install Redis, as it's used as a bus for delivering messages to platypush. On Debian/Ubuntu for example:
|
||||
- 🪝 **Hooks**. Users can define custom callbacks on events in the form of
|
||||
*hooks*. Hooks can contain lists of actions to execute when a certain event
|
||||
matches the hook *condition*, or any kind of custom logic - for example,
|
||||
*send a notification on my phone when the presence sensor in my garage goes
|
||||
on*, or *use a TTS plugin to process the digest of the latest RSS feeds if
|
||||
I tell the voice assistant "play the news"*. Event hooks can be expressed
|
||||
either in YAML format or as Python runtime scripts.
|
||||
|
||||
```shell
|
||||
apt-get install redis-server
|
||||
# Start and enable the service
|
||||
systemctl start redis.service
|
||||
systemctl enable redis.service
|
||||
```
|
||||
- 📜 **Procedures**. Procedures are custom snippets of logic that can be invoked
|
||||
using the Platypush API. For example, you can define an `at_home` procedure
|
||||
that will be executed when you arrive home, which turns on the lights, plays
|
||||
the music, sets the thermostat temperature etc., and then call it using the
|
||||
Platypush API from any device. Like event hooks, procedures can be defined
|
||||
both in YAML format (good if you just want to execute lists of actions
|
||||
without much added logic), or as Python scripts.
|
||||
|
||||
Then install platypush:
|
||||
- 🕗 **Cronjobs**. Cronjobs are special procedures that can be executed either
|
||||
at regular intervals (the [UNIX cron
|
||||
syntax](https://linuxhandbook.com/crontab/) is supported), or at a specific
|
||||
time (one-shot). Just like procedures, they can be defined either in YAML or
|
||||
as Python scripts.
|
||||
|
||||
```shell
|
||||
pip install platypush
|
||||
```
|
||||
|
||||
### Manual Installation
|
||||
|
||||
```shell
|
||||
git clone https://github.com/BlackLight/platypush
|
||||
cd platypush
|
||||
python setup.py build install
|
||||
```
|
||||
|
||||
### Extra dependencies
|
||||
|
||||
There are four possible ways to install extra dependencies for the plugins and backend that you want to run on your
|
||||
instance.
|
||||
|
||||
#### `platyvenv` and `platydock`
|
||||
|
||||
Upon installation, Platypush provides two utilities (`platyvenv` and `platydock`) that allow you to easily create
|
||||
respectively a virtual environment or a Docker image for your Platypush application from a `config.yaml`.
|
||||
|
||||
Write your `config.yaml` file, including all the plugins and backends that you want to enable. You can also include
|
||||
external YAML files through the `include` directive (as long as they are in the same folder as your `config.yaml`),
|
||||
and also custom Python scripts in the `scripts` directory.
|
||||
|
||||
Make sure to define a `device_id` field in your `config.yaml`. It defines the name that `platyvenv`/`platydock` use to
|
||||
identify and manage the service.
|
||||
|
||||
##### Building the environment/image
|
||||
|
||||
```shell
|
||||
platyvenv build -c /path/to/your/config.yaml
|
||||
# or
|
||||
platydock build -c /path/to/your/config.yaml
|
||||
```
|
||||
|
||||
##### Starting the environment/image
|
||||
|
||||
```shell
|
||||
platyvenv start <device_id>
|
||||
# or
|
||||
platydock start <device_id>
|
||||
```
|
||||
|
||||
##### Stopping the environment/image
|
||||
|
||||
```shell
|
||||
platyvenv stop <device_id>
|
||||
# or
|
||||
platydock stop <device_id>
|
||||
```
|
||||
|
||||
##### Removing the environment/image
|
||||
|
||||
```shell
|
||||
platyvenv rm <device_id>
|
||||
# or
|
||||
platydock rm <device_id>
|
||||
```
|
||||
|
||||
#### `pip` extras
|
||||
|
||||
You can easily install the optional dependencies for the extra plugins you want to use by using the [PEP-508 extras syntax](https://www.python.org/dev/peps/pep-0508/#extras). For example, if you want to run the [HTTP server](https://docs.platypush.tech/en/latest/platypush/backend/http.html) then you can install it through:
|
||||
|
||||
```shell
|
||||
pip install "platypush[http]"
|
||||
```
|
||||
|
||||
You can check the supported extras in the [`setup.py` file](https://github.com/BlackLight/platypush/blob/master/setup.py#L145). Installation of comma-separated lists of extras is also supported.
|
||||
|
||||
#### Plugins/backends documentation
|
||||
|
||||
The [official documentation](https://docs.platypush.tech) provides manual installation steps for all the supported
|
||||
extensions.
|
||||
|
||||
### Configuration
|
||||
|
||||
Copy the [example `config.yaml`](https://github.com/BlackLight/platypush/blob/master/examples/conf/config.yaml) to
|
||||
`/etc/platypush/config.yaml` (global installation, discouraged) or `~/.config/platypush/config/config.yaml`
|
||||
(user installation, recommended).
|
||||
|
||||
Explore it to get a grasp of the basic components of Platypush and their configuration and change it according to your needs.
|
||||
|
||||
### Start up
|
||||
|
||||
After configuring the server, start it by simply running `platypush`, `python -m platypush`. You can also a systemd service by copying the [example `platypush.service`](https://github.com/BlackLight/platypush/blob/master/examples/systemd/platypush.service) to either `/usr/lib/systemd/user/platypush.service` (global installation) or `~/.config/systemd/user/platypush.service` (user installation).
|
||||
|
||||
**NOTE**: Platypush is only compatible with Python 3 and higher.
|
||||
|
||||
After installing the application, you're ready to [start configuring it](quickstart) according to your needs.
|
||||
- 💡 **Entities**. Some plugins expose generic _entities_ - such a lights,
|
||||
sensors, media players, switches, voice assistants etc. These entities can be
|
||||
controlled through [the same generic
|
||||
APIs](https://docs.platypush.tech/platypush/plugins/entities.html), emit [the
|
||||
same types of
|
||||
events](https://docs.platypush.tech/platypush/events/entities.html), can
|
||||
be controlled from the same Web view or dashboard, and their state is
|
||||
persisted across runs.
|
||||
|
|
129
Installation.md
Normal file
129
Installation.md
Normal file
|
@ -0,0 +1,129 @@
|
|||
# Installation
|
||||
|
||||
## System package manager installation
|
||||
|
||||
### Arch Linux
|
||||
|
||||
You can either install the
|
||||
[`platypush`](https://aur.archlinux.org/packages/platypush) package (for the
|
||||
latest stable version) or the
|
||||
[`platypush-git`](https://aur.archlinux.org/packages/platypush-git) package
|
||||
(for the latest git version) through your favourite AUR package manager. For
|
||||
example, using `yay`:
|
||||
|
||||
```bash
|
||||
$ yay platypush
|
||||
# Or
|
||||
$ yay platypush-git
|
||||
```
|
||||
|
||||
The Arch Linux packages on AUR are automatically updated upon new git commits
|
||||
or tags.
|
||||
|
||||
### Debian/Ubuntu
|
||||
|
||||
Currently the following releases are supported:
|
||||
|
||||
1. The current Debian `stable`
|
||||
2. Debian `oldstable`
|
||||
|
||||
Ubuntu supported [to be added
|
||||
soon](https://git.platypush.tech/platypush/platypush/issues/368).
|
||||
|
||||
- Add the Platypush APT key to your trusted keyring:
|
||||
|
||||
```
|
||||
# wget -q -O \
|
||||
/etc/apt/trusted.gpg.d/platypush.asc \
|
||||
https://apt.platypush.tech/pubkey.txt
|
||||
```
|
||||
|
||||
- Add the Platypush repository to your APT sources:
|
||||
|
||||
```
|
||||
# wget -q -O \
|
||||
/etc/apt/sources.list.d/platypush.list \
|
||||
https://apt.platypush.tech/lists/platypush-<deb_version>-<branch>.list
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `deb_version` can be either *stable* (for the current Debian stable version) or
|
||||
*oldstable* (for the previous Debian stable version)
|
||||
- `branch` can be either *main* (for the latest releases) or *dev* (for a package
|
||||
that is always in sync with the git version)
|
||||
|
||||
For example, to install the latest stable tags on Debian stable:
|
||||
|
||||
```
|
||||
# wget -q -O \
|
||||
/etc/apt/sources.list.d/platypush.list \
|
||||
https://apt.platypush.tech/lists/platypush-stable-main.list
|
||||
```
|
||||
|
||||
- Update your repos and install Platypush:
|
||||
|
||||
```
|
||||
# apt update
|
||||
# apt install platypush
|
||||
```
|
||||
|
||||
### Fedora
|
||||
|
||||
RPM builds targeting the latest Fedora release are automatically built on every
|
||||
push pipeline.
|
||||
|
||||
To install Platypush via RPM on Fedora:
|
||||
|
||||
- Add the Platypush RPM repository configuration to the package manager:
|
||||
|
||||
```
|
||||
# yum config-manager --add-repo https://rpm.platypush.tech/platypush.repo
|
||||
```
|
||||
|
||||
- Install Platypush, either the latest stable release or the rolling release
|
||||
updated on every commit to the main branch:
|
||||
|
||||
```
|
||||
# yum install platypush
|
||||
# Or
|
||||
# yum install platypush-git
|
||||
```
|
||||
|
||||
## `pip`
|
||||
|
||||
```bash
|
||||
$ pip install platypush
|
||||
```
|
||||
|
||||
Or, for the latest git version:
|
||||
|
||||
```bash
|
||||
# Official repo
|
||||
$ pip install git+https://git.platypush.tech/platypush/platypush
|
||||
# Github mirror
|
||||
$ pip install git+https://github.com/blacklight/platypush
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
$ git clone https://git.platypush.tech/platypush/platypush.git
|
||||
$ cd platypush
|
||||
# Copy .env.example to .env and edit docker-compose.yml if required.
|
||||
# In particular, you may want /etc/platypush and /var/lib/platypush
|
||||
# to point to directories on your hosts
|
||||
$ docker compose up
|
||||
```
|
||||
|
||||
Note that the default `Dockerfile` uses Alpine, but in `docker-compose.yml` you
|
||||
can also specify an alternative `Dockerfile` - Debian, Ubuntu and Fedora are
|
||||
supported.
|
||||
|
||||
## Manual installation
|
||||
|
||||
```shell
|
||||
$ git clone https://git.platypush.tech/platypush/platypush.git
|
||||
$ cd platypush
|
||||
$ pip install .
|
||||
```
|
96
Plugins-installation.md
Normal file
96
Plugins-installation.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
# Plugins installation
|
||||
|
||||
All the plugins included in the main repo will be available once you have
|
||||
installed the core platform.
|
||||
|
||||
However, some plugins may require extra (optional) dependencies. You have
|
||||
several ways of installing those dependencies:
|
||||
|
||||
## `pip`
|
||||
|
||||
You can install extra dependencies via pip extras:
|
||||
|
||||
```shell
|
||||
pip install 'platypush[plugin1,plugin2,...]'
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
pip install 'platypush[light.hue,music.mpd,rss]'
|
||||
```
|
||||
|
||||
Will install Platypush with the dependencies for the `light.hue`, `music.mpd`
|
||||
and `rss` plugins.
|
||||
|
||||
## Web interface
|
||||
|
||||
Plugins can be installed from the Web interface too. Navigate to the
|
||||
_Extensions_ entry in the sidebar, select the extension that you want to install,
|
||||
select the _Install_ tab and click _Install_.
|
||||
|
||||

|
||||
|
||||
This section also includes the _Configuration_ tab, with a ready-to-paste
|
||||
configuration snippet template for that plugin, as well as a documentation page
|
||||
that includes all the actions supported by a given plugin and the events it
|
||||
triggers.
|
||||
|
||||
## Docker
|
||||
|
||||
If you already have the base installation of Platypush on your machine, and you
|
||||
have a configuration file with a custom set of integrations, then you may opt
|
||||
to generate a custom Docker image from your configuration file, with all the
|
||||
extra dependencies configured, using the `platydock` command.
|
||||
|
||||
The following command:
|
||||
|
||||
```shell
|
||||
❯ platydock -c /path/to/your/config.yaml -d platypush-test
|
||||
```
|
||||
|
||||
Will create a Platypush Docker image for a device with ID `platypush-test`,
|
||||
with all the requirements for the additional integrations listed in
|
||||
`config.yaml`.
|
||||
|
||||
You can pass the `--print` option if you just want to print the content of the
|
||||
output `Dockerfile` instead of generating the image.
|
||||
|
||||
By default the image will use Alpine Linux as a base. You can use the
|
||||
`-i`/`--image` to specify another supported base image - `ubuntu`, `debian` or
|
||||
`fedora`.
|
||||
|
||||
## Virtual environment
|
||||
|
||||
If you already have the base installation of Platypush on your machine, and you
|
||||
have a configuration file with a custom set of integrations, then you may opt
|
||||
to generate a custom virtual environment from your configuration file, with all
|
||||
the extra dependencies configured, using the `platyvenv` command.
|
||||
|
||||
The following command:
|
||||
|
||||
```bash
|
||||
❯ platyvenv -c /path/to/your/config.yaml -o /path/to/your/venv
|
||||
```
|
||||
|
||||
Will create a new virtual environment under `/path/to/your/venv` using the
|
||||
specified `config.yaml` to determine which optional dependencies should be installed.
|
||||
|
||||
You can then run Platypush after activating your new environment:
|
||||
|
||||
```bash
|
||||
❯ source /path/to/your/venv/bin/activate
|
||||
❯ platypush -c /path/to/your/config.yaml
|
||||
```
|
||||
|
||||
## Manual installation
|
||||
|
||||
The [plugin/backend documentation](https://docs.platypush.tech) reports all the
|
||||
dependencies required by each plugin, as well as the commands to install them
|
||||
on multiple platforms.
|
||||
|
||||
If you want to customize your installation, or if you need to install
|
||||
dependencies for a plugin that requires some manual steps, you can check out
|
||||
any plugin-specific installation steps from its documentation.
|
||||
|
942
Plugins.md
942
Plugins.md
|
@ -1,942 +0,0 @@
|
|||
* [MPD/Mopidy](#mpd-mopidy-support)
|
||||
* [Web interface](#web-interface)
|
||||
* [Start playback via HTTP request](#start-playback-via-http-request)
|
||||
* [Search and play songs and albums using the integrated voice assistant](#search-and-play-songs-and-albums-using-the-integrated-voice-assistant)
|
||||
* [Redis plugin](#redis-plugin)
|
||||
* [Video and media](#video-and-media-support)
|
||||
* [Philips Hue lights](#philips-hue-lights-support)
|
||||
* [Switch plugins](#switch-plugins)
|
||||
* [Belkin WeMo Switch](#belkin-wemo-switch)
|
||||
* [TP-Link smart plugs](#tp-link-smart-plugs)
|
||||
* [Switchbot](#switchbot)
|
||||
* [Text-to-Speech](#text-to-speech-support)
|
||||
* [Shell plugin](#shell-plugin)
|
||||
* [HTTP requests plugin](#http-requests-plugin)
|
||||
* [Database plugin](#database-plugin)
|
||||
* [Variables](#variables)
|
||||
* [Google Assistant plugin](#google-assistant-plugin)
|
||||
* [Calendar plugin](#calendar-plugin)
|
||||
* [Sensor plugins](#sensor-plugins)
|
||||
* [MCP3008](#mcp3008)
|
||||
* [Distance](#distance)
|
||||
* [Serial](#serial)
|
||||
* [Build a robot with the ZeroBorg plugin](#zeroborg)
|
||||
* [MIDI plugin](#midi-plugin)
|
||||
* [MQTT plugin](#mqtt-plugin)
|
||||
* [Pushbullet plugin](#pushbullet-plugin)
|
||||
* [Kafka plugin](#kafka-plugin)
|
||||
* [IFTTT plugin](#ifttt-plugin)
|
||||
* [Adafruit IO plugin](#adafruit-io-plugin)
|
||||
* [Autoremote plugin](#autoremote-plugin)
|
||||
* [Kodi plugin](#kodi-plugin)
|
||||
* [Torrent plugin](#torrent-plugin)
|
||||
* [Weather plugin](#weather-plugin)
|
||||
|
||||
A couple of plugins are available out of the box with Platypush under `plugins/`. Some of them may require extra Python or system dependencies. This page will show you some of the available plugins and some possible use cases, although the only real limit to how to connect things together is just your own imagination. This is not intended to be a complete reference of all the available plugins with their supported methods and dependencies, please refer to our [ReadTheDocs](https://docs.platypush.tech/en/latest/plugins.html) page for a more complete reference.
|
||||
|
||||
# MPD/Mopidy support
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/music.mpd.html).
|
||||
|
||||
[MPD](https://musicpd.org/) is an application that allows to manage and play your music collection through a scalable client/server model. You can have your server running on a machine with a hard drive stuffed with mp3s, and access your collection from anywhere using a big family of compatible command line, graphical, web or mobile clients. [Mopidy](https://www.mopidy.com/) is an evolution of MPD that allows you to access music content from multiple sources through a wide set of plugins - e.g. Spotify, SoundCloud, Deezer, Pandora, TuneIn, Google Music.
|
||||
|
||||
Platypush can be a client for your MPD/Mopidy music server, allowing you to search for music, control your queue and the playback upon requests or events.
|
||||
|
||||
Configuration:
|
||||
|
||||
```yaml
|
||||
music.mpd:
|
||||
host: localhost
|
||||
port: 6600
|
||||
```
|
||||
|
||||
It's advised to turn on the [MPD/Mopidy backend](backends#mpd-mopidy-backend) as well if you want to receive live events on your playback status.
|
||||
|
||||
# Web interface
|
||||
|
||||
If you have enabled the HTTP backend, you can already point your browser to `http://hostname:8008` and you would see a new tab named `music.mpd` in your control panel. You can browse your music from here, modify the current playlist, search for music and control the playback state. If you're using mopidy and you have some plugins configured (Spotify, SoundCloud, TuneIn...), you'll be able to control music from your cloud accounts from here as well. The interface will look [like this](https://i.imgur.com/HbpDL5K.png).
|
||||
|
||||
Let's take a look at a couple more use cases.
|
||||
|
||||
## Start playback via HTTP request
|
||||
|
||||
Simple use case to get started, start playing the current track through a cURL command:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"music.mpd.play"}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Search and play songs and albums using the integrated voice assistant
|
||||
|
||||
If you have configured already the [voice assistant backend](Backends#assistant-backend), you can configure an event hook to play a song or an album whenever you say _play [item] by [artist]_.
|
||||
|
||||
First configure an event hook for it that will invoke a new synchrounous procedure:
|
||||
|
||||
```yaml
|
||||
event.hook.SearchSongVoiceCommand:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
phrase: "play ${title} by ${artist}"
|
||||
then:
|
||||
-
|
||||
action: procedure.search_and_play_song
|
||||
```
|
||||
|
||||
Then define the `search_and_play_song` procedure:
|
||||
|
||||
```yaml
|
||||
procedure.sync.search_and_play_song:
|
||||
-
|
||||
# Clear the content of the current playlist
|
||||
action: music.mpd.clear
|
||||
-
|
||||
# Disable shuffle mode
|
||||
action: music.mpd.random
|
||||
args:
|
||||
value: 0
|
||||
-
|
||||
# Perform an mpd search. Note how we re-used the "title" and "artist"
|
||||
# context variables parsed from the voice assistant event
|
||||
action: music.mpd.search
|
||||
args:
|
||||
filter:
|
||||
- artist
|
||||
- ${artist}
|
||||
- any
|
||||
- ${title}
|
||||
-
|
||||
# Play the first of the search results above. Note how we re-used the
|
||||
# "output" context variable, that contains the output of the previous
|
||||
# action (an array in the case of `music.mpd.search`), to get the file id
|
||||
# of the first result and pass it to `music.mpd.play`
|
||||
action: music.mpd.play
|
||||
args:
|
||||
resource: ${output[0]['file']}
|
||||
```
|
||||
|
||||
# Redis plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/redis.html)
|
||||
|
||||
[Redis](https://redis.io/) is an in-memory data structure store. It can be used as an in-memory store, as a cache or as a message broker. Obviously, latter case is quite interesting when it comes to Platypush :)
|
||||
|
||||
Redis is also used heavily by some of our plugins and backends to communicate and synchronize properly, especially if the components live in different processes (for example, the web server) and need to exchange messages with the main process. Redis is a perfect candidate for the purpose. It has a low latency, and the server is lightweight enough to run even on a Raspberry Pi Zero without issues. It's therefore **strongly recommended** to enable both the Redis plugin and [backend](Backends#redis-backend) (and install a local Redis server) to take full advantage of Platypush features.
|
||||
|
||||
The Redis plugin has a quite simple API to deliver messages:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"redis.send_message", "args": {"queue":"my_queue_name", "msg":"My message"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
# Video and media support
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/video.omxplayer.html)
|
||||
|
||||
Platypush comes with support for video media, including YouTube, local media and torrents. It's quite handy to turn a RaspberryPi into a full-blown media server or a Chromecast on steroids, voice controls included.
|
||||
|
||||
```yaml
|
||||
video.omxplayer:
|
||||
media_dirs:
|
||||
# Local media content will be search in these directories
|
||||
- /mnt/exthd/media/movies
|
||||
- /mnt/exthd/media/series
|
||||
|
||||
# Torrents and other remote content will be downloaded to this directory
|
||||
download_dir: /mnt/exthd/downloads
|
||||
|
||||
# Torrent bind ports override (default ports: 6881, 6891)
|
||||
torrent_ports:
|
||||
- 7881
|
||||
- 7891
|
||||
|
||||
args:
|
||||
# You can specify any extra option passed to the OMXPlayer (https://elinux.org/Omxplayer) executable here
|
||||
- -o
|
||||
- alsa # or hdmi
|
||||
- --subtitles
|
||||
- /home/user/subs
|
||||
- -orientation
|
||||
- 90
|
||||
# ...
|
||||
```
|
||||
|
||||
Some cURL examples:
|
||||
|
||||
## Play local media
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"video.omxplayer.play", "args": {"resource":"file:///path/video.mp4"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Play media by URL
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"video.omxplayer.play", "args": {"resource":"http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_60fps_stereo_abl.mp4"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Play a YouTube video
|
||||
|
||||
**Note**: it requires [youtube-dl](https://rg3.github.io/youtube-dl/) installed on your system.
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"video.omxplayer.play", "args": {"resource":"https://www.youtube.com/watch?v=XCAQ0MZTJmg"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Play a torrent content by Magnet link
|
||||
|
||||
**Note**: it requires [python-libtorrent](https://pypi.org/project/python-libtorrent/).
|
||||
|
||||
This will first download the torrent content to `download_dir` and then play it (streaming while downloading isn't currently supported, the few tests I've run seem to stress the Raspberry Pi too much).
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"video.omxplayer.play", "args": {"resource":"magnet:?magnet_uri"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Search and play videos from any source
|
||||
|
||||
The OMXPlayer plugin comes with a powerful search feature that allows you to search and play videos from any available source (currently supported: local files, YouTube and torrent sources).
|
||||
|
||||
An example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"video.omxplayer.search", "args":{"query":"A Space Odyssey"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"type":"response",
|
||||
"response": {
|
||||
"output": [
|
||||
{
|
||||
"url": "file:///mnt/hd/media/movies/A Space Odyssey/2001 - A Space Odyssey.avi",
|
||||
"title": "2001 - A Space Odyssey.avi"
|
||||
},
|
||||
{
|
||||
"url": "magnet:?xt=urn:...",
|
||||
"title": "2001: A Space Odyssey"
|
||||
},
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=oR_e9y-bka0",
|
||||
"title": "2001: A SPACE ODYSSEY - Trailer"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can also pass `"queue_results":true` if you want to add the search results to the current play queue, or `"autoplay":true` if you want to automatically play the first search result.
|
||||
|
||||
If you enabled the plugin you'll also have a nice [video search and control tab](https://i.imgur.com/820732a.png) added to your web panel.
|
||||
|
||||
# Philips Hue lights support
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html)
|
||||
|
||||
Control your [Philips Hue](https://www2.meethue.com/en-us) lights with custom requests and events triggered by your devices.
|
||||
|
||||
```yaml
|
||||
light.hue:
|
||||
bridge: bridge_name_or_ip
|
||||
# If no lights or groups to actions are specified in
|
||||
# the action or in the default configuration, all the
|
||||
# available lights will be targeted by the commands
|
||||
|
||||
lights:
|
||||
- Hall
|
||||
- Living Room Left
|
||||
- Living Room Right
|
||||
- Garage
|
||||
groups:
|
||||
- Bedroom
|
||||
- Kitchen
|
||||
```
|
||||
|
||||
If you enabled the plugin, you'll also have a [lights control tab](https://i.imgur.com/HwsNsms.png) on your web panel.
|
||||
|
||||
Some cURL examples:
|
||||
|
||||
## Turn on the kitchen lights
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"light.hue.on", "args": {"groups":"Kitchen"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Set the sunset scene on the living room lights
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"light.hue.scene", "args": {"name":"Sunset", "groups":"Living Room"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Blink your living room lights for five seconds
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"light.hue.animate", "args": {"animation":"blink", "groups":"Living Room", "transition_seconds":0.5, "duration": 5}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
# Switch plugins
|
||||
|
||||
You can use Platypush to control a variety of smart plugs and switches in your smart home setup.
|
||||
By enabling any of these plugins (even creating an empty config entry just with `disabled: False` if no confi is required), you'll also get the associated switch tab in the web panel where you can control your devices through a web interface.
|
||||
|
||||
## Belkin WeMo Switch
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/switch.wemo.html)
|
||||
|
||||
The [WeMo Switch](http://www.belkin.com/us/p/P-F7C027/) is smart Wi-Fi controlled switch that can automate the control of any electric appliance - fridges, lights, coffee machines...
|
||||
|
||||
Example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"switch.wemo.on", "args": {"device":"192.168.1.2"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## TP-Link smart plugs
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/switch.tplink.html)
|
||||
|
||||
This plugin allows you to interact with TP-Link smart plugs like the [HS100](https://www.tp-link.com/us/products/details/cat-5516_HS100.html).
|
||||
|
||||
Example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"switch.tplink.on", "args": {"device":"192.168.1.3"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
## Switchbot
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/switch.switchbot.html)
|
||||
|
||||
[Switchbot](https://www.switch-bot.com/) is a quite interesting smart home device as it aims to make non-smart devices "smart". It consists in a box with a small bluetooth-controlled mechanical arm that can apply enough pressure to press any button - you can use it to control through Platypush the buttons on your coffee machine, your dishwasher or your old tv for instance.
|
||||
|
||||
Note that, unlike the other plugins, Switchbot requires root privileges as it needs to send a raw bluetooth low-energy message using GATT to communicate with the Switchbot. It means that if you're running Platypush as an unprivileged user (and you should!!), you'll need for now to make a `sudo` rule for it. I plan to make it better/safer though.
|
||||
|
||||
Example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"switch.switchbot.press", "args": {"device":"00:11:22:33:44:55"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
# Text-to-Speech support
|
||||
|
||||
If `mplayer` is installed, you can trigger a machine to say custom phrases in any language through the `tts` plugin. Quite cool if you want to let your RaspberryPi to automatically read you out loud the news or when you get a notification on your phone.
|
||||
|
||||
```yaml
|
||||
tts:
|
||||
lang: en-gb # Default language
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"tts.say", "args": {"phrase":"Connecting people"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
# HTTP requests plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/http.request.html)
|
||||
|
||||
You can programmatically send HTTP requests in your event hooks and procedures through the `http.request` plugin.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
event.hook.TellMeTheWeather:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
phrase: tell me the weather
|
||||
then:
|
||||
-
|
||||
action: http.request.get
|
||||
args:
|
||||
url: https://your-weather-provider.com/api/weather
|
||||
params:
|
||||
- latlng: 0.0,0.0
|
||||
headers:
|
||||
- X-Auth-Token: YOUR_TOKEN
|
||||
```
|
||||
|
||||
# Database plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/db.html)
|
||||
|
||||
You can use Platypush to programmatically insert, update, delete or select database records in your requests, procedures or event hooks. [SQLAlchemy](https://www.sqlalchemy.org/) is used as a backend, therefore Platypush support any engine schema natively supported by SQLAlchemy (SQLite, PostgreSQL, MySQL, Oracle...).
|
||||
|
||||
Configuration:
|
||||
|
||||
```yaml
|
||||
db:
|
||||
engine: sqlite:////home/user/temperature.db # (Optional) default engine; can still be overridden in your db calls
|
||||
```
|
||||
|
||||
```yaml
|
||||
procedure.sync.log_temperature:
|
||||
-
|
||||
action: http.request.get
|
||||
args:
|
||||
url: http://your-local-server/api/sensors/temperature # Example JSON output: {"temperature":21.0}
|
||||
-
|
||||
action: db.insert
|
||||
# engine: mysql://.... # Optionally, you can override the default engine to point to another db
|
||||
table: apartment_stats_temp
|
||||
records:
|
||||
-
|
||||
temperature: ${temperature}
|
||||
```
|
||||
|
||||
[update](https://docs.platypush.tech/en/latest/platypush/plugins/db.html#platypush.plugins.db.DbPlugin.update) and [delete](https://docs.platypush.tech/en/latest/platypush/plugins/db.html#platypush.plugins.db.DbPlugin.delete) methods are also available.
|
||||
|
||||
If you want to programmatically select from a table via HTTP call (returns a list of dictionaries):
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-type: application/json' \
|
||||
-d 'msg={"type":"request","target":"hostname","action":"db.select", "args": {"query":"select * from temperature", "engine":"sqlite:////home/user/temperature.db"}}' \
|
||||
http://hostname:8008
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "response",
|
||||
"response": {
|
||||
"output": [{"id": 1, "temperature": "21.0","created_at":"<timestamp>"}],
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Variables
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/variable.google.html)
|
||||
|
||||
`variable` is a special plugin that allows to set, get and unset variables that you can reuse for instance within a procedure execution, to store states that will be used by some other pieces of logic, or share data with other programs.
|
||||
|
||||
**NOTE**: this plugin relies on the [database plugin](#database-plugin) to be configured. It will indeed store the variables on a local database to persist them across restart and easily share them with other processes.
|
||||
|
||||
Example that sets a variable named `AT_HOME`:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-type: application/json' \
|
||||
-d 'msg={"type":"request","target":"hostname","action":"variable.set", "args": {"AT_HOME":1}' \
|
||||
http://hostname:8008
|
||||
```
|
||||
|
||||
You can now build some custom logic in a synchronous procedure based on that value:
|
||||
|
||||
```yaml
|
||||
procedure.sync.turn_lights_on_sunset:
|
||||
-
|
||||
action: variable.get
|
||||
args:
|
||||
name: AT_HOME
|
||||
|
||||
- if ${AT_HOME}:
|
||||
- action: light.hue.on
|
||||
```
|
||||
|
||||
And then unset it if you don't need it anymore (will delete the row):
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-type: application/json' \
|
||||
-d 'msg={"type":"request","target":"hostname","action":"variable.unset", "args": {"name":"AT_HOME"}' \
|
||||
http://hostname:8008
|
||||
```
|
||||
|
||||
# Google Assistant plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/assistant.google.html)
|
||||
|
||||
If you have the Google Assistant backend configured, then you can use the assistant plugin to programmatically start or stop an interaction with the assistant. For instance, you can start a conversation without saying the "Ok, Google" hotword by pressing a Flic button, if you have the Flic backend configured:
|
||||
|
||||
```yaml
|
||||
event.hook.FlicButtonStartConversation:
|
||||
if:
|
||||
type: platypush.message.event.button.flic.FlicButtonEvent
|
||||
btn_addr: <button MAC address>
|
||||
sequence:
|
||||
- ShortPressEvent
|
||||
then:
|
||||
action: assistant.google.start_conversation
|
||||
```
|
||||
|
||||
# Calendar plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/calendar.html)
|
||||
|
||||
You can use the calendar plugin to get your upcoming events or (*TODO*) change or create events on multiple data sources - Google Calendar, Facebook events calendar, remote ICal resource etc.
|
||||
|
||||
Example configuration:
|
||||
|
||||
```yaml
|
||||
calendar:
|
||||
calendars:
|
||||
-
|
||||
type: platypush.plugins.google.calendar.GoogleCalendarPlugin
|
||||
-
|
||||
type: platypush.plugins.calendar.ical.IcalCalendarPlugin
|
||||
url: https://www.facebook.com/ical/u.php?uid=USER_ID&key=FB_KEY
|
||||
```
|
||||
|
||||
Note the use of the Google Calendar plugin type. The Google Calendar plugin belongs to the family of Google plugins, which currently includes Calendar, GMail and Maps (to be expanded). Check the instruction on the [Google plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/google.html) on how to generate OAuth2 tokens for your Google account that these plugins can use.
|
||||
|
||||
# Sensor plugins
|
||||
|
||||
You can query sensors connect through multiple interfaces through Platypush.
|
||||
|
||||
## MCP3008
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/gpio.sensor.mcp3008.html)
|
||||
|
||||
The [MCP3008](https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/mcp3008) is a very useful ADC converter that you can use to read data from multiple analog sources and transmit them to a digital device that doesn't support direct GPIO analog input (like the Raspberry Pi). You can use it instead of an Arduino or serial device if you want lower latency, or a more compact or cheaper solution.
|
||||
|
||||
An example configuration:
|
||||
|
||||
```yaml
|
||||
gpio.sensor.mcp3008:
|
||||
# In this configuration the MCP3008 is connected in software SPI mode,
|
||||
# a better option if you don't have many GPIO pins available although
|
||||
# it introduces a bit of latency compared to the hardware SPI mode.
|
||||
# Here we specify the GPIO pin numbers where you connect your MCP3008
|
||||
# interface. Specify spi_port and spi_device instead if you want to run
|
||||
# in hardware SPI mode.
|
||||
CLK: 15
|
||||
MISO: 22
|
||||
MOSI: 17
|
||||
CS: 25
|
||||
|
||||
# Reference tension, usually 3.3V or 5V on a Raspberry
|
||||
Vdd: 3.3
|
||||
|
||||
# Here you can link names and analog conversion functions to the
|
||||
# analog sources connected to your MCP3008 pins.
|
||||
channels:
|
||||
# Channels are identified by MCP3008 pin number
|
||||
0:
|
||||
name: temperature
|
||||
|
||||
# The conversion function is a snippet of Python code that you can specify to
|
||||
# convert the output voltage of your analog sensor (normalized between 0 and 255)
|
||||
# into a human readable value (e.g. meters, Celsius degrees, km/h, % etc.).
|
||||
# In this example we used a simple LM35DZ (http://www.ti.com/lit/ds/symlink/lm35.pdf)
|
||||
# temperature sensors and specified a function to convert the analog value into
|
||||
# a Celsius degrees value.
|
||||
# Note that the analog value is denoted as `x` in the function definition.
|
||||
conv_function: 'round(x*100.0, 2)' # T = Vout / (10 [mV/C])
|
||||
1:
|
||||
name: light
|
||||
# Here we used a simple ALS-PT9
|
||||
# (http://www.everlight.com/file/ProductFile/201407061531031645.pdf) light sensor,
|
||||
# that comes with an internal 10 kΩ resistor. The detected luminosity (in lumen)
|
||||
# is proportional to the current (in μA) on the resistor, the conversion function
|
||||
# simply uses Ohm's law (I = V/R) to get the lumens from the analog voltage value.
|
||||
conv_function: 'round(x*1000.0, 6)'
|
||||
```
|
||||
|
||||
cURL example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request","target":"hostname","action":"gpio.sensor.mcp3008.get_measurement"}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "response",
|
||||
"response": {
|
||||
"output": {
|
||||
"temperature": 22.42,
|
||||
"light": 50.5
|
||||
},
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to poll your sensors periodically and get a Platypush event whenever their values change then you may want to enable the [MCP3008 backend](backends#mcp3008) as well.
|
||||
|
||||
## Distance
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/gpio.sensor.distance.html)
|
||||
|
||||
I've tested this plugin quite successfully with the [HC-SR04](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf) ultrasound distance sensor, an inexpensive and accurate options for anyone playing with robotics.
|
||||
|
||||
The sensor works like an ultrasound radar - it sends a pulse controlled by the `trigger_pin`, and detects the returning signal through the `echo_pin`. Known the average speed of sound in air, it's relatively easy to get the distance of the nearest obstacle. All you have to do is connect the trigger and echo pins to the GPIO interface of your device. Note: take into account that the HC-SR04 works at 5V. If you're interfacing it with a device that works with a lower voltage (the GPIO logic of a Raspberry usually runs at 3.3V) you may want to use a voltage converter or set up your [cheap voltage divider](https://learn.sparkfun.com/tutorials/voltage-dividers) with two resistors to prevent damage to your GPIO interface.
|
||||
|
||||
Example configuration:
|
||||
|
||||
```yaml
|
||||
gpio.sensor.distance:
|
||||
trigger_pin: 13
|
||||
echo_pin: 14
|
||||
```
|
||||
|
||||
cURL example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request","target":"hostname","action":"gpio.sensor.distance.get_measurement"}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
Output (in millimiters):
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "response",
|
||||
"response": {
|
||||
"output": 313.17,
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Serial
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/serial.html)
|
||||
|
||||
Use the serial plugin if you want to read analog data through serial interface (typical use cases: Arduino or compatible devices, serial ports etc.).
|
||||
|
||||
It's advised if the serial device returns data in JSON format (if you use Arduino you can use the [ArduinoJson](https://github.com/bblanchon/ArduinoJson) library to write JSON to the serial interface).
|
||||
|
||||
Example configuration:
|
||||
|
||||
```yaml
|
||||
serial:
|
||||
device: /dev/ACM0
|
||||
baud_rate: 9600
|
||||
```
|
||||
|
||||
If you're using udev to dynamically assign your device names, you might consider configuring [udev rules](https://wiki.archlinux.org/index.php/udev#About_udev_rules) to prevent the "dance" of the device names when they are disconnected and reconnected (and renamed to ACM0, ACM1, ACM2, or USB0, USB1 etc.).
|
||||
|
||||
cURL example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"serial.get_measurement"}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "response",
|
||||
"response": {
|
||||
"output": {
|
||||
"smoke": 0,
|
||||
"temperature": 23.90402,
|
||||
"humidity": 39.08141
|
||||
},
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once you enable the `serial` or `mcp3008` plugin and backend you'll be able to monitor the state of your sensors or analog sources through a new tab on the [web panel](https://i.imgur.com/yQYGuhW.png).
|
||||
|
||||
# ZeroBorg
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/gpio.zeroborg.html)
|
||||
|
||||
The [ZeroBorg](https://www.piborg.org/motor-control-1135/zeroborg) is a nice piece of circuitry that pairs quite well with Raspberry Pi and compatible devices. It comes with four outputs that you can use to control motors and servos by applying a current. It also comes with an infrared sensor that you can use to detect inputs from an IR remote, Platypush provides a backend to read events from this sensor as well.
|
||||
|
||||
The ZeroBorg plugin also allows you to interact with sensors data to control your motors.
|
||||
|
||||
Here's an example configuration I use for my 4WD robot controlled by a Raspberry Pi Zero paired with a ZeroBorg device. [MagPi](https://raspberrypi.org/magpi-issues/MagPi51.pdf) provides detailed instructions on how to build such a robot. Note that the calibration values came after numerous tests to get the robot to move straight. Your values may vary depending on your set up, the load of the connected components, the weight and how it is distributed.
|
||||
|
||||
```yaml
|
||||
gpio.zeroborg:
|
||||
directions:
|
||||
up:
|
||||
motor_1_power: 0.4821428571428572
|
||||
motor_2_power: 0.4821428571428572
|
||||
motor_3_power: -0.6707142857142858
|
||||
motor_4_power: -0.6707142857142858
|
||||
down:
|
||||
motor_1_power: -0.4821428571428572
|
||||
motor_2_power: -0.4821428571428572
|
||||
motor_3_power: 0.825
|
||||
motor_4_power: 0.825
|
||||
left:
|
||||
motor_1_power: -0.1392857142857143
|
||||
motor_2_power: -0.1392857142857143
|
||||
motor_3_power: -1.0553571428571429
|
||||
motor_4_power: -1.0553571428571429
|
||||
right:
|
||||
motor_1_power: 1.0017857142857143
|
||||
motor_2_power: 1.0017857142857143
|
||||
motor_3_power: 0.6214285714285713
|
||||
motor_4_power: 0.6214285714285713
|
||||
auto:
|
||||
sensors:
|
||||
-
|
||||
plugin: "gpio.sensor.distance",
|
||||
threshold: 400.0,
|
||||
timeout: 2.0,
|
||||
above_threshold_direction: "up",
|
||||
below_threshold_direction: "left"
|
||||
```
|
||||
|
||||
Note that the special direction `auto` can contain a configuration that allows your device to move autonomously based on the inputs it gets from some sensors. In this case, I set the sensors configuration (a list) to periodically poll a GPIO-based ultrasound distance sensor plugin. `timeout` says after how long a poll attempt should fail. The plugin package is specified through `plugin` (`gpio.sensor.distance`) in this case, note that the plugin must be configured as well in order to work). The `threshold` value says around which value your logic should trigger. In this case, threshold=400 (40 cm). When the distance value is above that threshold (`above_threshold_direction`), then go "up" (no obstacles ahead). Otherwise (`below_threshold_direction`), turn "left" (avoid the obstacle). Feel free to build a more robust autopilot by adding more sensors :)
|
||||
|
||||
Once you enable the plugin, you can also drive the robot through the [control tab](https://i.imgur.com/2n3amcs.png) that will be available in the control panel. It also supports directional keys and spacebar long-press to toggle the automatic pilot (click inside of the tab first to focus it).
|
||||
|
||||
cURL example to drive your robot up and stop after 5 seconds:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"gpio.zeroborg.drive", "args": {"direction":"up"}}' \
|
||||
http://hostname:8008/execute
|
||||
|
||||
sleep 5
|
||||
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"gpio.zeroborg.stop"}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
# MIDI plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/midi.html)
|
||||
|
||||
Some of the musicians who ended up on this page probably know the [MIDI protocol](http://www.indiana.edu/~emusic/361/midi.htm). Platypush allows you to register a custom MIDI device that can send messages to the OS MIDI sequencer. It's like tricking your machine to think that Platypush is a MIDI keyboard or drum machine. You can for instance create some instrument tracks in LMMS or FruityLoops, link them to your Platypush MIDI source, and play notes through any kind of events that Platypush can process - you can use a Leap Motion to play notes by just waving your hand, use a proximity sensor, play notes with switches and buttons, and so on, the only limit being your creativity.
|
||||
|
||||
An example that sends the C4 (middle C, MIDI note 0x60 or 96 in decimal) at medium velocity (64) for 1 second:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"midi.play_note", "args": {"note":96, "velocity":64, "duration":1}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
You can also send raw MIDI messages through the [`send_message`](https://docs.platypush.tech/en/latest/platypush/plugins/midi.html#platypush.plugins.midi.MidiPlugin.send_message) action.
|
||||
|
||||
You can also listen for MIDI events and run actions based on them by using the MIDI backend.
|
||||
|
||||
# MQTT plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/mqtt.html)
|
||||
|
||||
[MQTT](http://mqtt.org/) is a message-queue based protocol to exchange messages across devices. MQTT implementations like Paho MQTT, Mosquitto and Adafruit IO are quite popular for communication across IoT devices. You can interact with an MQTT service through this plugin to build any arbitrary complex message-based logic across your Platypush devices. The asynchronous nature of MQTT makes it a better candidate over the HTTP plugin to deliver messages to other devices if you don't mind much about the response. An HTTP call to the Flask server to turn on the lights, for example, requires the sender to wrap the request into an HTTP message, the receiver to react immediately on that while the sender is synchrounously waiting for an answer, execute the light control action (which might take a while), and then wrap the response into an HTTP message back to the sender. Compare it instead with a message-queue based implementation, where you send the message to a queue where the receiver is listening and as soon as the receiver is available it will pick it up - no need for the sender to hang for the response. Also, the message queue doesn't require the receiver to be directly accessible (through IP/hostname and port) to the sender, as it happens in an HTTP interaction. The sender can send a message to the queue, hosted by an MQTT server, and as long as the receiver (or any receiver) is listening on the same queue, the message will be picked up.
|
||||
|
||||
Sending a message over an MQTT backend requires an MQTT `host` server and `port` (default: 1883), the `message` to be sent (anything that implements `__str__`), and the `topic` to send the message to - see it like a channel where one or multiple devices might be listening.
|
||||
|
||||
Example:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"mqtt.send_message", "args": {"topic":"my_topic", "server":"my_mqtt_server", "port":1883, "message":"It worked"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
You can (or should) of course also use the [MQTT backend](Backends#mqtt-backend). By doing so you can send messages across that Platypush devices containing action requests, events or responses. You can create routing rules for messages, or propagate the events you receive on a device over another one - for example I've configured a rule for all of my devices with connected sensors to route their `SensorDataChangeEvent` events over MQTT to a hub device, where I can monitor from a single web panel the values of all my sensors around the house. Another good use case for MQTT is to send messages from your Android devices to your Platypush devices. The same developer of Taker has recently developed [Join](https://joaoapps.com/join/), that allows you among the other things to programmatically send messages over MQTT. You can then create tasks that send messages to Platypush when you get a call, receive an sms, connect to some WiFi network or enter some area. You can also create Join action to send custom commands to your Platypush devices from a tap on your phone.
|
||||
|
||||
# Pushbullet plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/pushbullet.html)
|
||||
|
||||
[Pushbullet](https://www.pushbullet.com/) is a quite cool piece of software to keep your devices in sync, exchange messages, synchronize clipboards and sms across devices, access remote files, and so on. You can install it as an Android or iPhone app, as a browser extension, or use it from your browser directly. It can be quite powerful if paired with Platypush - and it has the first backend I have developed as well. You can use the plugin in pair with the backend to do things like:
|
||||
|
||||
* Send URLs, text and Platypush messages to your Android devices
|
||||
* Trigger Platypush actions through your Android device, wherever you are
|
||||
* Synchronize the clipboards
|
||||
* Synchronize your phone notifications to your Raspberry Pi
|
||||
* Send and receive pictures
|
||||
* ...and so on
|
||||
|
||||
Note that you need to enable the [Pushbullet backend](backends#pushbullet-backend) in order to use this plugin.
|
||||
|
||||
Example command to send a file to all of your connected Pushbullet devices:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"pushbullet.send_file", "args": {"filename":"/home/user/myphoto.jpg"}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
# Kafka plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/kafka.html)
|
||||
|
||||
Use this plugin if you want to synchronize messages to your devices over a Kafka message instance. Some use cases:
|
||||
|
||||
* Send asynchronous messages to other Kafka nodes
|
||||
* Send raw messages to other Platypush devices and build event hooks on them
|
||||
* Send directly JSON-formatted requests, responses or events to other Platypush devices
|
||||
|
||||
The configuration is quite straightforward:
|
||||
|
||||
```yaml
|
||||
kafka:
|
||||
server: host:9092 # Default hostname and port where the Kafka broker runs. If None (default), then
|
||||
# you will either have to specify on `send_command`, or it will use the Kafka
|
||||
# backend configured server, if the Kafka backend is running
|
||||
```
|
||||
|
||||
If you want to use Kafka to deliver messages to other Platypush devices keep in mind that their [Kafka backends](backends#kafka-backend) will listen by default on a queue named `platypush.<device_id>`.
|
||||
|
||||
Example to send a text Kafka message:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"kafka.send_message", "args": {"msg":"My first Kafka message over Platypush"}}' \
|
||||
http://localhost:8008/execute
|
||||
```
|
||||
|
||||
# IFTTT plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/ifttt.html)
|
||||
|
||||
[IFTTT](https://ifttt.com) is a very versatile cloud service to automate tasks and trigger actions on particular events. IFTTT comes with some channels that may not be available on Platypush (e.g. trigger events on your Android or iOS device, send Telegram messages, create Trello tasks etc.), or you've been an IFTTT user already and you might want to integrate Platypush with your existing IFTTT configuration.
|
||||
|
||||
You can use Platypush to trigger IFTTT events using the [Maker API](https://ifttt.com/maker_webhooks).
|
||||
|
||||
Steps:
|
||||
|
||||
1. Click on the link above and sign in with your IFTTT account
|
||||
|
||||
2. Click on _Documentation_ and copy the key associated to your account
|
||||
|
||||
3. Configure the Platypush plugin:
|
||||
|
||||
```yaml
|
||||
ifttt:
|
||||
ifttt_key: YOUR_KEY
|
||||
```
|
||||
|
||||
4. In this example suppose that you want to automatically send a Telegram message to yourself with some content. Create an IFTTT applet having _Webhooks_ as a trigger channel and specify `telegram_send` as `event_name`
|
||||
|
||||
5. Specify Telegram as action channel and select the "Send message" action. Specify your own number and select the ingredient `value1` as body
|
||||
|
||||
6. Start Platypush and try to send a message to yourself:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"ifttt.trigger_event", "args": {"event_name":"telegram_send", "values":["IT WORKED"]}}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
# Adafruit IO plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/adafruit.io.html)
|
||||
|
||||
[Adafruit IO](https://io.adafruit.com) is a message-based cloud storage for numerical values. You can use it to store reads from your sensors, see the values on the Adafruit dashboard wherever you are, trigger IFTTT rules if a value goes below or above a threshold and so on.
|
||||
|
||||
First create an account on Adafruit and get your key from [Adafruit IO](https://io.adafruit.com). Then configure the Platypush plugin:
|
||||
|
||||
```yaml
|
||||
adafruit.io:
|
||||
username: your_user
|
||||
key: your_key
|
||||
```
|
||||
|
||||
Then you can create a feed on the web interface and configure for instance an event hook that forwards a new read from your temperature sensor to your remote feed:
|
||||
|
||||
```yaml
|
||||
event.hook.OnSensorData:
|
||||
if:
|
||||
type: platypush.message.event.sensor.SensorDataChangeEvent
|
||||
then:
|
||||
action: procedure.OnSensorData
|
||||
|
||||
procedure.sync.OnSensorData:
|
||||
- if ${'temperature' in data}:
|
||||
-
|
||||
action: adafruit.io.send
|
||||
args:
|
||||
feed: temperature
|
||||
value: ${data.get('temperature')}
|
||||
```
|
||||
|
||||
# Autoremote plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/autoremote.html)
|
||||
|
||||
[Tasker](https://tasker.joaoapps.com/) is a really powerful app for Android that allows you to automate everything on your system, create tasks and triggers to control app, settings, notifications and so on. Some of its features are quite similar to those offered by Platypush, but it runs on Android while Platypush will likely run on your favourite Linux-based computer or mini-computer :)
|
||||
|
||||
It'd be amazing to make those two worlds communicate, for instance by sending notifications to your phone about the media that plays on your Raspberry or triggering an alert on your phone if you're not at home and your Raspberry camera detected some motion.
|
||||
|
||||
It's relatively easy to send messages from Tasker to Platypush. Pick your favourite Tasker plugin (Pushbullet, MQTT or Node-Red over [Join](https://play.google.com/store/apps/details?id=com.joaomgcd.join), any web request plugin...) and you can start creating Tasker routines that send messages to Platypush over the configured channel.
|
||||
|
||||
In order to send messages from Platypush to Tasker instead you can leverage [AutoRemote](https://joaoapps.com/autoremote/), a Tasker plugin that allows you to send custom messages and notifications to an Android device through a multitude of ways (Chrome extension, web API, Tasker integration etc.).
|
||||
|
||||
All you need is to install the app on your Android device and follow the steps to register your device. You'll get a unique URL for your device. If you open it you'll notice a `key=` section in the URL. That's the key you'll need in order to configure the AutoRemote plugin on Platypush:
|
||||
|
||||
```yaml
|
||||
autoremote:
|
||||
devices:
|
||||
OnePlus6: AUTOREMOTE_KEY_1
|
||||
PixelC: AUTOREMOTE_KEY_2
|
||||
Nexus5: AUTOREMOTE_KEY_3
|
||||
```
|
||||
|
||||
Note that you can install and configure AutoRemote on multiple Android devices and configure the Platypush plugin with their keys and a unique name in order to send messages to them. You can now use the [send_message](https://docs.platypush.tech/en/latest/platypush/plugins/autoremote.html#platypush.plugins.autoremote.AutoremotePlugin.send_message) and [send_notification](https://docs.platypush.tech/en/latest/platypush/plugins/autoremote.html#platypush.plugins.autoremote.AutoremotePlugin.send_notification) to respectively send messages and notifications to your device and build Tasker routines on them.
|
||||
|
||||
# Kodi plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/media.kodi.html)
|
||||
|
||||
[Kodi](https://kodi.tv) is a popular media player and media center. It's compatible with plenty of devices and OSes (including Android, Linux, MacOS, Windows and several embedded players) and there are tons of add-ons available, for anything that goes from media library managemnt to subtitles to radio and tv channels to YouTube.
|
||||
|
||||
Kodi also comes with a powerful API, and Platypush can leverage it by allowing you to control your player. You can for instance build a DIY remote control system for your media center by using any IR remote and any IR sensor to navigate the Kodi interface or control the playback status. Or create rules to automatically add to your library and start playing a torrent file when it's done downloading. The [plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/media.kodi.html) is quite rich and the available methods should mirror almost at 100% what is provided by the Kodi API.
|
||||
|
||||
# Torrent plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/torrent.html)
|
||||
|
||||
You can use Platypush to search, download and manage torrents. Example configuration:
|
||||
|
||||
```yaml
|
||||
torrent:
|
||||
download_dir: ~//Downloads # Torrents download directory
|
||||
torrent_ports: # Pair of ports used by the torrent tracker (default: 6881 and 6891)
|
||||
- 6881
|
||||
- 6891
|
||||
```
|
||||
|
||||
Refer to the [plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/torrent.html) for documentation on the available methods and their interface.
|
||||
|
||||
Note also that the `download` method will generate few [types of events](https://docs.platypush.tech/en/latest/platypush/events/torrent.html) and you can build triggers on those, for instance an event hook that automatically starts your favourite player when a movie has done downloading or a notification for the progress of your downloads synced to your mobile device.
|
||||
|
||||
* [TorrentDownloadStartEvent](https://docs.platypush.tech/en/latest/platypush/events/torrent.html#platypush.message.event.torrent.TorrentDownloadStartEvent) when a torrent starts downloading.
|
||||
* [TorrentSeedingStartEvent](https://docs.platypush.tech/en/latest/platypush/events/torrent.html#platypush.message.event.torrent.TorrentSeedingStartEvent) when a torrent starts seeding.
|
||||
* [TorrentStateChangeEvent](https://docs.platypush.tech/en/latest/platypush/events/torrent.html#platypush.message.event.torrent.TorrentStateChangeEvent) when a torrent status changes.
|
||||
* [TorrentDownloadProgressEvent](https://docs.platypush.tech/en/latest/platypush/events/torrent.html#platypush.message.event.torrent.TorrentDownloadProgressEvent) when the download progress state of a torrent changes.
|
||||
* [TorrentDownloadStopEvent](https://docs.platypush.tech/en/latest/platypush/events/torrent.html#platypush.message.event.torrent.TorrentDownloadStopEvent) when the download of a torrent stops.
|
||||
* [TorrentDownloadCompletedEvent](https://docs.platypush.tech/en/latest/platypush/events/torrent.html#platypush.message.event.torrent.TorrentDownloadCompletedEvent) when a torrent download is complete.
|
||||
|
||||
# Weather plugin
|
||||
|
||||
[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/weather.forecast.html)
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
As an alternative to the procedure and hooks defined in `config.yaml`, you can also declare them as native Python entities. This is especially useful if your custom logic is more complex than a sequence of a few actions.
|
||||
|
||||
By default, you can place your custom scripts under `~/.config/platypush/scripts`. You can change the folder by setting the `scripts_dir` option in your `config.yaml`:
|
||||
|
||||
```yaml
|
||||
scripts_dir: /path/to/my/scripts
|
||||
```
|
||||
|
||||
N.B. It is quite important that the scripts folder, as well as its subfolder that are supposed to contain loadable script, contains an `__init__.py` file, even if it's empty. That serves to Python to identify a folder as a loadable module. The `__init__.py` in `scripts_dir` will be created automatically, but if you're planning to add more subfolders with your scripts then you'll have to manually create the file in them.
|
||||
|
||||
Defining a procedure in a custom script is just a matter of using the decorator `@procedure` on any function:
|
||||
|
||||
```python
|
||||
# ~/.config/platypush/scripts/test.py
|
||||
|
||||
from platypush.procedure import procedure
|
||||
from platypush.utils import run
|
||||
|
||||
@procedure
|
||||
def test_procedure():
|
||||
# Run some action
|
||||
return run('music.mpd.pause')
|
||||
```
|
||||
|
||||
You can then call the procedure either through any of the available APIs - e.g. over cURL:
|
||||
|
||||
```bash
|
||||
curl -XPOST -H 'Content-Type: application/json' -d '
|
||||
{
|
||||
"type": "request",
|
||||
"action":"procedure.test.test_procedure"
|
||||
}' http://localhost:8008/execute
|
||||
```
|
||||
|
||||
You can access a wide range of function directly from the platypush module in your code. Among those:
|
||||
|
||||
- `platypush.context.get_plugin` to load a plugin or get its loaded instance
|
||||
- `platypush.context.get_backend` to get the loaded instance of a backend
|
||||
- `platypush.context.get_bus` to access the internal bus directly (useful to dispatch any types of messages directly to the application)
|
||||
- `platypush.utils.run` to run an action by full name (`plugin.method`) and arguments
|
||||
|
||||
Similarly, you can also define custom hooks:
|
||||
|
||||
```python
|
||||
# ~/.config/platypush/scripts/test.py
|
||||
|
||||
from platypush.event.hook import hook
|
||||
from platypush.message.event.assistant import SpeechRecognizedEvent
|
||||
|
||||
@hook(SpeechRecognizedEvent)
|
||||
def test_procedure(event, **content):
|
||||
print('Recognized speech: {}'.format(event.args['phrase']))
|
||||
```
|
||||
As well as cronjobs:
|
||||
|
||||
```python
|
||||
# ~/.config/platypush/scripts/test.py
|
||||
|
||||
from platypush.cron import cron
|
||||
|
||||
# Run it every minute
|
||||
@cron('* * * * *')
|
||||
def test_cron(event, **content):
|
||||
import os
|
||||
import datetime
|
||||
|
||||
with open(os.path.expanduser('~/test.txt'), 'a') as f:
|
||||
f.write('The time is: {}\n'.format(datetime.datetime.now().isoformat()))
|
||||
```
|
650
Quickstart.md
650
Quickstart.md
|
@ -1,447 +1,323 @@
|
|||
* [Quick start](#quick-start)
|
||||
* [Procedures](#procedures)
|
||||
* [For loops](#for-loops)
|
||||
* [If conditions](#if-conditions)
|
||||
|
||||
* [Backends](#backends)
|
||||
* [HTTP service configuration](#http-service-configuration)
|
||||
* [PushBullet](#pushbullet-configuration)
|
||||
* [Apache Kafka](#apache-kafka-configuration)
|
||||
* [Local backend](#local-backend-configuration)
|
||||
* [Google Assistant](#google-assistant-configuration)
|
||||
* [Flic buttons](#flic-buttons-configuration)
|
||||
* [Plugins](#plugins)
|
||||
* [MPD/Mopidy](#mpd-mopidy-support)
|
||||
* [Video and media](#video-and-media-support)
|
||||
* [Philips Hue lights](#philips-hue-lights-support)
|
||||
* [Belkin WeMo Switch](#belkin-wemo-switch)
|
||||
* [Text-to-Speech](#text-to-speech-support)
|
||||
* [Shell plugin](#shell-plugin)
|
||||
* [HTTP requests plugin](#http-requests-plugin)
|
||||
* [Database plugin](#database-plugin)
|
||||
* [Event Hooks](#event-hooks)
|
||||
* [Mobile notification mirroring](#mobile-notification-mirroring)
|
||||
* [Include directive](#include-directive)
|
||||
|
||||
# Quick start
|
||||
|
||||
In this first example, let's suppose that you want to control your smart lights (we'll use the [Philips Hue](https://www2.meethue.com/en-us) plugin in this example, but you can easily use any other plugin) whenever you say "turn on the lights" to your embedded smart assistant (Platypush comes with [support for Google Assistant](https://docs.platypush.tech/en/latest/platypush/backend/assistant.google.html) through the [Google SDK](https://developers.google.com/assistant/sdk/), all you need is a microphone plugged into your device).
|
||||
The bulk of the configuration of Platypush lives under the `config.yaml` file.
|
||||
An extensive [`config.yaml`
|
||||
example](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/config/config.yaml)
|
||||
is provided in the repo. All the sections are optional - the only one enabled by
|
||||
default is the HTTP server, `backend.http`, but that is optional too.
|
||||
|
||||
1. Start by creating an empty configuration file. It will be `/etc/platypush/config.yaml` if you want to share the configuration with all the user on the machine, or `~/.config/platypush/config.yaml` if you want a user-specific configuration.
|
||||
Let's take an example where we want to control the following entities:
|
||||
|
||||
2. Download the `phue` Python package (``pip install phue``), required by the [Hue plugin](https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html)
|
||||
- A Philips Hue bridge and its connected smart lights.
|
||||
|
||||
3. Add the Hue configuration to your file:
|
||||
|
||||
```yaml
|
||||
light.hue:
|
||||
bridge: 192.168.1.100 # IP address or host name of your bridge
|
||||
groups:
|
||||
- Living Room # Default groups to control if not specified in the request
|
||||
```
|
||||
|
||||
4. Also, enable the web server backend, we'll use it to test our plugin through `curl`:
|
||||
- An on-device voice assistant (we'll consider the Google Assistant in this
|
||||
example as it's the easiest to configure, although Google deprecated the
|
||||
Assistant libraries long ago).
|
||||
|
||||
- A compatible music player - we'll consider MPD/Mopidy in this example as they
|
||||
are the ones best supported in Platypush, and Mopidy also offers plugins with
|
||||
basically any audio backend out there.
|
||||
|
||||
We'll need the following plugins enabled in the `config.yaml`:
|
||||
|
||||
- [`light.hue`](https://docs.platypush.tech/platypush/plugins/light.hue.html)
|
||||
- [`assistant.google`](https://docs.platypush.tech/platypush/plugins/assistant.google.html)
|
||||
- [`music.mopidy`](https://docs.platypush.tech/platypush/plugins/music.mopidy.html)
|
||||
or
|
||||
[`music.mpd`](https://docs.platypush.tech/platypush/plugins/music.mpd.html)
|
||||
(they expose the same API)
|
||||
|
||||
The documentation pages of these plugins already provide some comprehensive
|
||||
configuration snippets that you can use.
|
||||
|
||||
The most basic configuration would be something like this:
|
||||
|
||||
```yaml
|
||||
# Enable it if you want the enable the HTTP API and the Web interface
|
||||
backend.http:
|
||||
port: 8008
|
||||
|
||||
light.hue:
|
||||
# IP/hostname of the Hue bridge
|
||||
bridge: 192.168.1.10
|
||||
# Default groups that should be targeted by actions if none is specified
|
||||
# (default: all lights/groups)
|
||||
groups:
|
||||
- Living Room
|
||||
|
||||
# Check the plugin documentation on how to get the credentials
|
||||
assistant.google:
|
||||
|
||||
music.mopidy: # Or music.mpd
|
||||
# IP/hostname of the MPD/Mopidy server
|
||||
host: 192.168.1.2
|
||||
```
|
||||
|
||||
Note that `flask` is a required dependency to run the web server (``pip install flask``). `websockets` (``pip install websockets``) and ``redis`` (``pip install redis``) are optional dependency but I'd recommend to install them as well. Redis in particular is used by many components to communicate with each other, especially when they don't run in the same process, while websockets allows you to get live events on the web client.
|
||||
Now that we have our integrations configured, let's build some automation routines.
|
||||
|
||||
5. Now start Platypush:
|
||||
## Turn on the lights when I say so
|
||||
|
||||
In this case we will have to create a hook that listens to a
|
||||
[`SpeechRecognizedEvent`](https://docs.platypush.tech/platypush/events/assistant.html#platypush.message.event.assistant.SpeechRecognizedEvent)
|
||||
triggered by the assistant - for example, when we say "_OK, Google_" followed
|
||||
by "_turn on the lights_".
|
||||
|
||||
We can declare the hook in YAML format directly in the `config.yaml`, or in one
|
||||
of the files included in it through the `include:` directive:
|
||||
|
||||
```yaml
|
||||
$ platypush
|
||||
event.hook.turn_lights_on_voice_command:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
# Note that a minimal regex-like syntax is supported here.
|
||||
# This condition matches both a phrase that contains
|
||||
# "turn on the lights" and one that contains "turn on lights"
|
||||
phrase: "turn on (the)? lights"
|
||||
then:
|
||||
- action: light.hue.on
|
||||
args:
|
||||
groups:
|
||||
- Living Room
|
||||
```
|
||||
|
||||
If you want to use the web API you will first have to create a user through the web interface - just head to `http://your-host:8008/` and create the user.
|
||||
You will then have to generate a token for your new user that can be used for API calls. You can either do it from the web panel (Settings -> Generate token) or command line:
|
||||
Or we can declare the hook in a Python script - you just have to create a `.py`
|
||||
file (e.g. `lights.py`) under a `scripts` directory located under the same
|
||||
folder as your `config.yaml`:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' -d '
|
||||
{
|
||||
"username": "your-user",
|
||||
"password": "your-pass"
|
||||
}
|
||||
' http://localhost:8008/auth
|
||||
```python
|
||||
from platypush import run, when
|
||||
from platypush.events.assistant import SpeechRecognizedEvent
|
||||
|
||||
@when(SpeechRecognizedEvent, phrase="turn on (the)? lights")
|
||||
def lights_on_voice_command(): # Also accepts an optional `event` argument
|
||||
run('light.hue.on', groups=['Living Room'])
|
||||
```
|
||||
|
||||
You can then store this token in an environment variable (e.g. `$PP_TOKEN`) and include it in your API calls over the `Authorization: Bearer` header.
|
||||
Or, using the `get_plugin` API:
|
||||
|
||||
Note: if you have authentication issues with the Hue bridge, press the physical connect button on the bridge and restart the application.
|
||||
```python
|
||||
from platypush import get_plugin, when
|
||||
from platypush.events.assistant import SpeechRecognizedEvent
|
||||
|
||||
6. Try to send commands to your lights:
|
||||
|
||||
```shell
|
||||
curl -XPOST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $PP_TOKEN" \
|
||||
-d '{"type":"request", "action":"light.hue.on"}' \
|
||||
http://localhost:8008/execute
|
||||
@when(SpeechRecognizedEvent, phrase="turn on (the)? lights")
|
||||
def lights_on_voice_command():
|
||||
get_plugin('light.hue').on(groups=['Living Room'])
|
||||
```
|
||||
|
||||
Your lights should have turned on - congratulations!
|
||||
## Play the music when I say so
|
||||
|
||||
Note that each request has:
|
||||
|
||||
- The `type=request` field set
|
||||
- The action name. It will be the plugin package name followed by the name of the method in its main class, in this case `light.hue.on`
|
||||
- An optional key-valued list of method arguments named `args`
|
||||
|
||||
A Platypush response will always have a structure like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "response_id",
|
||||
"type": "response",
|
||||
"target": "target",
|
||||
"origin": "origin",
|
||||
"response": {
|
||||
"output": "The response output",
|
||||
"errors": ["The response errors"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
7. Another way to set an authentication token is by creating a global token in your `config.yaml`:
|
||||
The approach is similar for a "_play the music_" voice command. YAML:
|
||||
|
||||
```yaml
|
||||
token: your_authentication_token
|
||||
event.hook.play_music_voice_command:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
phrase: "play (the)? music"
|
||||
then:
|
||||
- action: music.mopidy.play
|
||||
```
|
||||
|
||||
If configured, the calls to the service will require this bearer token to be provided either:
|
||||
Python:
|
||||
|
||||
- As a query string parameter (`?token=your_authentication_token`)
|
||||
- As an HTTP header (`X-Token: your_authentication_token`)
|
||||
- At the root of your JSON request (attribute name: `token`)
|
||||
- On the `Authorization: Bearer` HTTP header.
|
||||
```python
|
||||
from platypush import run, when
|
||||
from platypush.events.assistant import SpeechRecognizedEvent
|
||||
|
||||
The web interface will also require basic HTTP authentication through this token.
|
||||
|
||||
8. You can also point your browser to _http://localhost:8008/_, and you should now see the web interface where you can control your lights - change colors, state, and animate them. You'll only see one tab for now as you've only configured one plugin, but once you configure more plugins your web interface may look as something [like this](https://i.imgur.com/KLGovbA.png).
|
||||
|
||||
Note that if you configured a token you'll be promped with a basic HTTP authentication. The password will be your token, any username works for now.
|
||||
|
||||
9. Check out [the plugin docs](https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html) to know more about the configuration variables or the supported methods for this plugin. The configuration values for any plugin are simply the parameters passed to its constructor. Same for the methods - just pass them on `args`:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $PP_TOKEN" \
|
||||
-d '{"type":"request", "target":"your_device_id", "action":"light.hue.on", "args": {"groups":["Bedroom"]}}' \
|
||||
http://localhost:8008/execute
|
||||
@when(SpeechRecognizedEvent, phrase="play (the)? music")
|
||||
def lights_on_voice_command():
|
||||
run('music.mopidy.play')
|
||||
```
|
||||
|
||||
10. Connect the action to your smart assistant now. Follow the steps on the [Google website](https://developers.google.com/assistant/sdk/guides/library/python/) to get the assistant SDK installed and the credential file ready. Then configure your assistant backend:
|
||||
## Turn on the lights when the sun goes down
|
||||
|
||||
This example requires the [`sun`
|
||||
plugin](https://docs.platypush.tech/platypush/plugins/sun.html) configured:
|
||||
|
||||
```yaml
|
||||
backend.assistant.google:
|
||||
device_model_id: your_model_id # From your Google project configuration
|
||||
credentials_file: /path/to/your/credentials.json
|
||||
sun:
|
||||
latitude: LAT
|
||||
longitude: LONG
|
||||
```
|
||||
|
||||
11. Connect a microphone, restart the application and try to say "Ok Google" and try some basic interaction with the assistant. If everything went well, you should now be able to use the Google Assistant on your device.
|
||||
|
||||
12. Configure an event hook to run the "lights on" action whenever you say "turn on the lights":
|
||||
You can then simply subscribe to
|
||||
[`SunsetEvent`](https://docs.platypush.tech/platypush/events/sun.html#platypush.message.event.sun.SunsetEvent).
|
||||
YAML:
|
||||
|
||||
```yaml
|
||||
event.hook.LightsOnAssistantCommand:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
phrase: "turn on the lights"
|
||||
then:
|
||||
action: light.hue.on
|
||||
event.hook.sunset_lights_on:
|
||||
if:
|
||||
type: platypush.message.event.sun.SunsetEvent
|
||||
then:
|
||||
- action: light.hue.on
|
||||
```
|
||||
|
||||
Event hooks:
|
||||
Python:
|
||||
|
||||
- Start with the `event.hook.` string followed by a unique name
|
||||
- Have an `if` and `then` clause. In the `if` clause you specify the `type` of the event that will trigger the hook (event inheritance works) and, optionally, the arguments in the event that must match to fire the action. In this case, `platypush.message.event.assistant.SpeechRecognizedEvent` has a `phrase` argument that contains the phrase recognized by the assistant. If the confition matches, then the list of requests in the `then` clause will be triggered (you don't need to specify `type`, as they will always be requests, nor `target`, as it will be the local host).
|
||||
```python
|
||||
from platypush import run, when
|
||||
from platypush.events.sun import SunsetEvent
|
||||
|
||||
You can also pass (partial) regular expressions as phrase. Something like "turn on (the)? lights?" would fire the hook even if the recognized phrase is "turn on lights" or "turn on the light". You can also pass named arguments, that will be used to match parts of the phrase and can be re-used in the action:
|
||||
@when(SunsetEvent)
|
||||
def sunset_lights_on():
|
||||
run('light.hue.on')
|
||||
```
|
||||
|
||||
## Event matching and token extraction through hook templates
|
||||
|
||||
You can also operate token extraction from event arguments if the values are
|
||||
strings.
|
||||
|
||||
For example, you can use advanced pattern matching and token extraction to
|
||||
create voice assistant hooks that will match a template with parametrized field
|
||||
which will be passed as arguments to your event hook:
|
||||
|
||||
```python
|
||||
from platypush import run, when
|
||||
from platypush.events.assistant import SpeechRecognizedEvent
|
||||
|
||||
@when(SpeechRecognizedEvent, phrase='play ${title} by ${artist}')
|
||||
def on_music_play_command(event, title, artist):
|
||||
results = run(
|
||||
'music.mpd.search',
|
||||
filter={
|
||||
'artist': artist,
|
||||
'title': title,
|
||||
}
|
||||
)
|
||||
|
||||
if results:
|
||||
run('music.mpd.play', results[0]['file'])
|
||||
```
|
||||
|
||||
## Complex hook conditions
|
||||
|
||||
Your event hooks can include more complex filters too. Structured filters
|
||||
against partial event arguments are also possible, and relational operators are
|
||||
supported as well. For example:
|
||||
|
||||
```python
|
||||
from platypush import when
|
||||
from platypush.events.sensor import SensorDataChangeEvent
|
||||
|
||||
@when(SensorDataChangeEvent, data=1):
|
||||
def hook_1(event):
|
||||
"""
|
||||
Triggered when event.data == 1
|
||||
"""
|
||||
|
||||
@when(SensorDataChangeEvent, data={'state': 1}):
|
||||
def hook_2(event):
|
||||
"""
|
||||
Triggered when event.data['state'] == 1
|
||||
"""
|
||||
|
||||
@when(SensorDataChangeEvent, data={
|
||||
'temperature': {'$gt': 25},
|
||||
'humidity': {'$le': 15}
|
||||
}):
|
||||
def hook_3(event):
|
||||
"""
|
||||
Triggered when event.data['temperature'] > 25 and
|
||||
event.data['humidity'] <= 15.
|
||||
"""
|
||||
```
|
||||
|
||||
The supported relational fields are the same supported by ElasticSearch - `$gt`
|
||||
for greater than, `$lt` for lesser than, `$ge` for greater or equal, `$ne` for
|
||||
not equal, etc.
|
||||
|
||||
## Turn off the lights at 1 AM
|
||||
|
||||
We can use a `cron` for this case. YAML:
|
||||
|
||||
```yaml
|
||||
event.hook.ChangeSceneAssistantCommand:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
phrase: "set the scene on ${scene}"
|
||||
then:
|
||||
-
|
||||
action: light.hue.scene
|
||||
args:
|
||||
name: ${scene}
|
||||
cron.lights_off_night:
|
||||
# Run this every day at 1 AM
|
||||
cron_expression: '0 1 * * *'
|
||||
actions:
|
||||
- action: light.hue.off
|
||||
```
|
||||
|
||||
In the example above we store whatever is detected after "set the scene on" in a context variable named `scene`, and reuse it in the command. Note that we used `args` to specify the arguments for the invoked method.
|
||||
Python:
|
||||
|
||||
You can also run multiple actions in the same hook:
|
||||
```python
|
||||
from platypush import cron, run
|
||||
|
||||
@cron('0 1 * * *')
|
||||
def lights_off_night():
|
||||
run('light.hue.off')
|
||||
```
|
||||
|
||||
## Greet me with lights and music when I come home
|
||||
|
||||
Let's create an `at_home` procedure for this purpose. We can also use a
|
||||
text-to-speech plugin like the [`tts`
|
||||
plugin](https://docs.platypush.tech/platypush/plugins/tts.html) (it requires no
|
||||
configuration as it relies on the Google Translate frontend API, but other,
|
||||
more sophisticated plugins are also available) to have a warm voice to welcome
|
||||
us home. YAML:
|
||||
|
||||
```yaml
|
||||
event.hook.LightsOnAssistantCommand:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
phrase: "turn on the lights"
|
||||
then:
|
||||
-
|
||||
action: light.hue.on
|
||||
-
|
||||
action: shell.exec
|
||||
args:
|
||||
cmd: echo "Lights turned on" >> /your/log/file
|
||||
# Make sure that the sound plugin is also enabled, for audio processing
|
||||
sound:
|
||||
|
||||
procedure.at_home:
|
||||
- action: tts.say
|
||||
args:
|
||||
text: "Welcome home!"
|
||||
|
||||
# Get luminosity data from a sensor - e.g. LTR559
|
||||
- action: gpio.sensor.ltr559.get_data
|
||||
|
||||
# If it's lower than a certain threshold, turn on the lights.
|
||||
# Note that we can directly access attributes returned by the
|
||||
# previous request(s) as local context variables within the
|
||||
# procedure/hook/cron. In this case, `light` is an attribute returned
|
||||
# on the response of the previous command.
|
||||
|
||||
# Otherwise, you can also use the special `output` variable to get only
|
||||
# the response of the latest action, e.g. `output['light']`
|
||||
|
||||
# Also note the use of the special `if ${}` construct. It accepts
|
||||
# a snippet of Python code and it can access variables within the
|
||||
# current context.
|
||||
- if ${light is not None and light < 110}:
|
||||
- action: light.hue.on
|
||||
|
||||
- action: music.mopidy.play
|
||||
args:
|
||||
resource: "uri:to:my:favourite:playlist"
|
||||
```
|
||||
|
||||
Note how the example above uses another plugin - `shell.exec` to run a shell command. Since this plugin doesn't require any configuration, you don't have to explicitly configure it in order to use it.
|
||||
Python:
|
||||
|
||||
Also, please note that the actions executed in an event hook will be executed in parallel. If you want to execute action synchronously, consider wrapping them into a synchronous _procedure_.
|
||||
```python
|
||||
from platypush import procedure, run
|
||||
|
||||
Congratulation, you've set up your first rule! Check out the [plugins documentation](https://docs.platypush.tech/en/latest/plugins.html), the [backends documentation](https://docs.platypush.tech/en/latest/backends.html) and the [events documentation](https://docs.platypush.tech/en/latest/events.html) for the list of supported plugins, backends and events.
|
||||
@procedure("at_home")
|
||||
def at_home_proc():
|
||||
run('tts.say', text='Welcome home!')
|
||||
|
||||
# Procedures
|
||||
luminosity = run('gpio.sensor.ltr559.get_data').get('light', 0)
|
||||
if luminosity < 110:
|
||||
run('light.hue.on')
|
||||
|
||||
As I mentioned above, event hooks allow you to run multiple actions in parallel. Sometimes however you want to run the commands in a series, especially if you want to reuse parts of the output from the previous commands. Let's suppose for instance that we want our assistant to tell us the weather in our city using the embedded weather forecast plugin, if we're not that happy with the accuracy of the Google weather forecast. That would require to run an action to get the forecast, and another action to say out the weather conditions.
|
||||
run('music.mopidy.play', resource='uri:to:my:favourite:playlist')
|
||||
```
|
||||
|
||||
Start by configuring the weather forecast plugin:
|
||||
You can then call the procedure from a hook or another script:
|
||||
|
||||
```python
|
||||
from platypush import run
|
||||
|
||||
run('procedure.at_home')
|
||||
```
|
||||
|
||||
Or, from YAML:
|
||||
|
||||
```yaml
|
||||
weather.forecast:
|
||||
lat: your_latitude
|
||||
long: your_longitude
|
||||
darksky_token: token # Get it from https://darksky.net/dev/register
|
||||
units: si
|
||||
procedure.some_other_procedure:
|
||||
- action: procedure.at_home
|
||||
```
|
||||
|
||||
Restart Platypush and test out the plugin with a curl call:
|
||||
Or using the API (see next section).
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $PP_TOKEN" \
|
||||
-d '{"type":"request", "target":"your_device_id", "action":"weather.forecast.get_current_weather"}' \
|
||||
http://localhost:8008/execute
|
||||
```
|
||||
|
||||
The response will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 123,
|
||||
"type": "response",
|
||||
"target": "device_id",
|
||||
"origin": "device_id",
|
||||
"response": {
|
||||
"output": {
|
||||
"...":"...",
|
||||
"summary": "Clear",
|
||||
"...":"..."
|
||||
},
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now configure a synchronous procedure that gets the forecast and uses the text-to-speech plugin to tell you about the current conditions:
|
||||
|
||||
```yaml
|
||||
procedure.sync.SayWeatherForecast:
|
||||
-
|
||||
action: shell.exec
|
||||
args:
|
||||
cmd: echo "Phrase recognized: ${event['args']['phrase']}" >> /your/log/file
|
||||
-
|
||||
action: weather.forecast.get_current_weather
|
||||
-
|
||||
action: tts.say
|
||||
args:
|
||||
phrase: ${summary}
|
||||
```
|
||||
|
||||
We declared the procedure as synchronous (use the `async` keyword instead of `sync` if you want to run the actions in parallel). Note how we used the `summary` from the `get_current_weather` action in `tts.say`. The variables returned by the previous actions become part of the _context_ for the next action. In particular, what is contained in the `output` is expanded into local variables that you can reuse through the `${}` notation.
|
||||
|
||||
You can also access the original event from the context. The context is just a key-value map that contains all the variables relevant to the executed procedure, and you can use the `${}` notation to wrap any Python snippet to manipulate it and access it
|
||||
|
||||
Now configure an event hook to trigger the procedure through an assistant command:
|
||||
|
||||
```yaml
|
||||
event.hook.WeatherAssistantCommand:
|
||||
if:
|
||||
type: platypush.message.event.assistant.SpeechRecognizedEvent
|
||||
phrase: "how is the weather"
|
||||
then:
|
||||
action: procedure.SayWeatherForecast
|
||||
```
|
||||
|
||||
You can also pass arguments to a procedure:
|
||||
|
||||
```yaml
|
||||
procedure.sync.LogEvent:
|
||||
-
|
||||
action: shell.exec
|
||||
args:
|
||||
cmd: echo "Event received on ${hostname} ${event}" >> /your/log/file
|
||||
|
||||
event.hook.OnEvent:
|
||||
if:
|
||||
type: platypush.message.event.Event
|
||||
then:
|
||||
action: procedure.LogEvent
|
||||
args:
|
||||
hostname: your_host
|
||||
```
|
||||
|
||||
## For loops
|
||||
|
||||
You can declare `for` loops in a procedure to iterate over values. Let's still use the weather forecast plugin to get an hourly forecast. That call will return a list of values under `data` in the response. We want to log those values to a file:
|
||||
|
||||
```yaml
|
||||
procedure.sync.LogHourlyForecast:
|
||||
-
|
||||
action: weather.forecast.get_hourly_forecast
|
||||
- for hour_data in ${data}:
|
||||
-
|
||||
action: shell.exec
|
||||
args:
|
||||
cmd: echo "${hour_data['time']}: ${hour_data['summary']}" >> /your/log/file
|
||||
```
|
||||
|
||||
`for` will execute the nested actions synchronously - use the `fork` keyword instead if you want to run the nested action in parallel.
|
||||
|
||||
## If conditions
|
||||
|
||||
You can also set up `if` conditions in your procedure, to only execute some actions if some conditions are met (you can use snippets of Python code for expressing the conditions):
|
||||
|
||||
```yaml
|
||||
procedure.sync.LogHourlyForecast:
|
||||
- action: weather.forecast.get_current_weather
|
||||
- if ${summary == "Clear"}:
|
||||
-
|
||||
action: tts.say
|
||||
args:
|
||||
phrase: The weather is good outside
|
||||
```
|
||||
|
||||
The syntax also supports an `else` statement that will be executed if the condition is not matched:
|
||||
|
||||
```yaml
|
||||
procedure.sync.LogHourlyForecast:
|
||||
- action: weather.forecast.get_current_weather
|
||||
- if ${summary == "Clear"}:
|
||||
-
|
||||
action: tts.say
|
||||
args:
|
||||
phrase: The weather is clear outside
|
||||
- else:
|
||||
-
|
||||
action: tts.say
|
||||
args:
|
||||
phrase: The weather is not clear outside
|
||||
```
|
||||
|
||||
And you can also build a more complex logic with nested `if-else` statements like in a real programming language.
|
||||
|
||||
You've now got all the basic ingredients to configure your own plugins and write you own rules. You can proceed looking at some examples with the available:
|
||||
|
||||
* [Plugins](plugins)
|
||||
* [Backends](backends)
|
||||
|
||||
# Backends
|
||||
|
||||
Backend configurations start with `backend.` in the `config.yaml`.
|
||||
|
||||
## HTTP service configuration
|
||||
|
||||
Already covered in [quick start](#quick-start).
|
||||
|
||||
## PushBullet configuration
|
||||
|
||||
You will need:
|
||||
|
||||
* Your PushBullet access token (create one [here](https://www.pushbullet.com/#settings/account));
|
||||
* The name of the (virtual) PushBullet device used to listen for events (create one [here](https://www.pushbullet.com/#devices)).
|
||||
|
||||
```yaml
|
||||
backend.pushbullet:
|
||||
token: PUSHBULLET_TOKEN
|
||||
device: platypush
|
||||
```
|
||||
|
||||
## Apache Kafka configuration
|
||||
|
||||
This would be a sample snippet for an Apache Kafka configuration:
|
||||
|
||||
```yaml
|
||||
backend.kafka:
|
||||
server: server:9092 # Kafka server and port
|
||||
topic: platypush # Topic prefix. Note: platypush will create a topic for each device named <topic>.<device_id>
|
||||
```
|
||||
|
||||
## Google Assistant configuration
|
||||
|
||||
Follow the steps on the [Google Assistant SDK](https://github.com/googlesamples/assistant-sdk-python/tree/master/google-assistant-sdk) page and get the assistant sample running on your machine.
|
||||
|
||||
Afterwards, you can enable custom speech-triggered actions on Platypush by just enabling the assistant backend:
|
||||
|
||||
```yaml
|
||||
backend.assistant.google:
|
||||
disabled: False
|
||||
```
|
||||
|
||||
## Flic buttons configuration
|
||||
|
||||
[Flic buttons](https://flic.io/) are a quite cool and useful accessory. You can pair them with your phone over Bluetooth and they can trigger anything on your device - play music on Spotify, start a timer, trigger a Tasker task, snooze alarms, trigger fake phone calls...
|
||||
|
||||
A [beta SDK](https://github.com/50ButtonsEach/fliclib-linux-hci) is available as well that allows you to pair the buttons to any bluetooth device, not necessarily running the Flic app.
|
||||
|
||||
Install the SDK and run the `flicd` server on your machine. You can then enable the Flic plugin:
|
||||
|
||||
```yaml
|
||||
backend.button.flic:
|
||||
server: localhost
|
||||
|
||||
```
|
||||
|
||||
By the way, the Flic app only supports a maximum of three events per button - short press, long press and double press. With the Platypush plugin you can trigger countless actions by configuring multiple combinations of short and long presses - provided that you can remember them.
|
||||
|
||||
# Mobile notification mirroring
|
||||
|
||||
If you enable the PushBullet backend and [notification mirroring](https://docs.pushbullet.com/#mirrored-notifications) on your Android or iOS device, the PushBullet backend will be able to post events to Platypush if you receive notifications on your mobile, and you can react on those. You can for instance configure Platypush to log specific Whatsapp messages on a local db, read out the headlines of your favourite news app when you receive a push, connect custom Tasker events through [AutoNotification](https://play.google.com/store/apps/details?id=com.joaomgcd.autonotification&hl=en), mirror the notifications on a display connected to a RaspberryPi, and so on.
|
||||
|
||||
Example configuration that logs all the notifications mirrored from your device on a MySQL database:
|
||||
|
||||
```yaml
|
||||
event.hook.OnMobileNotification:
|
||||
if:
|
||||
type: platypush.message.event.pushbullet.PushbulletEvent
|
||||
push_type: mirror
|
||||
then:
|
||||
-
|
||||
action: db.insert
|
||||
args:
|
||||
engine: mysql+mysqlconnector://user:password@localhost/notifications
|
||||
encoding: utf-8
|
||||
table: notifications
|
||||
records:
|
||||
-
|
||||
source_device_id: ${source_device_iden}
|
||||
source_user_id: ${source_user_iden}
|
||||
package_name: ${package_name}
|
||||
application_name: ${application_name}
|
||||
title: ${title}
|
||||
body: ${body}
|
||||
icon: ${icon}
|
||||
```
|
||||
|
||||
# Include directive
|
||||
|
||||
Your config.yaml file can easily become quite large if you have customized to automate all of your voice assistant, buttons, lights, database and media control events.
|
||||
|
||||
To keep the configuration neat and manageable, and/or keep some configuration parts shared among multiple nodes, you may want to use the built-in `include` directive to import some pieces of configuration from other files.
|
||||
|
||||
```yaml
|
||||
include:
|
||||
- include/backends.yaml
|
||||
- include/assistant_common.yaml
|
||||
```
|
||||
|
||||
Now you can take a more in-depth to look to the available:
|
||||
|
||||
- [Plugins](plugins)
|
||||
- [Backends](backends)
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
A very robust and scalable way to run Platypush is to build a Docker container image out of it.
|
||||
|
||||
The project comes with `platydock`, that will be installed in your prefix upon Platypush installation. You can use it to build, remove, start, stop and list Platypush container images.
|
||||
Note that both `docker` and `platypush` need to be installed on your host system for these steps to work.
|
||||
|
||||
Example:
|
||||
|
||||
1. Create your own `config.yaml` file for a Platypush instance:
|
||||
|
||||
```yaml
|
||||
device_id:
|
||||
# NOTE: It's mandatory to specify a device_id when building
|
||||
# a Platypush container. Containers will have their hostname
|
||||
# dynamycally set by Docker and therefore won't be a reliable default
|
||||
my-image
|
||||
|
||||
logging:
|
||||
# Log to container stdout/stderr
|
||||
level: INFO
|
||||
|
||||
main.db:
|
||||
engine: sqlite:////usr/local/share/platypush/platypush.db
|
||||
|
||||
backend.pushbullet:
|
||||
token: YOUR_TOKEN
|
||||
device: platypush/your_device
|
||||
|
||||
backend.redis:
|
||||
# Redis and Platypush can't run in the same Docker container, but platydock will
|
||||
# take care of pulling a Redis docker image and connect it to your container.
|
||||
redis_args:
|
||||
host: redis
|
||||
|
||||
backend.mqtt:
|
||||
host: YOUR_MQTT_HOST
|
||||
|
||||
backend.tcp:
|
||||
port: 3333
|
||||
|
||||
backend.websocket:
|
||||
port: 8765
|
||||
|
||||
backend.http:
|
||||
port: 8008
|
||||
|
||||
redis:
|
||||
host: redis
|
||||
|
||||
tts.google:
|
||||
language: en-US
|
||||
|
||||
ifttt:
|
||||
ifttt_key: YOUR_IFTTT_KEY
|
||||
|
||||
autoremote:
|
||||
devices:
|
||||
OnePlus6:
|
||||
key: KEY_1
|
||||
PixelC:
|
||||
key: KEY_2
|
||||
```
|
||||
|
||||
2. Build a Docker image out of the configuration file using `platydock`:
|
||||
|
||||
```shell
|
||||
platydock build -c /path/to/config.yaml
|
||||
```
|
||||
|
||||
Note that `platydock` will inspect your configuration file and automatically identify required dependencies and exposed ports.
|
||||
|
||||
3. Start the new image:
|
||||
|
||||
```shell
|
||||
platydock start my-image
|
||||
```
|
||||
|
||||
4. After it's started up, if everything went smooth, you should already be able to send messages to the new container over the available exposed service. For example, over JSON-RPC:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "action":"shell.exec", "args": {"cmd":"hostname"}}' \
|
||||
http://localhost:8008/execute | jq
|
||||
```
|
||||
|
||||
You can also easily inspect the application logs:
|
||||
|
||||
```shell
|
||||
docker logs my-image
|
||||
```
|
||||
|
||||
And you can also pass extra options to `platydock start`, that will be transparently passed to `docker run`, for instance `--add-host=`, `--device=` etc. Note that the exposed ports are automatically added to the container based on the configuration and by default will be exposed to the same port number on the host (e.g. 8008 on the container is published to 8008 on the host). You can override it through the `-p` option passed to `platypush start` (e.g. `-p 18008:8008` will map the port 8008 on the container to 18008 on the host).
|
||||
|
||||
Also note that `platypush start` will start both your Platypush container and the support Redis container.
|
||||
|
||||
5. Check the installed Platypush images:
|
||||
|
||||
```shell
|
||||
platydock ls [filter]
|
||||
```
|
||||
|
||||
6. Stop a running instance:
|
||||
|
||||
```shell
|
||||
platydock stop my-image
|
||||
```
|
||||
|
||||
7. Remove an image:
|
||||
|
||||
```shell
|
||||
platydock rm my-image
|
||||
```
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
You can run a Platypush instance in a [Python virtual environment](https://docs.python-guide.org/dev/virtualenvs/). There are several advantages for this option:
|
||||
|
||||
* You won't have to install dependencies at system level and you can easily create instances in user space
|
||||
* The available tools will take care for the required dependencies depending on your configuration. Just write your `config.yaml` and Platypush will figure out which dependencies are required by the plugins you wish to use
|
||||
* You can easily copy environments to other machines, as all the required dependencies and configuration for the application to run will all be inside of the `~/.local/share/platypush/<my-device>` folder
|
||||
* You can create multiple instances on the same machine and easily start, stop and remove them. Note however that this option will use more disk space compared to a system installation if you decide to use virtual environments: each environment will install its own set of dependencies instead of relying on those available on the system.
|
||||
|
||||
The project comes with `platyvenv`, a script that should be installed in your bin path upon Platypush installation.
|
||||
You can use it to build, remove, start, stop and list Platypush virtual environments.
|
||||
Note that both `python-venv` and `platypush` need to be installed on your host system for these steps to work.
|
||||
|
||||
Example:
|
||||
|
||||
1. Create your own `config.yaml` file for a Platypush instance:
|
||||
|
||||
```yaml
|
||||
device_id:
|
||||
my-device
|
||||
|
||||
logging:
|
||||
level: INFO
|
||||
|
||||
main.db:
|
||||
engine: sqlite:////home/user/.local/share/platypush/venv/my-device/usr/share/db/platypush.db
|
||||
|
||||
backend.pushbullet:
|
||||
token: YOUR_TOKEN
|
||||
device: platypush/your_device
|
||||
|
||||
backend.redis:
|
||||
redis_args:
|
||||
host: localhost
|
||||
port: 6397
|
||||
|
||||
backend.mqtt:
|
||||
host: YOUR_MQTT_HOST
|
||||
|
||||
backend.tcp:
|
||||
port: 3333
|
||||
|
||||
backend.websocket:
|
||||
port: 8765
|
||||
|
||||
backend.http:
|
||||
port: 8008
|
||||
|
||||
tts.google:
|
||||
language: en-US
|
||||
|
||||
ifttt:
|
||||
ifttt_key: YOUR_IFTTT_KEY
|
||||
|
||||
autoremote:
|
||||
devices:
|
||||
OnePlus6:
|
||||
key: KEY_1
|
||||
PixelC:
|
||||
key: KEY_2
|
||||
```
|
||||
|
||||
2. Build a virtual environment out of the configuration file using `platyvenv`:
|
||||
|
||||
```shell
|
||||
platyvenv build -c /path/to/config.yaml
|
||||
```
|
||||
|
||||
Note that `platyvenv` will inspect your configuration file, automatically identify the required dependencies and install them in your virtual environment.
|
||||
|
||||
3. Start the new environment:
|
||||
|
||||
```shell
|
||||
platyvenv start my-device
|
||||
```
|
||||
|
||||
The output of the Platypush service is printed on the terminal.
|
||||
|
||||
4. After it's started up, if everything went smooth, you should already be able to send messages to the new environment over the available exposed service. For example, over JSON-RPC:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "action":"shell.exec", "args": {"cmd":"hostname"}}' \
|
||||
http://localhost:8008/execute | jq
|
||||
```
|
||||
|
||||
6. Stop a running instance:
|
||||
|
||||
```shell
|
||||
platyvenv stop my-device
|
||||
```
|
||||
|
||||
7. Remove an environment:
|
||||
|
||||
```shell
|
||||
platyvenv rm my-device
|
||||
```
|
73
The-Web-interface.md
Normal file
73
The-Web-interface.md
Normal file
|
@ -0,0 +1,73 @@
|
|||
# The Web interface
|
||||
|
||||
## Other Web panels
|
||||
|
||||
Besides the built-in panels that we've already seen in the other sections,
|
||||
Several integrations add their own feature-rich panels to the Web view, turning
|
||||
Platypush into a gateway to all of your services - from Zigbee sensors, to
|
||||
media players and services, to your music cloud, and more.
|
||||
|
||||
For example, the music view is available to most of the `music` plugins.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Another example is the camera panel, to monitor your cameras, get stand-alone
|
||||
feed URLs, and take photos. This becomes available in the UI if you enable at
|
||||
least a `camera` plugin.
|
||||
|
||||

|
||||
|
||||
If you enabled at least one local `media` plugin (like `media.vlc`,
|
||||
`media.mplayer` etc.) then you'll also unlock the media UI, which allows you to
|
||||
index, search, view and cast media files under the configured `media_dirs`, and
|
||||
it also integrates with other configured/supported backends such as YouTube,
|
||||
Plex and Jellyfin.
|
||||
|
||||

|
||||
|
||||
## Dashboards
|
||||
|
||||
The web service also provides means for the user to create [custom
|
||||
dashboards](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/dashboard.xml)
|
||||
that can be used to show information from multiple sources on a large screen.
|
||||
|
||||

|
||||
|
||||
## PWA support
|
||||
|
||||
Note that having the web application served over SSL is a requirement for the
|
||||
PWA (progressive web app) to work. The Platypush PWA allows you to install a
|
||||
Platypush native-like client on your mobile devices if you don't want to use the
|
||||
full Android app.
|
||||
|
||||
## Mobile app
|
||||
|
||||
An [official Android
|
||||
app](https://f-droid.org/en/packages/tech.platypush.platypush/) is provided on
|
||||
the F-Droid store. It allows to easily discover and manage multiple Platypush
|
||||
services on a network through the web interface, and it easily brings the power
|
||||
of Platypush to your fingertips.
|
||||
|
||||
## Browser extension
|
||||
|
||||
A [browser extension](https://git.platypush.tech/platypush/platypush-webext) is
|
||||
available for [Chrome](https://git.platypush.tech/platypush/platypush-webext)
|
||||
and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/platypush/).
|
||||
|
||||
The browser extension allows you to run Platypush actions and procedures
|
||||
directly from your browser, associate keybindings with them, so you can run
|
||||
your favourite routines with a few keystrokes anywhere in your browser, and
|
||||
provides an advanced API to interact with the Web pages you visit - for
|
||||
example, you can build an action that gets the content of a page you're
|
||||
visiting and uses Platypush to distill it in readable format, or send the URL
|
||||
to another service.
|
||||
|
39
Variables.md
Normal file
39
Variables.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Variables
|
||||
|
||||
You can persist custom state across runs through _variables_.
|
||||
|
||||
Variables will be stored on the application database and can model any kind of
|
||||
state that you want to share across different pieces of automation.
|
||||
|
||||
For example, you can set a `AT_HOME` variable in the previous
|
||||
`procedure.at_home` - and, conversely, you may want to unset it if you have a
|
||||
`procedure.outside_home` when that procedure is called.
|
||||
|
||||
```python
|
||||
from platypush import Variable, procedure
|
||||
|
||||
@procedure
|
||||
def at_home():
|
||||
# ...
|
||||
Variable('AT_HOME').set(True)
|
||||
|
||||
@procedure
|
||||
def outside_home():
|
||||
# ...
|
||||
Variable('AT_HOME').set(False)
|
||||
```
|
||||
|
||||
Within another procedure or hook, for example, you may want to turn on the
|
||||
lights only if you're at home:
|
||||
|
||||
```python
|
||||
from platypush import Variable, procedure, run
|
||||
|
||||
@procedure
|
||||
def my_procedure():
|
||||
# ...
|
||||
at_home = Variable('AT_HOME')
|
||||
|
||||
if at_home.get():
|
||||
run('light.hue.on')
|
||||
```
|
|
@ -1,62 +0,0 @@
|
|||
You can also write your own backends, where a backend is nothing but a thread that listens for messages on a certain channel and pokes the main app whenever it receives one.
|
||||
|
||||
1. Create your backend directory under `platypush/backend` (e.g. `voicemail`)
|
||||
|
||||
2. In the case above, `platypush.backend.voicemail` will be your package name.
|
||||
|
||||
3. Create an `__init__.py` under `platypush/backend/voicemail`.
|
||||
|
||||
4. If your module is `voicemail`, then its main class should be named `VoicemailBackend`.
|
||||
|
||||
5. The configuration for your module will be read from a section named `backend.voicemail` from your `config.yaml`. Its values will be passed over the backend constructor arguments.
|
||||
|
||||
6. Implement the `run` method. Since a backend is a thread that polls for new messages on a channel, this will be the thread main method. `send_message` should call `self.on_message` at the end to post a new message to the application.
|
||||
|
||||
7. Implement the `send_message` method. This method will be called whenever the application needs to send a new message through `send_request` and `send_response`. You should never call `send_message` directly.
|
||||
|
||||
The `__init__.py` will look like this:
|
||||
|
||||
```python
|
||||
from .. import Backend
|
||||
|
||||
class VoicemailBackend(Backend)
|
||||
def __init__(self, phone)
|
||||
super().__init__()
|
||||
self.phone = phone
|
||||
self.voicemail = Voicemail(...)
|
||||
|
||||
def send_message(self, msg):
|
||||
self.voicemail.save_msg(msg)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
msg = self.voicemail.poll()
|
||||
self.on_message(msg)
|
||||
```
|
||||
|
||||
8. Add a `manifest.yaml` file to the same folder. Example template:
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
type: backend
|
||||
package: platypush.backend.voicemail
|
||||
|
||||
# Events launched by the extension
|
||||
events:
|
||||
platypush.message.event.voicemail.OnVoicemailMessage: When a message is received
|
||||
|
||||
# Installation requirements
|
||||
install:
|
||||
# List of system-wide requirements on Debian/Ubuntu and derived
|
||||
apt:
|
||||
- sudo
|
||||
# List of system-wide requirements on Arch Linux and derived
|
||||
pacman:
|
||||
- sudo
|
||||
# List of pip dependencies
|
||||
pip:
|
||||
- requests
|
||||
# Extra commands to run after the dependencies are installed
|
||||
exec:
|
||||
- sudo systemctl enable my-service
|
||||
```
|
|
@ -1,114 +0,0 @@
|
|||
Writing your own `platypush` plugin, that would execute your own custom logic whenever a bullet with your plugin name is received, is a very simple task.
|
||||
|
||||
1. Create your plugin directory under `platypush/plugins` (e.g. `light/batsignal`).
|
||||
|
||||
2. In the case above, `platypush.plugins.light.batsignal` will be your package name.
|
||||
|
||||
3. Create an `__init__.py` under `platypush/plugins/light/batsignal`.
|
||||
|
||||
4. If your module is `light/batsignal`, then its main class should be named `LightBatsignalPlugin`.
|
||||
|
||||
5. The configuration for your module will be read from a section named `light.batsignal` from your `config.yaml`. Its values will passed over the plugin constructor arguments.
|
||||
|
||||
The `__init__.py` will look like this:
|
||||
|
||||
```python
|
||||
import batman
|
||||
|
||||
# Decorator used to identify class methods to be exposed as plugin actions
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.light import LightPlugin
|
||||
|
||||
class LightBatsignalPlugin(LightPlugin):
|
||||
def __init__(self, intensity=100):
|
||||
super().__init__()
|
||||
self.batsignal = batman.Batsignal(intensity)
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
return {'status': self.batsignal.status()}
|
||||
|
||||
@action
|
||||
def on(self, urgent=False):
|
||||
if urgent:
|
||||
self.batsignal.notify_robin()
|
||||
|
||||
self.batsignal.on()
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def off(self):
|
||||
self.batsignal.off()
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def toggle(self):
|
||||
if self.batsignal.status().on:
|
||||
self.batsignal.off()
|
||||
else:
|
||||
self.batsignal.on()
|
||||
|
||||
return self.status()
|
||||
|
||||
```
|
||||
|
||||
6. Create a `manifest.yaml` file in the same directory that defines your plugin. Template:
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
type: plugin
|
||||
package: platypush.plugins.light.batsignal
|
||||
|
||||
# Events launched by the extension
|
||||
events:
|
||||
platypush.message.event.batsignal.SignalOnEvent: When the signal goes on
|
||||
platypush.message.event.batsignal.SignalOffEvent: When the signal goes off
|
||||
|
||||
# Installation requirements
|
||||
install:
|
||||
# List of system-wide requirements on Debian/Ubuntu and derived
|
||||
apt:
|
||||
- sudo
|
||||
# List of system-wide requirements on Arch Linux and derived
|
||||
pacman:
|
||||
- sudo
|
||||
# List of pip dependencies
|
||||
pip:
|
||||
- requests
|
||||
# Extra commands to run after the dependencies are installed
|
||||
exec:
|
||||
- sudo systemctl enable my-service
|
||||
```
|
||||
|
||||
8. Rebuild and reinstall `platypush` if required and relaunch it.
|
||||
|
||||
9. Test your new plugin by sending some requests to it:
|
||||
|
||||
* Via cURL:
|
||||
|
||||
```shell
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-d '{"type":"request", "target":"hostname", "action":"light.batsignal.on"}' \
|
||||
http://hostname:8008/execute
|
||||
```
|
||||
|
||||
* Via TCP backend:
|
||||
|
||||
```shell
|
||||
echo -n '{"type":"request", "target":"hostname", "action":"light.batsignal.on"}' | nc hostname 3333
|
||||
```
|
||||
|
||||
* Via Redis backend:
|
||||
|
||||
```shell
|
||||
echo "RPUSH platypush_bus_mq '{\"type\":\"request\",\"target\":\"turing\",\"action\":\"light.batsignal.on\"}'" | redis-cli
|
||||
```
|
||||
|
||||
* Via websocket backend:
|
||||
|
||||
```shell
|
||||
wscat -w 0 -c 'ws://turing:8765' -x '{"type":"request", "target":"hostname", "action":"light.batsignal.on"}'
|
||||
```
|
||||
|
||||
Or you can even experiment and connect [Node-Red](https://nodered.org) components and flows to trigger your custom action.
|
||||
|
1
index.md
Symbolic link
1
index.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
Home.md
|
Loading…
Add table
Reference in a new issue