187 lines
5.8 KiB
Markdown
187 lines
5.8 KiB
Markdown
Platypush
|
|
=========
|
|
|
|
Execute any command or custom complex logic on your devices, wherever they are, using your PushBullet account.
|
|
|
|
Installation
|
|
------------
|
|
|
|
```shell
|
|
pip install platypush
|
|
```
|
|
|
|
### Manual Installation
|
|
|
|
```shell
|
|
git clone https://github.com/BlackLight/platypush
|
|
cd platypush
|
|
python setup.py install
|
|
```
|
|
|
|
Configuration
|
|
-------------
|
|
|
|
Copy /etc/platypush/config.example.yaml to /etc/platypush/config.yaml (system-wise settings) or ~/.config/platypush/config.yaml (user-wise settings).
|
|
|
|
Edit the file to include:
|
|
|
|
### For the PushBullet backend
|
|
|
|
* 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)).
|
|
|
|
### For the Apache Kafka backend
|
|
|
|
* The host and port of the Kafka installation
|
|
* The topic that will be used to deliver and process messages
|
|
|
|
### For the local socket backend
|
|
|
|
* The name of the local FIFO that will be used to deliver and process messages
|
|
|
|
### device_id
|
|
|
|
Each target device is identified by a unique device_id in the messages sent over your account. The device_id is the hostname by default, unless changed in config.yaml.
|
|
|
|
Shell interface
|
|
---------------
|
|
|
|
`platypush` installs `pusher`, a command-line tool to send PushBullet messages to the connected devices in the format used by platypush.
|
|
|
|
Some examples:
|
|
|
|
```shell
|
|
pusher --target laptop --action shell.exec --cmd "scp /home/user/photos/*.jpg backup_host:/mnt/hd/photos"
|
|
pusher --target raspberrypi --action music.mpd.play
|
|
```
|
|
|
|
The logic to execute is specified by the `--action` option, whose format is `package_name.method_name` (with method_name part of the package main class).
|
|
|
|
Available plugins
|
|
-----------------
|
|
|
|
* `platypush.plugins.shell`: The simplest and yet most versatile plugin. Executes a remote command on the host identified by the `--target` device_id. Example:
|
|
|
|
```shell
|
|
pusher --target laptop --action shell.exec --cmd "scp /home/user/photos/*.jpg backup_host:/mnt/hd/photos"
|
|
```
|
|
|
|
* `platypush.plugins.music.mpd`: Controls the playback on a mpd/mopidy music server. Requires the package `mpd2` on the target machine. Example:
|
|
|
|
```shell
|
|
pusher --target raspberry --action music.mpd.play
|
|
```
|
|
|
|
Configure the plugin through an entry like this in your `config.yaml`:
|
|
|
|
```yaml
|
|
music.mpd:
|
|
host: your_mpd_host
|
|
port: 6600
|
|
```
|
|
|
|
* `platypush.plugins.switch.wemo`: Controls a WeMo Switch smart switch device. Requires the package `ouimeaux` on the target machine. Example:
|
|
|
|
```shell
|
|
pusher --target raspberry --action switch.wemo.on
|
|
```
|
|
|
|
* `platypush.plugins.light.hue`: Controls a Philips Hue smart lights system. Requires the package `phue` on the target machine. Example:
|
|
|
|
```shell
|
|
pusher --target raspberry --action light.hue.scene --name "Sunset" --group "Living Room"
|
|
```
|
|
|
|
Writing your plugins
|
|
--------------------
|
|
|
|
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
|
|
|
|
from platypush.message.response import Response
|
|
|
|
from .. import LightPlugin
|
|
|
|
class LightBatsignalPlugin(LightPlugin):
|
|
def __init__(self, intensity=100):
|
|
super().__init__()
|
|
self.batsignal = batman.Batsignal(intensity)
|
|
|
|
def on(self, urgent=False):
|
|
if urgent:
|
|
self.batsignal.notify_robin()
|
|
|
|
self.batsignal.on()
|
|
return Response(output='ok')
|
|
|
|
def off(self):
|
|
self.batsignal.off()
|
|
return Response(output='ok')
|
|
|
|
def toggle(self):
|
|
self.batsignal.toggle()
|
|
return Response(output='ok')
|
|
|
|
```
|
|
|
|
6. Rebuild and reinstall `platypush` if required and relaunch it.
|
|
|
|
7. Test your new plugin by sending some bullets to it:
|
|
|
|
```shell
|
|
pusher --target your_pc --action light.batsignal.on --urgent 1
|
|
```
|
|
|
|
Writing your backends
|
|
---------------------
|
|
|
|
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_msg` should call `self.on_msg` at the end to post a new message to the application.
|
|
|
|
7. Implement the `_send_msg` 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_msg` 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_msg(self, msg):
|
|
self.voicemail.save_msg(msg)
|
|
|
|
def run(self):
|
|
while True:
|
|
msg = self.voicemail.poll()
|
|
self.on_msg(msg)
|
|
```
|
|
|