A versatile and extensible platform for home and life automation with hundreds of supported integrations
Find a file
2017-12-27 11:29:33 +01:00
platypush Should import logging 2017-12-27 11:29:33 +01:00
tests Placed a sleep to let all the messages be received before stopping everything (TODO: make sure that all the threads are synchronized on receive_msg and stop 2017-12-25 17:23:12 +01:00
.gitignore Ignore .pypirc 2017-12-11 20:39:46 +01:00
.travis.requirements Added travis-ci files 2017-12-22 02:14:45 +01:00
.travis.yml - Version bump 2017-12-22 02:57:44 +01:00
LICENSE.txt MIT License 2017-11-03 18:06:58 +01:00
README.md Added travis-ci status to README.md 2017-12-22 03:00:05 +01:00
run_tests.sh Script name change 2017-12-22 02:18:12 +01:00
setup.cfg setup.cfg 2017-12-11 20:41:50 +01:00
setup.py Version bump 2017-12-27 10:22:30 +01:00

Platypush

Build Status

Execute any command or custom complex logic on your devices, wherever they are, using your PushBullet account.

Installation

pip install platypush

Manual Installation

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);
  • The name of the (virtual) PushBullet device used to listen for events (create one here).

For the Apache Kafka backend

  • The host and port of the Kafka installation
  • The topic 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:

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:
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:
pusher --target raspberry --action music.mpd.play

Configure the plugin through an entry like this in your config.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:
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:
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:

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')

  1. Rebuild and reinstall platypush if required and relaunch it.

  2. Test your new plugin by sending some bullets to it:

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_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:

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)