From 5415f0ccf3dbc775a98a80a01e25f9ecfac84c06 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Tue, 9 May 2023 02:54:02 +0200 Subject: [PATCH] Updated README --- README.md | 727 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 372 insertions(+), 355 deletions(-) diff --git a/README.md b/README.md index 8ce79eb61..d9177d089 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,16 @@ Platypush [![Build Status](https://ci.platypush.tech/status.svg)](https://ci.platypush.tech/latest.log) [![Documentation Status](https://ci.platypush.tech/docs/status.svg)](https://ci.platypush.tech/docs/latest.log) [![pip version](https://img.shields.io/pypi/v/platypush.svg?style=flat)](https://pypi.python.org/pypi/platypush/) -[![License](https://img.shields.io/github/license/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/-/blob/master/LICENSE.txt) -[![Last Commit](https://img.shields.io/github/last-commit/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/-/commits/master/) +[![License](https://img.shields.io/github/license/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/src/branch/master/LICENSE.txt) +[![Last Commit](https://img.shields.io/github/last-commit/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/commits/branch/master) [![Join chat on Matrix](https://img.shields.io/matrix/:platypush?server_fqdn=matrix.platypush.tech)](https://matrix.to/#/#platypush:matrix.platypush.tech) -[![Contributions](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://git.platypush.tech/platypush/platypush/-/blob/master/CONTRIBUTING.md) +[![Contributions](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://git.platypush.tech/platypush/platypush/src/branch/master/CONTRIBUTING.md) -- [Architecture](#architecture) - * [Plugins](#plugins) - * [Actions](#actions) - * [Backends](#backends) - * [Events](#events) - * [Hooks](#hooks) - * [Procedures](#procedures) - * [Cronjobs](#cronjobs) - * [The web interface](#the-web-interface) + + [Useful links](#useful-links) +- [Introduction](#introduction) + + [What it can do](#what-it-can-do) - [Installation](#installation) * [System installation](#system-installation) + [Install through `pip`](#install-through-pip) @@ -31,17 +25,27 @@ Platypush + [Check the instructions reported in the documentation](#check-the-instructions-reported-in-the-documentation) * [Virtual environment installation](#virtual-environment-installation) * [Docker installation](#docker-installation) +- [Architecture](#architecture) + * [Plugins](#plugins) + * [Actions](#actions) + * [Backends](#backends) + * [Events](#events) + * [Hooks](#hooks) + * [Procedures](#procedures) + * [Cronjobs](#cronjobs) + * [Entities](#entities) + * [The web interface](#the-web-interface) - [Mobile app](#mobile-app) - [Tests](#tests) - [Funding](#funding) +#### Useful links - Recommended read: [**Getting started with Platypush**](https://blog.platypush.tech/article/Ultimate-self-hosted-automation-with-Platypush). -- The [blog](https://blog.platypush.tech) is in general a good place to get - more insights on what you can build with it and inspiration about possible - usages. +- The [blog](https://blog.platypush.tech) is a good place to get more insights + and inspiration on what you can build. - The [wiki](https://git.platypush.tech/platypush/platypush/wiki) also contains many resources on getting started. @@ -49,19 +53,19 @@ Platypush - Extensive documentation for all the available integrations and messages [is available](https://docs.platypush.tech/). -- If you have issues/feature requests/enhancement ideas please [create an - issue](https://git.platypush.tech/platypush/platypush/-/issues). - -- A [Reddit channel](https://www.reddit.com/r/platypush) is also available for - more general questions. +- If you have issues/feature requests/enhancements please [create an + issue](https://git.platypush.tech/platypush/platypush/issues). - A [Matrix instance](https://matrix.to/#/#platypush:matrix.platypush.tech) is - also available if you are looking for more interactive support. + available if you are looking for interactive support. ---- +- A [Reddit channel](https://www.reddit.com/r/platypush) is available for + general questions. -Platypush is a general-purpose extensible platform for automation and -integration across multiple services and devices. +## Introduction + +Platypush is a general-purpose extensible platform for automation across +multiple services and devices. It enables users to create their own self-hosted pieces of automation based on events (*if this happens then do that*) @@ -70,16 +74,15 @@ everything you need to visualize and control under one roof. It takes some concepts from [IFTTT](https://ifttt.com), [Tasker](https://tasker.joaoapps.com/), [Microsoft -Flow](https://flow.microsoft.com), [PushBullet](https://pushbullet.com) and -[Home Assistant](https://www.home-assistant.io/) to provide an environment -where the user can easily connect things together. +Flow](https://flow.microsoft.com) and [Home +Assistant](https://www.home-assistant.io/) to provide an environment where the +user can easily connect things together. -Its ideal home is a single-board computer like a RaspberryPi that you can -configure to orchestrate any home automation and cloud automation in your own -living room or garage, but it can easily run on any device that can run a -Python interpreter, and the bar for the hardware requirements is very low as -well - I use it to run pieces of automation on devices as powerful as a -RaspberryPi Zero or an old Nokia N900 with Linux. +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 zero, to an +old smartphone, to a beefy server. + +#### What it can do You can use Platypush to do things like: @@ -110,323 +113,7 @@ You can use Platypush to do things like: - [Create a custom single hub for Zigbee and Z-Wave smart devices](https://blog.platypush.tech/article/Transform-a-RaspberryPi-into-a-universal-Zigbee-and-Z-Wave-bridge) - Build your own web dashboard with calendar, weather, news and music controls (basically, anything that has a Platypush web widget) -- ...and much more (basically, anything that comes with a [Platypush plugin](https://docs.platypush.tech/en/latest/plugins.html)) - -## Architecture - -The architecture of Platypush consists of a few simple pieces, orchestrated by -a configuration file stored by default under -[`~/.config/platypush/config.yaml`](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/config.yaml): - -### Plugins - -[Full list](https://docs.platypush.tech/en/latest/plugins.html) - -Plugins are integrations that do things - like [modify -files](https://docs.platypush.tech/en/latest/platypush/plugins/file.html), -[train and evaluate machine learning -models](https://docs.platypush.tech/en/latest/platypush/plugins/tensorflow.html), -[control -cameras](https://docs.platypush.tech/en/latest/platypush/plugins/camera.pi.html), -[read -sensors](https://docs.platypush.tech/en/latest/platypush/plugins/gpio.sensor.dht.html), -[parse a web -page](https://docs.platypush.tech/en/latest/platypush/plugins/http.webpage.html), -[control -lights](https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html), -[send -emails](https://docs.platypush.tech/en/latest/platypush/plugins/mail.smtp.html), -[control -Chromecasts](https://docs.platypush.tech/en/latest/platypush/plugins/media.chromecast.html), -[run voice -queries](https://docs.platypush.tech/en/latest/platypush/plugins/assistant.google.html), -[handle torrent -transfers](https://docs.platypush.tech/en/latest/platypush/plugins/torrent.html) -or control -[Zigbee](https://docs.platypush.tech/en/latest/platypush/plugins/zigbee.mqtt.html) -or [Z-Wave](https://docs.platypush.tech/en/latest/platypush/plugins/zwave.html) -devices. - -The configuration of a plugin matches one-on-one that of its documented class -constructor, so it's very straightforward to write a configuration for a plugin -by reading its documentation: - -```yaml -light.hue: - # Groups that will be controlled by default - groups: - - Living Room - - Hall -``` - -### Actions - -Plugins expose *actions*, that match one-on-one the plugin class methods -denoted by `@action`, so it's very straightforward to invoke plugin actions by -just reading the plugin documentation. They can be invoked directly from your -own scripts or they can be sent to the platform through any supported channel -as simple JSON messages: - -```json -{ - "type": "request", - "action": "light.hue.on", - "args": { - "lights": ["Entrance Bulb"] - } -} -``` - -### Backends - -[Full list](https://docs.platypush.tech/en/latest/backends.html) - -They are background services that either listen for messages on channels (like -an [HTTP -backend](https://docs.platypush.tech/en/latest/platypush/backend/http.html), an -[MQTT -instance](https://docs.platypush.tech/en/latest/platypush/backend/mqtt.html), a -[Kafka -instance](https://docs.platypush.tech/en/latest/platypush/backend/kafka.html), -[Pushbullet](https://docs.platypush.tech/en/latest/platypush/backend/pushbullet.html) -etc.) or monitor a device or a service for events (like a -[sensor](https://docs.platypush.tech/en/latest/platypush/backend/sensor.html), -a custom [voice -assistant](https://docs.platypush.tech/en/latest/platypush/backend/assistant.google.html), -a bridge running on a -[Zigbee](https://docs.platypush.tech/en/latest/platypush/backend/zigbee.mqtt.html) -or -[Z-Wave](https://docs.platypush.tech/en/latest/platypush/backend/zwave.html), -an [NFC card -reader](https://docs.platypush.tech/en/latest/platypush/backend/nfc.html), a -[MIDI -device](https://docs.platypush.tech/en/latest/platypush/backend/midi.html), a -[Telegram -channel](https://docs.platypush.tech/en/latest/platypush/backend/chat.telegram.html), -a [Bluetooth -scanner](https://docs.platypush.tech/en/latest/platypush/backend/bluetooth.scanner.ble.html) -etc.). - -If a backend supports the execution of requests (e.g. HTTP, MQTT, Kafka, -Websocket and TCP) then you can send requests to these services in JSON format. -For example, in the case of the HTTP backend: - -```shell - # Get a token -curl -XPOST -H 'Content-Type: application/json' -d ' - { - "username": "$YOUR_USER", - "password": "$YOUR_PASSWORD" - }' http://host:8008/auth - - # Execute a request - -curl -XPOST -H 'Content-Type: application/json' \ - -H "Authorization: Bearer $YOUR_TOKEN" -d ' - { - "type": "request", - "action": "tts.say", - "args": { - "text": "This is a test" - } - }' http://host:8008/execute -``` - -### Events - -[Full list](https://docs.platypush.tech/en/latest/events.html) - -When a certain event occurs (e.g. a JSON request is received, or a [Bluetooth -device is -connected](https://docs.platypush.tech/en/latest/platypush/events/bluetooth.html#platypush.message.event.bluetooth.BluetoothDeviceConnectedEvent), -or a [Flic button is -pressed](https://docs.platypush.tech/en/latest/platypush/events/button.flic.html#platypush.message.event.button.flic.FlicButtonEvent), -or some [speech is detected on the voice assistant -service](https://docs.platypush.tech/en/latest/platypush/events/assistant.html#platypush.message.event.assistant.SpeechRecognizedEvent), -or an [RSS feed has new -items](https://docs.platypush.tech/en/latest/platypush/events/http.rss.html#platypush.message.event.http.rss.NewFeedEvent), -or a [new email is -received](https://docs.platypush.tech/en/latest/platypush/events/mail.html#platypush.message.event.mail.MailReceivedEvent), -or a [new track is -played](https://docs.platypush.tech/en/latest/platypush/events/music.html#platypush.message.event.music.NewPlayingTrackEvent), -or an [NFC tag is -detected](https://docs.platypush.tech/en/latest/platypush/events/nfc.html#platypush.message.event.nfc.NFCTagDetectedEvent), -or [new sensor data is -available](https://docs.platypush.tech/en/latest/platypush/events/sensor.html#platypush.message.event.sensor.SensorDataChangeEvent), -or [a value of a Zigbee device -changes](https://docs.platypush.tech/en/latest/platypush/events/zigbee.mqtt.html#platypush.message.event.zigbee.mqtt.ZigbeeMqttDevicePropertySetEvent), -etc.), the associated backend will trigger an -[event](https://docs.platypush.tech/en/latest/events.html). - -### Hooks - -Event hooks are custom pieces of logic that will be run when a certain event is -triggered. Hooks are the glue that connects events to actions, exposing a -paradigm similar to IFTTT (_if a certain event happens then run these -actions_). They can declared as: - -- Sections of the [`config.yaml`](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/config.yaml). - Example: - -```yaml -event.hook.SearchSongVoiceCommand: - if: - type: platypush.message.event.assistant.SpeechRecognizedEvent - phrase: "play ${title} by ${artist}" - then: - - action: music.mpd.clear - - action: music.mpd.search - args: - filter: - artist: ${artist} - title: ${title} - - - if ${len(output)}: - - action: music.mpd.play - args: - resource: ${output[0]['file']} -``` - -- Stand-alone Python scripts stored under `~/.config/platypush/scripts` and - will be dynamically imported at start time. - [Example](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/hook.py): - -```python -from platypush.event.hook import hook -from platypush.utils import run -from platypush.message.event.assistant import SpeechRecognizedEvent - -@hook(SpeechRecognizedEvent, phrase='play ${title} by ${artist}') -def on_music_play_command(event, title=None, artist=None, **context): - results = run('music.mpd.search', filter={ - 'artist': artist, - 'title': title, - }) - - if results: - run('music.mpd.play', results[0]['file']) -``` - -### Procedures - -Procedures are pieces of custom logic that can be executed as atomic actions -using `procedure.` as an action name. - -They can be defined either in the `config.yaml` or as Python scripts stored -under `~/.config/platypush/scripts` - provided that the procedure is also -imported in `~/.config/platypush/scripts/__init__.py` so it can be discovered -by the service. - -YAML example for a procedure that can be executed when we arrive home and turns -on the lights if the luminosity is lower that a certain thresholds, says a -welcome home message using the TTS engine and starts playing the music: - -```yaml -procedure.at_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 - - if ${int(light or 0) < 110}: - - action: light.hue.on - - # Say a welcome home message - - action: tts.google.say - args: - text: Welcome home - - # Play the music - - action: music.mpd.play -``` - -Python example: - -```python - # Content of ~/.config/platypush/scripts/home.py -from platypush.procedure import procedure -from platypush.utils import run - -@procedure -def at_home(**context): - sensor_data = run('gpio.sensor.ltr559.get_data') - if sensor_data['light'] < 110: - run('light.hue.on') - - run('tts.google.say', text='Welcome home') - run('music.mpd.play') -``` - -In either case, you can easily trigger the at-home procedure by sending an -action request message to a backend - for example, over the HTTP backend: - -```shell -curl -XPOST -H 'Content-Type: application/json' \ - -H "Authorization: Bearer $YOUR_TOKEN" -d ' - { - "type": "request", - "action": "procedure.at_home" - }' http://host:8008/execute -``` - -### Cronjobs - -Cronjobs are pieces of logic that will be run at regular intervals, expressed -in crontab-compatible syntax. They can be defined either in the `config.yaml` -or as Python scripts stored under `~/.config/platypush/scripts` as functions -labelled by the `@cron` decorator. - -Note that seconds are also supported (unlike the standard crontab definition), -but, for back-compatibility with the standard crontab format, they are at the -end of the cron expression, so the expression is actually in the format -` `. - -YAML example for a cronjob that is executed every 30 seconds and checks if a -Bluetooth device is nearby: - -```yaml -cron.check_bt_device: - cron_expression: '* * * * * */30' - actions: - - action: bluetooth.lookup_name - args: - addr: XX:XX:XX:XX:XX:XX - - - if ${name}: - - action: procedure.on_device_on - - else: - - action: procedure.on_device_off -``` - -Python example: - -```python - # Content of ~/.config/platypush/scripts/bt_cron.py -from platypush.cron import cron -from platypush.utils import run - -@cron('* * * * * */30') -def check_bt_device(**context): - name = run('bluetooth.lookup_name').get('name') - if name: - # on_device_on logic here - else: - # on_device_off logic here -``` - -### The web interface - -If -[`backend.http`](https://docs.platypush.tech/en/latest/platypush/backend/http.html) -is enabled then a web interface will be provided by default on -`http://host:8008/`. Besides using the `/execute` endpoint for running -requests, the built-in web server also provides a full-featured interface that -groups together the controls for most of the plugins - e.g. sensors, switches, -music controls and search, media library and torrent management, lights, -Zigbee/Z-Wave devices and so on. The UI is responsive and mobile-friendly. - -The web service also provides means for the user to create [custom -dashboards](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/dashboard.xml) -that can be used to show information from multiple sources on a large screen. +- ...and much more (basically, anything that comes with a [Platypush plugin](https://docs.platypush.tech)) ## Installation @@ -435,10 +122,10 @@ that can be used to show information from multiple sources on a large screen. Platypush uses Redis to deliver and store requests and temporary messages: ```yaml - # Example for Debian-based distributions +# Example for Debian-based distributions [sudo] apt-get install redis-server - # Enable and start the service +# Enable and start the service [sudo] systemctl enable redis [sudo] systemctl start redis ``` @@ -475,7 +162,7 @@ or tags. git clone https://git.platypush.tech/platypush/platypush.git cd platypush [sudo] pip install . - # Or +# Or [sudo] python3 setup.py install ``` @@ -489,7 +176,7 @@ ways to check the dependencies required by an extension: All the extensions that require extra dependencies are listed in the [`extras_require` section under -`setup.py`](https://git.platypush.tech/platypush/platypush/-/blob/master/setup.py#L72). +`setup.py`](https://git.platypush.tech/platypush/platypush/src/branch/master/setup.py#L84). #### Install via `manifest.yaml` @@ -532,7 +219,7 @@ platypush It's advised to run it as a systemd service though - simply copy the provided [`.service` -file](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/systemd/platypush.service) +file](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/systemd/platypush.service) to `~/.config/systemd/user`, check if the path of `platypush` matches the path where it's installed on your system, and start the service via `systemctl`: @@ -613,6 +300,336 @@ directory in the same folder as the `config.yaml`. [Wiki instructions](https://git.platypush.tech/platypush/platypush/wiki/Run-platypush-in-a-container) +## Architecture + +The architecture of Platypush consists of a few simple pieces, orchestrated by +a configuration file stored by default under +[`~/.config/platypush/config.yaml`](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/config.yaml): + +### Plugins + +[Full list](https://docs.platypush.tech/en/latest/plugins.html) + +Plugins are integrations that do things - like [modify +files](https://docs.platypush.tech/en/latest/platypush/plugins/file.html), +[train and evaluate machine learning +models](https://docs.platypush.tech/en/latest/platypush/plugins/tensorflow.html), +[control +cameras](https://docs.platypush.tech/en/latest/platypush/plugins/camera.pi.html), +[read +sensors](https://docs.platypush.tech/en/latest/platypush/plugins/gpio.sensor.dht.html), +[parse a web +page](https://docs.platypush.tech/en/latest/platypush/plugins/http.webpage.html), +[control +lights](https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html), +[send +emails](https://docs.platypush.tech/en/latest/platypush/plugins/mail.smtp.html), +[control +Chromecasts](https://docs.platypush.tech/en/latest/platypush/plugins/media.chromecast.html), +[run voice +queries](https://docs.platypush.tech/en/latest/platypush/plugins/assistant.google.html), +[handle torrent +transfers](https://docs.platypush.tech/en/latest/platypush/plugins/torrent.html) +or control +[Zigbee](https://docs.platypush.tech/en/latest/platypush/plugins/zigbee.mqtt.html) +or [Z-Wave](https://docs.platypush.tech/en/latest/platypush/plugins/zwave.html) +devices. + +The configuration of a plugin matches one-on-one that of its documented class +constructor, so it's very straightforward to write a configuration for a plugin +by reading its documentation: + +```yaml +light.hue: + # Groups that will be controlled by default + groups: + - Living Room + - Hall +``` + +### Actions + +Plugins expose *actions*, that match one-on-one the plugin class methods +denoted by `@action`, so it's very straightforward to invoke plugin actions by +just reading the plugin documentation. They can be invoked directly from your +own scripts or they can be sent to the platform through any supported channel +as simple JSON messages: + +```json +{ + "type": "request", + "action": "light.hue.on", + "args": { + "lights": ["Entrance Bulb"] + } +} +``` + +### Backends + +[Full list](https://docs.platypush.tech/en/latest/backends.html) + +They are background services that listen for messages on channels (like +an [HTTP +backend](https://docs.platypush.tech/en/latest/platypush/backend/http.html), an +[MQTT +instance](https://docs.platypush.tech/en/latest/platypush/backend/mqtt.html), a +[Kafka +instance](https://docs.platypush.tech/en/latest/platypush/backend/kafka.html), +[Pushbullet](https://docs.platypush.tech/en/latest/platypush/backend/pushbullet.html) +etc.). + +If a backend supports the execution of requests (e.g. HTTP, MQTT, Kafka, +Websocket and TCP) then you can send requests to these services in JSON format. +For example, in the case of the HTTP backend: + +```shell +# Get a token +curl -XPOST -H 'Content-Type: application/json' -d ' +{ + "username": "$YOUR_USER", + "password": "$YOUR_PASSWORD" +}' http://host:8008/auth + +# Execute a request +curl -XPOST -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $YOUR_TOKEN" -d ' +{ + "type": "request", + "action": "tts.say", + "args": { + "text": "This is a test" + } +}' http://host:8008/execute +``` + +### Events + +[Full list](https://docs.platypush.tech/en/latest/events.html) + +When a certain event occurs (e.g. a JSON request is received, or a [Bluetooth +device is +connected](https://docs.platypush.tech/en/latest/platypush/events/bluetooth.html#platypush.message.event.bluetooth.BluetoothDeviceConnectedEvent), +or a [Flic button is +pressed](https://docs.platypush.tech/en/latest/platypush/events/button.flic.html#platypush.message.event.button.flic.FlicButtonEvent), +or some [speech is detected on the voice assistant +service](https://docs.platypush.tech/en/latest/platypush/events/assistant.html#platypush.message.event.assistant.SpeechRecognizedEvent), +or an [RSS feed has new +items](https://docs.platypush.tech/en/latest/platypush/events/http.rss.html#platypush.message.event.http.rss.NewFeedEvent), +or a [new email is +received](https://docs.platypush.tech/en/latest/platypush/events/mail.html#platypush.message.event.mail.MailReceivedEvent), +or a [new track is +played](https://docs.platypush.tech/en/latest/platypush/events/music.html#platypush.message.event.music.NewPlayingTrackEvent), +or an [NFC tag is +detected](https://docs.platypush.tech/en/latest/platypush/events/nfc.html#platypush.message.event.nfc.NFCTagDetectedEvent), +or [new sensor data is +available](https://docs.platypush.tech/en/latest/platypush/events/sensor.html#platypush.message.event.sensor.SensorDataChangeEvent), +or [a value of a Zigbee device +changes](https://docs.platypush.tech/en/latest/platypush/events/zigbee.mqtt.html#platypush.message.event.zigbee.mqtt.ZigbeeMqttDevicePropertySetEvent), +etc.), the associated backend will trigger an +[event](https://docs.platypush.tech/en/latest/events.html). + +### Hooks + +Event hooks are custom pieces of logic that will be run when a certain event is +triggered. Hooks are the glue that connects events to actions, exposing a +paradigm similar to IFTTT (_if a certain event happens then run these +actions_). They can declared as: + +- Sections of the [`config.yaml`](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/config.yaml). + Example: + +```yaml +event.hook.SearchSongVoiceCommand: + if: + type: platypush.message.event.assistant.SpeechRecognizedEvent + phrase: "play ${title} by ${artist}" + then: + - action: music.mpd.clear + - action: music.mpd.search + args: + filter: + artist: ${artist} + title: ${title} + + - if ${len(output)}: + - action: music.mpd.play + args: + resource: ${output[0]['file']} +``` + +- Stand-alone Python scripts stored under `~/.config/platypush/scripts` and + will be dynamically imported at start time. + [Example](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/hook.py): + +```python +from platypush.event.hook import hook +from platypush.utils import run +from platypush.message.event.assistant import SpeechRecognizedEvent + +@hook(SpeechRecognizedEvent, phrase='play ${title} by ${artist}') +def on_music_play_command(event, title=None, artist=None, **context): + results = run('music.mpd.search', filter={ + 'artist': artist, + 'title': title, + }) + + if results: + run('music.mpd.play', results[0]['file']) +``` + +### Procedures + +Procedures are pieces of custom logic that can be executed as atomic actions +using `procedure.` as an action name. + +They can be defined either in the `config.yaml` or as Python scripts stored +under `~/.config/platypush/scripts` - provided that the procedure is also +imported in `~/.config/platypush/scripts/__init__.py` so it can be discovered +by the service. + +YAML example for a procedure that can be executed when we arrive home and turns +on the lights if the luminosity is lower that a certain thresholds, says a +welcome home message using the TTS engine and starts playing the music: + +```yaml +procedure.at_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 + - if ${int(light or 0) < 110}: + - action: light.hue.on + + # Say a welcome home message + - action: tts.google.say + args: + text: Welcome home + + # Play the music + - action: music.mpd.play +``` + +Python example: + +```python +# Content of ~/.config/platypush/scripts/home.py +from platypush.procedure import procedure +from platypush.utils import run + +@procedure +def at_home(**context): + sensor_data = run('gpio.sensor.ltr559.get_data') + if sensor_data['light'] < 110: + run('light.hue.on') + + run('tts.google.say', text='Welcome home') + run('music.mpd.play') +``` + +In either case, you can easily trigger the at-home procedure by sending an +action request message to a backend - for example, over the HTTP backend: + +```shell +curl -XPOST -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $YOUR_TOKEN" -d ' +{ + "type": "request", + "action": "procedure.at_home" +}' http://host:8008/execute +``` + +### Cronjobs + +Cronjobs are pieces of logic that will be run at regular intervals, expressed +in crontab-compatible syntax. They can be defined either in the `config.yaml` +or as Python scripts stored under `~/.config/platypush/scripts` as functions +labelled by the `@cron` decorator. + +Note that seconds are also supported (unlike the standard crontab definition), +but, for back-compatibility with the standard crontab format, they are at the +end of the cron expression, so the expression is actually in the format +` `. + +YAML example for a cronjob that is executed every 30 seconds and checks if a +Bluetooth device is nearby: + +```yaml +cron.check_bt_device: + cron_expression: '* * * * * */30' + actions: + - action: bluetooth.lookup_name + args: + addr: XX:XX:XX:XX:XX:XX + + - if ${name}: + - action: procedure.on_device_on + - else: + - action: procedure.on_device_off +``` + +Python example: + +```python +# Content of ~/.config/platypush/scripts/bt_cron.py +from platypush.cron import cron +from platypush.utils import run + +@cron('* * * * * */30') +def check_bt_device(**context): + name = run('bluetooth.lookup_name').get('name') + if name: + # on_device_on logic here + else: + # on_device_off logic here +``` + +### Entities + +Entities are a fundamental building block of Platypush. Most of the +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. + +### The web interface + +If +[`backend.http`](https://docs.platypush.tech/en/latest/platypush/backend/http.html) +is enabled then a web interface will be provided by default on +`http://host:8008/`. Besides using the `/execute` endpoint for running +requests, the built-in web server also provides a full-featured interface that +groups together the controls for most of the plugins - e.g. sensors, switches, +music controls and search, media library and torrent management, lights, +Zigbee/Z-Wave devices and so on. The UI is responsive and mobile-friendly. + +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. + ## Mobile app An [official Android