Included documentation on procedures

Fabio Manganiello 2018-07-09 02:13:40 +02:00
parent c92c443b33
commit 1955423d4e
2 changed files with 117 additions and 140 deletions

@ -46,5 +46,5 @@ After configuring the server, start it by simply running `platypush`, `python -m
**NOTE**: Platypush is only compatible with Python 3 and higher.
After installing the application, you're ready to [start configuring it](configuration) according to your needs.
After installing the application, you're ready to [start configuring it](quickstart) according to your needs.

@ -1,4 +1,5 @@
* [Quick start](#quick-start)
* [Procedures](#procedures)
* [Backends](#backends)
* [HTTP service configuration](#http-service-configuration)
* [PushBullet](#pushbullet-configuration)
@ -15,12 +16,11 @@
* [Shell plugin](#shell-plugin)
* [HTTP requests plugin](#http-requests-plugin)
* [Database plugin](#database-plugin)
* [Procedures](#procedures)
* [Event Hooks](#event-hooks)
* [Mobile notification mirroring](#mobile-notification-mirroring)
* [Include directive](#include-directive)
## Quick start
# 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://platypush.readthedocs.io/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).
@ -144,21 +144,22 @@ Event hooks:
- 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).
If you wanted to pass extra arguments to the action:
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:
```yaml
event.hook.LightsOnAssistantCommand:
event.hook.ChangeSceneAssistantCommand:
if:
type: platypush.message.event.assistant.SpeechRecognizedEvent
phrase: "turn on the lights"
phrase: "set the scene on ${scene}"
then:
action: light.hue.on
args:
groups:
- Bedroom
- Bathroom
-
action: light.hue.scene
args:
name: ${scene}
```
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.
You can also run multiple actions in the same hook:
```yaml
@ -177,10 +178,114 @@ event.hook.LightsOnAssistantCommand:
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.
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** (we'll tackle them soon).
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_.
Congratulation, you've set up your first rule! Check out the [plugins documentation](https://platypush.readthedocs.io/en/latest/plugins.html) and the [backends documentation](https://platypush.readthedocs.io/en/latest/backends.html) for the list of supported plugins and backends (_documentation for events coming soon_).
# Procedures
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.
Start by configuring the weather forecast plugin:
```yaml
weather.forecast:
lat: your_latitude
long: your_longitude
darksky_token: token # Get it from https://darksky.net/dev/register
units: si
```
Restart Platypush and test out the plugin with a curl call:
```shell
curl -XPOST -H 'Content-Type: application/json' \
-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: ${context['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
```
## 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
```
# Backends
Backend configurations start with `backend.` in the `config.yaml`.
@ -385,134 +490,6 @@ curl -XPOST -d 'msg={"type":"request","target":"hostname","action":"db.select",
{"id": null, "type": "response", "target": null, "origin": null, "response": {"output": [{"id": 1, "temperature": "21.0","created_at":"<timestamp>"}], "errors": []}}
```
# Procedures
Procedures are lists of actions that will be executed by Platypush.
A procedure can be run:
## Synchronous
Configuration name starting with `procedure.sync.`.
The actions will be executed sequentially. The return values from the previous actions can be used in the following actions as well. `output` and `errors` are special variables that will contain the output and the errors of the previous action, and the attributes of the previous responses (also JSON strings) can be accessible directly by name. Just include the context expression in `${...}`. You can also inspect the context in case of nested JSON values or transform the values through Python string functions - the expression will be eval'd by the interpreter.
```yaml
procedure.sync.say_temperature:
-
action: http.request.get
args:
# Example JSON response: {"temperature":12.0, "location":{"city":"Amsterdam", "country":"nl"}}
url: https://your-weather-channel.com/api/temperature
headers:
X-Auth-Token: TOKEN
-
action: tts.say
args:
phrase: The temperature in ${location['city']} is ${temperature}
```
`for var in list` syntax loops are also supported if you want to iterate over some returned list and perform actions on each item individually. Two syntaxes are supported: `for` (synchronous execution of the commands, context from the previous responses can be used), and `fork` (asynchronous execution, the actions will be executed in parallel and are assumed to be independent):
```yaml
procedure.sync.turn_all_lights_on:
-
action: http.request.get
args:
# Example JSON response: {"lights": [{"name":"Kitchen"}, {"name":"Living Room"}]}
url: https://your-bridge/api/lights
headers:
X-Auth-Token: TOKEN
-
fork light in ${lights}:
-
action: your.lights.plugin.on
args:
light: ${light['name']}
```
## Asynchronous
Configuration name starting with `procedure.async.`.
The actions will be executed in parallel, and the context from the response of the previous action cannot be used. Useful if you need to run a set of independent task and you want to optimize the execution time.
```yaml
procedure.async.at_home:
-
action: tts.say
args:
phrase: Welcome home, YOUR_NAME
-
action: light.hue.on
-
action: switch.wemo.on
args:
device: Heater
-
action: music.mpd.play
args:
resource: spotify:user:you:playlist:your_favourite_playlist
-
action: shell.exec
args:
cmd: './bin/sensors_report.sh'
```
# Event Hooks
Event hooks are one of the most powerful features of Platypush. They are the equivalent of a profile in Tasker, or a recipe in IFTTT. They link events received on the main bus to actions that can be triggered on the local or on a remote node. Events will usually be ignored unless you configured a hook for handling them. Their configuration names start with `event.hook.`, the condition expressed in the `if` section and the actions to execute in the `then` section. `then` can include either a single action or a list of actions. Note that the actions will be executed in parallel and therefore the context of the previously run action is not available - run a synchronous procedure in the `then` section if you want to execute multiple actions in sequence.
Some examples:
```yaml
event.hook.AssistantConversationStarted:
if:
type: platypush.message.event.assistant.ConversationStartEvent
then:
-
action: shell.exec
args:
cmd: 'aplay /usr/share/sounds/start.wav'
event.hook.LightsSceneAssistantCommand:
if:
type: platypush.message.event.assistant.SpeechRecognizedEvent
# Note: regex support (still quite experimental though) and support for
# parsing context variables out of the trigger event, that can be used
# in the executed actions. Context variables names are used as ${...}
# (escape it with \ if you want to use the literal symbol instead).
# The context variables already include the variables of the source event,
# meaning that you can use ${phrase} as well in your action for this example.
phrase: "set (the)? scene on ${name}"
then:
-
action: light.hue.scene
args:
# If you said "set the scene on sunset", name="sunset"
name: ${name}
event.hook.NextSongFlicButton:
if:
type: platypush.message.event.button.flic.FlicButtonEvent
btn_addr: 00:11:22:33:44:55
sequence:
# Lists are supported too
- ShortPressEvent
- LongPressEvent
then:
-
action: music.mpd.next
# You can also specify multiple actions
-
action: media.ctrl.forward
# Or procedures
-
action: procedure.your_proc
```
# 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.